Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooFormula.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 RooFormula.cxx
21\class RooFormula
22\ingroup Roofitcore
23
24Internally uses ROOT's TFormula to compute user-defined expressions of RooAbsArgs.
25
26The string expression can be any valid TFormula expression referring to the
27listed servers either by name or by their ordinal list position. These three are
28forms equivalent:
29```
30 RooFormula("formula", "x*y", RooArgList(x,y)) or
31 RooFormula("formula", "@0*@1", RooArgList(x,y))
32 RooFormula("formula", "x[0]*x[1]", RooArgList(x,y))
33```
34Note that `x[i]` is an expression reserved for TFormula. If a variable with
35the name `x` is given, the RooFormula interprets `x` as a variable name,
36but `x[i]` as an index in the list of variables.
37
38### Category expressions
39State information of RooAbsCategories can be accessed using the '::' operator,
40*i.e.*, `tagCat::Kaon` will resolve to the numerical value of
41the `Kaon` state of the RooAbsCategory object named `tagCat`.
42
43A formula to switch between lepton categories could look like this:
44```
45 RooFormula("formulaWithCat",
46 "x * (leptonMulti == leptonMulti::one) + y * (leptonMulti == leptonMulti::two)",
47 RooArgList(x, y, leptonMulti));
48```
49
50### Debugging a formula that won't compile
51When the formula is preprocessed, RooFit can print information in the debug stream.
52These can be retrieved by activating the RooFit::MsgLevel `RooFit::DEBUG`
53and the RooFit::MsgTopic `RooFit::InputArguments`.
54Check the tutorial rf506_msgservice.C for details.
55**/
56
57#include "RooFormula.h"
58#include "RooAbsReal.h"
59#include "RooAbsCategory.h"
60#include "RooArgList.h"
61#include "RooMsgService.h"
62#include "RooBatchCompute.h"
63
64#include "TObjString.h"
65
66#include <memory>
67#include <regex>
68#include <sstream>
69#include <cctype>
70
71using std::sregex_iterator, std::ostream;
72
73namespace {
74
75/// Convert `@i`-style references to `x[i]`.
76void convertArobaseReferences(std::string &formula)
77{
78 bool match = false;
79 for (std::size_t i = 0; i < formula.size(); ++i) {
80 if (match && !isdigit(formula[i])) {
81 formula.insert(formula.begin() + i, ']');
82 i += 1;
83 match = false;
84 } else if (!match && formula[i] == '@') {
85 formula[i] = 'x';
86 formula.insert(formula.begin() + i + 1, '[');
87 i += 1;
88 match = true;
89 }
90 }
91 if (match)
92 formula += ']';
93}
94
95/// Replace all occurrences of `what` with `with` inside of `inOut`.
96void replaceAll(std::string &inOut, std::string_view what, std::string_view with)
97{
98 for (std::string::size_type pos{}; inOut.npos != (pos = inOut.find(what.data(), pos, what.length()));
99 pos += with.length()) {
100 inOut.replace(pos, what.length(), with.data(), with.length());
101 }
102}
103
104/// Find the word boundaries with a static std::regex and return a bool vector
105/// flagging their positions. The end of the string is considered a word
106/// boundary.
107std::vector<bool> getWordBoundaryFlags(std::string const &s)
108{
109 static const std::regex r{"\\b"};
110 std::vector<bool> out(s.size() + 1);
111
112 for (auto i = std::sregex_iterator(s.begin(), s.end(), r); i != std::sregex_iterator(); ++i) {
113 std::smatch m = *i;
114 out[m.position()] = true;
115 }
116
117 // The end of a string is also a word boundary
118 out[s.size()] = true;
119
120 return out;
121}
122
123// Receiving a RooConstVar as parameter having a numeric value as name, checks if the numeric value
124// of the name is equal to the value of the RooConstVar
125//
126// E.g.
127// RooConstVar("2.1", "const1", 2.1) returns true
128// RooConstVar("3.4", "const2", 2.1) returns false
130{
131 // Extract the value from the RooAbsArg
132 std::stringstream ss;
133 ss << _rooAbsArg;
134 double nameValue, actualValue;
135 try {
136 nameValue = std::stod(_rooAbsArg.GetName());
137 actualValue = std::stod(ss.str());
138 } catch (const std::invalid_argument &) {
139 std::stringstream ssExc;
140 ssExc << "RooConstVar named " << _rooAbsArg.GetName() << " has name or value that "
141 << "cannot be converted to number";
142 throw std::invalid_argument(ssExc.str());
143 } catch (const std::out_of_range &) {
144 std::stringstream ssExc;
145 ssExc << "RooConstVar named " << _rooAbsArg.GetName() << " has numeric name or value that "
146 << "gets out of a double range";
147 throw std::out_of_range(ssExc.str());
148 }
149
150 return nameValue == actualValue;
151}
152
153/// Replace all named references with "x[i]"-style.
154void replaceVarNamesWithIndexStyle(std::string &formula, RooArgList const &varList)
155{
156 std::vector<bool> isWordBoundary = getWordBoundaryFlags(formula);
157 for (unsigned int i = 0; i < varList.size(); ++i) {
158 std::string_view varName = varList[i].GetName();
159
160 // If the RooAbsArg has a number as name, we perform checks
161 std::string varNameStr{varName};
162 static const std::regex pureNumberNameRegex("^\\s*\\d+(\\.\\d+)?\\s*$");
163 if (std::regex_match(varNameStr, pureNumberNameRegex)) { // Name is a number
164 // Get class name
165 std::stringstream classNameSs;
166 varList[i].printClassName(classNameSs);
167 // If the RooAbsArg is a RooConstVar having (double)name == value
168 // we don't perform substitution
169 if (classNameSs.str() == "RooConstVar" && isNumericNameValid(varList[i])) {
170 continue;
171 } else {
172 std::stringstream exceptionSs;
173 exceptionSs << "Variable '" << varName << "' is not a valid argument for RooFormulaVar. "
174 << "Variables with a name that is a number can only be of type RooConstVar "
175 << "and have value equal to the name";
176 throw std::invalid_argument(exceptionSs.str());
177 }
178 }
179
180 std::stringstream replacementStream;
181 replacementStream << "x[" << i << "]";
182 std::string replacement = replacementStream.str();
183
184 for (std::string::size_type pos{}; formula.npos != (pos = formula.find(varName.data(), pos, varName.length()));
185 pos += replacement.size()) {
186
187 std::string::size_type next = pos + varName.length();
188
189 // The matched variable name has to be surrounded by word boundaries
190 // std::cout << pos << " " << next << std::endl;
191 if (!isWordBoundary[pos] || !isWordBoundary[next])
192 continue;
193
194 // Veto '[' and ']' as next characters. If the variable is called `x`
195 // or `0`, this might otherwise replace `x[0]`.
196 if (next < formula.size() && (formula[next] == '[' || formula[next] == ']')) {
197 continue;
198 }
199
200 // As we replace substrings in the middle of the string, we also have
201 // to update the word boundary flag vector. Note that we don't care
202 // the word boundaries in the `x[i]` are correct, as it has already
203 // been replaced.
204 std::size_t nOld = varName.length();
205 std::size_t nNew = replacement.size();
206 auto wbIter = isWordBoundary.begin() + pos;
207 if (nNew > nOld) {
208 isWordBoundary.insert(wbIter + nOld, nNew - nOld, false);
209 } else if (nNew < nOld) {
211 }
212
213 // Do the actual replacement
214 formula.replace(pos, varName.length(), replacement);
215 }
216
217 oocxcoutD(static_cast<TObject *>(nullptr), InputArguments)
218 << "Preprocessing formula: replace named references: " << varName << " --> " << replacement << "\n\t"
219 << formula << std::endl;
220 }
221}
222
223////////////////////////////////////////////////////////////////////////////////
224/// From the internal representation, construct a formula by replacing all index place holders
225/// with the names of the variables that are being used to evaluate it, and return it as string.
226std::string reconstructFormula(std::string internalRepr, RooArgList const& args) {
227 const auto nArgs = args.size();
228 for (unsigned int i = 0; i < nArgs; ++i) {
229 const auto& var = args[i];
230 std::stringstream regexStr;
231 regexStr << "x\\[" << i << "\\]|@" << i;
232 std::regex regex(regexStr.str());
233
234 std::string replacement = std::string("[") + var.GetName() + "]";
235 internalRepr = std::regex_replace(internalRepr, regex, replacement);
236 }
237
238 return internalRepr;
239}
240
241////////////////////////////////////////////////////////////////////////////////
242/// From the internal representation, construct a null-formula by replacing all
243/// index place holders with zeroes, and return it as string
244std::string reconstructNullFormula(std::string internalRepr, RooArgList const& args) {
245 const auto nArgs = args.size();
246 for (unsigned int i = 0; i < nArgs; ++i) {
247 std::stringstream regexStr;
248 regexStr << "x\\[" << i << "\\]|@" << i;
249 std::regex regex(regexStr.str());
250
251 std::string replacement = "1e-18";
252 internalRepr = std::regex_replace(internalRepr, regex, replacement);
253 }
254
255 return internalRepr;
256}
257
258}
259
260////////////////////////////////////////////////////////////////////////////////
261/// Construct a new formula.
262/// \param[in] name Name of the formula.
263/// \param[in] formula Formula to be evaluated. Parameters/observables are identified by name
264/// or ordinal position in `varList`.
265/// \param[in] varList List of variables to be passed to the formula.
266/// \param[in] checkVariables Unused parameter.
267RooFormula::RooFormula(const char *name, const char *formula, const RooArgList &varList, bool /*checkVariables*/)
268 : TNamed(name, formula)
269{
270 _origList.add(varList);
271 _varIsUsed.resize(varList.size());
272
273 installFormulaOrThrow(formula);
274
275 if (_tFormula == nullptr)
276 return;
277
278 const std::string processedFormula(_tFormula->GetTitle());
279
280 std::set<unsigned int> matchedOrdinals;
281 static const std::regex newOrdinalRegex("\\bx\\[([0-9]+)\\]");
284 assert(matchIt->size() == 2);
285 std::stringstream matchString((*matchIt)[1]);
286 unsigned int i;
287 matchString >> i;
288
289 matchedOrdinals.insert(i);
290 }
291
292 for (unsigned int i : matchedOrdinals) {
293 _varIsUsed[i] = true;
294 }
295}
296
297////////////////////////////////////////////////////////////////////////////////
298/// Copy constructor
299RooFormula::RooFormula(const RooFormula& other, const char* name) :
300 TNamed(name ? name : other.GetName(), other.GetTitle()),
302{
303 _origList.add(other._origList);
304
305 std::unique_ptr<TFormula> newTF;
306 if (other._tFormula) {
307 newTF = std::make_unique<TFormula>(*other._tFormula);
308 newTF->SetName(GetName());
309 }
310
311 _tFormula = std::move(newTF);
312}
313
314////////////////////////////////////////////////////////////////////////////////
315/// Process given formula by replacing all ordinal and name references by
316/// `x[i]`, where `i` matches the position of the argument in `_origList`.
317/// Further, references to category states such as `leptonMulti:one` are replaced
318/// by the category index.
319std::string RooFormula::processFormula(std::string formula) const {
320
321 // WARNING to developers: people use RooFormula a lot via RooGenericPdf and
322 // RooFormulaVar! Performance matters here. Avoid non-static std::regex,
323 // because constructing these can become a bottleneck because of the regex
324 // compilation.
325
326 cxcoutD(InputArguments) << "Preprocessing formula step 1: find category tags (catName::catState) in "
327 << formula << std::endl;
328
329 // Step 1: Find all category tags and the corresponding index numbers
330 static const std::regex categoryReg("(\\w+)::(\\w+)");
331 std::map<std::string, int> categoryStates;
332 for (sregex_iterator matchIt = sregex_iterator(formula.begin(), formula.end(), categoryReg);
334 assert(matchIt->size() == 3);
335 const std::string fullMatch = (*matchIt)[0];
336 const std::string catName = (*matchIt)[1];
337 const std::string catState = (*matchIt)[2];
338
339 const auto catVariable = dynamic_cast<const RooAbsCategory*>(_origList.find(catName.c_str()));
340 if (!catVariable) {
341 cxcoutD(InputArguments) << "Formula " << GetName() << " uses '::' to reference a category state as '" << fullMatch
342 << "' but a category '" << catName << "' cannot be found in the input variables." << std::endl;
343 continue;
344 }
345
346 if (!catVariable->hasLabel(catState)) {
347 coutE(InputArguments) << "Formula " << GetName() << " uses '::' to reference a category state as '" << fullMatch
348 << "' but the category '" << catName << "' does not seem to have the state '" << catState << "'." << std::endl;
349 throw std::invalid_argument(formula);
350 }
351 const int catNum = catVariable->lookupIndex(catState);
352
354 cxcoutD(InputArguments) << "\n\t" << fullMatch << "\tname=" << catName << "\tstate=" << catState << "=" << catNum;
355 }
356 cxcoutD(InputArguments) << "-- End of category tags --"<< std::endl;
357
358 // Step 2: Replace all category tags
359 for (const auto& catState : categoryStates) {
360 replaceAll(formula, catState.first, std::to_string(catState.second));
361 }
362
363 cxcoutD(InputArguments) << "Preprocessing formula step 2: replace category tags\n\t" << formula << std::endl;
364
365 // Step 3: Convert `@i`-style references to `x[i]`
367
368 cxcoutD(InputArguments) << "Preprocessing formula step 3: replace '@'-references\n\t" << formula << std::endl;
369
370 // Step 4: Replace all named references with "x[i]"-style
372
373 cxcoutD(InputArguments) << "Final formula:\n\t" << formula << std::endl;
374
375 return formula;
376}
377
378////////////////////////////////////////////////////////////////////////////////
379/// Analyse internal formula to find out which variables are actually in use.
380RooArgList RooFormula::usedVariables() const {
381 RooArgList useList;
382
383 for (std::size_t i = 0; i < _varIsUsed.size(); ++i) {
384 if (_varIsUsed[i]) {
385 useList.add(_origList[i]);
386 }
387 }
388
389 return useList;
390}
391
392////////////////////////////////////////////////////////////////////////////////
393/// Reindex the formula expression to map only the variables that are actually in use.
394/// Return the processed formula string with the `x[i]` positional indices
395/// remapped to each variable's position in usedVariables() (the pruned list of
396/// actually-used servers) instead of the full original list. This keeps the
397/// persisted pair (formula string, actualDependents()) self-consistent, so a
398/// RooFormulaVar or RooGenericPdf survives a write/read cycle even when unused
399/// parameters were pruned. See https://github.com/root-project/root/issues/21371
400/// \return A new formula string with reindexed variable placeholders.
401std::string RooFormula::reindexedFormulaForUsedVars() const
402{
403 const std::string processedFormula(_tFormula->GetTitle());
404
405 int unUsedCount = 0;
406 std::vector<int> newIndex;
407 newIndex.reserve(_varIsUsed.size());
408 // Map each original index to its position among the used variables;
409 // pruned entries get -1 and are never looked up (they don't appear in the formula).
410 for (std::size_t i = 0; i < _varIsUsed.size(); ++i) {
411 if (!_varIsUsed[i]) {
412 unUsedCount++;
413 newIndex.push_back(-1);
414 } else {
415 newIndex.push_back(static_cast<int>(i) - unUsedCount);
416 }
417 }
418
419 static const std::regex newOrdinalRegex("\\bx\\[([0-9]+)\\]");
420
421 std::string result;
422 std::size_t lastPos = 0;
423 result.reserve(processedFormula.size());
424 // Single pass: rewrite every x[old] to x[newIndex[old]].
427 std::smatch match = *matchIt;
428
429 result.append(processedFormula, lastPos, match.position() - lastPos);
430 const int oldIdx = std::stoi(match[1].str());
431 result += "x[" + std::to_string(newIndex[oldIdx]) + "]";
432
433 lastPos = match.position() + match.length();
434 }
435 result.append(processedFormula, lastPos, std::string::npos);
436
437 return result;
438}
439
440////////////////////////////////////////////////////////////////////////////////
441/// Change used variables to those with the same name in given list.
442/// \param[in] newDeps New dependents to replace the old ones.
443/// \param[in] mustReplaceAll Will yield an error if one dependent does not have a replacement.
444/// \param[in] nameChange Passed down to RooAbsArg::findNewServer(const RooAbsCollection&, bool) const.
445bool RooFormula::changeDependents(const RooAbsCollection& newDeps, bool mustReplaceAll, bool nameChange)
446{
447 //Change current servers to new servers with the same name given in list
448 bool errorStat = false;
449
450 // We only consider the usedVariables() for replacement, because only these
451 // are registered as servers.
452 for (const auto arg : usedVariables()) {
453 RooAbsReal* replace = static_cast<RooAbsReal*>(arg->findNewServer(newDeps,nameChange)) ;
454 if (replace) {
455 _origList.replace(*arg, *replace);
456
457 if (arg->getStringAttribute("origName")) {
458 replace->setStringAttribute("origName",arg->getStringAttribute("origName")) ;
459 } else {
460 replace->setStringAttribute("origName",arg->GetName()) ;
461 }
462
463 } else if (mustReplaceAll) {
464 coutE(LinkStateMgmt) << __func__ << ": cannot find replacement for " << arg->GetName() << std::endl;
465 errorStat = true;
466 }
467 }
468
469 return errorStat;
470}
471
472////////////////////////////////////////////////////////////////////////////////
473/// Evaluate the internal TFormula.
474///
475/// First, all variables serving this instance are evaluated given the normalisation set,
476/// and then the formula is evaluated.
477/// \param[in] nset Normalisation set passed to evaluation of arguments serving values.
478/// \return The result of the evaluation.
479double RooFormula::eval(const RooArgSet* nset) const
480{
481 if (!_tFormula) {
482 coutF(Eval) << __func__ << " (" << GetName() << "): Formula didn't compile: " << GetTitle() << std::endl;
483 std::string what = "Formula ";
484 what += GetTitle();
485 what += " didn't compile.";
486 throw std::runtime_error(what);
487 }
488
489 std::vector<double> pars;
490 pars.reserve(_origList.size());
491 for (unsigned int i = 0; i < _origList.size(); ++i) {
492 if (_origList[i].isCategory()) {
493 const auto& cat = static_cast<RooAbsCategory&>(_origList[i]);
494 pars.push_back(cat.getCurrentIndex());
495 } else {
496 const auto& real = static_cast<RooAbsReal&>(_origList[i]);
497 pars.push_back(real.getVal(nset));
498 }
499 }
500
501 return _tFormula->EvalPar(pars.data());
502}
503
504void RooFormula::doEval(RooArgList const &actualVars, RooFit::EvalContext &ctx) const
505{
506 std::span<double> output = ctx.output();
507
508 const int nPars = _origList.size();
509 std::vector<std::span<const double>> inputSpans(nPars);
510 int iActual = 0;
511 for (int i = 0; i < nPars; i++) {
512 if(_varIsUsed[i]) {
513 std::span<const double> rhs = ctx.at(static_cast<const RooAbsReal *>(&actualVars[iActual]));
514 inputSpans[i] = rhs;
515 ++iActual;
516 }
517 }
518
519 std::vector<double> pars(nPars);
520 for (size_t i = 0; i < output.size(); i++) {
521 for (int j = 0; j < nPars; j++) {
522 pars[j] = inputSpans[j].size() > 1 ? inputSpans[j][i] : inputSpans[j][0];
523 }
524 output[i] = _tFormula->EvalPar(pars.data());
525 }
526}
527
528////////////////////////////////////////////////////////////////////////////////
529/// Printing interface
530
531void RooFormula::printMultiline(ostream& os, Int_t /*contents*/, bool /*verbose*/, TString indent) const
532{
533 os << indent << "--- RooFormula ---" << std::endl;
534 os << indent << " Formula: '" << GetTitle() << "'" << std::endl;
535 os << indent << " Interpretation: '" << reconstructFormula(GetTitle(), _origList) << "'" << std::endl;
536 indent.Append(" ");
537 os << indent << "Servers: " << _origList << "\n";
538 os << indent << "In use : " << actualDependents() << std::endl;
539}
540
541////////////////////////////////////////////////////////////////////////////////
542/// Check that the formula compiles, and also fulfills the assumptions.
543///
544void RooFormula::installFormulaOrThrow(const std::string& formula) {
545 const std::string processedFormula = processFormula(formula);
546
547 cxcoutD(InputArguments) << "RooFormula '" << GetName() << "' will be compiled as "
548 << "\n\t" << processedFormula
549 << "\n and used as"
551 << "\n with the parameters " << _origList << std::endl;
552
553 auto theFormula = std::make_unique<TFormula>(GetName(), processedFormula.c_str(), /*addToGlobList=*/false);
554
555 if (!theFormula || !theFormula->IsValid()) {
556 std::stringstream msg;
557 msg << "RooFormula '" << GetName() << "' did not compile or is invalid."
558 << "\nInput:\n\t" << formula
559 << "\nPassed over to TFormula:\n\t" << processedFormula << std::endl;
560 coutF(InputArguments) << msg.str();
561 throw std::runtime_error(msg.str());
562 }
563
564 if (theFormula && theFormula->GetNdim() != 0) {
565 TFormula nullFormula{"nullFormula", reconstructNullFormula(processedFormula, _origList).c_str(), /*addToGlobList=*/false};
566 const auto nullDim = nullFormula.GetNdim();
567 if (nullDim != 0) {
568 // TFormula thinks that we have an n-dimensional formula (n>0), but it shouldn't, as
569 // these vars should have been replaced by zeroes in reconstructNullFormula
570 // since RooFit only uses the syntax x[0], x[1], x[2], ...
571 // This can happen e.g. with variables x,y,z,t that were not supplied in arglist.
572 std::stringstream msg;
573 msg << "TFormula interprets the formula " << formula << " as " << theFormula->GetNdim()+nullDim << "-dimensional with undefined variable(s) {";
574 for (auto i=0; i < nullDim; ++i) {
575 msg << nullFormula.GetVarName(i) << ",";
576 }
577 msg << "}, which could not be supplied by RooFit."
578 << "\nThe formula must be modified, or those variables must be supplied in the list of variables." << std::endl;
579 coutF(InputArguments) << msg.str();
580 throw std::invalid_argument(msg.str());
581 }
582 }
583
584 _tFormula = std::move(theFormula);
585}
586
587/// \endcond
#define cxcoutD(a)
#define oocxcoutD(o, a)
#define coutF(a)
#define coutE(a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
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:148
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
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
A space to attach TBranches.
Abstract container object that can hold multiple RooAbsArg objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
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
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
std::span< double > output()
The Formula class.
Definition TFormula.h:89
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
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)
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8