26#include <unordered_map>
30bool startsWith(std::string_view str, std::string_view prefix)
32 return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
76 throw std::runtime_error(
"You requested the result of a vector observable outside a loop scope for it!");
139 std::string indent_str =
"";
140 for (
unsigned i = 0; i <
_indent; ++i)
142 indented = indented.
Prepend(indent_str);
150 if (
_code.size() > 2 && isScopeIndep) {
153 _code.back() += indented;
163 unsigned loopLevel =
_code.size() - 2;
164 std::string idx =
"loopIdx" + std::to_string(loopLevel);
166 std::vector<TNamed const *> vars;
172 int firstObsIdx = -1;
177 vars.push_back(it.first);
178 _nodeNames[it.first] =
"obs[static_cast<int>(obs[" + std::to_string(2 * it.second) +
"]) + " + idx +
"]";
179 if (firstObsIdx == -1) {
180 firstObsIdx = it.second;
184 if (firstObsIdx == -1) {
185 throw std::runtime_error(
"Trying to loop over variables that are not observables!");
190 addToCodeBody(in,
"for(int " + idx +
" = 0; " + idx +
" < obs[" + std::to_string(2 * firstObsIdx + 1) +
"]; " + idx +
193 return std::make_unique<LoopScope>(*
this, std::move(vars));
201 for (
auto const &ptr : scope.
vars()) {
226 std::strtod(valueToSave.c_str(), &end);
227 bool isNumeric = (*end ==
'\0');
229 const bool hasOperations = valueToSave.find_first_of(
":-+/*") != std::string::npos;
233 if (hasOperations || isNumeric) {
234 std::string outVarDecl =
"const double " + savedName +
" = " + valueToSave +
";\n";
237 savedName = valueToSave;
257 bool canSaveOutside =
true;
259 std::stringstream declStrm;
260 declStrm << arrayType <<
" " << savedName <<
"[]{";
261 for (
const auto arg : in) {
265 declStrm.seekp(-1, declStrm.cur);
276 unsigned int n = arr.size();
277 std::string offset = std::to_string(
_xlArr.size());
279 for (
unsigned int i = 0; i <
n; i++) {
282 return "xlArr + " + offset;
287 std::ostringstream os;
291 const std::string info =
"// Begin -- " +
_fn;
298 const std::string info =
"// End -- " +
_fn +
"\n";
310 std::string active_scope =
_code.back();
312 _code.back() += active_scope;
347 static int iCodegen = 0;
348 auto funcName =
"roo_codegen_" + std::to_string(iCodegen++);
351 std::string funcBody = ctx.
getResult(arg);
353 funcBody = ctx.
_code[0] +
"\n return " + funcBody +
";\n";
356 std::stringstream bodyWithSigStrm;
357 bodyWithSigStrm <<
"double " << funcName <<
"(double* params, double const* obs, double const* xlArr) {\n"
358 <<
"constexpr double inf = std::numeric_limits<double>::infinity();\n"
359 << funcBody <<
"\n}\n\n";
372 std::string dispatcherCode = R
"(
374namespace Experimental {
376template <class Arg_t, int P>
377auto FUNC_NAME(Arg_t &arg, CodegenContext &ctx, Prio<P> p)
379 if constexpr (std::is_same<Prio<P>, PrioLowest>::value) {
380 return FUNC_NAME(arg, ctx);
382 return FUNC_NAME(arg, ctx, p.next());
386template <class Arg_t>
387struct Caller_FUNC_NAME {
389 static auto call(RooAbsArg &arg, CodegenContext &ctx)
391 return FUNC_NAME(static_cast<Arg_t &>(arg), ctx, PrioHighest{});
395} // namespace Experimental
405 static bool codeDeclared =
false;
411 using Func = void (*)(
RooAbsArg &, CodegenContext &);
418 static std::unordered_map<TClass *, Func> dispatchMap;
420 auto found = dispatchMap.find(tclass);
422 if (found != dispatchMap.end()) {
423 func = found->second;
426 std::stringstream cmd;
427 cmd <<
"&RooFit::Experimental::Caller_codegenImpl<" << tclass->
GetName() <<
">::call;";
428 func =
reinterpret_cast<Func
>(
gInterpreter->ProcessLine(cmd.str().c_str()));
429 dispatchMap[tclass] = func;
432 return func(arg, ctx);
bool startsWith(std::string_view str, std::string_view prefix)
const char Option_t
Option string (const char).
Common abstract base class for objects that represent a value and a "shape" in RooFit.
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
TClass * IsA() const override
const TNamed * namePtr() const
De-duplicated pointer to this object's name.
virtual bool isReducerNode() const
Abstract container object that can hold multiple RooAbsArg objects.
RooFit::UniqueId< RooAbsCollection > const & uniqueId() const
Returns a unique ID that is different for every instantiated RooAbsCollection.
A class to manage loop scopes using the RAII technique.
std::vector< TNamed const * > const & vars() const
A class to maintain the context for squashing of RooFit models into code.
std::unordered_map< RooFit::UniqueId< RooAbsCollection >::Value_t, std::string > _listNames
A map to keep track of list names as assigned by addResult.
void addToGlobalScope(std::string const &str)
Adds the given string to the string block that will be emitted at the top of the squashed function.
std::string const & getResult(RooAbsArg const &arg)
Gets the result for the given node using the node name.
std::string getTmpVarName() const
Get a unique variable name to be used in the generated code.
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 addToCodeBody(RooAbsArg const *klass, std::string const &in)
Adds the input string to the squashed code body.
std::unique_ptr< LoopScope > beginLoop(RooAbsArg const *in)
Create a RAII scope for iterating over vector observables.
void collectFunction(std::string const &name)
Register a function that is only know to the interpreter to the context.
std::vector< double > _xlArr
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::unordered_map< const TNamed *, int > _vecObsIndices
A map to keep track of the observable indices if they are non scalar.
int observableIndexOf(const RooAbsArg &arg) const
std::string buildArg(RooAbsCollection const &x, std::string const &arrayType="double")
Function to save a RooListProxy as an array in the squashed code.
void endLoop(LoopScope const &scope)
std::unordered_set< RooFit::Detail::DataKey > _dependsOnData
Indicate whether a node depends on the dataset.
std::vector< std::string > _collectedFunctions
std::string _collectedCode
bool isScopeIndependent(RooAbsArg const *in) const
std::vector< std::string > _code
The code layered by lexical scopes used as a stack.
unsigned _indent
The indentation level for pretty-printing.
std::string buildFunction(RooAbsArg const &arg, std::unordered_set< RooFit::Detail::DataKey > const &dependsOnData={})
Assemble and return the final code with the return expression and global statements.
std::unordered_map< const TNamed *, std::string > _nodeNames
Map of node names to their result strings.
auto const & dependsOnData() const
ScopeRAII OutputScopeRangeComment(RooAbsArg const *arg)
int _tmpVarIdx
Index to get unique names for temporary variables.
static const TNamed * known(const char *stringPtr)
If the name is already known, return its TNamed pointer. Otherwise return 0 (don't register the name)...
virtual void printStream(std::ostream &os, Int_t contents, StyleOption style, TString indent="") const
Print description of object on ostream, printing contents set by contents integer,...
TClass instances represent classes, structs and namespaces in the ROOT type system.
The TNamed class is the base class for all named ROOT classes.
const char * GetName() const override
Returns name of object.
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
TString & Prepend(const char *cs)
void replaceAll(std::string &inOut, std::string_view what, std::string_view with)
void declareDispatcherCode(std::string const &funcName)
void codegen(RooAbsArg &arg, CodegenContext &ctx)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
ScopeRAII(RooAbsArg const *arg, CodegenContext &ctx)
constexpr Value_t value() const
Return numerical value of ID.