34void replaceAll(std::string &str,
const std::string &from,
const std::string &to)
39 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
40 str.replace(start_pos, from.length(), to);
41 start_pos += to.length();
49namespace Experimental {
53 :
RooAbsReal{
name, title}, _params{
"!params",
"List of parameters", this}, _useEvaluator{useEvaluator}
56 _absReal = std::make_unique<RooEvaluatorWrapper>(obj,
const_cast<RooAbsData *
>(
data),
false,
"", simPdf,
false);
66 if (!param->isConstant()) {
67 floatingParamSet.
add(*param);
85 _params(
"!params", this, other._params),
86 _funcName(other._funcName),
89 _hasGradient(other._hasGradient),
90 _gradientVarBuffer(other._gradientVarBuffer),
91 _observables(other._observables)
99 std::stack<std::vector<double>> vectorBuffers;
100 std::map<RooFit::Detail::DataKey, std::span<const double>> spans;
103 spans = RooFit::Detail::BatchModeDataHelpers::getDataSpans(*
data,
"", simPdf,
true,
false, vectorBuffers);
107 for (
auto const &item : spans) {
108 std::size_t
n = item.second.size();
111 for (std::size_t i = 0; i <
n; ++i) {
118 for (
auto *param : paramSet) {
120 std::stringstream errorMsg;
121 errorMsg <<
"In creation of function " << GetName()
122 <<
" wrapper: input param expected to be of type RooAbsReal.";
124 throw std::runtime_error(errorMsg.str().c_str());
126 if (spans.find(param) == spans.end()) {
130 _gradientVarBuffer.resize(_params.size());
133 _nodeOutputSizes = RooFit::Detail::BatchModeDataHelpers::determineOutputSizes(
135 auto found = spans.find(key);
136 return found != spans.end() ? found->second.size() : -1;
141std::string RooFuncWrapper::declareFunction(std::string
const &funcBody)
143 static int iFuncWrapper = 0;
144 auto funcName =
"roo_func_wrapper_" + std::to_string(iFuncWrapper++);
147 std::stringstream bodyWithSigStrm;
148 bodyWithSigStrm <<
"double " << funcName <<
"(double* params, double const* obs, double const* xlArr) {\n"
149 << funcBody <<
"\n}";
150 _collectedFunctions.emplace_back(funcName);
151 if (!
gInterpreter->Declare(bodyWithSigStrm.str().c_str())) {
152 std::stringstream errorMsg;
153 errorMsg <<
"Function " << funcName <<
" could not be compiled. See above for details.";
155 throw std::runtime_error(errorMsg.str().c_str());
160void RooFuncWrapper::createGradient()
162 std::string gradName = _funcName +
"_grad_0";
163 std::string requestName = _funcName +
"_req";
166 gInterpreter->Declare(
"#include <Math/CladDerivator.h>\n");
169 std::stringstream requestFuncStrm;
170 requestFuncStrm <<
"#pragma clad ON\n"
171 "void " << requestName <<
"() {\n"
172 " clad::gradient(" << _funcName <<
", \"params\");\n"
176 if (!
gInterpreter->Declare(requestFuncStrm.str().c_str())) {
177 std::stringstream errorMsg;
178 errorMsg <<
"Function " << GetName() <<
" could not be differentiated. See above for details.";
180 throw std::runtime_error(errorMsg.str().c_str());
183 _grad =
reinterpret_cast<Grad>(
gInterpreter->ProcessLine((gradName +
";").c_str()));
187void RooFuncWrapper::gradient(
double *out)
const
189 updateGradientVarBuffer();
190 std::fill(out, out + _params.size(), 0.0);
192 _grad(_gradientVarBuffer.data(), _observables.data(), _xlArr.data(), out);
195void RooFuncWrapper::updateGradientVarBuffer()
const
197 std::transform(_params.begin(), _params.end(), _gradientVarBuffer.begin(),
198 [](
RooAbsArg *obj) { return static_cast<RooAbsReal *>(obj)->getVal(); });
201double RooFuncWrapper::evaluate()
const
204 return _absReal->getVal();
205 updateGradientVarBuffer();
207 return _func(_gradientVarBuffer.data(), _observables.data(), _xlArr.data());
210void RooFuncWrapper::gradient(
const double *
x,
double *
g)
const
212 std::fill(
g,
g + _params.size(), 0.0);
214 _grad(
const_cast<double *
>(
x), _observables.data(), _xlArr.data(),
g);
224 ctx.
addResult(param,
"params[" + std::to_string(idx) +
"]");
228 for (
auto const &item : _obsInfos) {
229 const char *
name = item.first->GetName();
233 if (item.second.size == 1) {
234 ctx.
addResult(
name,
"obs[" + std::to_string(item.second.idx) +
"]");
245void RooFuncWrapper::writeDebugMacro(std::string
const &
filename)
const
247 std::stringstream allCode;
248 std::set<std::string> seenFunctions;
251 for (std::string
const &
name : _collectedFunctions) {
252 if (seenFunctions.count(
name) > 0) {
255 seenFunctions.insert(
name);
256 std::unique_ptr<TInterpreterValue>
v =
gInterpreter->MakeInterpreterValue();
258 std::string s =
v->ToString();
259 for (
int i = 0; i < 2; ++i) {
260 s = s.erase(0, s.find(
"\n") + 1);
262 allCode << s << std::endl;
265 std::ofstream outFile;
267 outFile << R
"(//auto-generated test macro
268#include <RooFit/Detail/MathFuncs.h>
269#include <Math/CladDerivator.h>
271#pragma cling optimize(2)
275void gradient_request() {
277 << _funcName << R"(, "params");
282 updateGradientVarBuffer();
284 auto writeVector = [&](std::string
const &
name, std::span<const double>
vec) {
285 std::stringstream decl;
286 decl <<
"std::vector<double> " <<
name <<
" = {";
287 for (std::size_t i = 0; i <
vec.size(); ++i) {
291 if (i <
vec.size() - 1)
296 std::string declStr = decl.str();
298 replaceAll(declStr,
"inf",
"std::numeric_limits<double>::infinity()");
299 replaceAll(declStr,
"nan",
"NAN");
304 outFile <<
"// clang-format off\n" << std::endl;
305 writeVector(
"parametersVec", _gradientVarBuffer);
306 outFile << std::endl;
307 writeVector(
"observablesVec", _observables);
308 outFile << std::endl;
309 writeVector(
"auxConstantsVec", _xlArr);
310 outFile << std::endl;
311 outFile <<
"// clang-format on\n" << std::endl;
314// To run as a ROOT macro
318 std::vector<double> gradientVec(parametersVec.size());
320 auto func = [&](std::span<double> params) {
322 << _funcName << R"((params.data(), observablesVec.data(), auxConstantsVec.data());
324 auto grad = [&](std::span<double> params, std::span<double> out) {
326 << _funcName << R"(_grad_0(parametersVec.data(), observablesVec.data(), auxConstantsVec.data(),
330 grad(parametersVec, gradientVec);
332 auto numDiff = [&](int i) {
333 const double eps = 1e-6;
334 std::vector<double> p{parametersVec};
335 p[i] = parametersVec[i] - eps;
336 double funcValDown = func(p);
337 p[i] = parametersVec[i] + eps;
338 double funcValUp = func(p);
339 return (funcValUp - funcValDown) / (2 * eps);
342 for (std::size_t i = 0; i < parametersVec.size(); ++i) {
343 std::cout << i << ":" << std::endl;
344 std::cout << " numr : " << numDiff(i) << std::endl;
345 std::cout << " clad : " << gradientVec[i] << std::endl;
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Common abstract base class for objects that represent a value and a "shape" in RooFit.
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Abstract base class for binned and unbinned datasets.
Abstract base class for objects that represent a real value and implements functionality common to al...
RooArgSet is a container object that can hold multiple RooAbsArg objects.
A class to maintain the context for squashing of RooFit models into code.
std::string assembleCode(std::string const &returnExpr)
Assemble and return the final code with the return expression and global statements.
void addResult(RooAbsArg const *key, std::string const &value)
A function to save an expression that includes/depends on the result of the input node.
void addVecObs(const char *key, int idx)
Since the squashed code represents all observables as a single flattened array, it is important to ke...
std::string const & getResult(RooAbsArg const &arg)
Gets the result for the given node using the node name.
A wrapper class to store a C++ function of type 'double (*)(double*, double*)'.
double(*)(double *, double const *, double const *) Func
std::unique_ptr< RooAbsReal > _absReal
std::string buildCode(RooAbsReal const &head)
std::vector< double > _observables
void loadParamsAndData(RooAbsArg const *head, RooArgSet const ¶mSet, const RooAbsData *data, RooSimultaneous const *simPdf)
std::map< RooFit::Detail::DataKey, ObsInfo > _obsInfos
void(*)(double *, double const *, double const *, double *) Grad
std::string declareFunction(std::string const &funcBody)
RooFuncWrapper(const char *name, const char *title, RooAbsReal &obj, const RooAbsData *data=nullptr, RooSimultaneous const *simPdf=nullptr, bool useEvaluator=false)
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...