Logo ROOT  
Reference Guide
TFormula.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Author: Maciej Zimnoch 30/09/2013
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "TROOT.h"
13#include "TBuffer.h"
14#include "TMethod.h"
15#include "TMath.h"
16#include "TF1.h"
17#include "TMethodCall.h"
18#include <TBenchmark.h>
19#include "TError.h"
20#include "TInterpreter.h"
21#include "TInterpreterValue.h"
22#include "TFormula.h"
23#include "TRegexp.h"
24
25#include "ROOT/StringUtils.hxx"
26
27#include <array>
28#include <cassert>
29#include <iostream>
30#include <unordered_map>
31#include <functional>
32#include <set>
33#include <sstream>
34
35using namespace std;
36
37#ifdef WIN32
38#pragma optimize("",off)
39#endif
40#include "v5/TFormula.h"
41
43
44/** \class TFormula TFormula.h "inc/TFormula.h"
45 \ingroup Hist
46 The Formula class
47
48 This is a new version of the TFormula class based on Cling.
49 This class is not 100% backward compatible with the old TFormula class, which is still available in ROOT as
50 `ROOT::v5::TFormula`. Some of the TFormula member functions available in version 5, such as
51 `Analyze` and `AnalyzeFunction` are not available in the new TFormula.
52 On the other hand formula expressions which were valid in version 5 are still valid in TFormula version 6
53
54 This class has been implemented during Google Summer of Code 2013 by Maciej Zimnoch.
55
56 ### Example of valid expressions:
57
58 - `sin(x)/x`
59 - `[0]*sin(x) + [1]*exp(-[2]*x)`
60 - `x + y**2`
61 - `x^2 + y^2`
62 - `[0]*pow([1],4)`
63 - `2*pi*sqrt(x/y)`
64 - `gaus(0)*expo(3) + ypol3(5)*x`
65 - `gausn(0)*expo(3) + ypol3(5)*x`
66 - `gaus(x, [0..2]) + expo(y, [3..4])`
67
68 In the last examples above:
69
70 - `gaus(0)` is a substitute for `[0]*exp(-0.5*((x-[1])/[2])**2)`
71 and (0) means start numbering parameters at 0
72 - `gausn(0)` is a substitute for `[0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))`
73 and (0) means start numbering parameters at 0
74 - `expo(3)` is a substitute for `exp([3]+[4]*x)`
75 - `pol3(5)` is a substitute for `par[5]+par[6]*x+par[7]*x**2+par[8]*x**3`
76 (`PolN` stands for Polynomial of degree N)
77 - `gaus(x, [0..2])` is a more explicit way of writing `gaus(0)`
78 - `expo(y, [3..4])` is a substitute for `exp([3]+[4]*y)`
79
80 See below the [full list of predefined functions](\ref FormulaFuncs) which can be used as shortcuts in
81 TFormula.
82
83 `TMath` functions can be part of the expression, eg:
84
85 - `TMath::Landau(x)*sin(x)`
86 - `TMath::Erf(x)`
87
88 Formula may contain constants, eg:
89
90 - `sqrt2`
91 - `e`
92 - `pi`
93 - `ln10`
94 - `infinity`
95
96 and more.
97
98 Formulas may also contain other user-defined ROOT functions defined with a
99 TFormula, eg, where `f1` is defined on one x-dimension and 2 parameters:
100
101 - `f1(x, [omega], [phi])`
102 - `f1([0..1])`
103 - `f1([1], [0])`
104 - `f1(y)`
105
106 To replace only parameter names, the dimension variable can be dropped.
107 Alternatively, to change only the dimension variable, the parameters can be
108 dropped. Note that if a parameter is dropped or keeps its old name, its old
109 value will be copied to the new function. The syntax used in the examples
110 above also applies to the predefined parametrized functions like `gaus` and
111 `expo`.
112
113 Comparisons operators are also supported `(&amp;&amp;, ||, ==, &lt;=, &gt;=, !)`
114
115 Examples:
116
117 `sin(x*(x&lt;0.5 || x&gt;1))`
118
119 If the result of a comparison is TRUE, the result is 1, otherwise 0.
120
121 Already predefined names can be given. For example, if the formula
122
123 `TFormula old("old",sin(x*(x&lt;0.5 || x&gt;1)))`
124
125 one can assign a name to the formula. By default the name of the object = title = formula itself.
126
127 `TFormula new("new","x*old")`
128
129 is equivalent to:
130
131 `TFormula new("new","x*sin(x*(x&lt;0.5 || x&gt;1))")`
132
133 The class supports unlimited number of variables and parameters.
134 By default the names which can be used for the variables are `x,y,z,t` or
135 `x[0],x[1],x[2],x[3],....x[N]` for N-dimensional formulas.
136
137 This class is not anymore the base class for the function classes `TF1`, but it has now
138 a data member of TF1 which can be accessed via `TF1::GetFormula`.
139
140 TFormula supports gradient and hessian calculations through clad.
141 To calculate the gradient one needs to first declare a `CladStorage` of the
142 same size as the number of parameters and then pass the variables and the
143 created `CladStorage`:
144
145 ```
146 TFormula f("f", "x*[0] - y*[1]");
147 Double_t p[] = {40, 30};
148 Double_t x[] = {1, 2};
149 f.SetParameters(p);
150 TFormula::CladStorage grad(2);
151 f.GradientPar(x, grad);
152 ```
153
154 The process is similar for hessians, except that the size of the created
155 CladStorage should be the square of the number of parameters because
156 `HessianPar` returns a flattened matrix:
157
158 ```
159 TFormula::CladStorage hess(4);
160 f.HessianPar(x, hess);
161 ```
162
163 \anchor FormulaFuncs
164 ### List of predefined functions
165
166 The list of available predefined functions which can be used as shortcuts is the following:
167 1. One Dimensional functions:
168 - `gaus` is a substitute for `[Constant]*exp(-0.5*((x-[Mean])/[Sigma])*((x-[Mean])/[Sigma]))`
169 - `landau` is a substitute for `[Constant]*TMath::Landau (x,[MPV],[Sigma],false)`
170 - `expo` is a substitute for `exp([Constant]+[Slope]*x)`
171 - `crystalball` is substitute for `[Constant]*ROOT::Math::crystalball_function (x,[Alpha],[N],[Sigma],[Mean])`
172 - `breitwigner` is a substitute for `[p0]*ROOT::Math::breitwigner_pdf (x,[p2],[p1])`
173 - `pol0,1,2,...N` is a substitute for a polynomial of degree `N` :
174 `([p0]+[p1]*x+[p2]*pow(x,2)+....[pN]*pow(x,N)`
175 - `cheb0,1,2,...N` is a substitute for a Chebyshev polynomial of degree `N`:
176 `ROOT::Math::Chebyshev10(x,[p0],[p1],[p2],...[pN])`. Note the maximum N allowed here is 10.
177 2. Two Dimensional functions:
178 - `xygaus` is a substitute for `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- 0.5*pow(((y-[MeanY])/[SigmaY]),2))`, a 2d Gaussian without correlation.
179 - `bigaus` is a substitute for `[Constant]*ROOT::Math::bigaussian_pdf (x,y,[SigmaX],[SigmaY],[Rho],[MeanX],[MeanY])`, a 2d gaussian including a correlation parameter.
180 3. Three Dimensional functions:
181 - `xyzgaus` is for a 3d Gaussians without correlations:
182 `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- 0.5*pow(((y-[MeanY])/[SigmaY]),2 )- 0.5*pow(((z-[MeanZ])/[SigmaZ]),2))`
183
184
185 ### An expanded note on variables and parameters
186
187 In a TFormula, a variable is a defined by a name `x`, `y`, `z` or `t` or an
188 index like `x[0]`, `x[1]`, `x[2]`; that is `x[N]` where N is an integer.
189
190 ```
191 TFormula("", "x[0] * x[1] + 10")
192 ```
193
194 Parameters are similar and can take any name. It is specified using brackets
195 e.g. `[expected_mass]` or `[0]`.
196
197 ```
198 TFormula("", "exp([expected_mass])-1")
199 ```
200
201 Variables and parameters can be combined in the same TFormula. Here we consider
202 a very simple case where we have an exponential decay after some time t and a
203 number of events with timestamps for which we want to evaluate this function.
204
205 ```
206 TFormula tf ("", "[0]*exp(-[1]*t)");
207 tf.SetParameter(0, 1);
208 tf.SetParameter(1, 0.5);
209
210 for (auto & event : events) {
211 tf.Eval(event.t);
212 }
213 ```
214
215 The distinction between variables and parameters arose from the TFormula's
216 application in fitting. There parameters are fitted to the data provided
217 through variables. In other applications this distinction can go away.
218
219 Parameter values can be provided dynamically using `TFormula::EvalPar`
220 instead of `TFormula::Eval`. In this way parameters can be used identically
221 to variables. See below for an example that uses only parameters to model a
222 function.
223
224 ```
225 Int_t params[2] = {1, 2}; // {vel_x, vel_y}
226 TFormula tf ("", "[vel_x]/sqrt(([vel_x + vel_y])**2)");
227
228 tf.EvalPar(nullptr, params);
229 ```
230
231 ### A note on operators
232
233 All operators of C/C++ are allowed in a TFormula with a few caveats.
234
235 The operators `|`, `&`, `%` can be used but will raise an error if used in
236 conjunction with a variable or a parameter. Variables and parameters are treated
237 as doubles internally for which these operators are not defined.
238 This means the following command will run successfully
239 ```root -l -q -e TFormula("", "x+(10%3)").Eval(0)```
240 but not
241 ```root -l -q -e TFormula("", "x%10").Eval(0)```.
242
243 The operator `^` is defined to mean exponentiation instead of the C/C++
244 interpretation xor. `**` is added, also meaning exponentiation.
245
246 The operators `++` and `@` are added, and are shorthand for the a linear
247 function. That means the expression `x@2` will be expanded to
248 ```[n]*x + [n+1]*2``` where n is the first previously unused parameter number.
249
250 \class TFormulaFunction
251 Helper class for TFormula
252
253 \class TFormulaVariable
254 Another helper class for TFormula
255
256 \class TFormulaParamOrder
257 Functor defining the parameter order
258*/
259
260// prefix used for function name passed to Cling
261static const TString gNamePrefix = "TFormula__";
262
263// static map of function pointers and expressions
264//static std::unordered_map<std::string, TInterpreter::CallFuncIFacePtr_t::Generic_t> gClingFunctions = std::unordered_map<TString, TInterpreter::CallFuncIFacePtr_t::Generic_t>();
265static std::unordered_map<std::string, void *> gClingFunctions = std::unordered_map<std::string, void * >();
266
267static void R__v5TFormulaUpdater(Int_t nobjects, TObject **from, TObject **to)
268{
269 auto **fromv5 = (ROOT::v5::TFormula **)from;
270 auto **target = (TFormula **)to;
271
272 for (int i = 0; i < nobjects; ++i) {
273 if (fromv5[i] && target[i]) {
274 TFormula fnew(fromv5[i]->GetName(), fromv5[i]->GetExpFormula());
275 *(target[i]) = fnew;
276 target[i]->SetParameters(fromv5[i]->GetParameters());
277 }
278 }
279}
280
281using TFormulaUpdater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
283
285
286////////////////////////////////////////////////////////////////////////////////
288{
289 // operator ":" must be handled separately
290 const static std::set<char> ops {'+','^','-','/','*','<','>','|','&','!','=','?','%'};
291 return ops.end() != ops.find(c);
292}
293
294////////////////////////////////////////////////////////////////////////////////
296{
297 // Note that square brackets do not count as brackets here!!!
298 char brackets[] = { ')','(','{','}'};
299 Int_t bracketsLen = sizeof(brackets)/sizeof(char);
300 for(Int_t i = 0; i < bracketsLen; ++i)
301 if(brackets[i] == c)
302 return true;
303 return false;
304}
305
306////////////////////////////////////////////////////////////////////////////////
308{
309 return !IsBracket(c) && !IsOperator(c) && c != ',' && c != ' ';
310}
311
312////////////////////////////////////////////////////////////////////////////////
314{
315 return name == "x" || name == "z" || name == "y" || name == "t";
316}
317
318////////////////////////////////////////////////////////////////////////////////
320{
321 // check if the character at position i is part of a scientific notation
322 if ( (formula[i] == 'e' || formula[i] == 'E') && (i > 0 && i < formula.Length()-1) ) {
323 // handle cases: 2e+3 2e-3 2e3 and 2.e+3
324 if ( (isdigit(formula[i-1]) || formula[i-1] == '.') && ( isdigit(formula[i+1]) || formula[i+1] == '+' || formula[i+1] == '-' ) )
325 return true;
326 }
327 return false;
328}
329
330////////////////////////////////////////////////////////////////////////////////
332{
333 // check if the character at position i is part of a scientific notation
334 if ( (formula[i] == 'x' || formula[i] == 'X') && (i > 0 && i < formula.Length()-1) && formula[i-1] == '0') {
335 if (isdigit(formula[i+1]) )
336 return true;
337 static char hex_values[12] = { 'a','A', 'b','B','c','C','d','D','e','E','f','F'};
338 for (int jjj = 0; jjj < 12; ++jjj) {
339 if (formula[i+1] == hex_values[jjj])
340 return true;
341 }
342 }
343 // else
344 // return false;
345 // // handle cases: 2e+3 2e-3 2e3 and 2.e+3
346 // if ( (isdigit(formula[i-1]) || formula[i-1] == '.') && ( isdigit(formula[i+1]) || formula[i+1] == '+' || formula[i+1] == '-' ) )
347 // return true;
348 // }
349 return false;
350}
351////////////////////////////////////////////////////////////////////////////
352// check is given position is in a parameter name i.e. within "[ ]"
353////
354Bool_t TFormula::IsAParameterName(const TString & formula, int pos) {
355
356 Bool_t foundOpenParenthesis = false;
357 if (pos == 0 || pos == formula.Length()-1) return false;
358 for (int i = pos-1; i >=0; i--) {
359 if (formula[i] == ']' ) return false;
360 if (formula[i] == '[' ) {
361 foundOpenParenthesis = true;
362 break;
363 }
364 }
365 if (!foundOpenParenthesis ) return false;
366
367 // search after the position
368 for (int i = pos+1; i < formula.Length(); i++) {
369 if (formula[i] == ']' ) return true;
370 }
371 return false;
372}
373
374
375////////////////////////////////////////////////////////////////////////////////
377 // implement comparison used to set parameter orders in TFormula
378 // want p2 to be before p10
379
380 // Returns true if (a < b), meaning a comes before b, and false if (a >= b)
381
382 TRegexp numericPattern("p?[0-9]+");
383 Ssiz_t len; // buffer to store length of regex match
384
385 int patternStart = numericPattern.Index(a, &len);
386 bool aNumeric = (patternStart == 0 && len == a.Length());
387
388 patternStart = numericPattern.Index(b, &len);
389 bool bNumeric = (patternStart == 0 && len == b.Length());
390
391 if (aNumeric && !bNumeric)
392 return true; // assume a (numeric) is always before b (not numeric)
393 else if (!aNumeric && bNumeric)
394 return false; // b comes before a
395 else if (!aNumeric && !bNumeric)
396 return a < b;
397 else {
398 int aInt = (a[0] == 'p') ? TString(a(1, a.Length())).Atoi() : a.Atoi();
399 int bInt = (b[0] == 'p') ? TString(b(1, b.Length())).Atoi() : b.Atoi();
400 return aInt < bInt;
401 }
402
403}
404
405////////////////////////////////////////////////////////////////////////////////
406void TFormula::ReplaceAllNames(TString &formula, map<TString, TString> &substitutions)
407{
408 /// Apply the name substitutions to the formula, doing all replacements in one pass
409
410 for (int i = 0; i < formula.Length(); i++) {
411 // start of name
412 // (a little subtle, since we want to match names like "{V0}" and "[0]")
413 if (isalpha(formula[i]) || formula[i] == '{' || formula[i] == '[') {
414 int j; // index to end of name
415 for (j = i + 1;
416 j < formula.Length() && (IsFunctionNameChar(formula[j]) // square brackets are function name chars
417 || (formula[i] == '{' && formula[j] == '}'));
418 j++)
419 ;
420 TString name = (TString)formula(i, j - i);
421
422 // std::cout << "Looking for name: " << name << std::endl;
423
424 // if we find the name, do the substitution
425 if (substitutions.find(name) != substitutions.end()) {
426 formula.Replace(i, name.Length(), "(" + substitutions[name] + ")");
427 i += substitutions[name].Length() + 2 - 1; // +2 for parentheses
428 // std::cout << "made substitution: " << name << " to " << substitutions[name] << std::endl;
429 } else if (isalpha(formula[i])) {
430 // if formula[i] is alpha, can skip to end of candidate name, otherwise, we'll just
431 // move one character ahead and try again
432 i += name.Length() - 1;
433 }
434 }
435 }
436}
437
438////////////////////////////////////////////////////////////////////////////////
440{
441 fName = "";
442 fTitle = "";
443 fClingInput = "";
444 fReadyToExecute = false;
445 fClingInitialized = false;
446 fAllParametersSetted = false;
447 fNdim = 0;
448 fNpar = 0;
449 fNumber = 0;
450 fClingName = "";
451 fFormula = "";
452 fLambdaPtr = nullptr;
453}
454
455////////////////////////////////////////////////////////////////////////////////
456static bool IsReservedName(const char* name)
457{
458 if (strlen(name)!=1) return false;
459 for (auto const & specialName : {"x","y","z","t"}){
460 if (strcmp(name,specialName)==0) return true;
461 }
462 return false;
463}
464
465////////////////////////////////////////////////////////////////////////////////
467{
468
469 // N.B. a memory leak may happen if user set bit after constructing the object,
470 // Setting of bit should be done only internally
473 gROOT->GetListOfFunctions()->Remove(this);
474 }
475
476 int nLinParts = fLinearParts.size();
477 if (nLinParts > 0) {
478 for (int i = 0; i < nLinParts; ++i) delete fLinearParts[i];
479 }
480}
481
482////////////////////////////////////////////////////////////////////////////////
483TFormula::TFormula(const char *name, const char *formula, bool addToGlobList, bool vectorize) :
484 TNamed(name,formula),
485 fClingInput(formula),fFormula(formula)
486{
487 fReadyToExecute = false;
488 fClingInitialized = false;
489 fNdim = 0;
490 fNpar = 0;
491 fNumber = 0;
492 fLambdaPtr = nullptr;
493 fVectorized = vectorize;
494#ifndef R__HAS_VECCORE
495 fVectorized = false;
496#endif
497
498 FillDefaults();
499
500
501 //fName = gNamePrefix + name; // is this needed
502
503 // do not process null formulas.
504 if (!fFormula.IsNull() ) {
506
507 bool ok = PrepareFormula(fFormula);
508 // if the formula has been correctly initialized add to the list of global functions
509 if (ok) {
510 if (addToGlobList && gROOT) {
511 TFormula *old = 0;
513 old = dynamic_cast<TFormula *>(gROOT->GetListOfFunctions()->FindObject(name));
514 if (old)
515 gROOT->GetListOfFunctions()->Remove(old);
516 if (IsReservedName(name))
517 Error("TFormula", "The name %s is reserved as a TFormula variable name.\n", name);
518 else
519 gROOT->GetListOfFunctions()->Add(this);
520 }
521 SetBit(kNotGlobal,!addToGlobList);
522 }
523 }
524}
525
526////////////////////////////////////////////////////////////////////////////////
527/// Constructor from a full compile-able C++ expression
528
529TFormula::TFormula(const char *name, const char *formula, int ndim, int npar, bool addToGlobList) :
530 TNamed(name,formula),
531 fClingInput(formula),fFormula(formula)
532{
533 fReadyToExecute = false;
534 fClingInitialized = false;
535 fNpar = 0;
536 fNumber = 0;
537 fLambdaPtr = nullptr;
538 fFuncPtr = nullptr;
539 fGradFuncPtr = nullptr;
540 fHessFuncPtr = nullptr;
541
542
543 fNdim = ndim;
544 for (int i = 0; i < npar; ++i) {
545 DoAddParameter(TString::Format("p%d",i), 0, false);
546 }
548 assert (fNpar == npar);
549
550 bool ret = InitLambdaExpression(formula);
551
552 if (ret) {
553
555
556 fReadyToExecute = true;
557
558 if (addToGlobList && gROOT) {
559 TFormula *old = 0;
561 old = dynamic_cast<TFormula*> ( gROOT->GetListOfFunctions()->FindObject(name) );
562 if (old)
563 gROOT->GetListOfFunctions()->Remove(old);
564 if (IsReservedName(name))
565 Error("TFormula","The name %s is reserved as a TFormula variable name.\n",name);
566 else
567 gROOT->GetListOfFunctions()->Add(this);
568 }
569 SetBit(kNotGlobal,!addToGlobList);
570 }
571 else
572 Error("TFormula","Syntax error in building the lambda expression %s", formula );
573}
574
575////////////////////////////////////////////////////////////////////////////////
577 TNamed(formula.GetName(),formula.GetTitle())
578{
579 formula.TFormula::Copy(*this);
580
583 TFormula *old = (TFormula*)gROOT->GetListOfFunctions()->FindObject(formula.GetName());
584 if (old)
585 gROOT->GetListOfFunctions()->Remove(old);
586
587 if (IsReservedName(formula.GetName())) {
588 Error("TFormula","The name %s is reserved as a TFormula variable name.\n",formula.GetName());
589 } else
590 gROOT->GetListOfFunctions()->Add(this);
591 }
592
593}
594
595////////////////////////////////////////////////////////////////////////////////
596/// = operator.
597
599{
600 if (this != &rhs)
601 rhs.TFormula::Copy(*this);
602 return *this;
603}
604
605////////////////////////////////////////////////////////////////////////////////
607
608 std::string lambdaExpression = formula;
609
610 // check if formula exist already in the map
611 {
613
614 auto funcit = gClingFunctions.find(lambdaExpression);
615 if (funcit != gClingFunctions.end() ) {
616 fLambdaPtr = funcit->second;
617 fClingInitialized = true;
618 return true;
619 }
620 }
621
622 // to be sure the interpreter is initialized
625
626 // set the cling name using hash of the static formulae map
627 auto hasher = gClingFunctions.hash_function();
628 TString lambdaName = TString::Format("lambda__id%zu", hasher(lambdaExpression) );
629
630 //lambdaExpression = TString::Format("[&](double * x, double *){ return %s ;}",formula);
631 //TString lambdaName = TString::Format("mylambda_%s",GetName() );
632 TString lineExpr = TString::Format("std::function<double(double*,double*)> %s = %s ;",lambdaName.Data(), lambdaExpression.c_str() );
633 gInterpreter->ProcessLine(lineExpr);
634 fLambdaPtr = (void*) gInterpreter->ProcessLine(TString(lambdaName)+TString(";")); // add ; to avoid printing
635 if (fLambdaPtr != nullptr) {
637 gClingFunctions.insert ( std::make_pair ( lambdaExpression, fLambdaPtr) );
638 fClingInitialized = true;
639 return true;
640 }
641 fClingInitialized = false;
642 return false;
643}
644
645////////////////////////////////////////////////////////////////////////////////
646/// Compile the given expression with Cling
647/// backward compatibility method to be used in combination with the empty constructor
648/// if no expression is given , the current stored formula (retrieved with GetExpFormula()) or the title is used.
649/// return 0 if the formula compilation is successful
650
651Int_t TFormula::Compile(const char *expression)
652{
653 TString formula = expression;
654 if (formula.IsNull() ) {
655 formula = fFormula;
656 if (formula.IsNull() ) formula = GetTitle();
657 }
658
659 if (formula.IsNull() ) return -1;
660
661 // do not re-process if it was done before
662 if (IsValid() && formula == fFormula ) return 0;
663
664 // clear if a formula was already existing
665 if (!fFormula.IsNull() ) Clear();
666
667 fFormula = formula;
668
670 bool ret = InitLambdaExpression(fFormula);
671 return (ret) ? 0 : 1;
672 }
673
674 if (fVars.empty() ) FillDefaults();
675 // prepare the formula for Cling
676 //printf("compile: processing formula %s\n",fFormula.Data() );
678 // pass formula in CLing
679 bool ret = PrepareFormula(fFormula);
680
681 return (ret) ? 0 : 1;
682}
683
684////////////////////////////////////////////////////////////////////////////////
685void TFormula::Copy(TObject &obj) const
686{
687 TNamed::Copy(obj);
688 // need to copy also cling parameters
689 TFormula & fnew = dynamic_cast<TFormula&>(obj);
690
693
694 fnew.fFuncs = fFuncs;
695 fnew.fVars = fVars;
696 fnew.fParams = fParams;
697 fnew.fConsts = fConsts;
699 fnew.fFormula = fFormula;
700 fnew.fNdim = fNdim;
701 fnew.fNpar = fNpar;
702 fnew.fNumber = fNumber;
705 // copy Linear parts (it is a vector of TFormula pointers) needs to be copied one by one
706 // looping at all the elements
707 // delete first previous elements
708 int nLinParts = fnew.fLinearParts.size();
709 if (nLinParts > 0) {
710 for (int i = 0; i < nLinParts; ++i) delete fnew.fLinearParts[i];
711 fnew.fLinearParts.clear();
712 }
713 // old size that needs to be copied
714 nLinParts = fLinearParts.size();
715 if (nLinParts > 0) {
716 fnew.fLinearParts.reserve(nLinParts);
717 for (int i = 0; i < nLinParts; ++i) {
718 TFormula * linearNew = new TFormula();
719 TFormula * linearOld = (TFormula*) fLinearParts[i];
720 if (linearOld) {
721 linearOld->Copy(*linearNew);
722 fnew.fLinearParts.push_back(linearNew);
723 }
724 else
725 Warning("Copy","Function %s - expr %s has a dummy linear part %d",GetName(),GetExpFormula().Data(),i);
726 }
727 }
728
733 fnew.fClingName = fClingName;
736
737 // case of function based on a C++ expression (lambda's) which is ready to be compiled
739
740 bool ret = fnew.InitLambdaExpression(fnew.fFormula);
741 if (ret) {
743 fnew.fReadyToExecute = true;
744 }
745 else {
746 Error("TFormula","Syntax error in building the lambda expression %s", fFormula.Data() );
747 fnew.fReadyToExecute = false;
748 }
749 }
750
751 // use copy-constructor of TMethodCall
752 // if c++-14 could use std::make_unique
753 TMethodCall *m = (fMethod) ? new TMethodCall(*fMethod) : nullptr;
754 fnew.fMethod.reset(m);
755
756 fnew.fFuncPtr = fFuncPtr;
761
762}
763
764////////////////////////////////////////////////////////////////////////////////
765/// Clear the formula setting expression to empty and reset the variables and
766/// parameters containers.
767
769{
770 fNdim = 0;
771 fNpar = 0;
772 fNumber = 0;
773 fFormula = "";
774 fClingName = "";
775
776 fMethod.reset();
777
778 fClingVariables.clear();
779 fClingParameters.clear();
780 fReadyToExecute = false;
781 fClingInitialized = false;
782 fAllParametersSetted = false;
783 fFuncs.clear();
784 fVars.clear();
785 fParams.clear();
786 fConsts.clear();
787 fFunctionsShortcuts.clear();
788
789 // delete linear parts
790 int nLinParts = fLinearParts.size();
791 if (nLinParts > 0) {
792 for (int i = 0; i < nLinParts; ++i) delete fLinearParts[i];
793 }
794 fLinearParts.clear();
795
796}
797
798// Returns nullptr on failure.
799static std::unique_ptr<TMethodCall>
800prepareMethod(bool HasParameters, bool HasVariables, const char* FuncName,
801 bool IsVectorized, bool AddCladArrayRef = false) {
802 std::unique_ptr<TMethodCall>
803 Method = std::unique_ptr<TMethodCall>(new TMethodCall());
804
805 TString prototypeArguments = "";
806 if (HasVariables || HasParameters) {
807 if (IsVectorized)
808 prototypeArguments.Append("ROOT::Double_v*");
809 else
810 prototypeArguments.Append("Double_t*");
811 }
812 auto AddDoublePtrParam = [&prototypeArguments]() {
813 prototypeArguments.Append(",");
814 prototypeArguments.Append("Double_t*");
815 };
816 if (HasParameters)
817 AddDoublePtrParam();
818
819 // We need an extra Double_t* for the gradient return result.
820 if (AddCladArrayRef) {
821 prototypeArguments.Append(",");
822 prototypeArguments.Append("clad::array_ref<Double_t>");
823 }
824
825 // Initialize the method call using real function name (cling name) defined
826 // by ProcessFormula
827 Method->InitWithPrototype(FuncName, prototypeArguments);
828 if (!Method->IsValid()) {
829 Error("prepareMethod",
830 "Can't compile function %s prototype with arguments %s", FuncName,
831 prototypeArguments.Data());
832 return nullptr;
833 }
834
835 return Method;
836}
837
839 if (!method) return nullptr;
840 CallFunc_t *callfunc = method->GetCallFunc();
841
842 if (!gCling->CallFunc_IsValid(callfunc)) {
843 Error("prepareFuncPtr", "Callfunc retuned from Cling is not valid");
844 return nullptr;
845 }
846
848 = gCling->CallFunc_IFacePtr(callfunc).fGeneric;
849 if (!Result) {
850 Error("prepareFuncPtr", "Compiled function pointer is null");
851 return nullptr;
852 }
853 return Result;
854}
855
856////////////////////////////////////////////////////////////////////////////////
857/// Sets TMethodCall to function inside Cling environment.
858/// TFormula uses it to execute function.
859/// After call, TFormula should be ready to evaluate formula.
860/// Returns false on failure.
861
863{
864 if (!fMethod) {
865 Bool_t hasParameters = (fNpar > 0);
866 Bool_t hasVariables = (fNdim > 0);
867 fMethod = prepareMethod(hasParameters, hasVariables, fClingName,fVectorized);
868 if (!fMethod) return false;
870 }
871 return fFuncPtr;
872}
873
874////////////////////////////////////////////////////////////////////////////////
875/// Inputs formula, transfered to C++ code into Cling
876
878{
879
881 // make sure the interpreter is initialized
884
885 // Trigger autoloading / autoparsing (ROOT-9840):
886 TString triggerAutoparsing = "namespace ROOT_TFormula_triggerAutoParse {\n"; triggerAutoparsing += fClingInput + "\n}";
887 gCling->ProcessLine(triggerAutoparsing);
888
889 // add pragma for optimization of the formula
890 fClingInput = TString("#pragma cling optimize(2)\n") + fClingInput;
891
892 // Now that all libraries and headers are loaded, Declare() a performant version
893 // of the same code:
896 if (!fClingInitialized) Error("InputFormulaIntoCling","Error compiling formula expression in Cling");
897 }
898}
899
900////////////////////////////////////////////////////////////////////////////////
901/// Fill structures with default variables, constants and function shortcuts
902
904{
905 const TString defvars[] = { "x","y","z","t"};
906 const pair<TString, Double_t> defconsts[] = {{"pi", TMath::Pi()},
907 {"sqrt2", TMath::Sqrt2()},
908 {"infinity", TMath::Infinity()},
909 {"e", TMath::E()},
910 {"ln10", TMath::Ln10()},
911 {"loge", TMath::LogE()},
912 {"c", TMath::C()},
913 {"g", TMath::G()},
914 {"h", TMath::H()},
915 {"k", TMath::K()},
916 {"sigma", TMath::Sigma()},
917 {"r", TMath::R()},
918 {"eg", TMath::EulerGamma()},
919 {"true", 1},
920 {"false", 0}};
921 // const pair<TString,Double_t> defconsts[] = { {"pi",TMath::Pi()}, {"sqrt2",TMath::Sqrt2()},
922 // {"infinity",TMath::Infinity()}, {"ln10",TMath::Ln10()},
923 // {"loge",TMath::LogE()}, {"true",1},{"false",0} };
924 const pair<TString,TString> funShortcuts[] =
925 { {"sin","TMath::Sin" },
926 {"cos","TMath::Cos" }, {"exp","TMath::Exp"}, {"log","TMath::Log"}, {"log10","TMath::Log10"},
927 {"tan","TMath::Tan"}, {"sinh","TMath::SinH"}, {"cosh","TMath::CosH"},
928 {"tanh","TMath::TanH"}, {"asin","TMath::ASin"}, {"acos","TMath::ACos"},
929 {"atan","TMath::ATan"}, {"atan2","TMath::ATan2"}, {"sqrt","TMath::Sqrt"},
930 {"ceil","TMath::Ceil"}, {"floor","TMath::Floor"}, {"pow","TMath::Power"},
931 {"binomial","TMath::Binomial"},{"abs","TMath::Abs"},
932 {"min","TMath::Min"},{"max","TMath::Max"},{"sign","TMath::Sign" },
933 {"sq","TMath::Sq"}
934 };
935
936 std::vector<TString> defvars2(10);
937 for (int i = 0; i < 9; ++i)
938 defvars2[i] = TString::Format("x[%d]",i);
939
940 for (const auto &var : defvars) {
941 int pos = fVars.size();
942 fVars[var] = TFormulaVariable(var, 0, pos);
943 fClingVariables.push_back(0);
944 }
945 // add also the variables defined like x[0],x[1],x[2],...
946 // support up to x[9] - if needed extend that to higher value
947 // const int maxdim = 10;
948 // for (int i = 0; i < maxdim; ++i) {
949 // TString xvar = TString::Format("x[%d]",i);
950 // fVars[xvar] = TFormulaVariable(xvar,0,i);
951 // fClingVariables.push_back(0);
952 // }
953
954 for (auto con : defconsts) {
955 fConsts[con.first] = con.second;
956 }
957 if (fVectorized) {
959 } else {
960 for (auto fun : funShortcuts) {
961 fFunctionsShortcuts[fun.first] = fun.second;
962 }
963 }
964}
965
966////////////////////////////////////////////////////////////////////////////////
967/// Fill the shortcuts for vectorized functions
968/// We will replace for example sin with vecCore::Mat::Sin
969///
970
972#ifdef R__HAS_VECCORE
973 const pair<TString,TString> vecFunShortcuts[] =
974 { {"sin","vecCore::math::Sin" },
975 {"cos","vecCore::math::Cos" }, {"exp","vecCore::math::Exp"}, {"log","vecCore::math::Log"}, {"log10","vecCore::math::Log10"},
976 {"tan","vecCore::math::Tan"},
977 //{"sinh","vecCore::math::Sinh"}, {"cosh","vecCore::math::Cosh"},{"tanh","vecCore::math::Tanh"},
978 {"asin","vecCore::math::ASin"},
979 {"acos","TMath::Pi()/2-vecCore::math::ASin"},
980 {"atan","vecCore::math::ATan"},
981 {"atan2","vecCore::math::ATan2"}, {"sqrt","vecCore::math::Sqrt"},
982 {"ceil","vecCore::math::Ceil"}, {"floor","vecCore::math::Floor"}, {"pow","vecCore::math::Pow"},
983 {"cbrt","vecCore::math::Cbrt"},{"abs","vecCore::math::Abs"},
984 {"min","vecCore::math::Min"},{"max","vecCore::math::Max"},{"sign","vecCore::math::Sign" }
985 //{"sq","TMath::Sq"}, {"binomial","TMath::Binomial"} // this last two functions will not work in vectorized mode
986 };
987 // replace in the data member maps fFunctionsShortcuts
988 for (auto fun : vecFunShortcuts) {
989 fFunctionsShortcuts[fun.first] = fun.second;
990 }
991#endif
992 // do nothing in case Veccore is not enabled
993}
994
995
996////////////////////////////////////////////////////////////////////////////////
997/// Handling polN
998/// If before 'pol' exist any name, this name will be treated as variable used in polynomial
999/// eg.
1000/// varpol2(5) will be replaced with: [5] + [6]*var + [7]*var^2
1001/// Empty name is treated like variable x.
1002
1004{
1005 Int_t polPos = formula.Index("pol");
1006 while (polPos != kNPOS && !IsAParameterName(formula, polPos)) {
1007
1008 Bool_t defaultVariable = false;
1009 TString variable;
1010 Int_t openingBracketPos = formula.Index('(', polPos);
1011 Bool_t defaultCounter = openingBracketPos == kNPOS;
1012 Bool_t defaultDegree = true;
1013 Int_t degree, counter;
1014 TString sdegree;
1015 if (!defaultCounter) {
1016 // verify first of opening parenthesis belongs to pol expression
1017 // character between 'pol' and '(' must all be digits
1018 sdegree = formula(polPos + 3, openingBracketPos - polPos - 3);
1019 if (!sdegree.IsDigit())
1020 defaultCounter = true;
1021 }
1022 if (!defaultCounter) {
1023 degree = sdegree.Atoi();
1024 counter = TString(formula(openingBracketPos + 1, formula.Index(')', polPos) - openingBracketPos)).Atoi();
1025 } else {
1026 Int_t temp = polPos + 3;
1027 while (temp < formula.Length() && isdigit(formula[temp])) {
1028 defaultDegree = false;
1029 temp++;
1030 }
1031 degree = TString(formula(polPos + 3, temp - polPos - 3)).Atoi();
1032 counter = 0;
1033 }
1034
1035 TString replacement = TString::Format("[%d]", counter);
1036 if (polPos - 1 < 0 || !IsFunctionNameChar(formula[polPos - 1]) || formula[polPos - 1] == ':') {
1037 variable = "x";
1038 defaultVariable = true;
1039 } else {
1040 Int_t tmp = polPos - 1;
1041 while (tmp >= 0 && IsFunctionNameChar(formula[tmp]) && formula[tmp] != ':') {
1042 tmp--;
1043 }
1044 variable = formula(tmp + 1, polPos - (tmp + 1));
1045 }
1046 Int_t param = counter + 1;
1047 Int_t tmp = 1;
1048 while (tmp <= degree) {
1049 if (tmp > 1)
1050 replacement.Append(TString::Format("+[%d]*%s^%d", param, variable.Data(), tmp));
1051 else
1052 replacement.Append(TString::Format("+[%d]*%s", param, variable.Data()));
1053 param++;
1054 tmp++;
1055 }
1056 // add parenthesis before and after
1057 if (degree > 0) {
1058 replacement.Insert(0, '(');
1059 replacement.Append(')');
1060 }
1062 if (defaultCounter && !defaultDegree) {
1063 pattern = TString::Format("%spol%d", (defaultVariable ? "" : variable.Data()), degree);
1064 } else if (defaultCounter && defaultDegree) {
1065 pattern = TString::Format("%spol", (defaultVariable ? "" : variable.Data()));
1066 } else {
1067 pattern = TString::Format("%spol%d(%d)", (defaultVariable ? "" : variable.Data()), degree, counter);
1068 }
1069
1070 if (!formula.Contains(pattern)) {
1071 Error("HandlePolN", "Error handling polynomial function - expression is %s - trying to replace %s with %s ",
1072 formula.Data(), pattern.Data(), replacement.Data());
1073 break;
1074 }
1075 if (formula == pattern) {
1076 // case of single polynomial
1077 SetBit(kLinear, 1);
1078 fNumber = 300 + degree;
1079 }
1080 formula.ReplaceAll(pattern, replacement);
1081 polPos = formula.Index("pol");
1082 }
1083}
1084
1085////////////////////////////////////////////////////////////////////////////////
1086/// Handling parametrized functions
1087/// Function can be normalized, and have different variable then x.
1088/// Variables should be placed in brackets after function name.
1089/// No brackets are treated like [x].
1090/// Normalized function has char 'n' after name, eg.
1091/// gausn[var](0) will be replaced with [0]*exp(-0.5*((var-[1])/[2])^2)/(sqrt(2*pi)*[2])
1092///
1093/// Adding function is easy, just follow these rules, and add to
1094/// `TFormula::FillParametrizedFunctions` defined further below:
1095///
1096/// - Key for function map is pair of name and dimension of function
1097/// - value of key is a pair function body and normalized function body
1098/// - {Vn} is a place where variable appear, n represents n-th variable from variable list.
1099/// Count starts from 0.
1100/// - [num] stands for parameter number.
1101/// If user pass to function argument 5, num will stand for (5 + num) parameter.
1102///
1103
1105{
1106 // define all parametrized functions
1107 map< pair<TString,Int_t> ,pair<TString,TString> > functions;
1108 FillParametrizedFunctions(functions);
1109
1110 map<TString,Int_t> functionsNumbers;
1111 functionsNumbers["gaus"] = 100;
1112 functionsNumbers["bigaus"] = 102;
1113 functionsNumbers["landau"] = 400;
1114 functionsNumbers["expo"] = 200;
1115 functionsNumbers["crystalball"] = 500;
1116
1117 // replace old names xygaus -> gaus[x,y]
1118 formula.ReplaceAll("xyzgaus","gaus[x,y,z]");
1119 formula.ReplaceAll("xygaus","gaus[x,y]");
1120 formula.ReplaceAll("xgaus","gaus[x]");
1121 formula.ReplaceAll("ygaus","gaus[y]");
1122 formula.ReplaceAll("zgaus","gaus[z]");
1123 formula.ReplaceAll("xexpo","expo[x]");
1124 formula.ReplaceAll("yexpo","expo[y]");
1125 formula.ReplaceAll("zexpo","expo[z]");
1126 formula.ReplaceAll("xylandau","landau[x,y]");
1127 formula.ReplaceAll("xyexpo","expo[x,y]");
1128 // at the moment pre-defined functions have no more than 3 dimensions
1129 const char * defaultVariableNames[] = { "x","y","z"};
1130
1131 for (map<pair<TString, Int_t>, pair<TString, TString>>::iterator it = functions.begin(); it != functions.end();
1132 ++it) {
1133
1134 TString funName = it->first.first;
1135 Int_t funDim = it->first.second;
1136 Int_t funPos = formula.Index(funName);
1137
1138 // std::cout << formula << " ---- " << funName << " " << funPos << std::endl;
1139 while (funPos != kNPOS && !IsAParameterName(formula, funPos)) {
1140
1141 // should also check that function is not something else (e.g. exponential - parse the expo)
1142 Int_t lastFunPos = funPos + funName.Length();
1143
1144 // check that first and last character is not a special character
1145 Int_t iposBefore = funPos - 1;
1146 // std::cout << "looping on funpos is " << funPos << " formula is " << formula << " function " << funName <<
1147 // std::endl;
1148 if (iposBefore >= 0) {
1149 assert(iposBefore < formula.Length());
1150 //if (isalpha(formula[iposBefore])) {
1151 if (IsFunctionNameChar(formula[iposBefore])) {
1152 // std::cout << "previous character for function " << funName << " is " << formula[iposBefore] << "- skip
1153 // " << std::endl;
1154 funPos = formula.Index(funName, lastFunPos);
1155 continue;
1156 }
1157 }
1158
1159 Bool_t isNormalized = false;
1160 if (lastFunPos < formula.Length()) {
1161 // check if function is normalized by looking at "n" character after function name (e.g. gausn)
1162 isNormalized = (formula[lastFunPos] == 'n');
1163 if (isNormalized)
1164 lastFunPos += 1;
1165 if (lastFunPos < formula.Length()) {
1166 char c = formula[lastFunPos];
1167 // check if also last character is not alphanumeric or is not an operator and not a parenthesis ( or [.
1168 // Parenthesis [] are used to express the variables
1169 if (isalnum(c) || (!IsOperator(c) && c != '(' && c != ')' && c != '[' && c != ']')) {
1170 // std::cout << "last character for function " << funName << " is " << c << " skip .." << std::endl;
1171 funPos = formula.Index(funName, lastFunPos);
1172 continue;
1173 }
1174 }
1175 }
1176
1177 if (isNormalized) {
1178 SetBit(kNormalized, 1);
1179 }
1180 std::vector<TString> variables;
1181 Int_t dim = 0;
1182 TString varList = "";
1183 Bool_t defaultVariables = false;
1184
1185 // check if function has specified the [...] e.g. gaus[x,y]
1186 Int_t openingBracketPos = funPos + funName.Length() + (isNormalized ? 1 : 0);
1187 Int_t closingBracketPos = kNPOS;
1188 if (openingBracketPos > formula.Length() || formula[openingBracketPos] != '[') {
1189 dim = funDim;
1190 variables.resize(dim);
1191 for (Int_t idim = 0; idim < dim; ++idim)
1192 variables[idim] = defaultVariableNames[idim];
1193 defaultVariables = true;
1194 } else {
1195 // in case of [..] found, assume they specify all the variables. Use it to get function dimension
1196 closingBracketPos = formula.Index(']', openingBracketPos);
1197 varList = formula(openingBracketPos + 1, closingBracketPos - openingBracketPos - 1);
1198 dim = varList.CountChar(',') + 1;
1199 variables.resize(dim);
1200 Int_t Nvar = 0;
1201 TString varName = "";
1202 for (Int_t i = 0; i < varList.Length(); ++i) {
1203 if (IsFunctionNameChar(varList[i])) {
1204 varName.Append(varList[i]);
1205 }
1206 if (varList[i] == ',') {
1207 variables[Nvar] = varName;
1208 varName = "";
1209 Nvar++;
1210 }
1211 }
1212 if (varName != "") // we will miss last variable
1213 {
1214 variables[Nvar] = varName;
1215 }
1216 }
1217 // check if dimension obtained from [...] is compatible with what is defined in existing pre-defined functions
1218 // std::cout << " Found dim = " << dim << " and function dimension is " << funDim << std::endl;
1219 if (dim != funDim) {
1220 pair<TString, Int_t> key = make_pair(funName, dim);
1221 if (functions.find(key) == functions.end()) {
1222 Error("PreProcessFormula", "Dimension of function %s is detected to be of dimension %d and is not "
1223 "compatible with existing pre-defined function which has dim %d",
1224 funName.Data(), dim, funDim);
1225 return;
1226 }
1227 // skip the particular function found - we might find later on the corresponding pre-defined function
1228 funPos = formula.Index(funName, lastFunPos);
1229 continue;
1230 }
1231 // look now for the (..) brackets to get the parameter counter (e.g. gaus(0) + gaus(3) )
1232 // need to start for a position
1233 Int_t openingParenthesisPos = (closingBracketPos == kNPOS) ? openingBracketPos : closingBracketPos + 1;
1234 bool defaultCounter = (openingParenthesisPos > formula.Length() || formula[openingParenthesisPos] != '(');
1235
1236 // Int_t openingParenthesisPos = formula.Index('(',funPos);
1237 // Bool_t defaultCounter = (openingParenthesisPos == kNPOS);
1238 Int_t counter;
1239 if (defaultCounter) {
1240 counter = 0;
1241 } else {
1242 // Check whether this is just a number in parentheses. If not, leave
1243 // it to `HandleFunctionArguments` to be parsed
1244
1245 TRegexp counterPattern("([0-9]+)");
1246 Ssiz_t len;
1247 if (counterPattern.Index(formula, &len, openingParenthesisPos) == -1) {
1248 funPos = formula.Index(funName, funPos + 1);
1249 continue;
1250 } else {
1251 counter =
1252 TString(formula(openingParenthesisPos + 1, formula.Index(')', funPos) - openingParenthesisPos - 1))
1253 .Atoi();
1254 }
1255 }
1256 // std::cout << "openingParenthesisPos " << openingParenthesisPos << " counter is " << counter << std::endl;
1257
1258 TString body = (isNormalized ? it->second.second : it->second.first);
1259 if (isNormalized && body == "") {
1260 Error("PreprocessFormula", "%d dimension function %s has no normalized form.", it->first.second,
1261 funName.Data());
1262 break;
1263 }
1264 for (int i = 0; i < body.Length(); ++i) {
1265 if (body[i] == '{') {
1266 // replace {Vn} with variable names
1267 i += 2; // skip '{' and 'V'
1268 Int_t num = TString(body(i, body.Index('}', i) - i)).Atoi();
1269 TString variable = variables[num];
1270 TString pattern = TString::Format("{V%d}", num);
1271 i -= 2; // restore original position
1272 body.Replace(i, pattern.Length(), variable, variable.Length());
1273 i += variable.Length() - 1; // update i to reflect change in body string
1274 } else if (body[i] == '[') {
1275 // update parameter counters in case of many functions (e.g. gaus(0)+gaus(3) )
1276 Int_t tmp = i;
1277 while (tmp < body.Length() && body[tmp] != ']') {
1278 tmp++;
1279 }
1280 Int_t num = TString(body(i + 1, tmp - 1 - i)).Atoi();
1281 num += counter;
1282 TString replacement = TString::Format("%d", num);
1283
1284 body.Replace(i + 1, tmp - 1 - i, replacement, replacement.Length());
1285 i += replacement.Length() + 1;
1286 }
1287 }
1289 if (defaultCounter && defaultVariables) {
1290 pattern = TString::Format("%s%s", funName.Data(), (isNormalized ? "n" : ""));
1291 }
1292 if (!defaultCounter && defaultVariables) {
1293 pattern = TString::Format("%s%s(%d)", funName.Data(), (isNormalized ? "n" : ""), counter);
1294 }
1295 if (defaultCounter && !defaultVariables) {
1296 pattern = TString::Format("%s%s[%s]", funName.Data(), (isNormalized ? "n" : ""), varList.Data());
1297 }
1298 if (!defaultCounter && !defaultVariables) {
1299 pattern =
1300 TString::Format("%s%s[%s](%d)", funName.Data(), (isNormalized ? "n" : ""), varList.Data(), counter);
1301 }
1302 TString replacement = body;
1303
1304 // set the number (only in case a function exists without anything else
1305 if (fNumber == 0 && formula.Length() <= (pattern.Length() - funPos) + 1) { // leave 1 extra
1306 fNumber = functionsNumbers[funName] + 10 * (dim - 1);
1307 }
1308
1309 // std::cout << " replace " << pattern << " with " << replacement << std::endl;
1310
1311 formula.Replace(funPos, pattern.Length(), replacement, replacement.Length());
1312
1313 funPos = formula.Index(funName);
1314 }
1315 // std::cout << " End loop of " << funName << " formula is now " << formula << std::endl;
1316 }
1317}
1318
1319////////////////////////////////////////////////////////////////////////////////
1320/// Handling parameter ranges, in the form of [1..5]
1322{
1323 TRegexp rangePattern("\\[[0-9]+\\.\\.[0-9]+\\]");
1324 Ssiz_t len;
1325 int matchIdx = 0;
1326 while ((matchIdx = rangePattern.Index(formula, &len, matchIdx)) != -1) {
1327 int startIdx = matchIdx + 1;
1328 int endIdx = formula.Index("..", startIdx) + 2; // +2 for ".."
1329 int startCnt = TString(formula(startIdx, formula.Length())).Atoi();
1330 int endCnt = TString(formula(endIdx, formula.Length())).Atoi();
1331
1332 if (endCnt <= startCnt)
1333 Error("HandleParamRanges", "End parameter (%d) <= start parameter (%d) in parameter range", endCnt, startCnt);
1334
1335 TString newString = "[";
1336 for (int cnt = startCnt; cnt < endCnt; cnt++)
1337 newString += TString::Format("%d],[", cnt);
1338 newString += TString::Format("%d]", endCnt);
1339
1340 // std::cout << "newString generated by HandleParamRanges is " << newString << std::endl;
1341 formula.Replace(matchIdx, formula.Index("]", matchIdx) + 1 - matchIdx, newString);
1342
1343 matchIdx += newString.Length();
1344 }
1345
1346 // std::cout << "final formula is now " << formula << std::endl;
1347}
1348
1349////////////////////////////////////////////////////////////////////////////////
1350/// Handling user functions (and parametrized functions)
1351/// to take variables and optionally parameters as arguments
1353{
1354 // std::cout << "calling `HandleFunctionArguments` on " << formula << std::endl;
1355
1356 // Define parametrized functions, in case we need to use them
1357 std::map<std::pair<TString, Int_t>, std::pair<TString, TString>> parFunctions;
1358 FillParametrizedFunctions(parFunctions);
1359
1360 // loop through characters
1361 for (Int_t i = 0; i < formula.Length(); ++i) {
1362 // List of things to ignore (copied from `TFormula::ExtractFunctors`)
1363
1364 // ignore things that start with square brackets
1365 if (formula[i] == '[') {
1366 while (formula[i] != ']')
1367 i++;
1368 continue;
1369 }
1370 // ignore strings
1371 if (formula[i] == '\"') {
1372 do
1373 i++;
1374 while (formula[i] != '\"');
1375 continue;
1376 }
1377 // ignore numbers (scientific notation)
1378 if (IsScientificNotation(formula, i))
1379 continue;
1380 // ignore x in hexadecimal number
1381 if (IsHexadecimal(formula, i)) {
1382 while (!IsOperator(formula[i]) && i < formula.Length())
1383 i++;
1384 continue;
1385 }
1386
1387 // investigate possible start of function name
1388 if (isalpha(formula[i]) && !IsOperator(formula[i])) {
1389 // std::cout << "character : " << i << " " << formula[i] << " is not an operator and is alpha" << std::endl;
1390
1391 int j; // index to end of name
1392 for (j = i; j < formula.Length() && IsFunctionNameChar(formula[j]); j++)
1393 ;
1394 TString name = (TString)formula(i, j - i);
1395 // std::cout << "parsed name " << name << std::endl;
1396
1397 // Count arguments (careful about parentheses depth)
1398 // Make list of indices where each argument is separated
1399 int nArguments = 1;
1400 int depth = 1;
1401 std::vector<int> argSeparators;
1402 argSeparators.push_back(j); // opening parenthesis
1403 int k; // index for end of closing parenthesis
1404 for (k = j + 1; depth >= 1 && k < formula.Length(); k++) {
1405 if (formula[k] == ',' && depth == 1) {
1406 nArguments++;
1407 argSeparators.push_back(k);
1408 } else if (formula[k] == '(')
1409 depth++;
1410 else if (formula[k] == ')')
1411 depth--;
1412 }
1413 argSeparators.push_back(k - 1); // closing parenthesis
1414
1415 // retrieve `f` (code copied from ExtractFunctors)
1416 TObject *obj = 0;
1417 {
1419 obj = gROOT->GetListOfFunctions()->FindObject(name);
1420 }
1421 TFormula *f = dynamic_cast<TFormula *>(obj);
1422 if (!f) {
1423 // maybe object is a TF1
1424 TF1 *f1 = dynamic_cast<TF1 *>(obj);
1425 if (f1)
1426 f = f1->GetFormula();
1427 }
1428 // `f` should be found by now, if it was a user-defined function.
1429 // The other possibility we need to consider is that this is a
1430 // parametrized function (else case below)
1431
1432 bool nameRecognized = (f != nullptr);
1433
1434 // Get ndim, npar, and replacementFormula of function
1435 int ndim = 0;
1436 int npar = 0;
1437 TString replacementFormula;
1438 if (f) {
1439 ndim = f->GetNdim();
1440 npar = f->GetNpar();
1441 replacementFormula = f->GetExpFormula();
1442 } else {
1443 // otherwise, try to match default parametrized functions
1444
1445 for (const auto &keyval : parFunctions) {
1446 // (name, ndim)
1447 const pair<TString, Int_t> &name_ndim = keyval.first;
1448 // (formula without normalization, formula with normalization)
1449 const pair<TString, TString> &formulaPair = keyval.second;
1450
1451 // match names like gaus, gausn, breitwigner
1452 if (name == name_ndim.first)
1453 replacementFormula = formulaPair.first;
1454 else if (name == name_ndim.first + "n" && formulaPair.second != "")
1455 replacementFormula = formulaPair.second;
1456 else
1457 continue;
1458
1459 // set ndim
1460 ndim = name_ndim.second;
1461
1462 // go through replacementFormula to find the number of parameters
1463 npar = 0;
1464 int idx = 0;
1465 while ((idx = replacementFormula.Index('[', idx)) != kNPOS) {
1466 npar = max(npar, 1 + TString(replacementFormula(idx + 1, replacementFormula.Length())).Atoi());
1467 idx = replacementFormula.Index(']', idx);
1468 if (idx == kNPOS)
1469 Error("HandleFunctionArguments", "Square brackets not matching in formula %s",
1470 (const char *)replacementFormula);
1471 }
1472 // npar should be set correctly now
1473
1474 // break if number of arguments is good (note: `gaus`, has two
1475 // definitions with different numbers of arguments, but it works
1476 // out so that it should be unambiguous)
1477 if (nArguments == ndim + npar || nArguments == npar || nArguments == ndim) {
1478 nameRecognized = true;
1479 break;
1480 }
1481 }
1482 }
1483 if (nameRecognized && ndim > 4)
1484 Error("HandleFunctionArguments", "Number of dimensions %d greater than 4. Cannot parse formula.", ndim);
1485
1486 // if we have "recognizedName(...", then apply substitutions
1487 if (nameRecognized && j < formula.Length() && formula[j] == '(') {
1488 // std::cout << "naive replacement formula: " << replacementFormula << std::endl;
1489 // std::cout << "formula: " << formula << std::endl;
1490
1491 // map to rename each argument in `replacementFormula`
1492 map<TString, TString> argSubstitutions;
1493
1494 const char *defaultVariableNames[] = {"x", "y", "z", "t"};
1495
1496 // check nArguments and add to argSubstitutions map as appropriate
1497 bool canReplace = false;
1498 if (nArguments == ndim + npar) {
1499 // loop through all variables and parameters, filling in argSubstitutions
1500 for (int argNr = 0; argNr < nArguments; argNr++) {
1501
1502 // Get new name (for either variable or parameter)
1503 TString newName =
1504 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1505 PreProcessFormula(newName); // so that nesting works
1506
1507 // Get old name(s)
1508 // and add to argSubstitutions map as appropriate
1509 if (argNr < ndim) { // variable
1510 TString oldName = (f) ? TString::Format("x[%d]", argNr) : TString::Format("{V%d}", argNr);
1511 argSubstitutions[oldName] = newName;
1512
1513 if (f)
1514 argSubstitutions[defaultVariableNames[argNr]] = newName;
1515
1516 } else { // parameter
1517 int parNr = argNr - ndim;
1518 TString oldName =
1519 (f) ? TString::Format("[%s]", f->GetParName(parNr)) : TString::Format("[%d]", parNr);
1520 argSubstitutions[oldName] = newName;
1521
1522 // If the name stays the same, keep the old value of the parameter
1523 if (f && oldName == newName)
1524 DoAddParameter(f->GetParName(parNr), f->GetParameter(parNr), false);
1525 }
1526 }
1527
1528 canReplace = true;
1529 } else if (nArguments == npar) {
1530 // Try to assume variables are implicit (need all arguments to be
1531 // parameters)
1532
1533 // loop to check if all arguments are parameters
1534 bool varsImplicit = true;
1535 for (int argNr = 0; argNr < nArguments && varsImplicit; argNr++) {
1536 int openIdx = argSeparators[argNr] + 1;
1537 int closeIdx = argSeparators[argNr + 1] - 1;
1538
1539 // check brackets on either end
1540 if (formula[openIdx] != '[' || formula[closeIdx] != ']' || closeIdx <= openIdx + 1)
1541 varsImplicit = false;
1542
1543 // check that the middle is a single function-name
1544 for (int idx = openIdx + 1; idx < closeIdx && varsImplicit; idx++)
1545 if (!IsFunctionNameChar(formula[idx]))
1546 varsImplicit = false;
1547
1548 if (!varsImplicit)
1549 Warning("HandleFunctionArguments",
1550 "Argument %d is not a parameter. Cannot assume variables are implicit.", argNr);
1551 }
1552
1553 // loop to replace parameter names
1554 if (varsImplicit) {
1555 // if parametrized function, still need to replace parameter names
1556 if (!f) {
1557 for (int dim = 0; dim < ndim; dim++) {
1558 argSubstitutions[TString::Format("{V%d}", dim)] = defaultVariableNames[dim];
1559 }
1560 }
1561
1562 for (int argNr = 0; argNr < nArguments; argNr++) {
1563 TString oldName =
1564 (f) ? TString::Format("[%s]", f->GetParName(argNr)) : TString::Format("[%d]", argNr);
1565 TString newName =
1566 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1567
1568 // preprocess the formula so that nesting works
1569 PreProcessFormula(newName);
1570 argSubstitutions[oldName] = newName;
1571
1572 // If the name stays the same, keep the old value of the parameter
1573 if (f && oldName == newName)
1574 DoAddParameter(f->GetParName(argNr), f->GetParameter(argNr), false);
1575 }
1576
1577 canReplace = true;
1578 }
1579 }
1580 if (!canReplace && nArguments == ndim) {
1581 // Treat parameters as implicit
1582
1583 // loop to replace variable names
1584 for (int argNr = 0; argNr < nArguments; argNr++) {
1585 TString oldName = (f) ? TString::Format("x[%d]", argNr) : TString::Format("{V%d}", argNr);
1586 TString newName =
1587 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1588
1589 // preprocess so nesting works
1590 PreProcessFormula(newName);
1591 argSubstitutions[oldName] = newName;
1592
1593 if (f) // x, y, z are not used in parametrized function definitions
1594 argSubstitutions[defaultVariableNames[argNr]] = newName;
1595 }
1596
1597 if (f) {
1598 // keep old values of the parameters
1599 for (int parNr = 0; parNr < npar; parNr++)
1600 DoAddParameter(f->GetParName(parNr), f->GetParameter(parNr), false);
1601 }
1602
1603 canReplace = true;
1604 }
1605
1606 if (canReplace)
1607 ReplaceAllNames(replacementFormula, argSubstitutions);
1608 // std::cout << "after replacement, replacementFormula is " << replacementFormula << std::endl;
1609
1610 if (canReplace) {
1611 // std::cout << "about to replace position " << i << " length " << k-i << " in formula : " << formula <<
1612 // std::endl;
1613 formula.Replace(i, k - i, replacementFormula);
1614 i += replacementFormula.Length() - 1; // skip to end of replacement
1615 // std::cout << "new formula is : " << formula << std::endl;
1616 } else {
1617 Warning("HandleFunctionArguments", "Unable to make replacement. Number of parameters doesn't work : "
1618 "%d arguments, %d dimensions, %d parameters",
1619 nArguments, ndim, npar);
1620 i = j;
1621 }
1622
1623 } else {
1624 i = j; // skip to end of candidate "name"
1625 }
1626 }
1627 }
1628
1629}
1630
1631////////////////////////////////////////////////////////////////////////////////
1632/// Handling exponentiation
1633/// Can handle multiple carets, eg.
1634/// 2^3^4 will be treated like 2^(3^4)
1635
1637{
1638 Int_t caretPos = formula.Last('^');
1639 while (caretPos != kNPOS && !IsAParameterName(formula, caretPos)) {
1640
1641 TString right, left;
1642 Int_t temp = caretPos;
1643 temp--;
1644 // get the expression in ( ) which has the operator^ applied
1645 if (formula[temp] == ')') {
1646 Int_t depth = 1;
1647 temp--;
1648 while (depth != 0 && temp > 0) {
1649 if (formula[temp] == ')')
1650 depth++;
1651 if (formula[temp] == '(')
1652 depth--;
1653 temp--;
1654 }
1655 if (depth == 0)
1656 temp++;
1657 }
1658 // this in case of someting like sin(x+2)^2
1659 do {
1660 temp--; // go down one
1661 // handle scientific notation cases (1.e-2 ^ 3 )
1662 if (temp >= 2 && IsScientificNotation(formula, temp - 1))
1663 temp -= 3;
1664 } while (temp >= 0 && !IsOperator(formula[temp]) && !IsBracket(formula[temp]));
1665
1666 assert(temp + 1 >= 0);
1667 Int_t leftPos = temp + 1;
1668 left = formula(leftPos, caretPos - leftPos);
1669 // std::cout << "left to replace is " << left << std::endl;
1670
1671 // look now at the expression after the ^ operator
1672 temp = caretPos;
1673 temp++;
1674 if (temp >= formula.Length()) {
1675 Error("HandleExponentiation", "Invalid position of operator ^");
1676 return;
1677 }
1678 if (formula[temp] == '(') {
1679 Int_t depth = 1;
1680 temp++;
1681 while (depth != 0 && temp < formula.Length()) {
1682 if (formula[temp] == ')')
1683 depth--;
1684 if (formula[temp] == '(')
1685 depth++;
1686 temp++;
1687 }
1688 temp--;
1689 } else {
1690 // handle case first character is operator - or + continue
1691 if (formula[temp] == '-' || formula[temp] == '+')
1692 temp++;
1693 // handle cases x^-2 or x^+2
1694 // need to handle also cases x^sin(x+y)
1695 Int_t depth = 0;
1696 // stop right expression if is an operator or if is a ")" from a zero depth
1697 while (temp < formula.Length() && ((depth > 0) || !IsOperator(formula[temp]))) {
1698 temp++;
1699 // handle scientific notation cases (1.e-2 ^ 3 )
1700 if (temp >= 2 && IsScientificNotation(formula, temp))
1701 temp += 2;
1702 // for internal parenthesis
1703 if (temp < formula.Length() && formula[temp] == '(')
1704 depth++;
1705 if (temp < formula.Length() && formula[temp] == ')') {
1706 if (depth > 0)
1707 depth--;
1708 else
1709 break; // case of end of a previously started expression e.g. sin(x^2)
1710 }
1711 }
1712 }
1713 right = formula(caretPos + 1, (temp - 1) - caretPos);
1714 // std::cout << "right to replace is " << right << std::endl;
1715
1716 TString pattern = TString::Format("%s^%s", left.Data(), right.Data());
1717 TString replacement = TString::Format("pow(%s,%s)", left.Data(), right.Data());
1718
1719 // std::cout << "pattern : " << pattern << std::endl;
1720 // std::cout << "replacement : " << replacement << std::endl;
1721 formula.Replace(leftPos, pattern.Length(), replacement, replacement.Length());
1722
1723 caretPos = formula.Last('^');
1724 }
1725}
1726
1727
1728////////////////////////////////////////////////////////////////////////////////
1729/// Handle linear functions defined with the operator ++.
1730
1732{
1733 if(formula.Length() == 0) return;
1734 auto terms = ROOT::Split(formula.Data(), "@");
1735 if(terms.size() <= 1) return; // function is not linear
1736 // Handle Linear functions identified with "@" operator
1737 fLinearParts.reserve(terms.size());
1738 TString expandedFormula = "";
1739 int delimeterPos = 0;
1740 for(std::size_t iTerm = 0; iTerm < terms.size(); ++iTerm) {
1741 // determine the position of the "@" operator in the formula
1742 delimeterPos += terms[iTerm].size() + (iTerm == 0);
1743 if(IsAParameterName(formula, delimeterPos)) {
1744 // append the current term and the remaining formula unchanged to the expanded formula
1745 expandedFormula += terms[iTerm];
1746 expandedFormula += formula(delimeterPos, formula.Length() - (delimeterPos + 1));
1747 break;
1748 }
1749 SetBit(kLinear, 1);
1750 auto termName = std::string("__linear") + std::to_string(iTerm+1);
1751 fLinearParts.push_back(new TFormula(termName.c_str(), terms[iTerm].c_str(), false));
1752 std::stringstream ss;
1753 ss << "([" << iTerm << "]*(" << terms[iTerm] << "))";
1754 expandedFormula += ss.str();
1755 if(iTerm < terms.size() - 1) expandedFormula += "+";
1756 }
1757 formula = expandedFormula;
1758}
1759
1760////////////////////////////////////////////////////////////////////////////////
1761/// Preprocessing of formula
1762/// Replace all ** by ^, and removes spaces.
1763/// Handle also parametrized functions like polN,gaus,expo,landau
1764/// and exponentiation.
1765/// Similar functionality should be added here.
1766
1768{
1769 formula.ReplaceAll("**","^");
1770 formula.ReplaceAll("++","@"); // for linear functions
1771 formula.ReplaceAll(" ","");
1772 HandlePolN(formula);
1774 HandleParamRanges(formula);
1775 HandleFunctionArguments(formula);
1776 HandleExponentiation(formula);
1777 // "++" wil be dealt with Handle Linear
1778 HandleLinear(formula);
1779 // special case for "--" and "++"
1780 // ("++" needs to be written with whitespace that is removed before but then we re-add it again
1781 formula.ReplaceAll("--","- -");
1782 formula.ReplaceAll("++","+ +");
1783}
1784
1785////////////////////////////////////////////////////////////////////////////////
1786/// prepare the formula to be executed
1787/// normally is called with fFormula
1788
1790{
1791 fFuncs.clear();
1792 fReadyToExecute = false;
1793 ExtractFunctors(formula);
1794
1795 // update the expression with the new formula
1796 fFormula = formula;
1797 // save formula to parse variable and parameters for Cling
1798 fClingInput = formula;
1799 // replace all { and }
1800 fFormula.ReplaceAll("{","");
1801 fFormula.ReplaceAll("}","");
1802
1803 // std::cout << "functors are extracted formula is " << std::endl;
1804 // std::cout << fFormula << std::endl << std::endl;
1805
1806 fFuncs.sort();
1807 fFuncs.unique();
1808
1809 // use inputFormula for Cling
1811
1812 // for pre-defined functions (need after processing)
1813 if (fNumber != 0) SetPredefinedParamNames();
1814
1816}
1817
1818////////////////////////////////////////////////////////////////////////////////
1819/// Extracts functors from formula, and put them in fFuncs.
1820/// Simple grammar:
1821/// - `<function>` := name(arg1,arg2...)
1822/// - `<variable>` := name
1823/// - `<parameter>` := [number]
1824/// - `<name>` := String containing lower and upper letters, numbers, underscores
1825/// - `<number>` := Integer number
1826/// Operators are omitted.
1827
1829{
1830 // std::cout << "Commencing ExtractFunctors on " << formula << std::endl;
1831
1832 TString name = "";
1833 TString body = "";
1834 // printf("formula is : %s \n",formula.Data() );
1835 for (Int_t i = 0; i < formula.Length(); ++i) {
1836
1837 // std::cout << "loop on character : " << i << " " << formula[i] << std::endl;
1838 // case of parameters
1839 if (formula[i] == '[') {
1840 Int_t tmp = i;
1841 i++;
1842 TString param = "";
1843 while (i < formula.Length() && formula[i] != ']') {
1844 param.Append(formula[i++]);
1845 }
1846 i++;
1847 // rename parameter name XX to pXX
1848 // std::cout << "examine parameters " << param << std::endl;
1849 int paramIndex = -1;
1850 if (param.IsDigit()) {
1851 paramIndex = param.Atoi();
1852 param.Insert(0, 'p'); // needed for the replacement
1853 if (paramIndex >= fNpar || fParams.find(param) == fParams.end()) {
1854 // add all parameters up to given index found
1855 for (int idx = 0; idx <= paramIndex; ++idx) {
1856 TString pname = TString::Format("p%d", idx);
1857 if (fParams.find(pname) == fParams.end())
1858 DoAddParameter(pname, 0, false);
1859 }
1860 }
1861 } else {
1862 // handle whitespace characters in parname
1863 param.ReplaceAll("\\s", " ");
1864
1865 // only add if parameter does not already exist, because maybe
1866 // `HandleFunctionArguments` already assigned a default value to the
1867 // parameter
1868 if (fParams.find(param) == fParams.end() || GetParNumber(param) < 0 ||
1869 (unsigned)GetParNumber(param) >= fClingParameters.size()) {
1870 // std::cout << "Setting parameter " << param << " to 0" << std::endl;
1871 DoAddParameter(param, 0, false);
1872 }
1873 }
1874 TString replacement = TString::Format("{[%s]}", param.Data());
1875 formula.Replace(tmp, i - tmp, replacement, replacement.Length());
1876 fFuncs.push_back(TFormulaFunction(param));
1877 // we need to change index i after replacing since string length changes
1878 // and we need to re-calculate i position
1879 int deltai = replacement.Length() - (i-tmp);
1880 i += deltai;
1881 // printf("found parameter %s \n",param.Data() );
1882 continue;
1883 }
1884 // case of strings
1885 if (formula[i] == '\"') {
1886 // look for next instance of "\"
1887 do {
1888 i++;
1889 } while (formula[i] != '\"');
1890 }
1891 // case of e or E for numbers in exponential notation (e.g. 2.2e-3)
1892 if (IsScientificNotation(formula, i))
1893 continue;
1894 // case of x for hexadecimal numbers
1895 if (IsHexadecimal(formula, i)) {
1896 // find position of operator
1897 // do not check cases if character is not only a to f, but accept anything
1898 while (!IsOperator(formula[i]) && i < formula.Length()) {
1899 i++;
1900 }
1901 continue;
1902 }
1903
1904 // std::cout << "investigating character : " << i << " " << formula[i] << " of formula " << formula <<
1905 // std::endl;
1906 // look for variable and function names. They start in C++ with alphanumeric characters
1907 if (isalpha(formula[i]) &&
1908 !IsOperator(formula[i])) // not really needed to check if operator (if isalpha is not an operator)
1909 {
1910 // std::cout << "character : " << i << " " << formula[i] << " is not an operator and is alpha " <<
1911 // std::endl;
1912
1913 while (i < formula.Length() && IsFunctionNameChar(formula[i])) {
1914 // need special case for separating operator ":" from scope operator "::"
1915 if (formula[i] == ':' && ((i + 1) < formula.Length())) {
1916 if (formula[i + 1] == ':') {
1917 // case of :: (scopeOperator)
1918 name.Append("::");
1919 i += 2;
1920 continue;
1921 } else
1922 break;
1923 }
1924
1925 name.Append(formula[i++]);
1926 }
1927 // printf(" build a name %s \n",name.Data() );
1928 if (formula[i] == '(') {
1929 i++;
1930 if (formula[i] == ')') {
1931 fFuncs.push_back(TFormulaFunction(name, body, 0));
1932 name = body = "";
1933 continue;
1934 }
1935 Int_t depth = 1;
1936 Int_t args = 1; // we will miss first argument
1937 while (depth != 0 && i < formula.Length()) {
1938 switch (formula[i]) {
1939 case '(': depth++; break;
1940 case ')': depth--; break;
1941 case ',':
1942 if (depth == 1)
1943 args++;
1944 break;
1945 }
1946 if (depth != 0) // we don't want last ')' inside body
1947 {
1948 body.Append(formula[i++]);
1949 }
1950 }
1951 Int_t originalBodyLen = body.Length();
1952 ExtractFunctors(body);
1953 formula.Replace(i - originalBodyLen, originalBodyLen, body, body.Length());
1954 i += body.Length() - originalBodyLen;
1955 fFuncs.push_back(TFormulaFunction(name, body, args));
1956 } else {
1957
1958 // std::cout << "check if character : " << i << " " << formula[i] << " from name " << name << " is a
1959 // function " << std::endl;
1960
1961 // check if function is provided by gROOT
1962 TObject *obj = 0;
1963 // exclude case function name is x,y,z,t
1964 if (!IsReservedName(name))
1965 {
1967 obj = gROOT->GetListOfFunctions()->FindObject(name);
1968 }
1969 TFormula *f = dynamic_cast<TFormula *>(obj);
1970 if (!f) {
1971 // maybe object is a TF1
1972 TF1 *f1 = dynamic_cast<TF1 *>(obj);
1973 if (f1)
1974 f = f1->GetFormula();
1975 }
1976 if (f) {
1977 // Replacing user formula the old way (as opposed to 'HandleFunctionArguments')
1978 // Note this is only for replacing functions that do
1979 // not specify variables and/or parameters in brackets
1980 // (the other case is done by `HandleFunctionArguments`)
1981
1982 TString replacementFormula = f->GetExpFormula();
1983
1984 // analyze expression string
1985 // std::cout << "formula to replace for " << f->GetName() << " is " << replacementFormula <<
1986 // std::endl;
1987 PreProcessFormula(replacementFormula);
1988 // we need to define different parameters if we use the unnamed default parameters ([0])
1989 // I need to replace all the terms in the functor for backward compatibility of the case
1990 // f1("[0]*x") f2("[0]*x") f1+f2 - it is weird but it is better to support
1991 // std::cout << "current number of parameter is " << fNpar << std::endl;
1992 int nparOffset = 0;
1993 // if (fParams.find("0") != fParams.end() ) {
1994 // do in any case if parameters are existing
1995 std::vector<TString> newNames;
1996 if (fNpar > 0) {
1997 nparOffset = fNpar;
1998 newNames.resize(f->GetNpar());
1999 // start from higher number to avoid overlap
2000 for (int jpar = f->GetNpar() - 1; jpar >= 0; --jpar) {
2001 // parameters name have a "p" added in front
2002 TString pj = TString(f->GetParName(jpar));
2003 if (pj[0] == 'p' && TString(pj(1, pj.Length())).IsDigit()) {
2004 TString oldName = TString::Format("[%s]", f->GetParName(jpar));
2005 TString newName = TString::Format("[p%d]", nparOffset + jpar);
2006 // std::cout << "replace - parameter " << f->GetParName(jpar) << " with " << newName <<
2007 // std::endl;
2008 replacementFormula.ReplaceAll(oldName, newName);
2009 newNames[jpar] = newName;
2010 } else
2011 newNames[jpar] = f->GetParName(jpar);
2012 }
2013 // std::cout << "after replacing params " << replacementFormula << std::endl;
2014 }
2015 ExtractFunctors(replacementFormula);
2016 // std::cout << "after re-extracting functors " << replacementFormula << std::endl;
2017
2018 // set parameter value from replacement formula
2019 for (int jpar = 0; jpar < f->GetNpar(); ++jpar) {
2020 if (nparOffset > 0) {
2021 // parameter have an offset- so take this into account
2022 assert((int)newNames.size() == f->GetNpar());
2023 SetParameter(newNames[jpar], f->GetParameter(jpar));
2024 } else
2025 // names are the same between current formula and replaced one
2026 SetParameter(f->GetParName(jpar), f->GetParameter(jpar));
2027 }
2028 // need to add parenthesis at begin and end of replacementFormula
2029 replacementFormula.Insert(0, '(');
2030 replacementFormula.Insert(replacementFormula.Length(), ')');
2031 formula.Replace(i - name.Length(), name.Length(), replacementFormula, replacementFormula.Length());
2032 // move forward the index i of the main loop
2033 i += replacementFormula.Length() - name.Length();
2034
2035 // we have extracted all the functor for "fname"
2036 // std::cout << "We have extracted all the functors for fname" << std::endl;
2037 // std::cout << " i = " << i << " f[i] = " << formula[i] << " - " << formula << std::endl;
2038 name = "";
2039
2040 continue;
2041 }
2042
2043 // add now functor in
2044 TString replacement = TString::Format("{%s}", name.Data());
2045 formula.Replace(i - name.Length(), name.Length(), replacement, replacement.Length());
2046 i += 2;
2047 fFuncs.push_back(TFormulaFunction(name));
2048 }
2049 }
2050 name = body = "";
2051 }
2052}
2053
2054////////////////////////////////////////////////////////////////////////////////
2055/// Iterates through functors in fFuncs and performs the appropriate action.
2056/// If functor has 0 arguments (has only name) can be:
2057/// - variable
2058/// * will be replaced with x[num], where x is an array containing value of this variable under num.
2059/// - pre-defined formula
2060/// * will be replaced with formulas body
2061/// - constant
2062/// * will be replaced with constant value
2063/// - parameter
2064/// * will be replaced with p[num], where p is an array containing value of this parameter under num.
2065/// If has arguments it can be :
2066/// - function shortcut, eg. sin
2067/// * will be replaced with fullname of function, eg. sin -> TMath::Sin
2068/// - function from cling environment, eg. TMath::BreitWigner(x,y,z)
2069/// * first check if function exists, and has same number of arguments, then accept it and set as found.
2070/// If all functors after iteration are matched with corresponding action,
2071/// it inputs C++ code of formula into cling, and sets flag that formula is ready to evaluate.
2072
2074{
2075 // std::cout << "Begin: formula is " << formula << " list of functors " << fFuncs.size() << std::endl;
2076
2077 for (list<TFormulaFunction>::iterator funcsIt = fFuncs.begin(); funcsIt != fFuncs.end(); ++funcsIt) {
2078 TFormulaFunction &fun = *funcsIt;
2079
2080 // std::cout << "fun is " << fun.GetName() << std::endl;
2081
2082 if (fun.fFound)
2083 continue;
2084 if (fun.IsFuncCall()) {
2085 // replace with pre-defined functions
2086 map<TString, TString>::iterator it = fFunctionsShortcuts.find(fun.GetName());
2087 if (it != fFunctionsShortcuts.end()) {
2088 TString shortcut = it->first;
2089 TString full = it->second;
2090 // std::cout << " functor " << fun.GetName() << " found - replace " << shortcut << " with " << full << " in
2091 // " << formula << std::endl;
2092 // replace all functors
2093 Ssiz_t index = formula.Index(shortcut, 0);
2094 while (index != kNPOS) {
2095 // check that function is not in a namespace and is not in other characters
2096 // std::cout << "analyzing " << shortcut << " in " << formula << std::endl;
2097 Ssiz_t i2 = index + shortcut.Length();
2098 if ((index > 0) && (isalpha(formula[index - 1]) || formula[index - 1] == ':')) {
2099 index = formula.Index(shortcut, i2);
2100 continue;
2101 }
2102 if (i2 < formula.Length() && formula[i2] != '(') {
2103 index = formula.Index(shortcut, i2);
2104 continue;
2105 }
2106 // now replace the string
2107 formula.Replace(index, shortcut.Length(), full);
2108 Ssiz_t inext = index + full.Length();
2109 index = formula.Index(shortcut, inext);
2110 fun.fFound = true;
2111 }
2112 }
2113 // for functions we can live it to cling to decide if it is a valid function or NOT
2114 // We don't need to retrieve this information from the ROOT interpreter
2115 // we assume that the function is then found and all the following code does not need to be there
2116#ifdef TFORMULA_CHECK_FUNCTIONS
2117
2118 if (fun.fName.Contains("::")) // add support for nested namespaces
2119 {
2120 // look for last occurence of "::"
2121 std::string name(fun.fName.Data());
2122 size_t index = name.rfind("::");
2123 assert(index != std::string::npos);
2124 TString className = fun.fName(0, fun.fName(0, index).Length());
2125 TString functionName = fun.fName(index + 2, fun.fName.Length());
2126
2127 Bool_t silent = true;
2128 TClass *tclass = TClass::GetClass(className, silent);
2129 // std::cout << "looking for class " << className << std::endl;
2130 const TList *methodList = tclass->GetListOfAllPublicMethods();
2131 TIter next(methodList);
2132 TMethod *p;
2133 while ((p = (TMethod *)next())) {
2134 if (strcmp(p->GetName(), functionName.Data()) == 0 &&
2135 (fun.GetNargs() <= p->GetNargs() && fun.GetNargs() >= p->GetNargs() - p->GetNargsOpt())) {
2136 fun.fFound = true;
2137 break;
2138 }
2139 }
2140 }
2141 if (!fun.fFound) {
2142 // try to look into all the global functions in gROOT
2143 TFunction *f;
2144 {
2146 f = (TFunction *)gROOT->GetListOfGlobalFunctions(true)->FindObject(fun.fName);
2147 }
2148 // if found a function with matching arguments
2149 if (f && fun.GetNargs() <= f->GetNargs() && fun.GetNargs() >= f->GetNargs() - f->GetNargsOpt()) {
2150 fun.fFound = true;
2151 }
2152 }
2153
2154 if (!fun.fFound) {
2155 // ignore not found functions
2156 if (gDebug)
2157 Info("TFormula", "Could not find %s function with %d argument(s)", fun.GetName(), fun.GetNargs());
2158 fun.fFound = false;
2159 }
2160#endif
2161 } else {
2162 TFormula *old = 0;
2163 {
2165 old = (TFormula *)gROOT->GetListOfFunctions()->FindObject(gNamePrefix + fun.fName);
2166 }
2167 if (old) {
2168 // we should not go here (this analysis is done before in ExtractFunctors)
2169 assert(false);
2170 fun.fFound = true;
2171 TString pattern = TString::Format("{%s}", fun.GetName());
2172 TString replacement = old->GetExpFormula();
2173 PreProcessFormula(replacement);
2174 ExtractFunctors(replacement);
2175 formula.ReplaceAll(pattern, replacement);
2176 continue;
2177 }
2178 // looking for default variables defined in fVars
2179
2180 map<TString, TFormulaVariable>::iterator varsIt = fVars.find(fun.GetName());
2181 if (varsIt != fVars.end()) {
2182
2183 TString name = (*varsIt).second.GetName();
2184 Double_t value = (*varsIt).second.fValue;
2185
2186 AddVariable(name, value); // this set the cling variable
2187 if (!fVars[name].fFound) {
2188
2189 fVars[name].fFound = true;
2190 int varDim = (*varsIt).second.fArrayPos; // variable dimensions (0 for x, 1 for y, 2, for z)
2191 if (varDim >= fNdim) {
2192 fNdim = varDim + 1;
2193
2194 // we need to be sure that all other variables are added with position less
2195 for (auto &v : fVars) {
2196 if (v.second.fArrayPos < varDim && !v.second.fFound) {
2197 AddVariable(v.first, v.second.fValue);
2198 v.second.fFound = true;
2199 }
2200 }
2201 }
2202 }
2203 // remove the "{.. }" added around the variable
2204 TString pattern = TString::Format("{%s}", name.Data());
2205 TString replacement = TString::Format("x[%d]", (*varsIt).second.fArrayPos);
2206 formula.ReplaceAll(pattern, replacement);
2207
2208 // std::cout << "Found an observable for " << fun.GetName() << std::endl;
2209
2210 fun.fFound = true;
2211 continue;
2212 }
2213 // check for observables defined as x[0],x[1],....
2214 // maybe could use a regular expression here
2215 // only in case match with defined variables is not successful
2216 TString funname = fun.GetName();
2217 if (funname.Contains("x[") && funname.Contains("]")) {
2218 TString sdigit = funname(2, funname.Index("]"));
2219 int digit = sdigit.Atoi();
2220 if (digit >= fNdim) {
2221 fNdim = digit + 1;
2222 // we need to add the variables in fVars all of them before x[n]
2223 for (int j = 0; j < fNdim; ++j) {
2224 TString vname = TString::Format("x[%d]", j);
2225 if (fVars.find(vname) == fVars.end()) {
2226 fVars[vname] = TFormulaVariable(vname, 0, j);
2227 fVars[vname].fFound = true;
2228 AddVariable(vname, 0.);
2229 }
2230 }
2231 }
2232 // std::cout << "Found matching observable for " << funname << std::endl;
2233 fun.fFound = true;
2234 // remove the "{.. }" added around the variable
2235 TString pattern = TString::Format("{%s}", funname.Data());
2236 formula.ReplaceAll(pattern, funname);
2237 continue;
2238 }
2239 //}
2240
2241 auto paramsIt = fParams.find(fun.GetName());
2242 if (paramsIt != fParams.end()) {
2243 // TString name = (*paramsIt).second.GetName();
2244 TString pattern = TString::Format("{[%s]}", fun.GetName());
2245 // std::cout << "pattern is " << pattern << std::endl;
2246 if (formula.Index(pattern) != kNPOS) {
2247 // TString replacement = TString::Format("p[%d]",(*paramsIt).second.fArrayPos);
2248 TString replacement = TString::Format("p[%d]", (*paramsIt).second);
2249 // std::cout << "replace pattern " << pattern << " with " << replacement << std::endl;
2250 formula.ReplaceAll(pattern, replacement);
2251 }
2252 fun.fFound = true;
2253 continue;
2254 } else {
2255 // std::cout << "functor " << fun.GetName() << " is not a parameter " << std::endl;
2256 }
2257
2258 // looking for constants (needs to be done after looking at the parameters)
2259 map<TString, Double_t>::iterator constIt = fConsts.find(fun.GetName());
2260 if (constIt != fConsts.end()) {
2261 TString pattern = TString::Format("{%s}", fun.GetName());
2262 TString value = TString::Format("%lf", (*constIt).second);
2263 formula.ReplaceAll(pattern, value);
2264 fun.fFound = true;
2265 // std::cout << "constant with name " << fun.GetName() << " is found " << std::endl;
2266 continue;
2267 }
2268
2269 fun.fFound = false;
2270 }
2271 }
2272 // std::cout << "End: formula is " << formula << std::endl;
2273
2274 // ignore case of functors have been matched - try to pass it to Cling
2275 if (!fReadyToExecute) {
2276 fReadyToExecute = true;
2277 Bool_t hasVariables = (fNdim > 0);
2278 Bool_t hasParameters = (fNpar > 0);
2279 if (!hasParameters) {
2280 fAllParametersSetted = true;
2281 }
2282 // assume a function without variables is always 1-dimensional ???
2283 // if (hasParameters && !hasVariables) {
2284 // fNdim = 1;
2285 // AddVariable("x", 0);
2286 // hasVariables = true;
2287 // }
2288 // does not make sense to vectorize function which is of FNDim=0
2289 if (!hasVariables) fVectorized=false;
2290 // when there are no variables but only parameter we still need to ad
2291 //Bool_t hasBoth = hasVariables && hasParameters;
2292 Bool_t inputIntoCling = (formula.Length() > 0);
2293 if (inputIntoCling) {
2294 // save copy of inputFormula in a std::strig for the unordered map
2295 // and also formula is same as FClingInput typically and it will be modified
2296 std::string inputFormula(formula.Data());
2297
2298 // The name we really use for the unordered map will have a flag that
2299 // says whether the formula is vectorized
2300 std::string inputFormulaVecFlag = inputFormula;
2301 if (fVectorized)
2302 inputFormulaVecFlag += " (vectorized)";
2303
2304 TString argType = fVectorized ? "ROOT::Double_v" : "Double_t";
2305
2306 // valid input formula - try to put into Cling (in case of no variables but only parameter we need to add the standard signature)
2307 TString argumentsPrototype = TString::Format("%s%s%s", ( (hasVariables || hasParameters) ? (argType + " *x").Data() : ""),
2308 (hasParameters ? "," : ""), (hasParameters ? "Double_t *p" : ""));
2309
2310 // set the name for Cling using the hash_function
2312
2313 // check if formula exist already in the map
2315
2316 // std::cout << "gClingFunctions list" << std::endl;
2317 // for (auto thing : gClingFunctions)
2318 // std::cout << "gClingFunctions : " << thing.first << std::endl;
2319
2320 auto funcit = gClingFunctions.find(inputFormulaVecFlag);
2321
2322 if (funcit != gClingFunctions.end()) {
2323 fFuncPtr = (TFormula::CallFuncSignature)funcit->second;
2324 fClingInitialized = true;
2325 inputIntoCling = false;
2326 }
2327
2328
2329
2330 // set the cling name using hash of the static formulae map
2331 auto hasher = gClingFunctions.hash_function();
2332 fClingName = TString::Format("%s__id%zu", gNamePrefix.Data(), hasher(inputFormulaVecFlag));
2333
2334 fClingInput = TString::Format("%s %s(%s){ return %s ; }", argType.Data(), fClingName.Data(),
2335 argumentsPrototype.Data(), inputFormula.c_str());
2336
2337
2338 // std::cout << "Input Formula " << inputFormula << " \t vec formula : " << inputFormulaVecFlag << std::endl;
2339 // std::cout << "Cling functions existing " << std::endl;
2340 // for (auto & ff : gClingFunctions)
2341 // std::cout << ff.first << std::endl;
2342 // std::cout << "\n";
2343 // std::cout << fClingName << std::endl;
2344
2345 // this is not needed (maybe can be re-added in case of recompilation of identical expressions
2346 // // check in case of a change if need to re-initialize
2347 // if (fClingInitialized) {
2348 // if (oldClingInput == fClingInput)
2349 // inputIntoCling = false;
2350 // else
2351 // fClingInitialized = false;
2352 // }
2353
2354 if (inputIntoCling) {
2355 if (!fLazyInitialization) {
2357 if (fClingInitialized) {
2358 // if Cling has been successfully initialized
2359 // put function ptr in the static map
2361 gClingFunctions.insert(std::make_pair(inputFormulaVecFlag, (void *)fFuncPtr));
2362 }
2363 }
2364 if (!fClingInitialized) {
2365 // needed in case of lazy initialization of failure compiling the expression
2366 fSavedInputFormula = inputFormulaVecFlag;
2367 }
2368
2369 } else {
2370 fAllParametersSetted = true;
2371 fClingInitialized = true;
2372 }
2373 }
2374 }
2375
2376 // In case of a Cling Error check components which are not found in Cling
2377 // check that all formula components are matched otherwise emit an error
2379 //Bool_t allFunctorsMatched = false;
2380 for (list<TFormulaFunction>::iterator it = fFuncs.begin(); it != fFuncs.end(); ++it) {
2381 // functions are now by default always not checked
2382 if (!it->fFound && !it->IsFuncCall()) {
2383 //allFunctorsMatched = false;
2384 if (it->GetNargs() == 0)
2385 Error("ProcessFormula", "\"%s\" has not been matched in the formula expression", it->GetName());
2386 else
2387 Error("ProcessFormula", "Could not find %s function with %d argument(s)", it->GetName(), it->GetNargs());
2388 }
2389 }
2390 Error("ProcessFormula","Formula \"%s\" is invalid !", GetExpFormula().Data() );
2391 fReadyToExecute = false;
2392 }
2393
2394 // clean up un-used default variables in case formula is valid
2395 //if (fClingInitialized && fReadyToExecute) {
2396 //don't check fClingInitialized in case of lazy execution
2397 if (fReadyToExecute) {
2398 auto itvar = fVars.begin();
2399 // need this loop because after erase change iterators
2400 do {
2401 if (!itvar->second.fFound) {
2402 // std::cout << "Erase variable " << itvar->first << std::endl;
2403 itvar = fVars.erase(itvar);
2404 } else
2405 itvar++;
2406 } while (itvar != fVars.end());
2407 }
2408}
2409
2410////////////////////////////////////////////////////////////////////////////////
2411/// Fill map with parametrized functions
2412
2413void TFormula::FillParametrizedFunctions(map<pair<TString, Int_t>, pair<TString, TString>> &functions)
2414{
2415 // map< pair<TString,Int_t> ,pair<TString,TString> > functions;
2416 functions.insert(
2417 make_pair(make_pair("gaus", 1), make_pair("[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))",
2418 "[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))/(sqrt(2*pi)*[2])")));
2419 functions.insert(make_pair(make_pair("landau", 1), make_pair("[0]*TMath::Landau({V0},[1],[2],false)",
2420 "[0]*TMath::Landau({V0},[1],[2],true)")));
2421 functions.insert(make_pair(make_pair("expo", 1), make_pair("exp([0]+[1]*{V0})", "")));
2422 functions.insert(
2423 make_pair(make_pair("crystalball", 1), make_pair("[0]*ROOT::Math::crystalball_function({V0},[3],[4],[2],[1])",
2424 "[0]*ROOT::Math::crystalball_pdf({V0},[3],[4],[2],[1])")));
2425 functions.insert(
2426 make_pair(make_pair("breitwigner", 1), make_pair("[0]*ROOT::Math::breitwigner_pdf({V0},[2],[1])",
2427 "[0]*ROOT::Math::breitwigner_pdf({V0},[2],[4],[1])")));
2428 // chebyshev polynomial
2429 functions.insert(make_pair(make_pair("cheb0", 1), make_pair("ROOT::Math::Chebyshev0({V0},[0])", "")));
2430 functions.insert(make_pair(make_pair("cheb1", 1), make_pair("ROOT::Math::Chebyshev1({V0},[0],[1])", "")));
2431 functions.insert(make_pair(make_pair("cheb2", 1), make_pair("ROOT::Math::Chebyshev2({V0},[0],[1],[2])", "")));
2432 functions.insert(make_pair(make_pair("cheb3", 1), make_pair("ROOT::Math::Chebyshev3({V0},[0],[1],[2],[3])", "")));
2433 functions.insert(
2434 make_pair(make_pair("cheb4", 1), make_pair("ROOT::Math::Chebyshev4({V0},[0],[1],[2],[3],[4])", "")));
2435 functions.insert(
2436 make_pair(make_pair("cheb5", 1), make_pair("ROOT::Math::Chebyshev5({V0},[0],[1],[2],[3],[4],[5])", "")));
2437 functions.insert(
2438 make_pair(make_pair("cheb6", 1), make_pair("ROOT::Math::Chebyshev6({V0},[0],[1],[2],[3],[4],[5],[6])", "")));
2439 functions.insert(
2440 make_pair(make_pair("cheb7", 1), make_pair("ROOT::Math::Chebyshev7({V0},[0],[1],[2],[3],[4],[5],[6],[7])", "")));
2441 functions.insert(make_pair(make_pair("cheb8", 1),
2442 make_pair("ROOT::Math::Chebyshev8({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8])", "")));
2443 functions.insert(make_pair(make_pair("cheb9", 1),
2444 make_pair("ROOT::Math::Chebyshev9({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9])", "")));
2445 functions.insert(
2446 make_pair(make_pair("cheb10", 1),
2447 make_pair("ROOT::Math::Chebyshev10({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10])", "")));
2448 // 2-dimensional functions
2449 functions.insert(
2450 make_pair(make_pair("gaus", 2), make_pair("[0]*exp(-0.5*(({V0}-[1])/[2])^2 - 0.5*(({V1}-[3])/[4])^2)", "")));
2451 functions.insert(
2452 make_pair(make_pair("landau", 2),
2453 make_pair("[0]*TMath::Landau({V0},[1],[2],false)*TMath::Landau({V1},[3],[4],false)", "")));
2454 functions.insert(make_pair(make_pair("expo", 2), make_pair("exp([0]+[1]*{V0})", "exp([0]+[1]*{V0}+[2]*{V1})")));
2455 // 3-dimensional function
2456 functions.insert(
2457 make_pair(make_pair("gaus", 3), make_pair("[0]*exp(-0.5*(({V0}-[1])/[2])^2 - 0.5*(({V1}-[3])/[4])^2 - 0.5*(({V2}-[5])/[6])^2)", "")));
2458 // gaussian with correlations
2459 functions.insert(
2460 make_pair(make_pair("bigaus", 2), make_pair("[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])",
2461 "[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])")));
2462}
2463
2464////////////////////////////////////////////////////////////////////////////////
2465/// Set parameter names only in case of pre-defined functions.
2466
2468
2469 if (fNumber == 0) return;
2470
2471 if (fNumber == 100) { // Gaussian
2472 SetParName(0,"Constant");
2473 SetParName(1,"Mean");
2474 SetParName(2,"Sigma");
2475 return;
2476 }
2477 if (fNumber == 110) {
2478 SetParName(0,"Constant");
2479 SetParName(1,"MeanX");
2480 SetParName(2,"SigmaX");
2481 SetParName(3,"MeanY");
2482 SetParName(4,"SigmaY");
2483 return;
2484 }
2485 if (fNumber == 120) {
2486 SetParName(0,"Constant");
2487 SetParName(1,"MeanX");
2488 SetParName(2,"SigmaX");
2489 SetParName(3,"MeanY");
2490 SetParName(4,"SigmaY");
2491 SetParName(5,"MeanZ");
2492 SetParName(6,"SigmaZ");
2493 return;
2494 }
2495 if (fNumber == 112) { // bigaus
2496 SetParName(0,"Constant");
2497 SetParName(1,"MeanX");
2498 SetParName(2,"SigmaX");
2499 SetParName(3,"MeanY");
2500 SetParName(4,"SigmaY");
2501 SetParName(5,"Rho");
2502 return;
2503 }
2504 if (fNumber == 200) { // exponential
2505 SetParName(0,"Constant");
2506 SetParName(1,"Slope");
2507 return;
2508 }
2509 if (fNumber == 400) { // landau
2510 SetParName(0,"Constant");
2511 SetParName(1,"MPV");
2512 SetParName(2,"Sigma");
2513 return;
2514 }
2515 if (fNumber == 500) { // crystal-ball
2516 SetParName(0,"Constant");
2517 SetParName(1,"Mean");
2518 SetParName(2,"Sigma");
2519 SetParName(3,"Alpha");
2520 SetParName(4,"N");
2521 return;
2522 }
2523 if (fNumber == 600) { // breit-wigner
2524 SetParName(0,"Constant");
2525 SetParName(1,"Mean");
2526 SetParName(2,"Gamma");
2527 return;
2528 }
2529 // if formula is a polynomial (or chebyshev), set parameter names
2530 // not needed anymore (p0 is assigned by default)
2531 // if (fNumber == (300+fNpar-1) ) {
2532 // for (int i = 0; i < fNpar; i++) SetParName(i,TString::Format("p%d",i));
2533 // return;
2534 // }
2535
2536 // // general case if parameters are digits (XX) change to pXX
2537 // auto paramMap = fParams; // need to copy the map because SetParName is going to modify it
2538 // for ( auto & p : paramMap) {
2539 // if (p.first.IsDigit() )
2540 // SetParName(p.second,TString::Format("p%s",p.first.Data()));
2541 // }
2542
2543 return;
2544}
2545
2546////////////////////////////////////////////////////////////////////////////////
2547/// Return linear part.
2548
2550{
2551 if (!fLinearParts.empty()) {
2552 int n = fLinearParts.size();
2553 if (i < 0 || i >= n ) {
2554 Error("GetLinearPart","Formula %s has only %d linear parts - requested %d",GetName(),n,i);
2555 return nullptr;
2556 }
2557 return fLinearParts[i];
2558 }
2559 return nullptr;
2560}
2561
2562////////////////////////////////////////////////////////////////////////////////
2563/// Adds variable to known variables, and reprocess formula.
2564
2566{
2567 if (fVars.find(name) != fVars.end()) {
2568 TFormulaVariable &var = fVars[name];
2569 var.fValue = value;
2570
2571 // If the position is not defined in the Cling vectors, make space for it
2572 // but normally is variable is defined in fVars a slot should be also present in fClingVariables
2573 if (var.fArrayPos < 0) {
2574 var.fArrayPos = fVars.size();
2575 }
2576 if (var.fArrayPos >= (int)fClingVariables.size()) {
2577 fClingVariables.resize(var.fArrayPos + 1);
2578 }
2580 } else {
2581 TFormulaVariable var(name, value, fVars.size());
2582 fVars[name] = var;
2583 fClingVariables.push_back(value);
2584 if (!fFormula.IsNull()) {
2585 // printf("process formula again - %s \n",fClingInput.Data() );
2587 }
2588 }
2589}
2590
2591////////////////////////////////////////////////////////////////////////////////
2592/// Adds multiple variables.
2593/// First argument is an array of pairs<TString,Double>, where
2594/// first argument is name of variable,
2595/// second argument represents value.
2596/// size - number of variables passed in first argument
2597
2599{
2600 Bool_t anyNewVar = false;
2601 for (Int_t i = 0; i < size; ++i) {
2602
2603 const TString &vname = vars[i];
2604
2605 TFormulaVariable &var = fVars[vname];
2606 if (var.fArrayPos < 0) {
2607
2608 var.fName = vname;
2609 var.fArrayPos = fVars.size();
2610 anyNewVar = true;
2611 var.fValue = 0;
2612 if (var.fArrayPos >= (int)fClingVariables.capacity()) {
2613 Int_t multiplier = 2;
2614 if (fFuncs.size() > 100) {
2615 multiplier = TMath::Floor(TMath::Log10(fFuncs.size()) * 10);
2616 }
2617 fClingVariables.reserve(multiplier * fClingVariables.capacity());
2618 }
2619 fClingVariables.push_back(0.0);
2620 }
2621 // else
2622 // {
2623 // var.fValue = v.second;
2624 // fClingVariables[var.fArrayPos] = v.second;
2625 // }
2626 }
2627 if (anyNewVar && !fFormula.IsNull()) {
2629 }
2630}
2631
2632////////////////////////////////////////////////////////////////////////////////
2633/// Set the name of the formula. We need to allow the list of function to
2634/// properly handle the hashes.
2635
2636void TFormula::SetName(const char* name)
2637{
2638 if (IsReservedName(name)) {
2639 Error("SetName", "The name \'%s\' is reserved as a TFormula variable name.\n"
2640 "\tThis function will not be renamed.",
2641 name);
2642 } else {
2643 // Here we need to remove and re-add to keep the hashes consistent with
2644 // the underlying names.
2645 auto listOfFunctions = gROOT->GetListOfFunctions();
2646 TObject* thisAsFunctionInList = nullptr;
2648 if (listOfFunctions){
2649 thisAsFunctionInList = listOfFunctions->FindObject(this);
2650 if (thisAsFunctionInList) listOfFunctions->Remove(thisAsFunctionInList);
2651 }
2653 if (thisAsFunctionInList) listOfFunctions->Add(thisAsFunctionInList);
2654 }
2655}
2656
2657////////////////////////////////////////////////////////////////////////////////
2658///
2659/// Sets multiple variables.
2660/// First argument is an array of pairs<TString,Double>, where
2661/// first argument is name of variable,
2662/// second argument represents value.
2663/// size - number of variables passed in first argument
2664
2665void TFormula::SetVariables(const pair<TString,Double_t> *vars, const Int_t size)
2666{
2667 for(Int_t i = 0; i < size; ++i)
2668 {
2669 auto &v = vars[i];
2670 if (fVars.find(v.first) != fVars.end()) {
2671 fVars[v.first].fValue = v.second;
2672 fClingVariables[fVars[v.first].fArrayPos] = v.second;
2673 } else {
2674 Error("SetVariables", "Variable %s is not defined.", v.first.Data());
2675 }
2676 }
2677}
2678
2679////////////////////////////////////////////////////////////////////////////////
2680/// Returns variable value.
2681
2683{
2684 const auto nameIt = fVars.find(name);
2685 if (fVars.end() == nameIt) {
2686 Error("GetVariable", "Variable %s is not defined.", name);
2687 return -1;
2688 }
2689 return nameIt->second.fValue;
2690}
2691
2692////////////////////////////////////////////////////////////////////////////////
2693/// Returns variable number (positon in array) given its name.
2694
2696{
2697 const auto nameIt = fVars.find(name);
2698 if (fVars.end() == nameIt) {
2699 Error("GetVarNumber", "Variable %s is not defined.", name);
2700 return -1;
2701 }
2702 return nameIt->second.fArrayPos;
2703}
2704
2705////////////////////////////////////////////////////////////////////////////////
2706/// Returns variable name given its position in the array.
2707
2709{
2710 if (ivar < 0 || ivar >= fNdim) return "";
2711
2712 // need to loop on the map to find corresponding variable
2713 for ( auto & v : fVars) {
2714 if (v.second.fArrayPos == ivar) return v.first;
2715 }
2716 Error("GetVarName","Variable with index %d not found !!",ivar);
2717 //return TString::Format("x%d",ivar);
2718 return "";
2719}
2720
2721////////////////////////////////////////////////////////////////////////////////
2722/// Sets variable value.
2723
2725{
2726 if (fVars.find(name) == fVars.end()) {
2727 Error("SetVariable", "Variable %s is not defined.", name.Data());
2728 return;
2729 }
2730 fVars[name].fValue = value;
2731 fClingVariables[fVars[name].fArrayPos] = value;
2732}
2733
2734////////////////////////////////////////////////////////////////////////////////
2735/// Adds parameter to known parameters.
2736/// User should use SetParameter, because parameters are added during initialization part,
2737/// and after that adding new will be pointless.
2738
2740{
2741 //std::cout << "adding parameter " << name << std::endl;
2742
2743 // if parameter is already defined in fParams - just set the new value
2744 if(fParams.find(name) != fParams.end() )
2745 {
2746 int ipos = fParams[name];
2747 // TFormulaVariable & par = fParams[name];
2748 // par.fValue = value;
2749 if (ipos < 0) {
2750 ipos = fParams.size();
2751 fParams[name] = ipos;
2752 }
2753 //
2754 if (ipos >= (int)fClingParameters.size()) {
2755 if (ipos >= (int)fClingParameters.capacity())
2756 fClingParameters.reserve(TMath::Max(int(fParams.size()), ipos + 1));
2757 fClingParameters.insert(fClingParameters.end(), ipos + 1 - fClingParameters.size(), 0.0);
2758 }
2759 fClingParameters[ipos] = value;
2760 } else {
2761 // new parameter defined
2762 fNpar++;
2763 // TFormulaVariable(name,value,fParams.size());
2764 int pos = fParams.size();
2765 // fParams.insert(std::make_pair<TString,TFormulaVariable>(name,TFormulaVariable(name,value,pos)));
2766 auto ret = fParams.insert(std::make_pair(name, pos));
2767 // map returns a std::pair<iterator, bool>
2768 // use map the order for default position of parameters in the vector
2769 // (i.e use the alphabetic order)
2770 if (ret.second) {
2771 // a new element is inserted
2772 if (ret.first == fParams.begin())
2773 pos = 0;
2774 else {
2775 auto previous = (ret.first);
2776 --previous;
2777 pos = previous->second + 1;
2778 }
2779
2780 if (pos < (int)fClingParameters.size())
2781 fClingParameters.insert(fClingParameters.begin() + pos, value);
2782 else {
2783 // this should not happen
2784 if (pos > (int)fClingParameters.size())
2785 Warning("inserting parameter %s at pos %d when vector size is %d \n", name.Data(), pos,
2786 (int)fClingParameters.size());
2787
2788 if (pos >= (int)fClingParameters.capacity())
2789 fClingParameters.reserve(TMath::Max(int(fParams.size()), pos + 1));
2790 fClingParameters.insert(fClingParameters.end(), pos + 1 - fClingParameters.size(), 0.0);
2791 fClingParameters[pos] = value;
2792 }
2793
2794 // need to adjust all other positions
2795 for (auto it = ret.first; it != fParams.end(); ++it) {
2796 it->second = pos;
2797 pos++;
2798 }
2799
2800 // for (auto & p : fParams)
2801 // std::cout << "Parameter " << p.first << " position " << p.second << " value " <<
2802 // fClingParameters[p.second] << std::endl;
2803 // printf("inserted parameters size params %d size cling %d \n",fParams.size(), fClingParameters.size() );
2804 }
2805 if (processFormula) {
2806 // replace first in input parameter name with [name]
2809 }
2810 }
2811}
2812
2813////////////////////////////////////////////////////////////////////////////////
2814/// Return parameter index given a name (return -1 for not existing parameters)
2815/// non need to print an error
2816
2817Int_t TFormula::GetParNumber(const char * name) const {
2818 auto it = fParams.find(name);
2819 if (it == fParams.end()) {
2820 return -1;
2821 }
2822 return it->second;
2823
2824}
2825
2826////////////////////////////////////////////////////////////////////////////////
2827/// Returns parameter value given by string.
2828
2830{
2831 const int i = GetParNumber(name);
2832 if (i == -1) {
2833 Error("GetParameter","Parameter %s is not defined.",name);
2834 return TMath::QuietNaN();
2835 }
2836
2837 return GetParameter( i );
2838}
2839
2840////////////////////////////////////////////////////////////////////////////////
2841/// Return parameter value given by integer.
2842
2844{
2845 //TString name = TString::Format("%d",param);
2846 if(param >=0 && param < (int) fClingParameters.size())
2847 return fClingParameters[param];
2848 Error("GetParameter","wrong index used - use GetParameter(name)");
2849 return TMath::QuietNaN();
2850}
2851
2852////////////////////////////////////////////////////////////////////////////////
2853/// Return parameter name given by integer.
2854
2855const char * TFormula::GetParName(Int_t ipar) const
2856{
2857 if (ipar < 0 || ipar >= fNpar) return "";
2858
2859 // need to loop on the map to find corresponding parameter
2860 for ( auto & p : fParams) {
2861 if (p.second == ipar) return p.first.Data();
2862 }
2863 Error("GetParName","Parameter with index %d not found !!",ipar);
2864 //return TString::Format("p%d",ipar);
2865 return "";
2866}
2867
2868////////////////////////////////////////////////////////////////////////////////
2870{
2871 if(!fClingParameters.empty())
2872 return const_cast<Double_t*>(&fClingParameters[0]);
2873 return 0;
2874}
2875
2877{
2878 for (Int_t i = 0; i < fNpar; ++i) {
2879 if (Int_t(fClingParameters.size()) > i)
2880 params[i] = fClingParameters[i];
2881 else
2882 params[i] = -1;
2883 }
2884}
2885
2886////////////////////////////////////////////////////////////////////////////////
2887/// Sets parameter value.
2888
2890{
2892
2893 // do we need this ???
2894#ifdef OLDPARAMS
2895 if (fParams.find(name) == fParams.end()) {
2896 Error("SetParameter", "Parameter %s is not defined.", name.Data());
2897 return;
2898 }
2899 fParams[name].fValue = value;
2900 fParams[name].fFound = true;
2901 fClingParameters[fParams[name].fArrayPos] = value;
2902 fAllParametersSetted = true;
2903 for (map<TString, TFormulaVariable>::iterator it = fParams.begin(); it != fParams.end(); ++it) {
2904 if (!it->second.fFound) {
2905 fAllParametersSetted = false;
2906 break;
2907 }
2908 }
2909#endif
2910}
2911
2912#ifdef OLDPARAMS
2913
2914////////////////////////////////////////////////////////////////////////////////
2915/// Set multiple parameters.
2916/// First argument is an array of pairs<TString,Double>, where
2917/// first argument is name of parameter,
2918/// second argument represents value.
2919/// size - number of params passed in first argument
2920
2921void TFormula::SetParameters(const pair<TString,Double_t> *params,const Int_t size)
2922{
2923 for(Int_t i = 0 ; i < size ; ++i)
2924 {
2925 pair<TString, Double_t> p = params[i];
2926 if (fParams.find(p.first) == fParams.end()) {
2927 Error("SetParameters", "Parameter %s is not defined", p.first.Data());
2928 continue;
2929 }
2930 fParams[p.first].fValue = p.second;
2931 fParams[p.first].fFound = true;
2932 fClingParameters[fParams[p.first].fArrayPos] = p.second;
2933 }
2934 fAllParametersSetted = true;
2935 for (map<TString, TFormulaVariable>::iterator it = fParams.begin(); it != fParams.end(); ++it) {
2936 if (!it->second.fFound) {
2937 fAllParametersSetted = false;
2938 break;
2939 }
2940 }
2941}
2942#endif
2943
2944////////////////////////////////////////////////////////////////////////////////
2946{
2947 if(!params || size < 0 || size > fNpar) return;
2948 // reset vector of cling parameters
2949 if (size != (int) fClingParameters.size() ) {
2950 Warning("SetParameters","size is not same of cling parameter size %d - %d",size,int(fClingParameters.size()) );
2951 for (Int_t i = 0; i < size; ++i) {
2952 TString name = TString::Format("%d", i);
2953 SetParameter(name, params[i]);
2954 }
2955 return;
2956 }
2957 fAllParametersSetted = true;
2958 std::copy(params, params+size, fClingParameters.begin() );
2959}
2960
2961////////////////////////////////////////////////////////////////////////////////
2962/// Set a vector of parameters value.
2963/// Order in the vector is by default the alphabetic order given to the parameters
2964/// apart if the users has defined explicitly the parameter names
2965
2967{
2968 DoSetParameters(params,fNpar);
2969}
2970
2971////////////////////////////////////////////////////////////////////////////////
2972/// Set a list of parameters.
2973/// The order is by default the alphabetic order given to the parameters
2974/// apart if the users has defined explicitly the parameter names
2975
2977 Double_t p7, Double_t p8, Double_t p9, Double_t p10)
2978{
2979 if(fNpar >= 1) SetParameter(0,p0);
2980 if(fNpar >= 2) SetParameter(1,p1);
2981 if(fNpar >= 3) SetParameter(2,p2);
2982 if(fNpar >= 4) SetParameter(3,p3);
2983 if(fNpar >= 5) SetParameter(4,p4);
2984 if(fNpar >= 6) SetParameter(5,p5);
2985 if(fNpar >= 7) SetParameter(6,p6);
2986 if(fNpar >= 8) SetParameter(7,p7);
2987 if(fNpar >= 9) SetParameter(8,p8);
2988 if(fNpar >= 10) SetParameter(9,p9);
2989 if(fNpar >= 11) SetParameter(10,p10);
2990}
2991
2992////////////////////////////////////////////////////////////////////////////////
2993/// Set a parameter given a parameter index
2994/// The parameter index is by default the alphabetic order given to the parameters
2995/// apart if the users has defined explicitly the parameter names
2996
2998{
2999 if (param < 0 || param >= fNpar) return;
3000 assert(int(fClingParameters.size()) == fNpar);
3001 fClingParameters[param] = value;
3002 // TString name = TString::Format("%d",param);
3003 // SetParameter(name,value);
3004}
3005
3006////////////////////////////////////////////////////////////////////////////////
3007void TFormula::SetParNames(const char *name0, const char *name1, const char *name2, const char *name3,
3008 const char *name4, const char *name5, const char *name6, const char *name7,
3009 const char *name8, const char *name9, const char *name10)
3010{
3011 if (fNpar >= 1)
3012 SetParName(0, name0);
3013 if (fNpar >= 2)
3014 SetParName(1, name1);
3015 if (fNpar >= 3)
3016 SetParName(2, name2);
3017 if (fNpar >= 4)
3018 SetParName(3, name3);
3019 if (fNpar >= 5)
3020 SetParName(4, name4);
3021 if (fNpar >= 6)
3022 SetParName(5, name5);
3023 if (fNpar >= 7)
3024 SetParName(6, name6);
3025 if (fNpar >= 8)
3026 SetParName(7, name7);
3027 if (fNpar >= 9)
3028 SetParName(8, name8);
3029 if (fNpar >= 10)
3030 SetParName(9, name9);
3031 if (fNpar >= 11)
3032 SetParName(10, name10);
3033}
3034
3035////////////////////////////////////////////////////////////////////////////////
3036void TFormula::SetParName(Int_t ipar, const char * name)
3037{
3038
3039 if (ipar < 0 || ipar > fNpar) {
3040 Error("SetParName","Wrong Parameter index %d ",ipar);
3041 return;
3042 }
3043 TString oldName;
3044 // find parameter with given index
3045 for ( auto &it : fParams) {
3046 if (it.second == ipar) {
3047 oldName = it.first;
3048 fParams.erase(oldName);
3049 fParams.insert(std::make_pair(name, ipar) );
3050 break;
3051 }
3052 }
3053 if (oldName.IsNull() ) {
3054 Error("SetParName","Parameter %d is not existing.",ipar);
3055 return;
3056 }
3057
3058 //replace also parameter name in formula expression in case is not a lambda
3060
3061}
3062
3063////////////////////////////////////////////////////////////////////////////////
3064/// Replace in Formula expression the parameter name.
3065
3066void TFormula::ReplaceParamName(TString & formula, const TString & oldName, const TString & name){
3067 if (!formula.IsNull() ) {
3068 bool found = false;
3069 for(list<TFormulaFunction>::iterator it = fFuncs.begin(); it != fFuncs.end(); ++it)
3070 {
3071 if (oldName == it->GetName()) {
3072 found = true;
3073 it->fName = name;
3074 break;
3075 }
3076 }
3077 if (!found) {
3078 Error("SetParName", "Parameter %s is not defined.", oldName.Data());
3079 return;
3080 }
3081 // change whitespace to \s to avoid problems in parsing
3082 TString newName = name;
3083 newName.ReplaceAll(" ", "\\s");
3084 TString pattern = TString::Format("[%s]", oldName.Data());
3085 TString replacement = TString::Format("[%s]", newName.Data());
3086 formula.ReplaceAll(pattern, replacement);
3087 }
3088
3089}
3090
3091////////////////////////////////////////////////////////////////////////////////
3093{
3094#ifdef R__HAS_VECCORE
3095 if (fNdim == 0) {
3096 Info("SetVectorized","Cannot vectorized a function of zero dimension");
3097 return;
3098 }
3099 if (vectorized != fVectorized) {
3100 if (!fFormula)
3101 Error("SetVectorized", "Cannot set vectorized to %d -- Formula is missing", vectorized);
3102
3103 fVectorized = vectorized;
3104 // no need to JIT a new signature in case of zero dimension
3105 //if (fNdim== 0) return;
3106 fClingInitialized = false;
3107 fReadyToExecute = false;
3108 fClingName = "";
3110
3111 fMethod.reset();
3112
3113 FillVecFunctionsShurtCuts(); // to replace with the right vectorized signature (e.g. sin -> vecCore::math::Sin)
3116 }
3117#else
3118 if (vectorized)
3119 Warning("SetVectorized", "Cannot set vectorized -- try building with option -Dbuiltin_veccore=On");
3120#endif
3121}
3122
3123////////////////////////////////////////////////////////////////////////////////
3124Double_t TFormula::EvalPar(const Double_t *x,const Double_t *params) const
3125{
3126 if (!fVectorized)
3127 return DoEval(x, params);
3128
3129#ifdef R__HAS_VECCORE
3130
3131 if (fNdim == 0 || !x) {
3132 ROOT::Double_v ret = DoEvalVec(nullptr, params);
3133 return vecCore::Get( ret, 0 );
3134 }
3135
3136 // otherwise, regular Double_t inputs on a vectorized function
3137
3138 // convert our input into vectors then convert back
3139 if (gDebug)
3140 Info("EvalPar", "Function is vectorized - converting Double_t into ROOT::Double_v and back");
3141
3142 if (fNdim < 5) {
3143 const int maxDim = 4;
3144 std::array<ROOT::Double_v, maxDim> xvec;
3145 for (int i = 0; i < fNdim; i++)
3146 xvec[i] = x[i];
3147
3148 ROOT::Double_v ans = DoEvalVec(xvec.data(), params);
3149 return vecCore::Get(ans, 0);
3150 }
3151 // allocating a vector is much slower (we do only for dim > 4)
3152 std::vector<ROOT::Double_v> xvec(fNdim);
3153 for (int i = 0; i < fNdim; i++)
3154 xvec[i] = x[i];
3155
3156 ROOT::Double_v ans = DoEvalVec(xvec.data(), params);
3157 return vecCore::Get(ans, 0);
3158
3159#else
3160 // this should never happen, because fVectorized can only be set true with
3161 // R__HAS_VECCORE, but just in case:
3162 Error("EvalPar", "Formula is vectorized (even though VECCORE is disabled!)");
3163 return TMath::QuietNaN();
3164#endif
3165}
3166
3168
3169static bool functionExists(const string &Name) {
3170 return gInterpreter->GetFunction(/*cl*/0, Name.c_str());
3171}
3172
3173static void IncludeCladRuntime(Bool_t &IsCladRuntimeIncluded) {
3174 if (!IsCladRuntimeIncluded) {
3175 IsCladRuntimeIncluded = true;
3176 gInterpreter->Declare("#include <Math/CladDerivator.h>\n#pragma clad OFF");
3177 }
3178}
3179
3180static bool
3181DeclareGenerationInput(std::string FuncName, std::string CladStatement,
3182 std::string &GenerationInput) {
3183 std::string ReqFuncName = FuncName + "_req";
3184 // We want to call clad::differentiate(TFormula_id);
3185 GenerationInput = std::string("#pragma cling optimize(2)\n") +
3186 "#pragma clad ON\n" +
3187 "void " + ReqFuncName + "() {\n" +
3188 CladStatement + "\n " +
3189 "}\n" +
3190 "#pragma clad OFF";
3191
3192 return gInterpreter->Declare(GenerationInput.c_str());
3193}
3194
3196GetFuncPtr(std::string FuncName, Int_t Npar, Int_t Ndim, Bool_t Vectorized) {
3197 Bool_t hasParameters = (Npar > 0);
3198 Bool_t hasVariables = (Ndim > 0);
3199 std::unique_ptr<TMethodCall>
3200 method = prepareMethod(hasParameters, hasVariables, FuncName.c_str(),
3201 Vectorized, /*AddCladArrayRef*/ true);
3202 return prepareFuncPtr(method.get());
3203}
3204
3206 const Double_t *vars, const Double_t *pars,
3207 Double_t *result, const Int_t result_size) {
3208 void *args[3];
3209 args[0] = &vars;
3210 if (!pars) {
3211 // __attribute__((used)) extern "C" void __cf_0(void* obj, int nargs, void** args, void* ret)
3212 // {
3213 // if (ret) {
3214 // new (ret) (double) (((double (&)(double*))TFormula____id)(*(double**)args[0]));
3215 // return;
3216 // } else {
3217 // ((double (&)(double*))TFormula____id)(*(double**)args[0]);
3218 // return;
3219 // }
3220 // }
3221 args[1] = &result;
3222 (*FuncPtr)(0, 2, args, /*ret*/ nullptr); // We do not use ret in a return-void func.
3223 } else {
3224 // __attribute__((used)) extern "C" void __cf_0(void* obj, int nargs, void** args, void* ret)
3225 // {
3226 // ((void (&)(double*, double*,
3227 // clad::array_ref<double>))TFormula____id_grad_1)(*(double**)args[0],
3228 // *(double**)args[1],
3229 // *(clad::array_ref<double> *)args[2]);
3230 // return;
3231 // }
3232 args[1] = &pars;
3233
3234 // Using the interpreter to obtain the pointer to clad::array_ref is too
3235 // slow and we do not want to expose clad::array_ref to the interpreter
3236 // so this struct acts as a lightweight implementation of it
3237 struct array_ref_interface {
3238 Double_t *arr;
3239 std::size_t size;
3240 };
3241
3242 array_ref_interface ari{result, static_cast<size_t>(result_size)};
3243 args[2] = &ari;
3244 (*FuncPtr)(0, 3, args, /*ret*/nullptr); // We do not use ret in a return-void func.
3245 }
3246}
3247
3248/// returns true on success.
3250 // We already have generated the gradient.
3251 if (fGradFuncPtr)
3252 return true;
3253
3255 return false;
3256
3258
3259 // Check if the gradient request was made as part of another TFormula.
3260 // This can happen when we create multiple TFormula objects with the same
3261 // formula. In that case, the hasher will give identical id and we can
3262 // reuse the already generated gradient function.
3264 std::string GradientCall
3265 ("clad::gradient(" + std::string(fClingName.Data()) + ", \"p\");");
3267 GradientCall,
3269 return false;
3270 }
3271
3273 return true;
3274}
3275
3276// Compute the gradient with respect to the parameter passing
3277/// a CladStorageObject, i.e. a std::vector, which has the size as the nnumber of parameters.
3278/// Note that the result buffer needs to be initialized to zero before passing it to this function.
3280{
3281 if (DoEval(x) == TMath::QuietNaN())
3282 return;
3283
3284 if (!fClingInitialized) {
3285 Error("GradientPar", "Could not initialize the formula!");
3286 return;
3287 }
3288
3289 if (!GenerateGradientPar()) {
3290 Error("GradientPar", "Could not generate a gradient for the formula %s!",
3291 fClingName.Data());
3292 return;
3293 }
3294
3295 if ((int)result.size() < fNpar) {
3296 Warning("GradientPar",
3297 "The size of gradient result is %zu but %d is required. Resizing.",
3298 result.size(), fNpar);
3299 result.resize(fNpar);
3300 }
3301 GradientPar(x, result.data());
3302}
3303/// Compute the gradient with respect to the parameter passing
3304/// a buffer with a size at least equal to the number of parameters.
3305/// Note that the result buffer needs to be initialized to zero before passed to this function.
3307 const Double_t *vars = (x) ? x : fClingVariables.data();
3308 const Double_t *pars = (fNpar <= 0) ? nullptr : fClingParameters.data();
3310}
3311
3312/// returns true on success.
3314{
3315 // We already have generated the hessian.
3316 if (fHessFuncPtr)
3317 return true;
3318
3320 return false;
3321
3323
3324 // Check if the hessian request was made as part of another TFormula.
3325 // This can happen when we create multiple TFormula objects with the same
3326 // formula. In that case, the hasher will give identical id and we can
3327 // reuse the already generated hessian function.
3329 std::string indexes = (fNpar - 1 == 0) ? "0" : std::string("0:")
3330 + std::to_string(fNpar - 1);
3331 std::string HessianCall
3332 ("clad::hessian(" + std::string(fClingName.Data()) + ", \"p["
3333 + indexes + "]\" );");
3334 if (!DeclareGenerationInput(GetHessianFuncName(), HessianCall,
3336 return false;
3337 }
3338
3340 return true;
3341}
3342
3344{
3345 if (DoEval(x) == TMath::QuietNaN())
3346 return;
3347
3348 if (!fClingInitialized) {
3349 Error("HessianPar", "Could not initialize the formula!");
3350 return;
3351 }
3352
3353 if (!GenerateHessianPar()) {
3354 Error("HessianPar", "Could not generate a hessian for the formula %s!",
3355 fClingName.Data());
3356 return;
3357 }
3358
3359 if ((int)result.size() < fNpar) {
3360 Warning("HessianPar",
3361 "The size of hessian result is %zu but %d is required. Resizing.",
3362 result.size(), fNpar * fNpar);
3363 result.resize(fNpar * fNpar);
3364 }
3365 HessianPar(x, result.data());
3366}
3367
3369 const Double_t *vars = (x) ? x : fClingVariables.data();
3370 const Double_t *pars = (fNpar <= 0) ? nullptr : fClingParameters.data();
3372}
3373
3374////////////////////////////////////////////////////////////////////////////////
3375#ifdef R__HAS_VECCORE
3376// ROOT::Double_v TFormula::Eval(ROOT::Double_v x, ROOT::Double_v y, ROOT::Double_v z, ROOT::Double_v t) const
3377// {
3378// ROOT::Double_v xxx[] = {x, y, z, t};
3379// return EvalPar(xxx, nullptr);
3380// }
3381
3382ROOT::Double_v TFormula::EvalParVec(const ROOT::Double_v *x, const Double_t *params) const
3383{
3384 if (fVectorized)
3385 return DoEvalVec(x, params);
3386
3387 if (fNdim == 0 || !x)
3388 return DoEval(nullptr, params); // automatic conversion to vectorized
3389
3390 // otherwise, trying to input vectors into a scalar function
3391
3392 if (gDebug)
3393 Info("EvalPar", "Function is not vectorized - converting ROOT::Double_v into Double_t and back");
3394
3395 const int vecSize = vecCore::VectorSize<ROOT::Double_v>();
3396 std::vector<Double_t> xscalars(vecSize*fNdim);
3397
3398 for (int i = 0; i < vecSize; i++)
3399 for (int j = 0; j < fNdim; j++)
3400 xscalars[i*fNdim+j] = vecCore::Get(x[j],i);
3401
3402 ROOT::Double_v answers(0.);
3403 for (int i = 0; i < vecSize; i++)
3404 vecCore::Set(answers, i, DoEval(&xscalars[i*fNdim], params));
3405
3406 return answers;
3407}
3408#endif
3409
3410////////////////////////////////////////////////////////////////////////////////
3411/// Sets first 4 variables (e.g. x, y, z, t) and evaluate formula.
3412
3414{
3415 double xxx[4] = {x,y,z,t};
3416 return EvalPar(xxx, nullptr); // takes care of case where formula is vectorized
3417}
3418
3419////////////////////////////////////////////////////////////////////////////////
3420/// Sets first 3 variables (e.g. x, y, z) and evaluate formula.
3421
3423{
3424 double xxx[3] = {x,y,z};
3425 return EvalPar(xxx, nullptr);
3426}
3427
3428////////////////////////////////////////////////////////////////////////////////
3429/// Sets first 2 variables (e.g. x and y) and evaluate formula.
3430
3432{
3433 double xxx[2] = {x,y};
3434 return EvalPar(xxx, nullptr);
3435}
3436
3437////////////////////////////////////////////////////////////////////////////////
3438/// Sets first variable (e.g. x) and evaluate formula.
3439
3441{
3442 double * xxx = &x;
3443 return EvalPar(xxx, nullptr);
3444}
3445
3446////////////////////////////////////////////////////////////////////////////////
3447/// Evaluate formula.
3448/// If formula is not ready to execute(missing parameters/variables),
3449/// print these which are not known.
3450/// If parameter has default value, and has not been set, appropriate warning is shown.
3451
3452Double_t TFormula::DoEval(const double * x, const double * params) const
3453{
3454 if(!fReadyToExecute)
3455 {
3456 Error("Eval", "Formula is invalid and not ready to execute ");
3457 for (auto it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3458 TFormulaFunction fun = *it;
3459 if (!fun.fFound) {
3460 printf("%s is unknown.\n", fun.GetName());
3461 }
3462 }
3463 return TMath::QuietNaN();
3464 }
3465
3466 // Lazy initialization is set and needed when reading from a file
3468 // try recompiling the formula. We need to lock because this is not anymore thread safe
3470 // check again in case another thread has initialized the formula (see ROOT-10994)
3471 if (!fClingInitialized) {
3472 auto thisFormula = const_cast<TFormula*>(this);
3473 thisFormula->ReInitializeEvalMethod();
3474 }
3475 if (!fClingInitialized) {
3476 Error("DoEval", "Formula has error and it is not properly initialized ");
3477 return TMath::QuietNaN();
3478 }
3479 }
3480
3481 if (fLambdaPtr && TestBit(TFormula::kLambda)) {// case of lambda functions
3482 std::function<double(double *, double *)> & fptr = * ( (std::function<double(double *, double *)> *) fLambdaPtr);
3483 assert(x);
3484 //double * v = (x) ? const_cast<double*>(x) : const_cast<double*>(fClingVariables.data());
3485 double * v = const_cast<double*>(x);
3486 double * p = (params) ? const_cast<double*>(params) : const_cast<double*>(fClingParameters.data());
3487 return fptr(v, p);
3488 }
3489
3490
3491 Double_t result = 0;
3492 void* args[2];
3493 double * vars = (x) ? const_cast<double*>(x) : const_cast<double*>(fClingVariables.data());
3494 args[0] = &vars;
3495 if (fNpar <= 0) {
3496 (*fFuncPtr)(0, 1, args, &result);
3497 } else {
3498 double *pars = (params) ? const_cast<double *>(params) : const_cast<double *>(fClingParameters.data());
3499 args[1] = &pars;
3500 (*fFuncPtr)(0, 2, args, &result);
3501 }
3502 return result;
3503}
3504
3505////////////////////////////////////////////////////////////////////////////////
3506// Copied from DoEval, but this is the vectorized version
3507#ifdef R__HAS_VECCORE
3508ROOT::Double_v TFormula::DoEvalVec(const ROOT::Double_v *x, const double *params) const
3509{
3510 if (!fReadyToExecute) {
3511 Error("Eval", "Formula is invalid and not ready to execute ");
3512 for (auto it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3513 TFormulaFunction fun = *it;
3514 if (!fun.fFound) {
3515 printf("%s is unknown.\n", fun.GetName());
3516 }
3517 }
3518 return TMath::QuietNaN();
3519 }
3520 // todo maybe save lambda ptr stuff for later
3521
3523 // try recompiling the formula. We need to lock because this is not anymore thread safe
3525 // check again in case another thread has initialized the formula (see ROOT-10994)
3526 if (!fClingInitialized) {
3527 auto thisFormula = const_cast<TFormula*>(this);
3528 thisFormula->ReInitializeEvalMethod();
3529 }
3530 if (!fClingInitialized) {
3531 Error("DoEval", "Formula has error and it is not properly initialized ");
3533 return res;
3534 }
3535 }
3536
3538 void *args[2];
3539
3540 ROOT::Double_v *vars = const_cast<ROOT::Double_v *>(x);
3541 args[0] = &vars;
3542 if (fNpar <= 0) {
3543 (*fFuncPtr)(0, 1, args, &result);
3544 }else {
3545 double *pars = (params) ? const_cast<double *>(params) : const_cast<double *>(fClingParameters.data());
3546 args[1] = &pars;
3547 (*fFuncPtr)(0, 2, args, &result);
3548 }
3549 return result;
3550}
3551#endif // R__HAS_VECCORE
3552
3553
3554//////////////////////////////////////////////////////////////////////////////
3555/// Re-initialize eval method
3556///
3557/// This function is called by DoEval and DoEvalVector in case of a previous failure
3558/// or in case of reading from a file
3559////////////////////////////////////////////////////////////////////////////////
3561
3562
3563 if (TestBit(TFormula::kLambda) ) {
3564 Info("ReInitializeEvalMethod","compile now lambda expression function using Cling");
3566 fLazyInitialization = false;
3567 return;
3568 }
3569 fMethod.reset();
3570
3571 if (!fLazyInitialization) Warning("ReInitializeEvalMethod", "Formula is NOT properly initialized - try calling again TFormula::PrepareEvalMethod");
3572 //else Info("ReInitializeEvalMethod", "Compile now the formula expression using Cling");
3573
3574 // check first if formula exists in the global map
3575 {
3576
3578
3579 // std::cout << "gClingFunctions list" << std::endl;
3580 // for (auto thing : gClingFunctions)
3581 // std::cout << "gClingFunctions : " << thing.first << std::endl;
3582
3583 auto funcit = gClingFunctions.find(fSavedInputFormula);
3584
3585 if (funcit != gClingFunctions.end()) {
3586 fFuncPtr = (TFormula::CallFuncSignature)funcit->second;
3587 fClingInitialized = true;
3588 fLazyInitialization = false;
3589 return;
3590 }
3591 }
3592 // compile now formula using cling
3594 if (fClingInitialized && !fLazyInitialization) Info("ReInitializeEvalMethod", "Formula is now properly initialized !!");
3595 fLazyInitialization = false;
3596
3597 // add function pointer in global map
3598 if (fClingInitialized) {
3599 R__ASSERT(!fSavedInputFormula.empty());
3600 // if Cling has been successfully initialized
3601 // put function ptr in the static map
3603 gClingFunctions.insert(std::make_pair(fSavedInputFormula, (void *)fFuncPtr));
3604 }
3605
3606
3607 return;
3608}
3609
3610////////////////////////////////////////////////////////////////////////////////
3611/// Return the expression formula.
3612///
3613/// - If option = "P" replace the parameter names with their values
3614/// - If option = "CLING" return the actual expression used to build the function passed to cling
3615/// - If option = "CLINGP" replace in the CLING expression the parameter with their values
3616
3618{
3619 TString opt(option);
3620 if (opt.IsNull() || TestBit(TFormula::kLambda) ) return fFormula;
3621 opt.ToUpper();
3622
3623 // if (opt.Contains("N") ) {
3624 // TString formula = fFormula;
3625 // ReplaceParName(formula, ....)
3626 // }
3627
3628 if (opt.Contains("CLING") ) {
3629 std::string clingFunc = fClingInput.Data();
3630 std::size_t found = clingFunc.find("return");
3631 std::size_t found2 = clingFunc.rfind(";");
3632 if (found == std::string::npos || found2 == std::string::npos) {
3633 Error("GetExpFormula","Invalid Cling expression - return default formula expression");
3634 return fFormula;
3635 }
3636 TString clingFormula = fClingInput(found+7,found2-found-7);
3637 // to be implemented
3638 if (!opt.Contains("P")) return clingFormula;
3639 // replace all "p[" with "[parname"
3640 int i = 0;
3641 while (i < clingFormula.Length()-2 ) {
3642 // look for p[number
3643 if (clingFormula[i] == 'p' && clingFormula[i+1] == '[' && isdigit(clingFormula[i+2]) ) {
3644 int j = i+3;
3645 while ( isdigit(clingFormula[j]) ) { j++;}
3646 if (clingFormula[j] != ']') {
3647 Error("GetExpFormula","Parameters not found - invalid expression - return default cling formula");
3648 return clingFormula;
3649 }
3650 TString parNumbName = clingFormula(i+2,j-i-2);
3651 int parNumber = parNumbName.Atoi();
3652 assert(parNumber < fNpar);
3653 TString replacement = TString::Format("%f",GetParameter(parNumber));
3654 clingFormula.Replace(i,j-i+1, replacement );
3655 i += replacement.Length();
3656 }
3657 i++;
3658 }
3659 return clingFormula;
3660 }
3661 if (opt.Contains("P") ) {
3662 // replace parameter names with their values
3663 TString expFormula = fFormula;
3664 int i = 0;
3665 while (i < expFormula.Length()-2 ) {
3666 // look for [parName]
3667 if (expFormula[i] == '[') {
3668 int j = i+1;
3669 while ( expFormula[j] != ']' ) { j++;}
3670 if (expFormula[j] != ']') {
3671 Error("GetExpFormula","Parameter names not found - invalid expression - return default formula");
3672 return expFormula;
3673 }
3674 TString parName = expFormula(i+1,j-i-1);
3675 TString replacement = TString::Format("%g",GetParameter(parName));
3676 expFormula.Replace(i,j-i+1, replacement );
3677 i += replacement.Length();
3678 }
3679 i++;
3680 }
3681 return expFormula;
3682 }
3683 Warning("GetExpFormula","Invalid option - return default formula expression");
3684 return fFormula;
3685}
3686
3688 std::unique_ptr<TInterpreterValue> v = gInterpreter->MakeInterpreterValue();
3689 std::string s("(void (&)(Double_t *, Double_t *, clad::array_ref<Double_t>)) ");
3691 gInterpreter->Evaluate(s.c_str(), *v);
3692 return v->ToString();
3693}
3694
3696 std::unique_ptr<TInterpreterValue> v = gInterpreter->MakeInterpreterValue();
3697 gInterpreter->Evaluate(GetHessianFuncName().c_str(), *v);
3698 return v->ToString();
3699}
3700
3701////////////////////////////////////////////////////////////////////////////////
3702/// Print the formula and its attributes.
3703
3705{
3706 printf(" %20s : %s Ndim= %d, Npar= %d, Number= %d \n",GetName(),GetTitle(), fNdim,fNpar,fNumber);
3707 printf(" Formula expression: \n");
3708 printf("\t%s \n",fFormula.Data() );
3709 TString opt(option);
3710 opt.ToUpper();
3711 // do an evaluation as a cross-check
3712 //if (fReadyToExecute) Eval();
3713
3714 if (opt.Contains("V") ) {
3715 if (fNdim > 0 && !TestBit(TFormula::kLambda)) {
3716 printf("List of Variables: \n");
3717 assert(int(fClingVariables.size()) >= fNdim);
3718 for ( int ivar = 0; ivar < fNdim ; ++ivar) {
3719 printf("Var%4d %20s = %10f \n",ivar,GetVarName(ivar).Data(), fClingVariables[ivar]);
3720 }
3721 }
3722 if (fNpar > 0) {
3723 printf("List of Parameters: \n");
3724 if ( int(fClingParameters.size()) < fNpar)
3725 Error("Print","Number of stored parameters in vector %zu in map %zu is different than fNpar %d",fClingParameters.size(), fParams.size(), fNpar);
3726 assert(int(fClingParameters.size()) >= fNpar);
3727 // print with order passed to Cling function
3728 for ( int ipar = 0; ipar < fNpar ; ++ipar) {
3729 printf("Par%4d %20s = %10f \n",ipar,GetParName(ipar), fClingParameters[ipar] );
3730 }
3731 }
3732 printf("Expression passed to Cling:\n");
3733 printf("\t%s\n",fClingInput.Data() );
3734 if (fGradFuncPtr) {
3735 printf("Generated Gradient:\n");
3736 printf("%s\n", fGradGenerationInput.c_str());
3737 printf("%s\n", GetGradientFormula().Data());
3738 }
3739 if(fHessFuncPtr) {
3740 printf("Generated Hessian:\n");
3741 printf("%s\n", fHessGenerationInput.c_str());
3742 printf("%s\n", GetHessianFormula().Data());
3743 }
3744 }
3745 if(!fReadyToExecute)
3746 {
3747 Warning("Print", "Formula is not ready to execute. Missing parameters/variables");
3748 for (list<TFormulaFunction>::const_iterator it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3749 TFormulaFunction fun = *it;
3750 if (!fun.fFound) {
3751 printf("%s is unknown.\n", fun.GetName());
3752 }
3753 }
3754 }
3755 if (!fAllParametersSetted) {
3756 // we can skip this
3757 // Info("Print","Not all parameters are set.");
3758 // for(map<TString,TFormulaVariable>::const_iterator it = fParams.begin(); it != fParams.end(); ++it)
3759 // {
3760 // pair<TString,TFormulaVariable> param = *it;
3761 // if(!param.second.fFound)
3762 // {
3763 // printf("%s has default value %lf\n",param.first.Data(),param.second.GetInitialValue());
3764 // }
3765 // }
3766 }
3767}
3768
3769////////////////////////////////////////////////////////////////////////////////
3770/// Stream a class object.
3771
3773{
3774 if (b.IsReading() ) {
3775 UInt_t R__s, R__c;
3776 Version_t v = b.ReadVersion(&R__s, &R__c);
3777 //std::cout << "version " << v << std::endl;
3778 if (v <= 8 && v > 3 && v != 6) {
3779 // old TFormula class
3781 // read old TFormula class
3782 fold->Streamer(b, v, R__s, R__c, TFormula::Class());
3783 //std::cout << "read old tformula class " << std::endl;
3784 TFormula fnew(fold->GetName(), fold->GetExpFormula() );
3785
3786 *this = fnew;
3787
3788 // printf("copying content in a new TFormula \n");
3789 SetParameters(fold->GetParameters() );
3790 if (!fReadyToExecute ) {
3791 Error("Streamer","Old formula read from file is NOT valid");
3792 Print("v");
3793 }
3794 delete fold;
3795 return;
3796 }
3797 else if (v > 8) {
3798 // new TFormula class
3799 b.ReadClassBuffer(TFormula::Class(), this, v, R__s, R__c);
3800
3801 //std::cout << "reading npar = " << GetNpar() << std::endl;
3802
3803 // initialize the formula
3804 // need to set size of fClingVariables which is transient
3805 //fClingVariables.resize(fNdim);
3806
3807 // case of formula contains only parameters
3808 if (fFormula.IsNull() ) return;
3809
3810
3811 // store parameter values, names and order
3812 std::vector<double> parValues = fClingParameters;
3813 auto paramMap = fParams;
3814 fNpar = fParams.size();
3815
3816 fLazyInitialization = true; // when reading we initialize the formula later to avoid problem of recursive Jitting
3817
3818 if (!TestBit(TFormula::kLambda) ) {
3819
3820 // save dimension read from the file (stored for V >=12)
3821 // and we check after initializing if it is the same
3822 int ndim = fNdim;
3823 fNdim = 0;
3824
3825 //std::cout << "Streamer::Reading preprocess the formula " << fFormula << " ndim = " << fNdim << " npar = " << fNpar << std::endl;
3826 // for ( auto &p : fParams)
3827 // std::cout << "parameter " << p.first << " index " << p.second << std::endl;
3828
3829 fClingParameters.clear(); // need to be reset before re-initializing it
3830
3831 FillDefaults();
3832
3833
3835
3836 //std::cout << "Streamer::after pre-process the formula " << fFormula << " ndim = " << fNdim << " npar = " << fNpar << std::endl;
3837
3839
3840 //std::cout << "Streamer::after prepared " << fClingInput << " ndim = " << fNdim << " npar = " << fNpar << std::endl;
3841
3842
3843 // restore parameter values
3844 if (fNpar != (int) parValues.size() ) {
3845 Error("Streamer","number of parameters computed (%d) is not same as the stored parameters (%d)",fNpar,int(parValues.size()) );
3846 Print("v");
3847 }
3848 if (v > 11 && fNdim != ndim) {
3849 Error("Streamer","number of dimension computed (%d) is not same as the stored value (%d)",fNdim, ndim );
3850 Print("v");
3851 }
3852 }
3853 else {
3854 // we also delay the initialization of lamda expressions
3855 if (!fLazyInitialization) {
3856 bool ret = InitLambdaExpression(fFormula);
3857 if (ret) {
3858 fClingInitialized = true;
3859 }
3860 }else {
3861 fReadyToExecute = true;
3862 }
3863 }
3864 assert(fNpar == (int) parValues.size() );
3865 std::copy( parValues.begin(), parValues.end(), fClingParameters.begin() );
3866 // restore parameter names and order
3867 if (fParams.size() != paramMap.size() ) {
3868 Warning("Streamer","number of parameters list found (%zu) is not same as the stored one (%zu) - use re-created list",fParams.size(),paramMap.size()) ;
3869 //Print("v");
3870 }
3871 else
3872 //assert(fParams.size() == paramMap.size() );
3873 fParams = paramMap;
3874
3875 // input formula into Cling
3876 // need to replace in cling the name of the pointer of this object
3877 // TString oldClingName = fClingName;
3878 // fClingName.Replace(fClingName.Index("_0x")+1,fClingName.Length(), TString::Format("%p",this) );
3879 // fClingInput.ReplaceAll(oldClingName, fClingName);
3880 // InputFormulaIntoCling();
3881
3882 if (!TestBit(kNotGlobal)) {
3884 gROOT->GetListOfFunctions()->Add(this);
3885 }
3886 if (!fReadyToExecute ) {
3887 Error("Streamer","Formula read from file is NOT ready to execute");
3888 Print("v");
3889 }
3890 //std::cout << "reading 2 npar = " << GetNpar() << std::endl;
3891
3892 return;
3893 }
3894 else {
3895 Error("Streamer","Reading version %d is not supported",v);
3896 return;
3897 }
3898 }
3899 else {
3900 // case of writing
3901 b.WriteClassBuffer(TFormula::Class(), this);
3902 // std::cout << "writing npar = " << GetNpar() << std::endl;
3903 }
3904}
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Definition: RtypesCore.h:63
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
short Version_t
Definition: RtypesCore.h:65
double Double_t
Definition: RtypesCore.h:59
const char Option_t
Definition: RtypesCore.h:66
#define ClassImp(name)
Definition: Rtypes.h:375
#define R__ASSERT(e)
Definition: TError.h:118
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:188
void GetParameters(TFitEditor::FuncParams_t &pars, TF1 *func)
Stores the parameters of the given function into pars.
Definition: TFitEditor.cxx:256
static std::unordered_map< std::string, void * > gClingFunctions
Definition: TFormula.cxx:265
static void IncludeCladRuntime(Bool_t &IsCladRuntimeIncluded)
Definition: TFormula.cxx:3173
void(*)(Int_t nobjects, TObject **from, TObject **to) TFormulaUpdater_t
Definition: TFormula.cxx:281
static void CallCladFunction(TInterpreter::CallFuncIFacePtr_t::Generic_t FuncPtr, const Double_t *vars, const Double_t *pars, Double_t *result, const Int_t result_size)
Definition: TFormula.cxx:3205
static const TString gNamePrefix
Definition: TFormula.cxx:261
static std::unique_ptr< TMethodCall > prepareMethod(bool HasParameters, bool HasVariables, const char *FuncName, bool IsVectorized, bool AddCladArrayRef=false)
Definition: TFormula.cxx:800
static bool DeclareGenerationInput(std::string FuncName, std::string CladStatement, std::string &GenerationInput)
Definition: TFormula.cxx:3181
static bool IsReservedName(const char *name)
Definition: TFormula.cxx:456
bool R__SetClonesArrayTFormulaUpdater(TFormulaUpdater_t func)
static bool functionExists(const string &Name)
Definition: TFormula.cxx:3169
int R__RegisterTFormulaUpdaterTrigger
Definition: TFormula.cxx:284
static TInterpreter::CallFuncIFacePtr_t::Generic_t prepareFuncPtr(TMethodCall *method)
Definition: TFormula.cxx:838
static void R__v5TFormulaUpdater(Int_t nobjects, TObject **from, TObject **to)
Definition: TFormula.cxx:267
static TInterpreter::CallFuncIFacePtr_t::Generic_t GetFuncPtr(std::string FuncName, Int_t Npar, Int_t Ndim, Bool_t Vectorized)
Definition: TFormula.cxx:3196
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
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 b
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 Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
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
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
char name[80]
Definition: TGX11.cxx:110
R__EXTERN TInterpreter * gCling
Definition: TInterpreter.h:565
#define gInterpreter
Definition: TInterpreter.h:564
Int_t gDebug
Definition: TROOT.cxx:585
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:63
#define gROOT
Definition: TROOT.h:404
#define R__LOCKGUARD(mutex)
The FORMULA class (ROOT version 5)
Definition: TFormula.h:65
virtual Double_t * GetParameters() const
Definition: TFormula.h:243
virtual TString GetExpFormula(Option_t *option="") const
Reconstruct the formula expression from the internal TFormula member variables.
void Streamer(TBuffer &b, const TClass *onfile_class)
Stream a class object.
Buffer base class used for serializing objects.
Definition: TBuffer.h:43
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:81
const TList * GetListOfAllPublicMethods(Bool_t load=kTRUE)
Returns a list of all public methods of this class and its base classes.
Definition: TClass.cxx:3834
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2969
1-Dim function class
Definition: TF1.h:213
virtual TFormula * GetFormula()
Definition: TF1.h:458
Helper class for TFormula.
Definition: TFormula.h:30
Bool_t fFound
Definition: TFormula.h:35
const char * GetName() const
Definition: TFormula.h:37
Int_t GetNargs() const
Definition: TFormula.h:39
TString fName
Definition: TFormula.h:32
Bool_t IsFuncCall() const
Definition: TFormula.h:40
Another helper class for TFormula.
Definition: TFormula.h:63
TString fName
Definition: TFormula.h:65
Int_t fArrayPos
Definition: TFormula.h:67
Double_t fValue
Definition: TFormula.h:66
The Formula class.
Definition: TFormula.h:87
CallFuncSignature fHessFuncPtr
! Function pointer, owned by the JIT.
Definition: TFormula.h:107
Double_t GetParameter(const char *name) const
Returns parameter value given by string.
Definition: TFormula.cxx:2829
Bool_t PrepareFormula(TString &formula)
prepare the formula to be executed normally is called with fFormula
Definition: TFormula.cxx:1789
std::atomic< Bool_t > fClingInitialized
! Transient to force re-initialization
Definition: TFormula.h:95
void GradientPar(const Double_t *x, TFormula::CladStorage &result)
Compute the gradient employing automatic differentiation.
Definition: TFormula.cxx:3279
void FillDefaults()
Fill structures with default variables, constants and function shortcuts.
Definition: TFormula.cxx:903
TString GetHessianFormula() const
Definition: TFormula.cxx:3695
void Clear(Option_t *option="") override
Clear the formula setting expression to empty and reset the variables and parameters containers.
Definition: TFormula.cxx:768
const TObject * GetLinearPart(Int_t i) const
Return linear part.
Definition: TFormula.cxx:2549
void InputFormulaIntoCling()
Inputs formula, transfered to C++ code into Cling.
Definition: TFormula.cxx:877
void DoAddParameter(const TString &name, Double_t value, bool processFormula)
Adds parameter to known parameters.
Definition: TFormula.cxx:2739
void HandleLinear(TString &formula)
Handle linear functions defined with the operator ++.
Definition: TFormula.cxx:1731
TString fClingName
! Unique name passed to Cling to define the function ( double clingName(double*x, double*p) )
Definition: TFormula.h:99
TString GetVarName(Int_t ivar) const
Returns variable name given its position in the array.
Definition: TFormula.cxx:2708
void SetVariable(const TString &name, Double_t value)
Sets variable value.
Definition: TFormula.cxx:2724
void HessianPar(const Double_t *x, TFormula::CladStorage &result)
Compute the gradient employing automatic differentiation.
Definition: TFormula.cxx:3343
Int_t GetParNumber(const char *name) const
Return parameter index given a name (return -1 for not existing parameters) non need to print an erro...
Definition: TFormula.cxx:2817
void DoSetParameters(const Double_t *p, Int_t size)
Definition: TFormula.cxx:2945
bool GenerateHessianPar()
Generate hessian computation routine with respect to the parameters.
Definition: TFormula.cxx:3313
TString GetGradientFormula() const
Definition: TFormula.cxx:3687
Double_t Eval(Double_t x) const
Sets first variable (e.g. x) and evaluate formula.
Definition: TFormula.cxx:3440
void HandleParametrizedFunctions(TString &formula)
Handling parametrized functions Function can be normalized, and have different variable then x.
Definition: TFormula.cxx:1104
~TFormula() override
Definition: TFormula.cxx:466
TInterpreter::CallFuncIFacePtr_t::Generic_t CallFuncSignature
Definition: TFormula.h:102
Double_t * GetParameters() const
Definition: TFormula.cxx:2869
void SetParName(Int_t ipar, const char *name)
Definition: TFormula.cxx:3036
void SetName(const char *name) override
Set the name of the formula.
Definition: TFormula.cxx:2636
std::string GetHessianFuncName() const
Definition: TFormula.h:130
std::string fGradGenerationInput
! Input query to clad to generate a gradient
Definition: TFormula.h:103
static Bool_t IsAParameterName(const TString &formula, int ipos)
Definition: TFormula.cxx:354
bool HasGradientGenerationFailed() const
Definition: TFormula.h:134
void ReplaceParamName(TString &formula, const TString &oldname, const TString &name)
Replace in Formula expression the parameter name.
Definition: TFormula.cxx:3066
void SetPredefinedParamNames()
Set parameter names only in case of pre-defined functions.
Definition: TFormula.cxx:2467
void Copy(TObject &f1) const override
Copy this to obj.
Definition: TFormula.cxx:685
static TClass * Class()
std::map< TString, Double_t > fConsts
!
Definition: TFormula.h:146
std::map< TString, TString > fFunctionsShortcuts
!
Definition: TFormula.h:147
void HandleParamRanges(TString &formula)
Handling parameter ranges, in the form of [1..5].
Definition: TFormula.cxx:1321
std::vector< TObject * > fLinearParts
Vector of linear functions.
Definition: TFormula.h:152
static Bool_t IsBracket(const char c)
Definition: TFormula.cxx:295
Bool_t fVectorized
Whether we should use vectorized or regular variables.
Definition: TFormula.h:153
TString fClingInput
! Input function passed to Cling
Definition: TFormula.h:91
Bool_t PrepareEvalMethod()
Sets TMethodCall to function inside Cling environment.
Definition: TFormula.cxx:862
Int_t fNumber
!
Definition: TFormula.h:151
std::string GetGradientFuncName() const
Definition: TFormula.h:126
static bool fIsCladRuntimeIncluded
Definition: TFormula.h:109
std::vector< Double_t > CladStorage
Definition: TFormula.h:184
Double_t GetVariable(const char *name) const
Returns variable value.
Definition: TFormula.cxx:2682
std::list< TFormulaFunction > fFuncs
!
Definition: TFormula.h:143
Bool_t fAllParametersSetted
Flag to control if all parameters are setted.
Definition: TFormula.h:96
void ProcessFormula(TString &formula)
Iterates through functors in fFuncs and performs the appropriate action.
Definition: TFormula.cxx:2073
static Bool_t IsOperator(const char c)
Definition: TFormula.cxx:287
bool HasHessianGenerationFailed() const
Definition: TFormula.h:137
void SetVectorized(Bool_t vectorized)
Definition: TFormula.cxx:3092
void FillVecFunctionsShurtCuts()
Fill the shortcuts for vectorized functions We will replace for example sin with vecCore::Mat::Sin.
Definition: TFormula.cxx:971
const char * GetParName(Int_t ipar) const
Return parameter name given by integer.
Definition: TFormula.cxx:2855
std::map< TString, TFormulaVariable > fVars
! List of variable names
Definition: TFormula.h:144
CallFuncSignature fFuncPtr
! Function pointer, owned by the JIT.
Definition: TFormula.h:105
void HandlePolN(TString &formula)
Handling polN If before 'pol' exist any name, this name will be treated as variable used in polynomia...
Definition: TFormula.cxx:1003
static Bool_t IsHexadecimal(const TString &formula, int ipos)
Definition: TFormula.cxx:331
void ExtractFunctors(TString &formula)
Extracts functors from formula, and put them in fFuncs.
Definition: TFormula.cxx:1828
Bool_t InitLambdaExpression(const char *formula)
Definition: TFormula.cxx:606
void SetParameters(const Double_t *params)
Set a vector of parameters value.
Definition: TFormula.cxx:2966
std::string fSavedInputFormula
! Unique name used to defined the function and used in the global map (need to be saved in case of la...
Definition: TFormula.h:100
Bool_t IsValid() const
Definition: TFormula.h:268
void ReplaceAllNames(TString &formula, std::map< TString, TString > &substitutions)
Definition: TFormula.cxx:406
static Bool_t IsDefaultVariableName(const TString &name)
Definition: TFormula.cxx:313
void FillParametrizedFunctions(std::map< std::pair< TString, Int_t >, std::pair< TString, TString > > &functions)
Fill map with parametrized functions.
Definition: TFormula.cxx:2413
Double_t EvalPar(const Double_t *x, const Double_t *params=nullptr) const
Definition: TFormula.cxx:3124
void SetParNames(const char *name0="p0", const char *name1="p1", const char *name2="p2", const char *name3="p3", const char *name4="p4", const char *name5="p5", const char *name6="p6", const char *name7="p7", const char *name8="p8", const char *name9="p9", const char *name10="p10")
Definition: TFormula.cxx:3007
void AddVariables(const TString *vars, const Int_t size)
Adds multiple variables.
Definition: TFormula.cxx:2598
Int_t GetVarNumber(const char *name) const
Returns variable number (positon in array) given its name.
Definition: TFormula.cxx:2695
std::vector< Double_t > fClingVariables
! Cached variables
Definition: TFormula.h:92
std::unique_ptr< TMethodCall > fMethod
! Pointer to methodcall
Definition: TFormula.h:98
TString fFormula
String representing the formula expression.
Definition: TFormula.h:148
static Bool_t IsScientificNotation(const TString &formula, int ipos)
Definition: TFormula.cxx:319
CallFuncSignature fGradFuncPtr
! Function pointer, owned by the JIT.
Definition: TFormula.h:106
std::vector< Double_t > fClingParameters
Parameter values.
Definition: TFormula.h:93
void SetParameter(const char *name, Double_t value)
Sets parameter value.
Definition: TFormula.cxx:2889
void Print(Option_t *option="") const override
Print the formula and its attributes.
Definition: TFormula.cxx:3704
void PreProcessFormula(TString &formula)
Preprocessing of formula Replace all ** by ^, and removes spaces.
Definition: TFormula.cxx:1767
TString GetExpFormula(Option_t *option="") const
Return the expression formula.
Definition: TFormula.cxx:3617
Int_t fNdim
Dimension - needed for lambda expressions.
Definition: TFormula.h:149
void SetVariables(const std::pair< TString, Double_t > *vars, const Int_t size)
Sets multiple variables.
Definition: TFormula.cxx:2665
void ReInitializeEvalMethod()
Re-initialize eval method.
Definition: TFormula.cxx:3560
@ kNotGlobal
Don't store in gROOT->GetListOfFunction (it should be protected)
Definition: TFormula.h:179
@ kLambda
Set to true if TFormula has been build with a lambda.
Definition: TFormula.h:182
@ kLinear
Set to true if the TFormula is for linear fitting.
Definition: TFormula.h:181
@ kNormalized
Set to true if the TFormula (ex gausn) is normalized.
Definition: TFormula.h:180
void * fLambdaPtr
! Pointer to the lambda function
Definition: TFormula.h:108
TFormula & operator=(const TFormula &rhs)
= operator.
Definition: TFormula.cxx:598
Int_t Compile(const char *expression="")
Compile the given expression with Cling backward compatibility method to be used in combination with ...
Definition: TFormula.cxx:651
Int_t fNpar
! Number of parameter (transient since we save the vector)
Definition: TFormula.h:150
void HandleFunctionArguments(TString &formula)
Handling user functions (and parametrized functions) to take variables and optionally parameters as a...
Definition: TFormula.cxx:1352
std::map< TString, Int_t, TFormulaParamOrder > fParams
|| List of parameter names
Definition: TFormula.h:145
void AddVariable(const TString &name, Double_t value=0)
Adds variable to known variables, and reprocess formula.
Definition: TFormula.cxx:2565
Bool_t fLazyInitialization
! Transient flag to control lazy initialization (needed for reading from files)
Definition: TFormula.h:97
void HandleExponentiation(TString &formula)
Handling exponentiation Can handle multiple carets, eg.
Definition: TFormula.cxx:1636
static Bool_t IsFunctionNameChar(const char c)
Definition: TFormula.cxx:307
std::string fHessGenerationInput
! Input query to clad to generate a hessian
Definition: TFormula.h:104
Double_t DoEval(const Double_t *x, const Double_t *p=nullptr) const
Evaluate formula.
Definition: TFormula.cxx:3452
Bool_t fReadyToExecute
! Transient to force initialization
Definition: TFormula.h:94
bool GenerateGradientPar()
Generate gradient computation routine with respect to the parameters.
Definition: TFormula.cxx:3249
void Streamer(TBuffer &) override
Stream a class object.
Definition: TFormula.cxx:3772
Global functions class (global functions are obtained from CINT).
Definition: TFunction.h:30
virtual Longptr_t ProcessLine(const char *line, EErrorCode *error=nullptr)=0
virtual Bool_t Declare(const char *code)=0
virtual Bool_t CallFunc_IsValid(CallFunc_t *) const
Definition: TInterpreter.h:331
virtual CallFuncIFacePtr_t CallFunc_IFacePtr(CallFunc_t *) const
Definition: TInterpreter.h:332
A doubly linked list.
Definition: TList.h:38
Method or function calling interface.
Definition: TMethodCall.h:37
CallFunc_t * GetCallFunc() const
Definition: TMethodCall.h:93
Each ROOT class (see TClass) has a linked list of methods.
Definition: TMethod.h:38
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
void Copy(TObject &named) const override
Copy this to obj.
Definition: TNamed.cxx:94
const char * GetName() const override
Returns name of object.
Definition: TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition: TNamed.h:48
TString fTitle
Definition: TNamed.h:33
TString fName
Definition: TNamed.h:32
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:140
Mother of all ROOT objects.
Definition: TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:440
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:201
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:956
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:404
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:775
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:970
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:944
Regular expression class.
Definition: TRegexp.h:31
Ssiz_t Index(const TString &str, Ssiz_t *len, Ssiz_t start=0) const
Find the first occurrence of the regexp in string and return the position, or -1 if there is no match...
Definition: TRegexp.cxx:209
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:649
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1955
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:682
const char * Data() const
Definition: TString.h:369
Bool_t IsDigit() const
Returns true if all characters in string are digits (0-9) or white spaces, i.e.
Definition: TString.cxx:1797
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:692
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:925
void ToUpper()
Change string to upper case.
Definition: TString.cxx:1172
Bool_t IsNull() const
Definition: TString.h:407
Int_t CountChar(Int_t c) const
Return number of times character c occurs in the string.
Definition: TString.cxx:509
TString & Append(const char *cs)
Definition: TString.h:564
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2345
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:639
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
TF1 * f1
Definition: legend1.C:11
void(off) SmallVectorTemplateBase< T
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:167
static const std::string pattern("pattern")
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
Definition: StringUtils.cxx:23
TROOT * GetROOT()
Definition: TROOT.cxx:464
static constexpr double s
static constexpr double degree
void variables(TString dataset, TString fin="TMVA.root", TString dirName="InputVariables_Id", TString title="TMVA Input Variables", Bool_t isRegression=kFALSE, Bool_t useTMVAStyle=kTRUE)
constexpr Double_t G()
Gravitational constant in: .
Definition: TMath.h:135
constexpr Double_t C()
Velocity of light in .
Definition: TMath.h:114
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition: TMathBase.h:250
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754.
Definition: TMath.h:900
Double_t Floor(Double_t x)
Rounds x downward, returning the largest integral value that is not greater than x.
Definition: TMath.h:678
constexpr Double_t K()
Boltzmann's constant in : .
Definition: TMath.h:247
constexpr Double_t Sqrt2()
Definition: TMath.h:86
constexpr Double_t E()
Base of natural log: .
Definition: TMath.h:93
constexpr Double_t Sigma()
Stefan-Boltzmann constant in : .
Definition: TMath.h:270
constexpr Double_t H()
Planck's constant in : .
Definition: TMath.h:188
constexpr Double_t LogE()
Base-10 log of e (to convert ln to log)
Definition: TMath.h:107
constexpr Double_t Ln10()
Natural log of 10 (to convert log to ln)
Definition: TMath.h:100
constexpr Double_t EulerGamma()
Euler-Mascheroni Constant.
Definition: TMath.h:332
constexpr Double_t Pi()
Definition: TMath.h:37
constexpr Double_t R()
Universal gas constant ( ) in
Definition: TMath.h:302
Double_t Log10(Double_t x)
Returns the common (base-10) logarithm of x.
Definition: TMath.h:760
Double_t Infinity()
Returns an infinity as defined by the IEEE standard.
Definition: TMath.h:915
const char * Name
Definition: TXMLSetup.cxx:67
const char * cnt
Definition: TXMLSetup.cxx:75
bool operator()(const TString &a, const TString &b) const
Definition: TFormula.cxx:376
void(* Generic_t)(void *, int, void **, void *)
Definition: TInterpreter.h:94
TMarker m
Definition: textangle.C:8
TArc a
Definition: textangle.C:12