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