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