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