Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooFormulaUtils.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
9 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
10 * *
11 * Copyright (c) 2000-2005, Regents of the University of California *
12 * and Stanford University. All rights reserved. *
13 * *
14 * Redistribution and use in source and binary forms, *
15 * with or without modification, are permitted according to the terms *
16 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
17 *****************************************************************************/
18
19/**
20\file RooFormulaUtils.cxx
21\ingroup Roofitcore
22
23Free functions to translate and evaluate user-defined expressions of
24RooAbsArgs. See RooFormulaUtils.h for a description of the supported
25expression dialect. To debug the formula preprocessing, activate the
26RooFit::DEBUG message level for the RooFit::InputArguments topic.
27**/
28
29#include "RooFormulaUtils.h"
30#include "RooAbsBinning.h"
31#include "RooAbsCategory.h"
32#include "RooAbsReal.h"
33#include "RooAbsRealLValue.h"
34#include "RooArgList.h"
35#include "RooCurve.h"
36#include "RooFitImplHelpers.h"
37#include "RooMsgService.h"
39
40#include "TFormula.h"
41
42#include <cassert>
43#include <cctype>
44#include <map>
45#include <memory>
46#include <regex>
47#include <sstream>
48
49using std::sregex_iterator;
50
51namespace {
52
53/// Convert `@i`-style references to `x[i]`.
54void convertArobaseReferences(std::string &formula)
55{
56 bool match = false;
57 for (std::size_t i = 0; i < formula.size(); ++i) {
58 if (match && !isdigit(formula[i])) {
59 formula.insert(formula.begin() + i, ']');
60 i += 1;
61 match = false;
62 } else if (!match && formula[i] == '@') {
63 formula[i] = 'x';
64 formula.insert(formula.begin() + i + 1, '[');
65 i += 1;
66 match = true;
67 }
68 }
69 if (match)
70 formula += ']';
71}
72
73/// Replace all occurrences of `what` with `with` inside of `inOut`.
74void replaceAll(std::string &inOut, std::string_view what, std::string_view with)
75{
76 for (std::string::size_type pos{}; inOut.npos != (pos = inOut.find(what.data(), pos, what.length()));
77 pos += with.length()) {
78 inOut.replace(pos, what.length(), with.data(), with.length());
79 }
80}
81
82/// Find the word boundaries with a static std::regex and return a bool vector
83/// flagging their positions. The end of the string is considered a word
84/// boundary.
85std::vector<bool> getWordBoundaryFlags(std::string const &s)
86{
87 static const std::regex r{"\\b"};
88 std::vector<bool> out(s.size() + 1);
89
90 for (auto i = std::sregex_iterator(s.begin(), s.end(), r); i != std::sregex_iterator(); ++i) {
91 std::smatch m = *i;
92 out[m.position()] = true;
93 }
94
95 // The end of a string is also a word boundary
96 out[s.size()] = true;
97
98 return out;
99}
100
101// Check if a RooConstVar whose name is a number (e.g. from RooFit::RooConst())
102// has a value that matches its name.
104{
105 // Extract the value from the RooAbsArg
106 std::stringstream ss;
107 ss << arg;
108 try {
109 return std::stod(arg.GetName()) == std::stod(ss.str());
110 } catch (const std::exception &) {
111 throw std::invalid_argument(std::string("RooConstVar named ") + arg.GetName() +
112 " has a name or value that cannot be converted to a valid number");
113 }
114}
115
116/// Replace all named references with "x[i]"-style.
118{
119 std::vector<bool> isWordBoundary = getWordBoundaryFlags(formula);
120 for (unsigned int i = 0; i < varList.size(); ++i) {
121 std::string_view varName = varList[i].GetName();
122
123 // If the RooAbsArg has a number as name, we perform checks
124 std::string varNameStr{varName};
125 static const std::regex pureNumberNameRegex("^\\s*\\d+(\\.\\d+)?\\s*$");
126 if (std::regex_match(varNameStr, pureNumberNameRegex)) { // Name is a number
127 // If the RooAbsArg is a RooConstVar having (double)name == value
128 // we don't perform substitution
129 if (varList[i].InheritsFrom("RooConstVar") && isNumericNameValid(varList[i])) {
130 continue;
131 } else {
132 std::stringstream exceptionSs;
133 exceptionSs << "Variable '" << varName << "' is not a valid argument for RooFormulaVar. "
134 << "Variables with a name that is a number can only be of type RooConstVar "
135 << "and have value equal to the name";
136 throw std::invalid_argument(exceptionSs.str());
137 }
138 }
139
140 std::stringstream replacementStream;
141 replacementStream << "x[" << i << "]";
142 std::string replacement = replacementStream.str();
143
144 for (std::string::size_type pos{}; formula.npos != (pos = formula.find(varName.data(), pos, varName.length()));
145 pos += replacement.size()) {
146
147 std::string::size_type next = pos + varName.length();
148
149 // The matched variable name has to be surrounded by word boundaries
150 if (!isWordBoundary[pos] || !isWordBoundary[next])
151 continue;
152
153 // Veto '[' and ']' as next characters. If the variable is called `x`
154 // or `0`, this might otherwise replace `x[0]`.
155 if (next < formula.size() && (formula[next] == '[' || formula[next] == ']')) {
156 continue;
157 }
158
159 // As we replace substrings in the middle of the string, we also have
160 // to update the word boundary flag vector. Note that we don't care
161 // the word boundaries in the `x[i]` are correct, as it has already
162 // been replaced.
163 std::size_t nOld = varName.length();
164 std::size_t nNew = replacement.size();
165 auto wbIter = isWordBoundary.begin() + pos;
166 if (nNew > nOld) {
167 isWordBoundary.insert(wbIter + nOld, nNew - nOld, false);
168 } else if (nNew < nOld) {
170 }
171
172 // Do the actual replacement
173 formula.replace(pos, varName.length(), replacement);
174 }
175
176 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
177 << "Preprocessing formula: replace named references: " << varName << " --> " << replacement << "\n\t"
178 << formula << std::endl;
179 }
180}
181
182} // namespace
183
184////////////////////////////////////////////////////////////////////////////////
185/// Process a formula by replacing all ordinal and name references by `x[i]`,
186/// where `i` matches the position of the argument in `varList`, and category
187/// state references such as `leptonMulti::one` by the category index. The
188/// caller name is used in debug and error messages.
189std::string
190RooFormulaUtils::processFormula(std::string formula, RooArgList const &varList, std::string const &callerName)
191{
192 // WARNING to developers: people use these functions a lot via RooGenericPdf
193 // and RooFormulaVar! Performance matters here. Avoid non-static
194 // std::regex, because constructing these can become a bottleneck because
195 // of the regex compilation.
196
197 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
198 << "Preprocessing formula step 1: find category tags (catName::catState) in " << formula << std::endl;
199
200 // Step 1: Find all category tags and the corresponding index numbers
201 static const std::regex categoryReg("(\\w+)::(\\w+)");
202 std::map<std::string, int> categoryStates;
205 assert(matchIt->size() == 3);
206 const std::string fullMatch = (*matchIt)[0];
207 const std::string catName = (*matchIt)[1];
208 const std::string catState = (*matchIt)[2];
209
210 const auto catVariable = dynamic_cast<const RooAbsCategory *>(varList.find(catName.c_str()));
211 if (!catVariable) {
212 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
213 << "Formula " << callerName << " uses '::' to reference a category state as '" << fullMatch
214 << "' but a category '" << catName << "' cannot be found in the input variables." << std::endl;
215 continue;
216 }
217
218 if (!catVariable->hasLabel(catState)) {
219 oocoutE(static_cast<TObject *>(nullptr), InputArguments)
220 << "Formula " << callerName << " uses '::' to reference a category state as '" << fullMatch
221 << "' but the category '" << catName << "' does not seem to have the state '" << catState << "'."
222 << std::endl;
223 throw std::invalid_argument(formula);
224 }
225 const int catNum = catVariable->lookupIndex(catState);
226
228 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
229 << "\n\t" << fullMatch << "\tname=" << catName << "\tstate=" << catState << "=" << catNum;
230 }
231 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments) << "-- End of category tags --" << std::endl;
232
233 // Step 2: Replace all category tags
234 for (const auto &catState : categoryStates) {
235 replaceAll(formula, catState.first, std::to_string(catState.second));
236 }
237
238 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
239 << "Preprocessing formula step 2: replace category tags\n\t" << formula << std::endl;
240
241 // Step 3: Convert `@i`-style references to `x[i]`
243
244 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
245 << "Preprocessing formula step 3: replace '@'-references\n\t" << formula << std::endl;
246
247 // Step 4: Replace all named references with "x[i]"-style
249
250 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments) << "Final formula:\n\t" << formula << std::endl;
251
252 return formula;
253}
254
255namespace {
256
257/// Prune the variables that a processed formula doesn't reference as `x[i]`,
258/// adding the used subset of `varList` to `actualVars` and returning the
259/// formula with the `x[i]` indices remapped to the pruned list. The remapping
260/// keeps the persisted pair (formula string, dependents) self-consistent, see
261/// https://github.com/root-project/root/issues/21371. Out-of-range references
262/// are kept as they are; they are reported when the evaluator is created.
263std::string pruneAndReindexFormula(std::string const &processedFormula, RooArgList const &varList,
265{
266 static const std::regex ordinalRegex("\\bx\\[([0-9]+)\\]");
267
268 // First pass: find out which variables are actually referenced as `x[i]`.
269 std::vector<bool> varIsUsed(varList.size());
272 const std::size_t i = std::stoi((*matchIt)[1].str());
273 if (i < varIsUsed.size()) {
274 varIsUsed[i] = true;
275 }
276 }
277
278 // Map each original index to its position among the used variables; pruned
279 // entries get -1 and are never looked up (they don't appear in the formula).
280 std::vector<int> newIndex(varList.size(), -1);
281 for (std::size_t i = 0; i < varList.size(); ++i) {
282 if (varIsUsed[i]) {
283 newIndex[i] = actualVars.size();
284 actualVars.add(varList[i]);
285 }
286 }
287
288 // Second pass: rewrite every x[old] to x[newIndex[old]].
289 std::string result;
290 result.reserve(processedFormula.size());
291 std::size_t lastPos = 0;
294 std::smatch match = *matchIt;
295 result.append(processedFormula, lastPos, match.position() - lastPos);
296 const std::size_t oldIdx = std::stoi(match[1].str());
297 result += oldIdx < newIndex.size() ? "x[" + std::to_string(newIndex[oldIdx]) + "]" : match[0].str();
298 lastPos = match.position() + match.length();
299 }
300 result.append(processedFormula, lastPos, std::string::npos);
301
302 return result;
303}
304
305} // namespace
306
307////////////////////////////////////////////////////////////////////////////////
308/// Reconstruct a user-facing formula string by replacing the index
309/// placeholders in the internal representation with the variable names, or
310/// with `fixedReplacement` if given.
311std::string
312RooFormulaUtils::reconstructFormula(std::string internalRepr, RooArgList const &args, const char *fixedReplacement)
313{
314 const auto nArgs = args.size();
315 for (unsigned int i = 0; i < nArgs; ++i) {
316 std::stringstream regexStr;
317 regexStr << "x\\[" << i << "\\]|@" << i;
318 std::regex regex(regexStr.str());
319
320 std::string replacement = fixedReplacement ? fixedReplacement : std::string("[") + args[i].GetName() + "]";
321 internalRepr = std::regex_replace(internalRepr, regex, replacement);
322 }
323
324 return internalRepr;
325}
326
327////////////////////////////////////////////////////////////////////////////////
328/// Create the evaluation engine for a processed formula, checking that the
329/// formula compiles and also fulfills the assumptions. Throws on failure,
330/// with the original formula string appearing in the error messages.
331std::unique_ptr<RooFormulaEvaluator>
332RooFormulaUtils::makeEvaluator(std::string const &name, std::string const &processedFormula,
333 std::string const &origFormula, RooArgList const &varList)
334{
335 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
336 << "RooFormula '" << name << "' will be compiled as "
337 << "\n\t" << processedFormula << "\n and used as"
338 << "\n\t" << reconstructFormula(processedFormula, varList) << "\n with the parameters " << varList << std::endl;
339
340 return std::make_unique<RooTFormulaEvaluator>(name.c_str(), processedFormula, origFormula, varList);
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// Create the evaluation engine for an unprocessed formula expression, e.g. a
345/// cut expression on a dataset, with `x[i]` in the engine referring to
346/// `varList[i]`. Unused variables are not pruned. Throws if the expression is
347/// invalid.
348std::unique_ptr<RooFormulaEvaluator>
349RooFormulaUtils::makeFormulaEvaluator(std::string const &name, std::string const &expression, RooArgList const &varList)
350{
351 return makeEvaluator(name, processFormula(expression, varList, name), expression, varList);
352}
353
354////////////////////////////////////////////////////////////////////////////////
355/// Implementation of the formula constructors of RooFormulaVar and
356/// RooGenericPdf: compile the expression currently held in `formExpr` and
357/// initialize the owner's state, pruning the variables that the expression
358/// doesn't use. Throws if the expression is invalid.
359void RooFormulaUtils::initFormula(std::unique_ptr<RooFormulaEvaluator> &evaluator, TString &formExpr,
360 RooAbsCollection &actualVars, RooArgList const &dependents, const char *name)
361{
362 const std::string processed = processFormula(formExpr.Data(), dependents, name);
364 const std::string pruned = pruneAndReindexFormula(processed, dependents, usedVars);
365 evaluator = makeEvaluator(name, pruned, formExpr.Data(), usedVars);
366 actualVars.add(usedVars);
367 formExpr = pruned.c_str();
368}
369
370////////////////////////////////////////////////////////////////////////////////
371/// Return an owner's formula evaluation engine, creating it on the fly if it
372/// doesn't exist yet (i.e. after being read from file). The expression is
373/// normalized to the `x[i]` dialect in the process, as old files may store it
374/// with name or ordinal references. Throws if the formula is invalid.
375RooFormulaEvaluator &RooFormulaUtils::ensureEvaluator(std::unique_ptr<RooFormulaEvaluator> &evaluator,
377 const char *name)
378{
379 if (!evaluator) {
380 std::string processed = processFormula(formExpr.Data(), actualVars, name);
381 evaluator = makeEvaluator(name, processed, formExpr.Data(), actualVars);
382 formExpr = processed.c_str();
383 }
384 return *evaluator;
385}
386
387////////////////////////////////////////////////////////////////////////////////
388/// Clone a formula evaluation engine, renaming the copied TFormula (if any)
389/// after the possibly-different name of the new owner.
390std::unique_ptr<RooFormulaEvaluator> RooFormulaUtils::cloneEvaluator(RooFormulaEvaluator const &other,
391 const char *newName)
392{
393 std::unique_ptr<RooFormulaEvaluator> out = other.clone();
394 if (TFormula *tFormula = out->getTFormula()) {
395 tFormula->SetName(newName);
396 }
397 return out;
398}
399
400////////////////////////////////////////////////////////////////////////////////
401/// Evaluate a formula for the current values of the variables: all variables
402/// are evaluated given the normalisation set, and then the formula is
403/// evaluated with `x[i]` taking the value of the i-th variable.
404double
405RooFormulaUtils::evalFormula(RooFormulaEvaluator const &evaluator, RooAbsCollection const &vars, RooArgSet const *nset)
406{
407 std::vector<double> pars;
408 pars.reserve(vars.size());
409 for (RooAbsArg const *arg : vars) {
410 if (arg->isCategory()) {
411 auto const &cat = static_cast<RooAbsCategory const &>(*arg);
412 pars.push_back(cat.getCurrentIndex());
413 } else {
414 auto const &real = static_cast<RooAbsReal const &>(*arg);
415 pars.push_back(real.getVal(nset));
416 }
417 }
418
419 return evaluator.eval(pars.data());
420}
421
422////////////////////////////////////////////////////////////////////////////////
423/// Evaluate a formula for a batch of input values from the evaluation context,
424/// with `x[i]` taking the values of the i-th variable in `actualVars`.
425void RooFormulaUtils::doEvalFormula(RooFormulaEvaluator const &evaluator, RooArgList const &actualVars,
427{
428 std::span<double> output = ctx.output();
429
430 const std::size_t nPars = actualVars.size();
431 // Note: emplace_back() instead of assignment into a pre-sized vector,
432 // because the custom std::span backport for C++ < 20 in ROOT/span.hxx is
433 // not move-assignable.
434 std::vector<std::span<const double>> inputSpans;
435 inputSpans.reserve(nPars);
436 for (std::size_t i = 0; i < nPars; ++i) {
437 inputSpans.emplace_back(ctx.at(static_cast<const RooAbsReal *>(&actualVars[i])));
438 }
439
440 std::vector<double> pars(nPars);
441 for (std::size_t i = 0; i < output.size(); ++i) {
442 for (std::size_t j = 0; j < nPars; ++j) {
443 pars[j] = inputSpans[j].size() > 1 ? inputSpans[j][i] : inputSpans[j][0];
444 }
445 output[i] = evaluator.eval(pars.data());
446 }
447}
448
449////////////////////////////////////////////////////////////////////////////////
450/// Print info about a compiled formula to the given stream.
451void RooFormulaUtils::printFormula(std::ostream &os, TString indent, std::string const &formula,
452 RooArgList const &actualVars)
453{
454 os << indent << "--- RooFormula ---" << std::endl;
455 os << indent << " Formula: '" << formula << "'" << std::endl;
456 os << indent << " Interpretation: '" << reconstructFormula(formula, actualVars) << "'" << std::endl;
457 indent.Append(" ");
458 os << indent << "Servers: " << actualVars << std::endl;
459}
460
461////////////////////////////////////////////////////////////////////////////////
462/// Deep-clone a map of user-defined binnings.
463RooFormulaUtils::BinningMap RooFormulaUtils::cloneBinnings(BinningMap const &binnings)
464{
465 BinningMap out;
466 for (auto const &item : binnings) {
467 out[item.first] = std::unique_ptr<RooAbsBinning>{item.second->clone()};
468 }
469 return out;
470}
471
472////////////////////////////////////////////////////////////////////////////////
473/// Declare a binning in which `caller` is piecewise constant (flat); see
474/// RooGenericPdf::setBinning() for details.
475void RooFormulaUtils::setBinning(BinningMap &binnings, RooAbsReal const &caller, RooArgList const &actualVars,
476 const char *formExpr, RooAbsRealLValue const &obs, RooAbsBinning const &binning,
477 bool checkFlatness)
478{
479 // Match the observable to a formula variable by name, so that a same-named
480 // stand-in for the actual server is accepted too.
481 const int idx = actualVars.index(obs.GetName());
482 if (idx < 0) {
483 oocoutE(&caller, InputArguments) << caller.ClassName() << "::setBinning(" << caller.GetName()
484 << ") the observable " << obs.GetName()
485 << " is not one of the formula variables, nothing done." << std::endl;
486 return;
487 }
488
489 if (checkFlatness) {
490 // Sample the function by varying the actual formula variable (the server),
491 // which may be a different object than `obs` if `obs` is just a same-named
492 // stand-in: the function's value depends on the server, not on `obs`.
493 if (auto *serverObs = dynamic_cast<RooAbsRealLValue *>(actualVars.at(idx))) {
494 std::span<const double> boundaries{binning.array(), static_cast<std::size_t>(binning.numBoundaries())};
496 oocoutE(&caller, InputArguments)
497 << caller.ClassName() << "::setBinning(" << caller.GetName() << ") the expression \"" << formExpr
498 << "\" is not flat within the given bins of " << obs.GetName()
499 << ". The binning is not set. Pass checkFlatness=false to override this check." << std::endl;
500 return;
501 }
502 }
503 }
504
505 // Key the binning by the observable's index in the formula variables (not
506 // its name), so that it survives a renaming of the variable or a server
507 // redirection.
508 binnings[idx] = std::unique_ptr<RooAbsBinning>{binning.clone()};
509}
510
511////////////////////////////////////////////////////////////////////////////////
512/// Return the binning declared with setBinning() for observable `obs` (which
513/// is matched to a formula variable by name), or nullptr.
514const RooAbsBinning *
515RooFormulaUtils::getBinning(BinningMap const &binnings, RooArgList const &actualVars, RooAbsRealLValue const &obs)
516{
517 auto found = binnings.find(actualVars.index(obs.GetName()));
518 return found != binnings.end() ? found->second.get() : nullptr;
519}
520
521////////////////////////////////////////////////////////////////////////////////
522/// Return true if a binning was declared for every observable in the
523/// integration set `obs`.
524bool RooFormulaUtils::isBinnedDistribution(BinningMap const &binnings, RooArgList const &actualVars,
525 RooArgSet const &obs)
526{
527 if (obs.empty() || binnings.empty()) {
528 return false;
529 }
530 for (RooAbsArg *o : obs) {
531 const int idx = actualVars.index(o->GetName());
532 // Observables that are not formula variables are ones the caller does
533 // not depend on: the function is constant (hence trivially binned) in
534 // them, so they must be ignored here. This matches the convention that
535 // composite functions like RooProduct rely on, where each component's
536 // isBinnedDistribution() is queried with the full observable set.
537 if (idx < 0) {
538 continue;
539 }
540 if (binnings.find(idx) == binnings.end()) {
541 return false;
542 }
543 }
544 return true;
545}
546
547////////////////////////////////////////////////////////////////////////////////
548/// Return the boundaries of the declared binning that fall within [xlo, xhi],
549/// or a null pointer if no binning was declared for this observable.
550std::list<double> *RooFormulaUtils::binBoundaries(BinningMap const &binnings, RooArgList const &actualVars,
551 RooAbsRealLValue const &obs, double xlo, double xhi)
552{
553 auto found = binnings.find(actualVars.index(obs.GetName()));
554 if (found == binnings.end()) {
555 return nullptr;
556 }
557 const RooAbsBinning &binning = *found->second;
558 auto hint = new std::list<double>;
559 for (int i = 0; i < binning.numBoundaries(); ++i) {
560 const double boundary = binning.array()[i];
561 if (boundary >= xlo && boundary <= xhi) {
562 hint->push_back(boundary);
563 }
564 }
565 return hint;
566}
567
568////////////////////////////////////////////////////////////////////////////////
569/// Return sampling hints that draw the piecewise-flat shape exactly, or a
570/// null pointer if no binning was declared for this observable.
571std::list<double> *RooFormulaUtils::plotSamplingHint(BinningMap const &binnings, RooArgList const &actualVars,
572 RooAbsRealLValue const &obs, double xlo, double xhi)
573{
574 const RooAbsBinning *binning = getBinning(binnings, actualVars, obs);
575 if (!binning) {
576 return nullptr;
577 }
579 {binning->array(), static_cast<std::size_t>(binning->numBoundaries())}, xlo, xhi);
580}
581
582/// \endcond
#define oocxcoutD(o, a)
#define oocoutE(o, a)
static void indent(ostringstream &buf, int indent_level)
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 char Point_t Rectangle_t WindowAttributes_t Float_t r
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 result
char name[80]
Definition TGX11.cxx:142
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
virtual bool isCategory() const
Definition RooAbsArg.h:522
Abstract base class for RooRealVar binning definitions.
virtual Int_t numBoundaries() const =0
virtual double * array() const =0
virtual RooAbsBinning * clone(const char *name=nullptr) const =0
A space to attach TBranches.
Abstract container object that can hold multiple RooAbsArg objects.
const char * GetName() const override
Returns name of object.
Storage_t::size_type size() const
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
static std::list< double > * plotSamplingHintForBinBoundaries(std::span< const double > boundaries, double xlo, double xhi)
Returns sampling hints for a histogram with given boundaries.
Definition RooCurve.cxx:897
The Formula class.
Definition TFormula.h:89
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
Basic string class.
Definition TString.h:138
void replaceAll(std::string &inOut, std::string_view what, std::string_view with)
bool isFunctionFlatInBins(const RooAbsReal &function, RooAbsRealLValue &obs, std::span< const double > boundaries, double relTol=1e-9)
Check that function is constant (flat) inside each bin defined by the sorted boundaries when scanning...
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8