Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CodegenContext.h
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Garima Singh, CERN 2023
5 * Jonas Rembser, CERN 2023
6 *
7 * Copyright (c) 2023, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
14#ifndef RooFit_Detail_CodegenContext_h
15#define RooFit_Detail_CodegenContext_h
16
17#include <RooAbsCollection.h>
18#include <RooFit/EvalContext.h>
19
20#include <ROOT/RSpan.hxx>
21
22#include <cstddef>
23#include <iomanip>
24#include <map>
25#include <sstream>
26#include <string>
27#include <type_traits>
28#include <unordered_map>
29
30template <class T>
32
33namespace RooFit {
34namespace Experimental {
35
36template <int P>
37struct Prio {
38 static_assert(P >= 1 && P <= 10, "P must be 1 <= P <= 10!");
39 static auto next() { return Prio<P + 1>{}; }
40};
41
44
45/// @brief A class to maintain the context for squashing of RooFit models into code.
47public:
48 void addResult(RooAbsArg const *key, std::string const &value);
49 void addResult(const char *key, std::string const &value);
50
51 std::string const &getResult(RooAbsArg const &arg);
52
53 template <class T>
54 std::string const &getResult(RooTemplateProxy<T> const &key)
55 {
56 return getResult(key.arg());
57 }
58
59 /// @brief Figure out the output size of a node. It is the size of the
60 /// vector observable that it depends on, or 1 if it doesn't depend on any
61 /// or is a reducer node.
62 /// @param key The node to look up the size for.
63 std::size_t outputSize(RooFit::Detail::DataKey key) const
64 {
65 auto found = _nodeOutputSizes.find(key);
66 if (found != _nodeOutputSizes.end())
67 return found->second;
68 return 1;
69 }
70
71 void addToGlobalScope(std::string const &str);
72 void addVecObs(const char *key, int idx);
73 int observableIndexOf(const RooAbsArg &arg) const;
74
75 void addToCodeBody(RooAbsArg const *klass, std::string const &in);
76
77 void addToCodeBody(std::string const &in, bool isScopeIndep = false);
78
79 /// @brief Build the code to call the function with name `funcname`, passing some arguments.
80 /// The arguments can either be doubles or some RooFit arguments whose
81 /// results will be looked up in the context.
82 template <typename... Args_t>
83 std::string buildCall(std::string const &funcname, Args_t const &...args)
84 {
85 std::stringstream ss;
86 ss << funcname << "(" << buildArgs(args...) << ")";
87 return ss.str();
88 }
89
90 /// @brief A class to manage loop scopes using the RAII technique. To wrap your code around a loop,
91 /// simply place it between a brace inclosed scope with a call to beginLoop at the top. For e.g.
92 /// {
93 /// auto scope = ctx.beginLoop({<-set of vector observables to loop over->});
94 /// // your loop body code goes here.
95 /// }
96 class LoopScope {
97 public:
98 LoopScope(CodegenContext &ctx, std::vector<TNamed const *> &&vars) : _ctx{ctx}, _vars{vars} {}
99 ~LoopScope() { _ctx.endLoop(*this); }
100
101 std::vector<TNamed const *> const &vars() const { return _vars; }
102
103 private:
105 const std::vector<TNamed const *> _vars;
106 };
107
108 std::unique_ptr<LoopScope> beginLoop(RooAbsArg const *in);
109
110 std::string getTmpVarName() const;
111
112 std::string buildArg(RooAbsCollection const &x);
113
114 std::string buildArg(std::span<const double> arr);
115 std::string buildArg(std::span<const int> arr) { return buildArgSpanImpl(arr); }
116
117 std::vector<double> const &xlArr() { return _xlArr; }
118
119 void collectFunction(std::string const &name);
120 std::vector<std::string> const &collectedFunctions() { return _collectedFunctions; }
121
122 std::string
123 buildFunction(RooAbsArg const &arg, std::map<RooFit::Detail::DataKey, std::size_t> const &outputSizes = {});
124
125 auto const &outputSizes() const { return _nodeOutputSizes; }
126
127 struct ScopeRAII {
128 std::string _fn;
131
132 public:
133 ScopeRAII(RooAbsArg const *arg, CodegenContext &ctx);
134 ~ScopeRAII();
135 };
136 ScopeRAII OutputScopeRangeComment(RooAbsArg const *arg) { return {arg, *this}; }
137
138private:
139 void pushScope();
140 void popScope();
141 template <class T>
142 std::string buildArgSpanImpl(std::span<const T> arr);
143
144 bool isScopeIndependent(RooAbsArg const *in) const;
145
146 void endLoop(LoopScope const &scope);
147
148 void addResult(TNamed const *key, std::string const &value);
149
150 template <class T, typename std::enable_if<std::is_floating_point<T>{}, bool>::type = true>
151 std::string buildArg(T x)
152 {
153 std::stringstream ss;
154 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << x;
155 return ss.str();
156 }
157
158 // If input is integer, we want to print it into the code like one (i.e. avoid the unnecessary '.0000').
159 template <class T, typename std::enable_if<std::is_integral<T>{}, bool>::type = true>
160 std::string buildArg(T x)
161 {
162 return std::to_string(x);
163 }
164
165 std::string buildArg(std::string const &x) { return x; }
166
167 std::string buildArg(std::nullptr_t) { return "nullptr"; }
168
169 std::string buildArg(RooAbsArg const &arg) { return getResult(arg); }
170
171 template <class T>
172 std::string buildArg(RooTemplateProxy<T> const &arg)
173 {
174 return getResult(arg);
175 }
176
177 std::string buildArgs() { return ""; }
178
179 template <class Arg_t>
180 std::string buildArgs(Arg_t const &arg)
181 {
182 return buildArg(arg);
183 }
184
185 template <typename Arg_t, typename... Args_t>
186 std::string buildArgs(Arg_t const &arg, Args_t const &...args)
187 {
188 return buildArg(arg) + ", " + buildArgs(args...);
189 }
190
191 template <class T>
192 std::string typeName() const;
193
194 /// @brief Map of node names to their result strings.
195 std::unordered_map<const TNamed *, std::string> _nodeNames;
196 /// @brief A map to keep track of the observable indices if they are non scalar.
197 std::unordered_map<const TNamed *, int> _vecObsIndices;
198 /// @brief Map of node output sizes.
199 std::map<RooFit::Detail::DataKey, std::size_t> _nodeOutputSizes;
200 /// @brief The code layered by lexical scopes used as a stack.
201 std::vector<std::string> _code;
202 /// @brief The indentation level for pretty-printing.
203 unsigned _indent = 0;
204 /// @brief Index to get unique names for temporary variables.
205 mutable int _tmpVarIdx = 0;
206 /// @brief A map to keep track of list names as assigned by addResult.
207 std::unordered_map<RooFit::UniqueId<RooAbsCollection>::Value_t, std::string> _listNames;
208 std::vector<double> _xlArr;
209 std::vector<std::string> _collectedFunctions;
210};
211
212template <>
213inline std::string CodegenContext::typeName<double>() const
214{
215 return "double";
216}
217template <>
218inline std::string CodegenContext::typeName<int>() const
219{
220 return "int";
221}
222
223template <class T>
224std::string CodegenContext::buildArgSpanImpl(std::span<const T> arr)
225{
226 unsigned int n = arr.size();
227 std::string arrName = getTmpVarName();
228 std::stringstream ss;
229 ss << typeName<T>() << " " << arrName << "[" << n << "] = {";
230 for (unsigned int i = 0; i < n; i++) {
231 ss << " " << arr[i] << ",";
232 }
233 std::string arrDecl = ss.str();
234 arrDecl.back() = '}';
235 arrDecl += ";\n";
236 addToCodeBody(arrDecl, true);
237
238 return arrName;
239}
240
241void declareDispatcherCode(std::string const &funcName);
242
243void codegen(RooAbsArg &arg, CodegenContext &ctx);
244
245} // namespace Experimental
246} // namespace RooFit
247
248#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
Abstract container object that can hold multiple RooAbsArg objects.
A class to manage loop scopes using the RAII technique.
std::vector< TNamed const * > const & vars() const
const std::vector< TNamed const * > _vars
LoopScope(CodegenContext &ctx, std::vector< TNamed const * > &&vars)
A class to maintain the context for squashing of RooFit models into code.
std::string buildArgs(Arg_t const &arg)
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.
std::string const & getResult(RooTemplateProxy< T > const &key)
void collectFunction(std::string const &name)
Register a function that is only know to the interpreter to the context.
std::string buildArg(std::string const &x)
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::map< RooFit::Detail::DataKey, std::size_t > _nodeOutputSizes
Map of node output sizes.
std::string buildFunction(RooAbsArg const &arg, std::map< RooFit::Detail::DataKey, std::size_t > const &outputSizes={})
Assemble and return the final code with the return expression and global statements.
void endLoop(LoopScope const &scope)
std::vector< std::string > _collectedFunctions
bool isScopeIndependent(RooAbsArg const *in) const
std::vector< std::string > _code
The code layered by lexical scopes used as a stack.
std::string buildArgSpanImpl(std::span< const T > arr)
unsigned _indent
The indentation level for pretty-printing.
std::string buildArg(std::span< const int > arr)
std::string buildCall(std::string const &funcname, Args_t const &...args)
Build the code to call the function with name funcname, passing some arguments.
std::string buildArg(std::nullptr_t)
std::vector< std::string > const & collectedFunctions()
std::unordered_map< const TNamed *, std::string > _nodeNames
Map of node names to their result strings.
std::size_t outputSize(RooFit::Detail::DataKey key) const
Figure out the output size of a node.
ScopeRAII OutputScopeRangeComment(RooAbsArg const *arg)
std::string buildArg(RooAbsCollection const &x)
Function to save a RooListProxy as an array in the squashed code.
std::string buildArg(RooTemplateProxy< T > const &arg)
int _tmpVarIdx
Index to get unique names for temporary variables.
std::vector< double > const & xlArr()
std::string buildArg(RooAbsArg const &arg)
std::string buildArgs(Arg_t const &arg, Args_t const &...args)
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
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...
Definition CodegenImpl.h:67
ScopeRAII(RooAbsArg const *arg, CodegenContext &ctx)