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