Logo ROOT   6.10/09
Reference Guide
TFormula_v5.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Nicolas Brun 19/08/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <cmath>
13 
14 #include "Riostream.h"
15 #include "TROOT.h"
16 #include "TClass.h"
17 #include "v5/TFormula.h"
18 #include "TMath.h"
19 #include "TRandom.h"
20 #include "TFunction.h"
21 #include "TMethodCall.h"
22 #include "TObjString.h"
23 #include "TError.h"
24 #include "v5/TFormulaPrimitive.h"
25 #include "TInterpreter.h"
26 #include "TVirtualMutex.h"
27 
28 #ifdef WIN32
29 #pragma optimize("",off)
30 #endif
31 
32 static Int_t gMAXOP=1000,gMAXPAR=1000,gMAXCONST=1000;
35 
37 
38 namespace ROOT {
39 
40  namespace v5 {
41 
42 /** \class TFormula TFormula.h "inc/v5/TFormula.h"
43  \ingroup Hist
44 The FORMULA class (ROOT version 5)
45 
46  Example of valid expressions:
47 
48  - `sin(x)/x`
49  - `[0]*sin(x) + [1]*exp(-[2]*x)`
50  - `x + y**2`
51  - `x^2 + y^2`
52  - `[0]*pow([1],4)`
53  - `2*pi*sqrt(x/y)`
54  - `gaus(0)*expo(3) + ypol3(5)*x`
55  - `gausn(0)*expo(3) + ypol3(5)*x`
56 
57  In the last example above:
58 
59  gaus(0) is a substitute for `[0]*exp(-0.5*((x-[1])/[2])**2)`
60  and (0) means start numbering parameters at 0
61 
62  gausn(0) is a substitute for `[0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))`
63  and (0) means start numbering parameters at 0
64 
65  expo(3) is a substitute for `exp([3]+[4]*x)`
66 
67  pol3(5) is a substitute for `par[5]+par[6]*x+par[7]*x**2+par[8]*x**3`
68  (here Pol3 stands for Polynomial of degree 3)
69 
70  TMath functions can be part of the expression, eg:
71 
72  - `TMath::Landau(x)*sin(x)`
73  - `TMath::Erf(x)`
74 
75  Comparisons operators are also supported (&&, ||, ==, <=, >=, !)
76  Examples:
77 
78  sin(x*(x<0.5 || x>1))
79 
80  If the result of a comparison is TRUE, the result is 1, otherwise 0.
81 
82  Already predefined names can be given. For example, if the formula
83 
84  TFormula old(sin(x*(x<0.5 || x>1))) one can assign a name to the formula. By default
85  the name of the object = title = formula itself.
86  old.SetName("old").
87  then, old can be reused in a new expression.
88  TFormula new("x*old") is equivalent to:
89  TFormula new("x*sin(x*(x<0.5 || x>1))")
90 
91  Up to 4 dimensions are supported (indicated by x, y, z, t)
92  An expression may have 0 parameters or a list of parameters
93  indicated by the sequence [par_number]
94 
95  A graph showing the logic to compile and analyze a formula
96  is shown in TFormula::Compile and TFormula::Analyze.
97  Once a formula has been compiled, it can be evaluated for a given
98  set of parameters. see graph in TFormula::EvalPar.
99 
100  This class is the base class for the function classes TF1,TF2 and TF3.
101  It is also used by the ntuple selection mechanism TNtupleFormula.
102 
103  In version 7 of TFormula, the usage of fOper has been changed
104  to improve the performance of TFormula::EvalPar.
105  Conceptually, fOper was changed from a simple array of Int_t
106  to an array of composite values.
107  For example a 'ylandau(5)' operation used to be encoded as 4105;
108  it is now encoded as (klandau >> kTFOperShit) + 5
109  Any class inheriting from TFormula and using directly fOper (which
110  is now a private data member), needs to be updated to take this
111  in consideration. The member functions recommended to set and
112  access fOper are: SetAction, GetAction, GetActionParam
113  For more performant access to the information, see the implementation
114  TFormula::EvalPar
115 
116  ### CHANGING DEFAULT SETTINGS
117 
118  When creating complex formula , it may be necessary to increase
119  some default parameters. see static function TFormula::SetMaxima
120 
121  ### WHY TFormula CANNOT ACCEPT A CLASS MEMBER FUNCTION ?
122 
123  This is a frequently asked question.
124  C++ is a strongly typed language. There is no way for TFormula (without
125  recompiling this class) to know about all possible user defined data types.
126  This also apply to the case of a static class function.
127  Because TMath is a special and frequent case, TFormula is aware
128  of all TMath functions.
129 */
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 /// Formula default constructor.
133 
135 {
136  fNdim = 0;
137  fNpar = 0;
138  fNoper = 0;
139  fNconst = 0;
140  fNumber = 0;
141  fExpr = 0;
142  fOper = 0;
143  fConst = 0;
144  fParams = 0;
145  fNstring= 0;
146  fNames = 0;
147  fNval = 0;
148  //
149  //MI change
150  fNOperOptimized = 0;
151  fExprOptimized = 0;
152  fOperOptimized = 0;
153  fOperOffset = 0;
154  fPredefined = 0;
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Normal Formula constructor.
160 
161 TFormula::TFormula(const char *name,const char *expression) :
162  TNamed(name,expression)
163 {
164  fNdim = 0;
165  fNpar = 0;
166  fNoper = 0;
167  fNconst = 0;
168  fNumber = 0;
169  fExpr = 0;
170  fOper = 0;
171  fConst = 0;
172  fParams = 0;
173  fNstring= 0;
174  fNames = 0;
175  fNval = 0;
176  //
177  //MI change
178  fNOperOptimized = 0;
179  fExprOptimized = 0;
180  fOperOptimized = 0;
181  fOperOffset = 0;
182  fPredefined = 0;
184 
185  if (!expression || !*expression) {
186  Error("TFormula", "expression may not be 0 or have 0 length");
187  return;
188  }
189 
190  //eliminate blanks in expression
191  Int_t i,j,nch;
192  nch = strlen(expression);
193  char *expr = new char[nch+1];
194  j = 0;
195  for (i=0;i<nch;i++) {
196  if (expression[i] == ' ') continue;
197  if (i > 0 && (expression[i] == '*') && (expression[i-1] == '*')) {
198  expr[j-1] = '^';
199  continue;
200  }
201  expr[j] = expression[i]; j++;
202  }
203  expr[j] = 0;
204  Bool_t gausNorm = kFALSE;
205  Bool_t landauNorm = kFALSE;
206  Bool_t linear = kFALSE;
207 
208  if (j) {
209  TString chaine = expr;
210  //special case for functions for linear fitting
211  if (chaine.Contains("++"))
212  linear = kTRUE;
213  // special case for normalized gaus
214  if (chaine.Contains("gausn")) {
215  gausNorm = kTRUE;
216  TString tmp = chaine;
217  tmp.ReplaceAll("gausn","");
218  tmp.ReplaceAll("landaun","");
219  if ( tmp.Contains("gaus") )
220  Warning("TFormula","Cannot use both gaus and gausn - gaus will be treated as gausn");
221  if ( tmp.Contains("landau") )
222  Warning("TFormula","Cannot use both gausn and landau - landau will be treated as landaun");
223  }
224  // special case for normalized landau
225  if (chaine.Contains("landaun")) {
226  landauNorm = kTRUE;
227  TString tmp = chaine;
228  tmp.ReplaceAll("landaun","");
229  tmp.ReplaceAll("gausn","");
230  if ( tmp.Contains("gaus") ) {
231  Warning("TFormula","Cannot use both gaus and landaun - gaus will be treated as gausn");
232  }
233  if ( tmp.Contains("landau") )
234  Warning("TFormula","Cannot use both landau and landaun - landau will be treated as landaun");
235  }
236  // need to the replacement here for the error message before
237  if (gausNorm)
238  chaine.ReplaceAll("gausn","gaus");
239  if (landauNorm)
240  chaine.ReplaceAll("landaun","landau");
241 
242  SetTitle(chaine.Data());
243  }
244  delete [] expr;
245 
246  if (linear) SetBit(kLinear);
247 
248  if (Compile()) return;
249 
250  if (gausNorm) SetBit(kNormalized);
251  if (landauNorm) SetBit(kNormalized);
252 
253  // Store formula in linked list of formula in ROOT
254 
255 
256  if (strcmp(name,"x")==0 || strcmp(name,"y")==0 ||
257  strcmp(name,"z")==0 || strcmp(name,"t")==0 )
258  {
259  Error("TFormula","The name \'%s\' is reserved as a TFormula variable name.\n"
260  "\tThis function will not be registered in the list of functions",name);
261  } else {
263  TFormula *old = (TFormula*)gROOT->GetListOfFunctions()->FindObject(name);
264  if (old) {
265  gROOT->GetListOfFunctions()->Remove(old);
266  }
267  gROOT->GetListOfFunctions()->Add(this);
268  }
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Default constructor.
273 
274 TFormula::TFormula(const TFormula &formula) : TNamed()
275 {
276  fNdim = 0;
277  fNpar = 0;
278  fNoper = 0;
279  fNconst = 0;
280  fNumber = 0;
281  fExpr = 0;
282  fOper = 0;
283  fConst = 0;
284  fParams = 0;
285  fNstring= 0;
286  fNames = 0;
287  fNval = 0;
288  fNOperOptimized = 0;
289  fPredefined = 0;
290  fOperOffset = 0;
291  fExprOptimized = 0;
292  fOperOptimized = 0;
293 
294  ((TFormula&)formula).TFormula::Copy(*this);
295 }
296 
297 ////////////////////////////////////////////////////////////////////////////////
298 /// Operator =
299 
301 {
302  if (this != &rhs) {
303  rhs.Copy(*this);
304  }
305  return *this;
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Formula default destructor.
310 
312 {
313  if (gROOT) {
315  gROOT->GetListOfFunctions()->Remove(this);
316  }
317 
318  ClearFormula();
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Check if the chain as function call.
323 ///
324 /// If you overload this member function, you also HAVE TO
325 /// never call the constructor:
326 ///
327 /// ~~~ {.cpp}
328 /// TFormula::TFormula(const char *name,const char *expression)
329 /// ~~~
330 ///
331 /// and write your own constructor
332 ///
333 /// ~~~ {.cpp}
334 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
335 /// ~~~
336 ///
337 /// which has to call the TFormula default constructor and whose implementation
338 /// should be similar to the implementation of the normal TFormula constructor
339 ///
340 /// This is necessary because the normal TFormula constructor call indirectly
341 /// the virtual member functions Analyze, DefaultString, DefaultValue
342 /// and DefaultVariable.
343 
345 {
346  int i;
347 
348  // We have to decompose the chain is 3 potential components:
349  // namespace::functionName( args )
350 
351  Ssiz_t argStart = chaine.First('(');
352  if (argStart<0) return false;
353 
354  TString functionName = chaine(0,argStart);
355 
356  // This does not support template yet (where the scope operator might be in
357  // one of the template arguments
358  Ssiz_t scopeEnd = functionName.Last(':');
359  TString spaceName;
360  if (scopeEnd>0 && functionName[scopeEnd-1]==':') {
361  spaceName = functionName(0,scopeEnd-1);
362  functionName.Remove(0,scopeEnd+1);
363  }
364 
365  // Now we need to count and decompose the actual arguments, we could also check the type
366  // of the arguments
367  if (chaine[chaine.Length()-1] != ')') {
368  Error("AnalyzeFunction","We thought we had a function but we dont (in %s)\n",chaine.Data());
369  }
370 
371  TString args = chaine(argStart+1,chaine.Length()-2-argStart);
372  TObjArray argArr;
373  argArr.SetOwner(kTRUE);
374  //fprintf(stderr,"args are '%s'\n",args.Data());
375 
376  Bool_t inString = false;
377  int paran = 0;
378  int brack = 0;
379  int prevComma = 0;
380  int nargs = 0;
381  for(i=0; i<args.Length(); i++) {
382  if (args[i]=='"') inString = !inString;
383  if (inString) continue;
384 
385  Bool_t foundArg = false;
386  switch(args[i]) {
387 
388  case '(': paran++; break;
389  case ')': paran--; break;
390  case '[': brack++; break;
391  case ']': brack--; break;
392 
393  case ',': if (paran==0 && brack==0) { foundArg = true; } break;
394  }
395  if ((i+1)==args.Length()) {
396  foundArg = true; i++;
397  }
398  if (foundArg) {
399  TString arg = args(prevComma,i-prevComma);
400 
401  // Here we could
402  // a) check the type
403  //fprintf(stderr,"found #%d arg %s\n",nargs,arg.Data());
404 
405  // We register the arg for later usage
406  argArr.Add(new TObjString(arg));
407  nargs++;
408 
409  prevComma = i+1;
410  };
411  }
412 
413  if (nargs>999) {
414  err = 7;
415  return false;
416  }
417 
418  // Now we need to lookup the function and check its arguments.
419  TClass *ns = (spaceName.Length()) ? TClass::GetClass(spaceName) : 0;
420  ClassInfo_t *cinfo = 0;
421  if (ns) {
422  cinfo = ns->GetClassInfo();
423  } else {
424  cinfo = gInterpreter->ClassInfo_Factory();
425  }
426 
427  // ROOT does yet have a complete TType class, but TCling does,
428  // so let's use that for now.
429  static TypeInfo_t *const doubletype { gInterpreter->TypeInfo_Factory("double") };
430 
431  std::vector<TypeInfo_t*> proto(nargs,doubletype);
432 
433  CallFunc_t *callfunc = gInterpreter->CallFunc_Factory();
434  Long_t func_offset;
435  gInterpreter->CallFunc_SetFuncProto(callfunc,cinfo,functionName,proto,false,&func_offset,ROOT::kConversionMatch);
436 
437  TMethodCall *method = new TMethodCall(ns,callfunc,func_offset);
438 
439  if (!ns) gInterpreter->ClassInfo_Delete(cinfo);
440  gInterpreter->CallFunc_Delete(callfunc);
441 
442  if (method->IsValid()) {
443  if (method->ReturnType() == TMethodCall::kOther) {
444  /*
445  Error("Compile",
446  "TFormula can only call interpreted and compiled function that returns a numerical type %s returns a %s\n",
447  method->GetMethodName(), method->GetMethod()->GetReturnTypeName());
448  */
449  err=29;
450 
451  } else {
452 
453  // Analyze the arguments
454  TIter next(&argArr);
455  TObjString *objstr;
456  while ( (objstr=(TObjString*)next()) ) {
457  Analyze(objstr->String(),err,offset);
458  }
459 
460  fFunctions.Add(method);
461  fExpr[fNoper] = method->GetMethod()->GetPrototype();
462  SetAction(fNoper, kFunctionCall, fFunctions.GetLast()*1000 + nargs);
463  fNoper++;
464  return true;
465  }
466  }
467 
468  delete method;
469  //
470  // MI change - extended space of functions
471  // not forward compatible change
472  //
473  TString cbase(chaine);
474  Int_t args_paran = cbase.First("(");
475  if (args_paran>0){
476  cbase[args_paran]=0;
477  }
478 
479  ROOT::v5::TFormulaPrimitive *prim = ROOT::v5::TFormulaPrimitive::FindFormula(cbase, args_paran>0 ? cbase.Data() + args_paran + 1 : (const char*)0);
480  if (prim && (!IsA()->GetBaseClass("TTreeFormula"))) {
481  // TO BE DONE ALSO IN TTREFORMULA - temporary fix MI
482  // Analyze the arguments
483  TIter next(&argArr);
484  TObjString *objstr;
485  while ( (objstr=(TObjString*)next()) ) {
486  Analyze(objstr->String(),err,offset); if (err) return kFALSE;
487  }
488  if (nargs!=prim->fNArguments) {
489  Error("Compile", "%s requires %d arguments",
490  prim->GetName(), prim->fNArguments);
491  return kFALSE;
492  }
493  fExpr[fNoper] = prim->GetName();
494  if (prim->fType==10){
496  }
497  if (prim->fType==110){
499  }
500  if (prim->fType==1110){
502  }
503  if (prim->fType==-1){
505  if (fNpar<prim->fNParameters) fNpar+=prim->fNParameters;
506  }
507 
508  fNoper++;
509  return kTRUE;
510  }
511 
512  return kFALSE;
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 /// Analyze a sub-expression in one formula.
517 ///
518 /// Expressions in one formula are recursively analyzed.
519 /// Result of analysis is stored in the object tables.
520 ///
521 /// ### Table of function codes and errors
522 ///
523 /// ~~~ {.cpp}
524 /// * functions :
525 ///
526 /// + 1 pow 20
527 /// - 2 sq 21
528 /// * 3 sqrt 22
529 /// / 4 strstr 23
530 /// % 5 min 24
531 /// max 25
532 /// log 30
533 /// cos 10 exp 31
534 /// sin 11 log10 32
535 /// tan 12
536 /// acos 13 abs 41
537 /// asin 14 sign 42
538 /// atan 15 int 43
539 /// atan2 16
540 /// fmod 17 rndm 50
541 ///
542 /// cosh 70 acosh 73
543 /// sinh 71 asinh 74
544 /// tanh 72 atanh 75
545 ///
546 /// expo 100 gaus 110 gausn (see note below)
547 /// expo(0) 100 0 gaus(0) 110 0 gausn(0)
548 /// expo(1) 100 1 gaus(1) 110 1 gausn(1)
549 /// xexpo 100 x xgaus 110 x xgausn
550 /// yexpo 101 x ygaus 111 x ygausn
551 /// zexpo 102 x zgaus 112 x zgausn
552 /// xyexpo 105 x xygaus 115 x xygausn
553 /// yexpo(5) 102 5 ygaus(5) 111 5 ygausn(5)
554 /// xyexpo(2) 105 2 xygaus(2) 115 2 xygausn(2)
555 ///
556 /// landau 120 x landaun (see note below)
557 /// landau(0) 120 0 landaun(0)
558 /// landau(1) 120 1 landaun(1)
559 /// xlandau 120 x xlandaun
560 /// ylandau 121 x ylandaun
561 /// zlandau 122 x zlandaun
562 /// xylandau 125 x xylandaun
563 /// ylandau(5) 121 5 ylandaun(5)
564 /// xylandau(2) 125 2 xylandaun(2)
565 ///
566 /// pol0 130 x pol1 130 1xx
567 /// pol0(0) 130 0 pol1(0) 130 100
568 /// pol0(1) 130 1 pol1(1) 130 101
569 /// xpol0 130 x xpol1 130 101
570 /// ypol0 131 x ypol1 131 101
571 /// zpol0 132 x zpol1 132 1xx
572 /// ypol0(5) 131 5 ypol1(5) 131 105
573 ///
574 /// pi 40
575 ///
576 /// && 60 < 64
577 /// || 61 > 65
578 /// == 62 <= 66
579 /// != 63 => 67
580 /// ! 68
581 /// ==(string) 76 & 78
582 /// !=(string) 77 | 79
583 /// <<(shift) 80 >>(shift) 81
584 /// ? : 82
585 ///
586 /// * constants (kConstants) :
587 ///
588 /// c0 141 1 c1 141 2 etc..
589 ///
590 /// * strings (kStringConst):
591 ///
592 /// sX 143 x
593 ///
594 /// * variables (kFormulaVar) :
595 ///
596 /// x 144 0 y 144 1 z 144 2 t 144 3
597 ///
598 /// * parameters :
599 ///
600 /// [1] 140 1
601 /// [2] 140 2
602 /// etc.
603 /// ~~~
604 ///
605 /// ### Special cases for normalized gaussian or landau distributions
606 ///
607 /// the expression "gaus" is a substitute for
608 ///
609 /// [0]*exp(-0.5*((x-[1])/[2])**2)
610 ///
611 /// to obtain a standard normalized gaussian, use "gausn" instead of "gaus"
612 /// the expression "gausn" is a substitute for
613 ///
614 /// [0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))
615 ///
616 /// WARNING: gaus and gausn are mutually exclusive in the same expression.
617 ///
618 /// In the same way the expression "landau" is a substitute for
619 ///
620 /// [0]*TMath::Landau(x,[1],[2],kFALSE)
621 ///
622 /// to obtain a standard normalized landau, use "landaun" instead of "landau"
623 /// the expression "landaun" is a substitute for
624 ///
625 /// [0]*TMath::Landau(x,[1],[2],kTRUE)
626 ///
627 /// WARNING: landau and landaun are mutually exclusive in the same expression.
628 ///
629 /// ### Boolean optimization (kBoolOptmize) :
630 ///
631 /// Those pseudo operation are used to implement lazy evaluation of
632 /// && and ||. When the left hand of the expression if false
633 /// (respectively true), the evaluation of the right is entirely skipped
634 /// (since it would not change the value of the expression).
635 ///
636 /// && 142 11 (one operation on right) 142 21 (2 operations on right)
637 /// || 142 12 (one operation on right) 142 22 (2 operations on right)
638 ///
639 /// * functions calls (kFunctionCall) :
640 ///
641 /// f0 145 0 f1 145 1 etc..
642 ///
643 /// ### Errors :
644 ///
645 /// 1 : Division By Zero
646 /// 2 : Invalid Floating Point Operation
647 /// 4 : Empty String
648 /// 5 : invalid syntax
649 /// 6 : Too many operators
650 /// 7 : Too many parameters
651 /// 10 : z specified but not x and y
652 /// 11 : z and y specified but not x
653 /// 12 : y specified but not x
654 /// 13 : z and x specified but not y
655 /// 20 : non integer value for parameter number
656 /// 21 : atan2 requires two arguments
657 /// 22 : pow requires two arguments
658 /// 23 : degree of polynomial not specified
659 /// 24 : Degree of polynomial must be positive
660 /// 25 : Degree of polynomial must be less than 20
661 /// 26 : Unknown name
662 /// 27 : Too many constants in expression
663 /// 28 : strstr requires two arguments
664 /// 29 : interpreted or compiled function have to return a numerical type
665 /// 30 : Bad numerical expression
666 /// 31 : Part of the variable exist but some of it is not accessible or useable
667 /// 40 : '(' is expected
668 /// 41 : ')' is expected
669 /// 42 : '[' is expected
670 /// 43 : ']' is expected
671 ///
672 /// \image html TFormula_analyze.png
673 ///
674 /// ### Special functions
675 ///
676 /// By default, the formula is assigned fNumber=0. However, the following
677 /// formula built with simple functions are assigned fNumber:
678 ///
679 /// "gaus" 100 (or gausn)
680 /// "xygaus" 110
681 /// "expo" 200
682 /// "polN" 300+N
683 /// "landau" 400
684 /// "xylandau" 410
685 ///
686 /// Note that expressions like gaus(0), expo(1) will force fNumber=0
687 ///
688 /// ### Warning when deriving a class from TFormula
689 ///
690 /// If you overload this member function, you also HAVE TO
691 /// never call the constructor:
692 ///
693 /// ~~~ {.cpp}
694 /// TFormula::TFormula(const char *name,const char *expression)
695 /// ~~~
696 ///
697 /// and write your own constructor
698 ///
699 /// ~~~ {.cpp}
700 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
701 /// ~~~
702 ///
703 /// which has to call the TFormula default constructor and whose implementation
704 /// should be similar to the implementation of the normal TFormula constructor
705 ///
706 /// This is necessary because the normal TFormula constructor call indirectly
707 /// the virtual member functions Analyze, DefaultString, DefaultValue
708 /// and DefaultVariable.
709 
710 void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset)
711 {
712 
713 
714  Int_t valeur,find,n,i,j,k,lchain,nomb,virgule,inter,nest;
715  valeur=find=n=i=j=k=lchain=nomb=virgule=inter=nest = 0;
716  Int_t compt,compt2,compt3,compt4;
717  Bool_t inString;
718  Double_t vafConst;
719  ULong_t vafConst2;
720  Bool_t parenthese;
721  TString s,chaine_error,chaine1ST;
722  TString s1,s2,s3,ctemp;
723 
724  TString chaine = schain;
725  const TFormula *oldformula;
726  Int_t modulo,plus,puiss10,puiss10bis,moins,multi,divi,puiss,et,ou,petit,grand,egal,diff,peteg,grdeg,etx,oux,rshift,lshift,tercond,terelse;
727  char t;
728  TString slash("/"), escapedSlash("\\/");
729  Int_t inter2 = 0;
730  SetNumber(0);
731  Int_t actionCode,actionParam;
732  Int_t err_hint = 0;
733 
734  // Verify correct matching of parenthesis and remove unnecessary parenthesis.
735  lchain = chaine.Length();
736  //if (chaine(lchain-2,2) == "^2") chaine = "sq(" + chaine(0,lchain-2) + ")";
737  parenthese = kTRUE;
738  lchain = chaine.Length();
739  while (parenthese && lchain>0 && err==0){
740  compt = 0;
741  compt2 = 0;
742  inString = false;
743  lchain = chaine.Length();
744  if (lchain==0) err=4;
745  else {
746  for (i=1; i<=lchain; ++i) {
747  if (chaine(i-1,1) == "\"") inString = !inString;
748  if (!inString) {
749  if (chaine(i-1,1) == "[") compt2++;
750  if (chaine(i-1,1) == "]") compt2--;
751  if (chaine(i-1,1) == "(") compt++;
752  if (chaine(i-1,1) == ")") compt--;
753  }
754  if (compt < 0) err = 40; // more open parentheses than close parentheses
755  if (compt2< 0) err = 42; // more ] than [
756  if (compt==0 && (i!=lchain || lchain==1)) parenthese = kFALSE;
757  // if (lchain<3 && chaine(0,1)!="(" && chaine(lchain-1,1)!=")") parenthese = kFALSE;
758  }
759  if (compt > 0) err = 41; // more ( than )
760  if (compt2> 0) err = 43; // more [ than ]
761  if (parenthese) chaine = chaine(1,lchain-2);
762  }
763  } // while parenthesis
764 
765  if (lchain==0) err=4; // empty string
766  modulo=plus=moins=multi=divi=puiss=et=ou=petit=grand=egal=diff=peteg=grdeg=etx=oux=rshift=lshift=tercond=terelse=0;
767 
768  // Look for simple operators
769 
770  if (err==0) {
771  compt = compt2 = compt3 = compt4 = 0;puiss10=0;puiss10bis = 0;
772  inString = false;
773  j = lchain;
774  Bool_t isdecimal = 1; // indicates whether the left part is decimal.
775 
776  for (i=1;i<=lchain; i++) {
777 
778  puiss10=puiss10bis=0;
779  if (i>2) {
780  t = chaine[i-3];
781  isdecimal = isdecimal && (strchr("0123456789.",t)!=0);
782  if (isdecimal) {
783  if ( chaine[i-2] == 'e' || chaine[i-2] == 'E' ) puiss10 = 1;
784  } else if ( strchr("+-/[]()&|><=!*/%^\\",t) ) {
785  isdecimal = 1; // reset after delimiter
786  }
787  }
788  if (j>2) {
789  if (chaine[j-2] == 'e' || chaine[j-2] == 'E') {
790  Bool_t isrightdecimal = 1;
791 
792  for(k=j-3; k>=0 && isrightdecimal; --k) {
793  t = chaine[k];
794  isrightdecimal = isrightdecimal && (strchr("0123456789.",t)!=0);
795  if (!isrightdecimal) {
796  if (strchr("+-/[]()&|><=!*/%^\\",t)!=0) {
797  puiss10bis = 1;
798  }
799  }
800  }
801  if (k<0 && isrightdecimal) puiss10bis = 1;
802  }
803  }
804  if (puiss10 && (i<=lchain)) {
805  t = chaine[i];
806  puiss10 = (strchr("0123456789.",t)!=0);
807  }
808  if (puiss10bis && (j<=lchain)) {
809  t = chaine[j];
810  puiss10bis = (strchr("0123456789.",t)!=0);
811  }
812 
813  if (chaine(i-1,1) == "\"") inString = !inString;
814  if (inString) continue;
815  if (chaine(i-1,1) == "[") compt2++;
816  if (chaine(i-1,1) == "]") compt2--;
817  if (chaine(i-1,1) == "(") compt++;
818  if (chaine(i-1,1) == ")") compt--;
819  if (chaine(j-1,1) == "[") compt3++;
820  if (chaine(j-1,1) == "]") compt3--;
821  if (chaine(j-1,1) == "(") compt4++;
822  if (chaine(j-1,1) == ")") compt4--;
823  if (chaine(i-1,2)=="&&" && !inString && compt==0 && compt2==0 && et==0) {et=i;puiss=0;}
824  if (chaine(i-1,2)=="||" && compt==0 && compt2==0 && ou==0) {puiss10=0; ou=i;}
825  if (chaine(i-1,1)=="&" && compt==0 && compt2==0 && etx==0) {etx=i;puiss=0;}
826  if (chaine(i-1,1)=="|" && compt==0 && compt2==0 && oux==0) {puiss10=0; oux=i;}
827  if (chaine(i-1,2)==">>" && compt==0 && compt2==0 && rshift==0) {puiss10=0; rshift=i;}
828  if (chaine(i-1,1)==">" && compt==0 && compt2==0 && rshift==0 && grand==0)
829  {puiss10=0; grand=i;}
830  if (chaine(i-1,2)=="<<" && compt==0 && compt2==0 && lshift==0) {puiss10=0; lshift=i;}
831  if (chaine(i-1,1)=="<" && compt==0 && compt2==0 && lshift==0 && petit==0)
832  {puiss10=0; petit=i;
833  // Check whether or not we have a template names! (actually this can
834  // only happen in TTreeFormula.
835  for(int ip = i,depth=0; ip < lchain; ++ip) {
836  char c = chaine(ip);
837  // The characters allowed in the template parameter are alpha-numerical characters,
838  // underscores, comma, <, > and scope operator.
839  if (isalnum(c) || c=='_' || c==',') continue;
840  if (c==':' && chaine(ip+1)==':') { ++ip; continue; }
841  if (c=='<') { ++depth; continue; }
842  if (c=='>') {
843  if (depth) { --depth; continue; }
844  else {
845  // We reach the end of the template parameter.
846  petit = 0;
847  i = ip+1;
848  break;
849  }
850  }
851  // Character not authorized within a template parameter
852  break;
853  }
854  if (petit==0) {
855  // We found a template parameter and modified i
856  continue; // the for(int i ,...)
857  }
858  }
859  if ((chaine(i-1,2)=="<=" || chaine(i-1,2)=="=<") && compt==0 && compt2==0
860  && peteg==0) {peteg=i; puiss10=0; petit=0;}
861  if ((chaine(i-1,2)=="=>" || chaine(i-1,2)==">=") && compt==0 && compt2==0
862  && grdeg==0) {puiss10=0; grdeg=i; grand=0;}
863  if (chaine(i-1,2) == "==" && compt == 0 && compt2 == 0 && egal == 0) {puiss10=0; egal=i;}
864  if (chaine(i-1,2) == "!=" && compt == 0 && compt2 == 0 && diff == 0) {puiss10=0; diff=i;}
865  if (i>1 && chaine(i-1,1) == "+" && compt == 0 && compt2 == 0 && puiss10==0) plus=i;
866  if (chaine(j-1,1) == "-" && chaine(j-2,1) != "*" && chaine(j-2,1) != "/"
867  && chaine(j-2,1)!="^" && compt3==0 && compt4==0 && moins==0 && puiss10bis==0) moins=j;
868  if (chaine(i-1,1)=="%" && compt==0 && compt2==0 && modulo==0) {puiss10=0; modulo=i;}
869  if (chaine(i-1,1)=="*" && compt==0 && compt2==0 && multi==0) {puiss10=0; multi=i;}
870  if (chaine(j-1,1)=="/" && chaine(j-2,1)!="\\"
871  && compt4==0 && compt3==0 && divi==0)
872  {
873  puiss10=0; divi=j;
874  }
875  if (chaine(j-1)=='^' && compt4==0 && compt3==0 && puiss==0) {puiss10=0; puiss=j;}
876  if (chaine(i-1)=='?' && compt == 0 && compt2 == 0 && tercond == 0) {puiss10=0; tercond=i;}
877  if (chaine(i-1)==':' && tercond && compt == 0 && compt2 == 0 && terelse == 0) {
878  if (i>2 && chaine(i-2)!=':' && chaine(i)!=':') {
879  puiss10=0; terelse=i;
880  }
881  }
882 
883  j--;
884  }
885 
886  // If operator found, analyze left and right part of the statement
887 
888  actionParam = 0;
889  if (tercond && terelse) {
890  if (tercond == 1 || terelse == lchain || tercond == (terelse-1) ) {
891  err = 5;
892  chaine_error = "?:";
893  } else {
894  // Condition
895  ctemp = chaine(0,tercond-1);
896  Analyze(ctemp.Data(),err,offset); if (err) return;
897 
898  fExpr[fNoper] = "?: condition jump";
899  actionCode = kJumpIf;
900  actionParam = 0;
901  SetAction(fNoper,actionCode, actionParam);
902  Int_t optloc = fNoper++;
903 
904  // Expression executed if condition is true.
905  ctemp = chaine(tercond,terelse-tercond-1);
906  Analyze(ctemp.Data(),err,offset); if (err) return;
907  actionParam = fNoper; // We want to skip the next instruction ('else jump'), so we set the param to the current cursor and the next instruction will be skip by the ++i in the eval loop
908  SetAction(optloc, actionCode, actionParam);
909 
910  fExpr[fNoper] = "?: else jump";
911  actionCode = kJump;
912  actionParam = 0;
913  // Set jump target.
914  SetAction(fNoper,actionCode, actionParam);
915  optloc = fNoper++;
916 
917  // Expression executed if condition is false.
918  ctemp = chaine(terelse,lchain-terelse);
919  Analyze(ctemp.Data(),err,offset); if (err) return;
920  // Set jump target.
921  actionParam = fNoper - 1; // We need to not skip the next instruction, so we compensate for the ++i in the eval loop
922  SetAction(optloc, actionCode, actionParam);
923 
924  if (IsString(optloc-1) != IsString(fNoper-1)) {
925  err = 45;
926  chaine_error = "?:";
927  }
928  }
929  } else if (ou != 0) { //check for ||
930  if (ou==1 || ou==lchain-1) {
931  err=5;
932  chaine_error="||";
933  }
934  else {
935  ctemp = chaine(0,ou-1);
936  Analyze(ctemp.Data(),err,offset); if (err) return;
937 
938  fExpr[fNoper] = "|| checkpoint";
939  actionCode = kBoolOptimize;
940  actionParam = 2;
941  SetAction(fNoper,actionCode, actionParam);
942  Int_t optloc = fNoper++;
943 
944  ctemp = chaine(ou+1,lchain-ou-1);
945  Analyze(ctemp.Data(),err,offset); if (err) return;
946  fExpr[fNoper] = "||";
947  actionCode = kOr;
948  SetAction(fNoper,actionCode, 0);
949 
950  SetAction( optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
951  fNoper++;
952  if (!CheckOperands(optloc-1,fNoper-1,err)) return;
953  }
954  } else if (et!=0) {
955  if (et==1 || et==lchain-1) {
956  err=5;
957  chaine_error="&&";
958  }
959  else {
960  ctemp = chaine(0,et-1);
961  Analyze(ctemp.Data(),err,offset); if (err) return;
962 
963  fExpr[fNoper] = "&& checkpoint";
964  actionCode = kBoolOptimize;
965  actionParam = 1;
966  SetAction(fNoper,actionCode,actionParam);
967 
968  Int_t optloc = fNoper++;
969 
970  ctemp = chaine(et+1,lchain-et-1);
971  Analyze(ctemp.Data(),err,offset); if (err) return;
972  fExpr[fNoper] = "&&";
973  actionCode = kAnd;
974  SetAction(fNoper,actionCode,0);
975 
976  SetAction(optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
977  fNoper++;
978  if (!CheckOperands(optloc-1,fNoper-1,err)) return;
979  }
980  } else if (oux!=0) {
981  if (oux==1 || oux==lchain) {
982  err=5;
983  chaine_error="|";
984  }
985  else {
986  ctemp = chaine(0,oux-1);
987  Analyze(ctemp.Data(),err,offset); if (err) return;
988  UInt_t leftopr = fNoper-1;
989  ctemp = chaine(oux,lchain-oux);
990  Analyze(ctemp.Data(),err,offset); if (err) return;
991  fExpr[fNoper] = "|";
992  actionCode = kBitOr;
993  SetAction(fNoper,actionCode,actionParam);
994  fNoper++;
995  if (!CheckOperands(leftopr,fNoper-1,err)) return;
996  }
997  } else if (etx!=0) {
998  if (etx==1 || etx==lchain) {
999  err=5;
1000  chaine_error="&";
1001  }
1002  else {
1003  ctemp = chaine(0,etx-1);
1004  Analyze(ctemp.Data(),err,offset); if (err) return;
1005  UInt_t leftopr = fNoper-1;
1006  ctemp = chaine(etx,lchain-etx);
1007  Analyze(ctemp.Data(),err,offset); if (err) return;
1008  fExpr[fNoper] = "&";
1009  actionCode = kBitAnd;
1010  SetAction(fNoper,actionCode,actionParam);
1011  fNoper++;
1012  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1013  }
1014  } else if (petit != 0) {
1015  if (petit==1 || petit==lchain) {
1016  err=5;
1017  chaine_error="<";
1018  }
1019  else {
1020  ctemp = chaine(0,petit-1);
1021  Analyze(ctemp.Data(),err,offset); if (err) return;
1022  UInt_t leftopr = fNoper-1;
1023  ctemp = chaine(petit,lchain-petit);
1024  Analyze(ctemp.Data(),err,offset); if (err) return;
1025  fExpr[fNoper] = "<";
1026  actionCode = kLess;
1027  SetAction(fNoper,actionCode,actionParam);
1028  fNoper++;
1029  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1030  }
1031  } else if (grand != 0) {
1032  if (grand==1 || grand==lchain) {
1033  err=5;
1034  chaine_error=">";
1035  }
1036  else {
1037  ctemp = chaine(0,grand-1);
1038  Analyze(ctemp.Data(),err,offset); if (err) return;
1039  UInt_t leftopr = fNoper-1;
1040  ctemp = chaine(grand,lchain-grand);
1041  Analyze(ctemp.Data(),err,offset); if (err) return;
1042  fExpr[fNoper] = ">";
1043  actionCode = kGreater;
1044  SetAction(fNoper,actionCode,actionParam);
1045  fNoper++;
1046  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1047  }
1048  } else if (peteg != 0) {
1049  if (peteg==1 || peteg==lchain-1) {
1050  err=5;
1051  chaine_error="<=";
1052  }
1053  else {
1054  ctemp = chaine(0,peteg-1);
1055  Analyze(ctemp.Data(),err,offset); if (err) return;
1056  ctemp = chaine(peteg+1,lchain-peteg-1);
1057  UInt_t leftopr = fNoper-1;
1058  Analyze(ctemp.Data(),err,offset); if (err) return;
1059  fExpr[fNoper] = "<=";
1060  actionCode = kLessThan;
1061  SetAction(fNoper,actionCode,actionParam);
1062  fNoper++;
1063  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1064  }
1065  } else if (grdeg != 0) {
1066  if (grdeg==1 || grdeg==lchain-1) {
1067  err=5;
1068  chaine_error="=>";
1069  }
1070  else {
1071  ctemp = chaine(0,grdeg-1);
1072  Analyze(ctemp.Data(),err,offset); if (err) return;
1073  UInt_t leftopr = fNoper-1;
1074  ctemp = chaine(grdeg+1,lchain-grdeg-1);
1075  Analyze(ctemp.Data(),err,offset); if (err) return;
1076  fExpr[fNoper] = ">=";
1077  actionCode = kGreaterThan;
1078  SetAction(fNoper,actionCode,actionParam);
1079  fNoper++;
1080  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1081  }
1082  } else if (egal != 0) {
1083  if (egal==1 || egal==lchain-1) {
1084  err=5;
1085  chaine_error="==";
1086  }
1087  else {
1088  ctemp = chaine(0,egal-1);
1089  Analyze(ctemp.Data(),err,offset); if (err) return;
1090  Int_t optloc = fNoper-1;
1091 
1092  ctemp = chaine(egal+1,lchain-egal-1);
1093  Analyze(ctemp.Data(),err,offset); if (err) return;
1094  fExpr[fNoper] = "==";
1095  actionCode = kEqual;
1096 
1097  Bool_t isstring = IsString(fNoper-1);
1098  if (IsString(optloc) != isstring) {
1099  err = 45;
1100  chaine_error = "==";
1101  } else if (isstring) {
1102  actionCode = kStringEqual;
1103  }
1104  SetAction(fNoper,actionCode,actionParam);
1105  fNoper++;
1106  }
1107  } else if (diff != 0) {
1108  if (diff==1 || diff==lchain-1) {
1109  err=5;
1110  chaine_error = "!=";
1111  }
1112  else {
1113  ctemp = chaine(0,diff-1);
1114  Analyze(ctemp.Data(),err,offset); if (err) return;
1115  Int_t optloc = fNoper-1;
1116 
1117  ctemp = chaine(diff+1,lchain-diff-1);
1118  Analyze(ctemp.Data(),err,offset); if (err) return;
1119  fExpr[fNoper] = "!=";
1120  actionCode = kNotEqual;
1121 
1122  Bool_t isstring = IsString(fNoper-1);
1123  if (IsString(optloc) != isstring) {
1124  err = 45;
1125  chaine_error = "!=";
1126  } else if (isstring) {
1127  actionCode = kStringNotEqual;
1128  }
1129  SetAction(fNoper,actionCode,actionParam);
1130  fNoper++;
1131  }
1132  } else if (plus != 0) {
1133  if (plus==lchain) {
1134  err=5;
1135  chaine_error = "+";
1136  }
1137  else {
1138  ctemp = chaine(0,plus-1);
1139  Analyze(ctemp.Data(),err,offset); if (err) return;
1140  UInt_t leftopr = fNoper-1;
1141  ctemp = chaine(plus,lchain-plus);
1142  Analyze(ctemp.Data(),err,offset); if (err) return;
1143  fExpr[fNoper] = "+";
1144  actionCode = kAdd;
1145  SetAction(fNoper,actionCode,actionParam);
1146  fNoper++;
1147  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1148  }
1149  } else {
1150  if (moins != 0) {
1151  if (moins == 1) {
1152  ctemp = chaine(moins,lchain-moins);
1153  Analyze(ctemp.Data(),err,offset); if (err) return;
1154  fExpr[fNoper] = "-";
1155  actionCode = kSignInv;
1156  SetAction(fNoper,actionCode,actionParam);
1157  ++fNoper;
1158  if (!CheckOperands(fNoper-1,err)) return;
1159  } else {
1160  if (moins == lchain) {
1161  err=5;
1162  chaine_error = "-";
1163  } else {
1164  ctemp = chaine(0,moins-1);
1165  Analyze(ctemp.Data(),err,offset); if (err) return;
1166  UInt_t leftopr = fNoper-1;
1167  ctemp = chaine(moins,lchain-moins);
1168  Analyze(ctemp.Data(),err,offset); if (err) return;
1169  fExpr[fNoper] = "-";
1170  actionCode = kSubstract;
1171  SetAction(fNoper,actionCode,actionParam);
1172  fNoper++;
1173  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1174  }
1175  }
1176  } else if (modulo != 0) {
1177  if (modulo == 1 || modulo == lchain) {
1178  err=5;
1179  chaine_error="%";
1180  } else {
1181  ctemp = chaine(0,modulo-1);
1182  Analyze(ctemp.Data(),err,offset); if (err) return;
1183  UInt_t leftopr = fNoper-1;
1184  ctemp = chaine(modulo,lchain-modulo);
1185  Analyze(ctemp.Data(),err,offset); if (err) return;
1186  fExpr[fNoper] = "%";
1187  actionCode = kModulo;
1188  SetAction(fNoper,actionCode,actionParam);
1189  fNoper++;
1190  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1191  }
1192  } else if (rshift != 0) {
1193  if (rshift == 1 || rshift == lchain) {
1194  err=5;
1195  chaine_error=">>";
1196  } else {
1197  ctemp = chaine(0,rshift-1);
1198  Analyze(ctemp.Data(),err,offset); if (err) return;
1199  UInt_t leftopr = fNoper-1;
1200  ctemp = chaine(rshift+1,lchain-rshift-1);
1201  Analyze(ctemp.Data(),err,offset); if (err) return;
1202  fExpr[fNoper] = ">>";
1203  actionCode = kRightShift;
1204  SetAction(fNoper,actionCode,actionParam);
1205  fNoper++;
1206  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1207  }
1208  } else if (lshift != 0) {
1209  if (lshift == 1 || lshift == lchain) {
1210  err=5;
1211  chaine_error=">>";
1212  } else {
1213  ctemp = chaine(0,lshift-1);
1214  Analyze(ctemp.Data(),err,offset); if (err) return;
1215  UInt_t leftopr = fNoper-1;
1216  ctemp = chaine(lshift+1,lchain-lshift-1);
1217  Analyze(ctemp.Data(),err,offset); if (err) return;
1218  fExpr[fNoper] = ">>";
1219  actionCode = kLeftShift;
1220  SetAction(fNoper,actionCode,actionParam);
1221  fNoper++;
1222  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1223  }
1224  } else {
1225  if (multi != 0) {
1226  if (multi == 1 || multi == lchain) {
1227  err=5;
1228  chaine_error="*";
1229  }
1230  else {
1231  ctemp = chaine(0,multi-1);
1232  Analyze(ctemp.Data(),err,offset); if (err) return;
1233  UInt_t leftopr = fNoper-1;
1234  ctemp = chaine(multi,lchain-multi);
1235  Analyze(ctemp.Data(),err,offset); if (err) return;
1236  fExpr[fNoper] = "*";
1237  actionCode = kMultiply;
1238  SetAction(fNoper,actionCode,actionParam);
1239  fNoper++;
1240  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1241  }
1242  } else {
1243  if (divi != 0) {
1244  if (divi == 1 || divi == lchain) {
1245  err=5;
1246  chaine_error = "/";
1247  }
1248  else {
1249  ctemp = chaine(0,divi-1);
1250  Analyze(ctemp.Data(),err,offset); if (err) return;
1251  UInt_t leftopr = fNoper-1;
1252  ctemp = chaine(divi,lchain-divi);
1253  Analyze(ctemp.Data(),err,offset); if (err) return;
1254  fExpr[fNoper] = "/";
1255  actionCode = kDivide;
1256  SetAction(fNoper,actionCode,actionParam);
1257  fNoper++;
1258  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1259  }
1260  } else {
1261  if (puiss != 0) {
1262  if (puiss == 1 || puiss == lchain) {
1263  err = 5;
1264  chaine_error = "**";
1265  }
1266  else {
1267  if (chaine(lchain-2,2) == "^2") {
1268  ctemp = "sq(" + chaine(0,lchain-2) + ")";
1269  Analyze(ctemp.Data(),err,offset); if (err) return;
1270  } else {
1271  ctemp = chaine(0,puiss-1);
1272  Analyze(ctemp.Data(),err,offset); if (err) return;
1273  UInt_t leftopr = fNoper-1;
1274  ctemp = chaine(puiss,lchain-puiss);
1275  Analyze(ctemp.Data(),err,offset); if (err) return;
1276  fExpr[fNoper] = "^";
1277  actionCode = kpow;
1278  SetAction(fNoper,actionCode,actionParam);
1279  fNoper++;
1280  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1281  }
1282  }
1283  } else {
1284 
1285  find=0;
1286 
1287  // Check for a numerical expression
1288  {
1289  Bool_t hasDot = kFALSE;
1290  Bool_t isHexa = kFALSE;
1291  Bool_t hasExpo= kFALSE;
1292  if ((chaine(0,2)=="0x")||(chaine(0,2)=="0X")) isHexa=kTRUE;
1293  for (j=0; j<chaine.Length() && err==0; j++) {
1294  t=chaine[j];
1295  if (!isHexa) {
1296  if (j>0 && (chaine(j,1)=="e" || chaine(j,2)=="e+" || chaine(j,2)=="e-" || chaine(j,1)=="E" || chaine(j,2)=="E+" || chaine(j,2)=="E-")) {
1297  if (hasExpo) {
1298  err=26;
1299  chaine_error=chaine;
1300  }
1301  hasExpo = kTRUE;
1302  // The previous implementation allowed a '.' in the exponent.
1303  // That information was ignored (by sscanf), we now make it an error
1304  // hasDot = kFALSE;
1305  hasDot = kTRUE; // forbid any additional '.'
1306  if (chaine(j,2)=="e+" || chaine(j,2)=="e-" || chaine(j,2)=="E+" || chaine(j,2)=="E-") j++;
1307  }
1308  else {
1309  if (chaine(j,1) == "." && !hasDot) hasDot = kTRUE; // accept only one '.' in the number
1310  else {
1311  // The previous implementation was allowing ANYTHING after the '.' and thus
1312  // made legal code like '2.3 and fpx' and was just silently ignoring the
1313  // 'and fpx'.
1314  if (!strchr("0123456789",t) && (chaine(j,1)!="+" || j!=0)) {
1315  err = 30;
1316  chaine_error=chaine;
1317  }
1318  }
1319  }
1320  }
1321  else {
1322  if (!strchr("0123456789abcdefABCDEF",t) && (j>1)) {
1323  err = 30;
1324  chaine_error=chaine;
1325  }
1326  }
1327  }
1328  if (fNconst >= gMAXCONST) err = 27;
1329  if (!err) {
1330  if (!isHexa) {if (sscanf((const char*)chaine,"%lg",&vafConst) > 0) err = 0; else err =1;}
1331  else {if (sscanf((const char*)chaine,"%lx",&vafConst2) > 0) err = 0; else err=1;
1332  vafConst = (Double_t) vafConst2;}
1333  fExpr[fNoper] = chaine;
1334  k = -1;
1335  for (j=0;j<fNconst;j++) {
1336  if (vafConst == fConst[j] ) k= j;
1337  }
1338  if ( k < 0) { k = fNconst; fNconst++; fConst[k] = vafConst; }
1339  actionCode = kConstant;
1340  actionParam = k;
1341  SetAction(fNoper,actionCode,actionParam);
1342  fNoper++;
1343  }
1344  if (err==30) err=0;
1345  else find = kTRUE;
1346  }
1347 
1348  // Look for an already defined expression
1349 
1350  if (find==0) {
1351  {
1353  oldformula = (const TFormula*)gROOT->GetListOfFunctions()->FindObject((const char*)chaine);
1354  }
1355  if (oldformula && strcmp(schain,oldformula->GetTitle())) {
1356  Int_t nprior = fNpar;
1357  Analyze(oldformula->GetExpFormula(),err,fNpar);
1358  // if the oldformula was using a normalized function (gausn or landaun) set also in this one
1359  if (oldformula->IsNormalized()) SetBit(kNormalized);
1360  if (err) return; // changes fNpar
1361  fNpar = nprior;
1362  find=1;
1363  if (!err) {
1364  Int_t npold = oldformula->GetNpar();
1365  fNpar += npold;
1366  for (Int_t ipar=0;ipar<npold;ipar++) {
1367  fParams[ipar+fNpar-npold] = oldformula->GetParameter(ipar);
1368  }
1369  }
1370  }
1371  }
1372  if (find == 0) {
1373 
1374  // Check if chaine is a defined variable.
1375  // Note that DefinedVariable can be overloaded
1376 
1377  ctemp = chaine;
1378  ctemp.ReplaceAll(escapedSlash, slash);
1379  Int_t action;
1380  k = DefinedVariable(ctemp,action);
1381  if (k==-3) {
1382  // Error message already issued
1383  err = 1;
1384  } else if (k==-2) {
1385  err = 31;
1386  chaine_error = ctemp;
1387  } else if ( k >= 0 ) {
1388  fExpr[fNoper] = ctemp;
1389  actionCode = action;
1390  actionParam = k;
1391  SetAction(fNoper,actionCode,actionParam);
1392  if (action==kDefinedString) fNstring++;
1393  else if (k <kMAXFOUND && !fAlreadyFound.TestBitNumber(k)) {
1395  fNval++;
1396  }
1397  fNoper++;
1398  } else if (chaine(0,1) == "!") {
1399  ctemp = chaine(1,lchain-1);
1400  Analyze(ctemp.Data(),err,offset); if (err) return;
1401  fExpr[fNoper] = "!";
1402  actionCode = kNot;
1403  SetAction(fNoper,actionCode,actionParam);
1404  fNoper++;
1405  if (!CheckOperands(fNoper-1,err)) return;
1406  } else if (chaine(0,1)=="\"" && chaine(chaine.Length()-1,1)=="\"") {
1407  // It is a string !!!
1408  fExpr[fNoper] = chaine(1,chaine.Length()-2);
1409  actionCode = kStringConst;
1410  SetAction(fNoper,actionCode,actionParam);
1411  fNoper++;
1412  } else if (chaine(0,4) == "cos(") {
1413  ctemp = chaine(3,lchain-3);
1414  Analyze(ctemp.Data(),err,offset); if (err) return;
1415  fExpr[fNoper] = "cos";
1416  actionCode = kcos;
1417  SetAction(fNoper,actionCode,actionParam);
1418  fNoper++;
1419  if (!CheckOperands(fNoper-1,err)) return;
1420  } else if (chaine(0,4) == "sin(") {
1421  ctemp = chaine(3,lchain-3);
1422  Analyze(ctemp.Data(),err,offset); if (err) return;
1423  fExpr[fNoper] = "sin";
1424  actionCode = ksin;
1425  SetAction(fNoper,actionCode,actionParam);
1426  fNoper++;
1427  if (!CheckOperands(fNoper-1,err)) return;
1428  } else if (chaine(0,4) == "tan(") {
1429  ctemp = chaine(3,lchain-3);
1430  Analyze(ctemp.Data(),err,offset); if (err) return;
1431  fExpr[fNoper] = "tan";
1432  actionCode = ktan;
1433  SetAction(fNoper,actionCode,actionParam);
1434  fNoper++;
1435  if (!CheckOperands(fNoper-1,err)) return;
1436  } else if (chaine(0,5) == "acos(") {
1437  ctemp = chaine(4,lchain-4);
1438  Analyze(ctemp.Data(),err,offset); if (err) return;
1439  fExpr[fNoper] = "acos";
1440  actionCode = kacos;
1441  SetAction(fNoper,actionCode,actionParam);
1442  fNoper++;
1443  if (!CheckOperands(fNoper-1,err)) return;
1444  } else if (chaine(0,5) == "asin(") {
1445  ctemp = chaine(4,lchain-4);
1446  Analyze(ctemp.Data(),err,offset); if (err) return;
1447  fExpr[fNoper] = "asin";
1448  actionCode = kasin;
1449  SetAction(fNoper,actionCode,actionParam);
1450  fNoper++;
1451  if (!CheckOperands(fNoper-1,err)) return;
1452  } else if (chaine(0,5) == "atan(") {
1453  ctemp = chaine(4,lchain-4);
1454  Analyze(ctemp.Data(),err,offset); if (err) return;
1455  fExpr[fNoper] = "atan";
1456  actionCode = katan;
1457  SetAction(fNoper,actionCode,actionParam);
1458  fNoper++;
1459  if (!CheckOperands(fNoper-1,err)) return;
1460  } else if (chaine(0,5) == "cosh(") {
1461  ctemp = chaine(4,lchain-4);
1462  Analyze(ctemp.Data(),err,offset); if (err) return;
1463  fExpr[fNoper] = "cosh";
1464  actionCode = kcosh;
1465  SetAction(fNoper,actionCode,actionParam);
1466  fNoper++;
1467  if (!CheckOperands(fNoper-1,err)) return;
1468  } else if (chaine(0,5) == "sinh(") {
1469  ctemp = chaine(4,lchain-4);
1470  Analyze(ctemp.Data(),err,offset); if (err) return;
1471  fExpr[fNoper] = "sinh";
1472  actionCode = ksinh;
1473  SetAction(fNoper,actionCode,actionParam);
1474  fNoper++;;
1475  if (!CheckOperands(fNoper-1,err)) return;
1476  } else if (chaine(0,5) == "tanh(") {
1477  ctemp = chaine(4,lchain-4);
1478  Analyze(ctemp.Data(),err,offset); if (err) return;
1479  fExpr[fNoper] = "tanh";
1480  actionCode = ktanh;
1481  SetAction(fNoper,actionCode,actionParam);
1482  fNoper++;;
1483  if (!CheckOperands(fNoper-1,err)) return;
1484  } else if (chaine(0,6) == "acosh(") {
1485  ctemp = chaine(5,lchain-5);
1486  Analyze(ctemp.Data(),err,offset); if (err) return;
1487  fExpr[fNoper] = "acosh";
1488  actionCode = kacosh;
1489  SetAction(fNoper,actionCode,actionParam);
1490  fNoper++;;
1491  if (!CheckOperands(fNoper-1,err)) return;
1492  } else if (chaine(0,6) == "asinh(") {
1493  ctemp = chaine(5,lchain-5);
1494  Analyze(ctemp.Data(),err,offset); if (err) return;
1495  fExpr[fNoper] = "asinh";
1496  actionCode = kasinh;
1497  SetAction(fNoper,actionCode,actionParam);
1498  fNoper++;;
1499  if (!CheckOperands(fNoper-1,err)) return;
1500  } else if (chaine(0,6) == "atanh(") {
1501  ctemp = chaine(5,lchain-5);
1502  Analyze(ctemp.Data(),err,offset); if (err) return;
1503  fExpr[fNoper] = "atanh";
1504  actionCode = katanh;
1505  SetAction(fNoper,actionCode,actionParam);
1506  fNoper++;;
1507  if (!CheckOperands(fNoper-1,err)) return;
1508  } else if (chaine(0,3) == "sq(") {
1509  ctemp = chaine(2,lchain-2);
1510  Analyze(ctemp.Data(),err,offset); if (err) return;
1511  fExpr[fNoper] = "sq";
1512  actionCode = ksq;
1513  SetAction(fNoper,actionCode,actionParam);
1514  fNoper++;;
1515  if (!CheckOperands(fNoper-1,err)) return;
1516  } else if (chaine(0,4) == "log(") {
1517  ctemp = chaine(3,lchain-3);
1518  Analyze(ctemp.Data(),err,offset); if (err) return;
1519  fExpr[fNoper] = "log";
1520  actionCode = klog;
1521  SetAction(fNoper,actionCode,actionParam);
1522  fNoper++;;
1523  if (!CheckOperands(fNoper-1,err)) return;
1524  } else if (chaine(0,6) == "log10(") {
1525  ctemp = chaine(5,lchain-5);
1526  Analyze(ctemp.Data(),err,offset); if (err) return;
1527  fExpr[fNoper] = "log10";
1528  actionCode = klog10;
1529  SetAction(fNoper,actionCode,actionParam);
1530  fNoper++;;
1531  if (!CheckOperands(fNoper-1,err)) return;
1532  } else if (chaine(0,4) == "exp(") {
1533  ctemp = chaine(3,lchain-3);
1534  Analyze(ctemp.Data(),err,offset); if (err) return;
1535  fExpr[fNoper] = "exp";
1536  actionCode = kexp;
1537  SetAction(fNoper,actionCode,actionParam);
1538  fNoper++;;
1539  if (!CheckOperands(fNoper-1,err)) return;
1540  } else if (chaine(0,4) == "abs(") {
1541  ctemp = chaine(3,lchain-3);
1542  Analyze(ctemp.Data(),err,offset); if (err) return;
1543  fExpr[fNoper] = "abs";
1544  actionCode = kabs;
1545  SetAction(fNoper,actionCode,actionParam);
1546  fNoper++;;
1547  if (!CheckOperands(fNoper-1,err)) return;
1548  } else if (chaine(0,5) == "sign(") {
1549  ctemp = chaine(4,lchain-4);
1550  Analyze(ctemp.Data(),err,offset); if (err) return;
1551  fExpr[fNoper] = "sign";
1552  actionCode = ksign;
1553  SetAction(fNoper,actionCode,actionParam);
1554  fNoper++;;
1555  if (!CheckOperands(fNoper-1,err)) return;
1556  } else if (chaine(0,4) == "int(") {
1557  ctemp = chaine(3,lchain-3);
1558  Analyze(ctemp.Data(),err,offset); if (err) return;
1559  fExpr[fNoper] = "int";
1560  actionCode = kint;
1561  SetAction(fNoper,actionCode,actionParam);
1562  fNoper++;;
1563  if (!CheckOperands(fNoper-1,err)) return;
1564  } else if (chaine == "rndm" || chaine(0,5) == "rndm(") {
1565  fExpr[fNoper] = "rndm";
1566  actionCode = krndm;
1567  SetAction(fNoper,actionCode,actionParam);
1568  fNoper++;;
1569  } else if (chaine(0,5) == "sqrt(") {
1570  ctemp = chaine(4,lchain-4);
1571  Analyze(ctemp.Data(),err,offset); if (err) return;
1572  fExpr[fNoper] = "sqrt";
1573  actionCode = ksqrt;
1574  SetAction(fNoper,actionCode,actionParam);
1575  fNoper++;;
1576  if (!CheckOperands(fNoper-1,err)) return;
1577 
1578  // Look for an exponential
1579 
1580  } else if ( chaine == "expo" || chaine(0,5)=="expo("
1581  || (lchain==5 && chaine(1,4)=="expo")
1582  || (lchain==6 && chaine(2,4)=="expo")
1583  || chaine(1,5)=="expo(" || chaine(2,5)=="expo(" ) {
1584  chaine1ST=chaine;
1585  if (chaine(1,4) == "expo") {
1586  ctemp=chaine(0,1);
1587  if (ctemp=="x") {
1588  inter2=0;
1589  if (fNdim < 1) fNdim = 1; }
1590  else if (ctemp=="y") {
1591  inter2=1;
1592  if (fNdim < 2) fNdim = 2; }
1593  else if (ctemp=="z") {
1594  inter2=2;
1595  if (fNdim < 3) fNdim = 3; }
1596  else if (ctemp=="t") {
1597  inter2=3;
1598  if (fNdim < 4) fNdim = 4; }
1599  else {
1600  err=26; // unknown name;
1601  chaine_error=chaine1ST;
1602  }
1603  chaine=chaine(1,lchain-1);
1604  lchain=chaine.Length();
1605  } else inter2=0;
1606  if (chaine(2,4) == "expo") {
1607  if (chaine(0,2) != "xy") {
1608  err=26; // unknown name
1609  chaine_error=chaine1ST;
1610  }
1611  else {
1612  inter2=5;
1613  if (fNdim < 2) fNdim = 2;
1614  chaine=chaine(2,lchain-2);
1615  lchain=chaine.Length();
1616  }
1617  }
1618  if (lchain == 4) {
1619  if (fNpar>=gMAXPAR) err=7; // too many parameters
1620  if (!err) {
1621  fExpr[fNoper] = chaine1ST;
1622  actionCode = kexpo + inter2;
1623  actionParam = offset;
1624  SetAction(fNoper,actionCode,actionParam);
1625  if (inter2 == 5+offset && fNpar < 3+offset) fNpar = 3+offset;
1626  if (fNpar < 2+offset) fNpar = 2+offset;
1627  if (fNpar>=gMAXPAR) err=7; // too many parameters
1628  if (!err) {
1629  fNoper++;
1630  if (fNdim < 1) fNdim = 1;
1631  if (fNpar == 2) SetNumber(200);
1632  }
1633  }
1634  } else if (chaine(4,1) == "(") {
1635  ctemp = chaine(5,lchain-6);
1636  fExpr[fNoper] = chaine1ST;
1637  for (j=0; j<ctemp.Length(); j++) {
1638  t=ctemp[j];
1639  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1640  err=20;
1641  chaine_error=chaine1ST;
1642  }
1643  }
1644  if (err==0) {
1645  sscanf(ctemp.Data(),"%d",&inter);
1646  if (inter>=0) {
1647  inter += offset;
1648  actionCode = kexpo + inter2;
1649  actionParam = inter;
1650  SetAction(fNoper,actionCode,actionParam);
1651  if (inter2 == 5) inter++;
1652  if (inter+2>fNpar) fNpar = inter+2;
1653  if (fNpar>=gMAXPAR) err=7; // too many parameters
1654  if (!err) fNoper++;
1655  if (fNpar == 2) SetNumber(200);
1656  } else err=20;
1657  } else err = 20; // non integer value for parameter number
1658  } else {
1659  err=26; // unknown name
1660  chaine_error=chaine;
1661  }
1662 
1663  // Look for gaus, xgaus,ygaus,xygaus
1664 
1665  } else if (chaine=="gaus"
1666  || (lchain==5 && chaine(1,4)=="gaus")
1667  || (lchain==6 && chaine(2,4)=="gaus")
1668  || chaine(0,5)=="gaus(" || chaine(1,5)=="gaus(" || chaine(2,5)=="gaus(") {
1669  chaine1ST=chaine;
1670  if (chaine(1,4) == "gaus") {
1671  ctemp=chaine(0,1);
1672  if (ctemp=="x") {
1673  inter2=0;
1674  if (fNdim < 1) fNdim = 1; }
1675  else if (ctemp=="y") {
1676  inter2=1;
1677  if (fNdim < 2) fNdim = 2; }
1678  else if (ctemp=="z") {
1679  inter2=2;
1680  if (fNdim < 3) fNdim = 3; }
1681  else if (ctemp=="t") {
1682  inter2=3;
1683  if (fNdim < 4) fNdim = 4; }
1684  else {
1685  err=26; // unknown name
1686  chaine_error=chaine1ST;
1687  }
1688  chaine=chaine(1,lchain-1);
1689  lchain=chaine.Length();
1690  } else inter2=0;
1691  if (chaine(2,4) == "gaus") {
1692  if (chaine(0,2) != "xy") {
1693  err=26; // unknown name
1694  chaine_error=chaine1ST;
1695  }
1696  else {
1697  inter2=5;
1698  if (fNdim < 2) fNdim = 2;
1699  chaine=chaine(2,lchain-2);
1700  lchain=chaine.Length();
1701  SetNumber(110); // xygaus
1702  }
1703  }
1704  if (lchain == 4 && err==0) {
1705  if (fNpar>=gMAXPAR) err=7; // too many parameters
1706  if (!err) {
1707  fExpr[fNoper] = chaine1ST;
1708  actionCode = kgaus + inter2;
1709  actionParam = offset;
1710  SetAction(fNoper,actionCode,actionParam);
1711  if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
1712  if (3+offset>fNpar) fNpar = 3+offset;
1713  if (fNpar>=gMAXPAR) err=7; // too many parameters
1714  if (!err) {
1715  fNoper++;
1716  if (fNdim < 1) fNdim = 1;
1717  if (fNpar == 3) SetNumber(100);
1718  }
1719  }
1720  } else if (chaine(4,1) == "(" && err==0) {
1721  ctemp = chaine(5,lchain-6);
1722  fExpr[fNoper] = chaine1ST;
1723  for (j=0; j<ctemp.Length(); j++) {
1724  t=ctemp[j];
1725  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1726  err=20;
1727  chaine_error=chaine1ST;
1728  }
1729  }
1730  if (err==0) {
1731  sscanf(ctemp.Data(),"%d",&inter);
1732  if (inter >= 0) {
1733  inter += offset;
1734  actionCode = kgaus + inter2;
1735  actionParam = inter;
1736  SetAction(fNoper,actionCode,actionParam);
1737  if (inter2 == 5) inter += 2;
1738  if (inter+3>fNpar) fNpar = inter+3;
1739  if (fNpar>=gMAXPAR) err=7; // too many parameters
1740  if (!err) fNoper++;
1741  if(fNpar == 3) SetNumber(100);
1742  } else err = 20; // non integer value for parameter number
1743  }
1744  } else if (err==0) {
1745  err=26; // unknown name
1746  chaine_error=chaine1ST;
1747  }
1748 
1749  // Look for landau, xlandau,ylandau,xylandau
1750 
1751  } else if (chaine=="landau" || (lchain==7 && chaine(1,6)=="landau")
1752  || (lchain==8 && chaine(2,6)=="landau")
1753  || chaine(0,7)=="landau(" || chaine(1,7)=="landau(" || chaine(2,7)=="landau(") {
1754  chaine1ST=chaine;
1755  if (chaine(1,6) == "landau") {
1756  ctemp=chaine(0,1);
1757  if (ctemp=="x") {
1758  inter2=0;
1759  if (fNdim < 1) fNdim = 1; }
1760  else if (ctemp=="y") {
1761  inter2=1;
1762  if (fNdim < 2) fNdim = 2; }
1763  else if (ctemp=="z") {
1764  inter2=2;
1765  if (fNdim < 3) fNdim = 3; }
1766  else if (ctemp=="t") {
1767  inter2=3;
1768  if (fNdim < 4) fNdim = 4; }
1769  else {
1770  err=26; // unknown name
1771  chaine_error=chaine1ST;
1772  }
1773  chaine=chaine(1,lchain-1);
1774  lchain=chaine.Length();
1775  } else inter2=0;
1776  if (chaine(2,6) == "landau") {
1777  if (chaine(0,2) != "xy") {
1778  err=26; // unknown name
1779  chaine_error=chaine1ST;
1780  }
1781  else {
1782  inter2=5;
1783  if (fNdim < 2) fNdim = 2;
1784  chaine=chaine(2,lchain-2);
1785  lchain=chaine.Length();
1786  SetNumber(410);
1787  }
1788  }
1789  if (lchain == 6 && err==0) {
1790  if (fNpar>=gMAXPAR) err=7; // too many parameters
1791  if (!err) {
1792  fExpr[fNoper] = chaine1ST;
1793  actionCode = klandau + inter2;
1794  actionParam = offset;
1795  SetAction(fNoper,actionCode,actionParam);
1796  if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
1797  if (3+offset>fNpar) fNpar = 3+offset;
1798  if (fNpar>=gMAXPAR) err=7; // too many parameters
1799  if (!err) {
1800  fNoper++;
1801  if (fNdim < 1) fNdim = 1;
1802  if (fNpar == 3) SetNumber(400);
1803  }
1804  }
1805  } else if (chaine(6,1) == "(" && err==0) {
1806  ctemp = chaine(7,lchain-8);
1807  fExpr[fNoper] = chaine1ST;
1808  for (j=0; j<ctemp.Length(); j++) {
1809  t=ctemp[j];
1810  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1811  err=20;
1812  chaine_error=chaine1ST;
1813  }
1814  }
1815  if (err==0) {
1816  sscanf(ctemp.Data(),"%d",&inter);
1817  if (inter >= 0) {
1818  inter += offset;
1819  actionCode = klandau + inter2;
1820  actionParam = inter;
1821  SetAction(fNoper,actionCode,actionParam);
1822  if (inter2 == 5) inter += 2;
1823  if (inter+3>fNpar) fNpar = inter+3;
1824  if (fNpar>=gMAXPAR) err=7; // too many parameters
1825  if (!err) fNoper++;
1826  if (fNpar == 3) SetNumber(400);
1827  } else err = 20; // non integer value for parameter number
1828  }
1829  } else if (err==0) {
1830  err=26; // unknown name
1831  chaine_error=chaine1ST;
1832  }
1833 
1834  // Look for a polynomial
1835 
1836  } else if (chaine(0,3) == "pol" || chaine(1,3) == "pol") {
1837  chaine1ST=chaine;
1838  if (chaine(1,3) == "pol") {
1839  ctemp=chaine(0,1);
1840  if (ctemp=="x") {
1841  inter2=1;
1842  if (fNdim < 1) fNdim = 1; }
1843  else if (ctemp=="y") {
1844  inter2=2;
1845  if (fNdim < 2) fNdim = 2; }
1846  else if (ctemp=="z") {
1847  inter2=3;
1848  if (fNdim < 3) fNdim = 3; }
1849  else if (ctemp=="t") {
1850  inter2=4;
1851  if (fNdim < 4) fNdim = 4; }
1852  else {
1853  err=26; // unknown name;
1854  chaine_error=chaine1ST;
1855  }
1856  chaine=chaine(1,lchain-1);
1857  lchain=chaine.Length();
1858  } else inter2=1;
1859  if (chaine(lchain-1,1) == ")") {
1860  nomb = 0;
1861  for (j=3;j<lchain;j++) if (chaine(j,1)=="(" && nomb == 0) nomb = j;
1862  if (nomb == 3) err = 23; // degree of polynomial not specified
1863  if (nomb == 0) err = 40; // '(' is expected
1864  ctemp = chaine(nomb+1,lchain-nomb-2);
1865  for (j=0; j<ctemp.Length(); j++) {
1866  t=ctemp[j];
1867  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
1868  err=20;
1869  chaine_error=chaine1ST;
1870  }
1871  }
1872  if (!err) {
1873  sscanf(ctemp.Data(),"%d",&inter);
1874  if (inter < 0) err = 20;
1875  }
1876  }
1877  else {
1878  nomb = lchain;
1879  inter = 0;
1880  }
1881  if (!err) {
1882  inter--;
1883  ctemp = chaine(3,nomb-3);
1884  if (sscanf(ctemp.Data(),"%d",&n) > 0) {
1885  if (n < 0 ) err = 24; //Degree of polynomial must be positive
1886  if (n >= 20) err = 25; //Degree of polynomial must be less than 20
1887  } else err = 20;
1888  }
1889  if (!err) {
1890  fExpr[fNoper] = chaine1ST;
1891  actionCode = kpol+(inter2-1);
1892  actionParam = n*100+inter+2;
1893  SetAction(fNoper,actionCode,actionParam);
1894  if (inter+n+1>=fNpar) fNpar = inter + n + 2;
1895  if (fNpar>=gMAXPAR) err=7; // too many parameters
1896  if (!err) {
1897  fNoper++;
1898  if (fNdim < 1) fNdim = 1;
1899  SetNumber(300+n);
1900  }
1901  }
1902 
1903  // Look for pow,atan2,etc
1904 
1905  } else if (chaine(0,4) == "pow(") {
1906  compt = 4; nomb = 0; virgule = 0; nest=0;
1907  while(compt != lchain) {
1908  compt++;
1909  if (chaine(compt-1,1) == "(") nest++;
1910  else if (chaine(compt-1,1) == ")") nest--;
1911  else if (chaine(compt-1,1) == "," && nest==0) {
1912  nomb++;
1913  if (nomb == 1 && virgule == 0) virgule = compt;
1914  }
1915  }
1916  if (nomb != 1) err = 22; // There are plus or minus than 2 arguments for pow
1917  else {
1918  ctemp = chaine(4,virgule-5);
1919  Analyze(ctemp.Data(),err,offset); if (err) return;
1920  UInt_t leftopr = fNoper-1;
1921  ctemp = chaine(virgule,lchain-virgule-1);
1922  Analyze(ctemp.Data(),err,offset); if (err) return;
1923  fExpr[fNoper] = "^";
1924  actionCode = kpow;
1925  SetAction(fNoper,actionCode,actionParam);
1926  fNoper++;
1927  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1928  }
1929  } else if (chaine(0,7) == "strstr(") {
1930  compt = 7; nomb = 0; virgule = 0; nest=0;
1931  inString = false;
1932  while(compt != lchain) {
1933  compt++;
1934  if (chaine(compt-1,1) == "\"") {
1935  inString = !inString;
1936  } else if (!inString) {
1937  if (chaine(compt-1,1) == "(") nest++;
1938  else if (chaine(compt-1,1) == ")") nest--;
1939  else if (chaine(compt-1,1) == "," && nest==0) {
1940  nomb++;
1941  if (nomb == 1 && virgule == 0) virgule = compt;
1942  }
1943  }
1944  }
1945  if (nomb != 1) err = 28; // There are plus or minus than 2 arguments for strstr
1946  else {
1947  ctemp = chaine(7,virgule-8);
1948  Analyze(ctemp.Data(),err,offset); if (err) return;
1949  Int_t optloc = fNoper-1;
1950 
1951  ctemp = chaine(virgule,lchain-virgule-1);
1952  Analyze(ctemp.Data(),err,offset); if (err) return;
1953  fExpr[fNoper] = "strstr";
1954  actionCode = kstrstr;
1955  SetAction(fNoper,actionCode,actionParam);
1956  fNoper++;
1957 
1958  if ( !IsString(optloc) || !IsString(fNoper-2) ) {
1959  err = 46;
1960  chaine_error = "strstr";
1961  }
1962  }
1963  } else if (chaine(0,4) == "min(") {
1964  compt = 4; nomb = 0; virgule = 0; nest=0;
1965  while(compt != lchain) {
1966  compt++;
1967  if (chaine(compt-1,1) == "(") nest++;
1968  else if (chaine(compt-1,1) == ")") nest--;
1969  else if (chaine(compt-1,1) == "," && nest==0) {
1970  nomb++;
1971  if (nomb == 1 && virgule == 0) virgule = compt;
1972  }
1973  }
1974  if (nomb != 1) {
1975  err = 44; // There are plus or minus than 2 arguments for min
1976  err_hint = 3;
1977  }
1978  else {
1979  ctemp = chaine(4,virgule-5);
1980  Analyze(ctemp.Data(),err,offset); if (err) return;
1981  UInt_t leftopr = fNoper-1;
1982  ctemp = chaine(virgule,lchain-virgule-1);
1983  Analyze(ctemp.Data(),err,offset); if (err) return;
1984  fExpr[fNoper] = "min";
1985  actionCode = kmin;
1986  SetAction(fNoper,actionCode,actionParam);
1987  fNoper++;
1988  if (!CheckOperands(leftopr,fNoper-1,err)) return;
1989  }
1990  } else if (chaine(0,4) == "max(") {
1991  compt = 4; nomb = 0; virgule = 0; nest=0;
1992  while(compt != lchain) {
1993  compt++;
1994  if (chaine(compt-1,1) == "(") nest++;
1995  else if (chaine(compt-1,1) == ")") nest--;
1996  else if (chaine(compt-1,1) == "," && nest==0) {
1997  nomb++;
1998  if (nomb == 1 && virgule == 0) virgule = compt;
1999  }
2000  }
2001  if (nomb != 1) {
2002  err = 44; // There are plus or minus than 2 arguments for min
2003  err_hint = 3;
2004  }
2005  else {
2006  ctemp = chaine(4,virgule-5);
2007  Analyze(ctemp.Data(),err,offset); if (err) return;
2008  UInt_t leftopr = fNoper-1;
2009  ctemp = chaine(virgule,lchain-virgule-1);
2010  Analyze(ctemp.Data(),err,offset); if (err) return;
2011  fExpr[fNoper] = "max";
2012  actionCode = kmax;
2013  SetAction(fNoper,actionCode,actionParam);
2014  fNoper++;
2015  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2016  }
2017 
2018  } else if (chaine(0,6) == "atan2(") {
2019  compt = 6; nomb = 0; virgule = 0; nest=0;
2020  while(compt != lchain) {
2021  compt++;
2022  if (chaine(compt-1,1) == "(") nest++;
2023  else if (chaine(compt-1,1) == ")") nest--;
2024  else if (chaine(compt-1,1) == "," && nest==0) {
2025  nomb++;
2026  if (nomb == 1 && virgule == 0) virgule = compt;
2027  }
2028  }
2029  if (nomb != 1) err = 21; //{ There are plus or minus than 2 arguments for atan2
2030  else {
2031  ctemp = chaine(6,virgule-7);
2032  Analyze(ctemp.Data(),err,offset); if (err) return;
2033  UInt_t leftopr = fNoper-1;
2034  ctemp = chaine(virgule,lchain-virgule-1);
2035  Analyze(ctemp.Data(),err,offset); if (err) return;
2036  fExpr[fNoper] = "atan2";
2037  actionCode = katan2;
2038  SetAction(fNoper,actionCode,actionParam);
2039  fNoper++;
2040  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2041  }
2042  } else if (chaine(0,5) == "fmod(") {
2043  compt = 5; nomb = 0; virgule = 0; nest=0;
2044  while(compt != lchain) {
2045  compt++;
2046  if (chaine(compt-1,1) == "(") nest++;
2047  else if (chaine(compt-1,1) == ")") nest--;
2048  else if (chaine(compt-1,1) == "," && nest==0) {
2049  nomb++;
2050  if (nomb == 1 && virgule == 0) virgule = compt;
2051  }
2052  }
2053  if (nomb != 1) {
2054  err = 44; // There are plus or minus than 2 arguments for fmod
2055  err_hint = 4;
2056  }
2057  else {
2058  ctemp = chaine(5,virgule-6);
2059  Analyze(ctemp.Data(),err,offset); if (err) return;
2060  UInt_t leftopr = fNoper-1;
2061  ctemp = chaine(virgule,lchain-virgule-1);
2062  Analyze(ctemp.Data(),err,offset); if (err) return;
2063  fExpr[fNoper] = "fmod";
2064  actionCode = kfmod;
2065  SetAction(fNoper,actionCode,actionParam);
2066  fNoper++;
2067  if (!CheckOperands(leftopr,fNoper-1,err)) return;
2068  }
2069  } else if (AnalyzeFunction(chaine,err,offset) || err) { // The '||err' is to grab an error coming from AnalyzeFunction
2070  if (err) {
2071  chaine_error = chaine;
2072  } else {
2073  // We have a function call. Note that all the work was already,
2074  // eventually done in AnalyzeFunction
2075  //fprintf(stderr,"We found a foreign function in %s\n",chaine.Data());
2076  }
2077  } else if (chaine(0,1) == "[" && chaine(lchain-1,1) == "]") {
2078  fExpr[fNoper] = chaine;
2079  fNoper++;
2080  ctemp = chaine(1,lchain-2);
2081  for (j=0; j<ctemp.Length(); j++) {
2082  t=ctemp[j];
2083  if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
2084  err=20;
2085  chaine_error=chaine1ST; // le numero ? de par[?] n'est pas un entier }
2086  }
2087  }
2088  if (!err) {
2089  sscanf(ctemp.Data(),"%d",&valeur);
2090  actionCode = kParameter;
2091  actionParam = offset + valeur;
2092  SetAction(fNoper-1, actionCode, actionParam);
2093  fExpr[fNoper-1] = "[";
2094  fExpr[fNoper-1] = (fExpr[fNoper-1] + (long int)(valeur+offset)) + "]";
2095  }
2096  } else if (chaine == "pi") {
2097  fExpr[fNoper] = "pi";
2098  actionCode = kpi;
2099  SetAction(fNoper,actionCode,actionParam);
2100  fNoper++;
2101  }
2102  else {
2103 
2104  // None of the above.
2105 
2106  err = 30;
2107  }
2108  }
2109  }
2110  }
2111  }
2112  }
2113  }
2114 
2115  // Overflows
2116  if (fNoper>=gMAXOP) err=6; // too many operators
2117 
2118  }
2119 
2120  // errors!
2121  if (err>1) {
2122  TString er = "";
2123  chaine_error = "\""+chaine_error+"\"";
2124  switch(err) {
2125  case 2 : er = " Invalid Floating Point Operation"; break;
2126  case 4 : er = " Empty String"; break;
2127  case 5 : er = " Invalid Syntax " + chaine_error; break;
2128  case 6 : er = " Too many operators !"; break;
2129  case 7 : er = " Too many parameters !"; break;
2130  case 10 : er = " z specified but not x and y"; break;
2131  case 11 : er = " z and y specified but not x"; break;
2132  case 12 : er = " y specified but not x"; break;
2133  case 13 : er = " z and x specified but not y"; break;
2134  case 20 : er = " Non integer value for parameter number : " + chaine_error; break;
2135  case 21 : er = " ATAN2 requires two arguments"; break;
2136  case 22 : er = " POW requires two arguments"; break;
2137  case 23 : er = " Degree of polynomial not specified"; break;
2138  case 24 : er = " Degree of polynomial must be positive"; break;
2139  case 25 : er = " Degree of polynomial must be less than 20"; break;
2140  case 26 : er = " Unknown name : " + chaine_error; break;
2141  case 27 : er = " Too many constants in expression"; break;
2142  case 28 : er = " strstr requires two arguments"; break;
2143  case 29 : er = " TFormula can only call interpreted and compiled functions that return a numerical type: " + chaine_error; break;
2144  case 30 : er = " Bad numerical expression : " + chaine_error; break;
2145  case 31 : er = " Part of the Variable " + chaine_error; er += " exists but some of it is not accessible or useable"; break;
2146  case 40 : er = " '(' is expected"; break;
2147  case 41 : er = " ')' is expected"; break;
2148  case 42 : er = " '[' is expected"; break;
2149  case 43 : er = " ']' is expected"; break;
2150  case 44 : er = " The function '" + chaine(0,err_hint) + "' requires two arguments."; break;
2151  case 45 : er = "The operator " + chaine_error + " requires a numerical operand."; break;
2152  case 46 : er = "Both operands of the operator " + chaine_error + " have to be either numbers or strings."; break;
2153  case 47 : er = chaine_error + " requires 2 string arguments"; break;
2154  }
2155  Error("Compile", "%s", er.Data());
2156  err=1;
2157  }
2158 
2159 }
2160 
2161 ////////////////////////////////////////////////////////////////////////////////
2162 /// Check whether the operand at 'oper-1' is compatible with the operation
2163 /// at 'oper'.
2164 
2166 {
2167  if ( IsString(oper-1) && !StringToNumber(oper-1) ) {
2168  Error("Compile","\"%s\" requires a numerical operand.",fExpr[oper].Data());
2169  err = 45;
2170  return kFALSE;
2171  }
2172  return kTRUE;
2173 }
2174 
2175 ////////////////////////////////////////////////////////////////////////////////
2176 /// Check whether the operands at 'leftoper' and 'oper-1' are compatible with
2177 /// the operation at 'oper'.
2178 
2180 {
2181  if ( IsString(oper-1) || IsString(leftoper) ) {
2182  if (IsString(oper-1) && StringToNumber(oper-1)) {
2183  return kTRUE;
2184  }
2185  if (IsString(leftoper) && StringToNumber(leftoper)) {
2186  return kTRUE;
2187  }
2188  Error("Compile","\"%s\" requires two numerical operands.",fExpr[oper].Data());
2189  err = 46;
2190  return kFALSE;
2191  }
2192  return kTRUE;
2193 }
2194 
2195 ////////////////////////////////////////////////////////////////////////////////
2196 /// Try to 'demote' a string into an array bytes. If this is not possible,
2197 /// return false.
2198 
2200 {
2201  // In TFormula proper, we can not handle array of bytes ...
2202  return kFALSE;
2203 }
2204 
2205 ////////////////////////////////////////////////////////////////////////////////
2206 /// Resets the objects.
2207 ///
2208 /// Resets the object to its state before compilation.
2209 
2210 void TFormula::Clear(Option_t * /*option*/ )
2211 {
2212  ClearFormula();
2213 }
2214 
2215 ////////////////////////////////////////////////////////////////////////////////
2216 /// Resets the objects.
2217 ///
2218 /// Resets the object to its state before compilation.
2219 
2221 {
2222  fNdim = 0;
2223  fNpar = 0;
2224  fNoper = 0;
2225  fNconst = 0;
2226  fNumber = 0;
2227  fNstring= 0;
2228  fNval = 0;
2229 
2230  if (fExpr) { delete [] fExpr; fExpr = 0;}
2231  if (fNames) { delete [] fNames; fNames = 0;}
2232  if (fOper) { delete [] fOper; fOper = 0;}
2233  if (fConst) { delete [] fConst; fConst = 0;}
2234  if (fParams) { delete [] fParams; fParams = 0;}
2235  fFunctions.Delete();
2236  fLinearParts.Delete();
2237  //
2238  //MI change
2239  if (fPredefined) { delete [] fPredefined; fPredefined = 0;}
2240  if (fOperOffset) { delete [] fOperOffset; fOperOffset = 0;}
2241  if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
2242  if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
2243  // should we also remove the object from the list?
2244  // gROOT->GetListOfFunctions()->Remove(this);
2245  // if we don't, what happens if it fails the new compilation?
2246 }
2247 
2248 namespace {
2249  template <class T>
2250  inline static void ResizeArrayIfAllocated(T*& oldArray, int newSize){
2251 
2252  // Don't do anything in this case.
2253  if (!oldArray || newSize <=0) return;
2254 
2255  T* newArray = new T[newSize];
2256  std::copy(oldArray, oldArray+newSize, newArray);
2257  delete [] oldArray;
2258  oldArray = newArray;
2259  }
2260 }
2261 
2262 ////////////////////////////////////////////////////////////////////////////////
2263 /// Compile expression already stored in fTitle.
2264 ///
2265 /// Loop on all subexpressions of formula stored in fTitle
2266 ///
2267 /// If you overload this member function, you also HAVE TO
2268 /// never call the constructor:
2269 ///
2270 /// ~~~ {.cpp}
2271 /// TFormula::TFormula(const char *name,const char *expression)
2272 /// ~~~
2273 ///
2274 /// and write your own constructor
2275 ///
2276 /// ~~~ {.cpp}
2277 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2278 /// ~~~
2279 ///
2280 /// which has to call the TFormula default constructor and whose implementation
2281 /// should be similar to the implementation of the normal TFormula constructor
2282 ///
2283 /// This is necessary because the normal TFormula constructor call indirectly
2284 /// the virtual member functions Analyze, DefaultString, DefaultValue
2285 /// and DefaultVariable.
2286 ///
2287 /// \image html TFormula_compile.png
2288 
2289 Int_t TFormula::Compile(const char *expression)
2290 {
2291  Int_t i,j,lc,valeur,err;
2292  TString ctemp;
2293 
2294  ClearFormula();
2295 
2296  // If expression is not empty, take it, otherwise take the title
2297  if (strlen(expression)) SetTitle(expression);
2298 
2299  TString chaine = GetTitle();
2300 
2301  if (chaine.Contains(";")) {
2302  char *sctemp = new char[chaine.Length()+1];
2303  strlcpy(sctemp,chaine.Data(),chaine.Length()+1);
2304  char *semicol = (char*)strstr(sctemp,";");
2305  if (semicol) *semicol = 0;
2306  chaine = sctemp;
2307  delete [] sctemp;
2308  }
2309 
2310  // if the function is linear, process it and fill the array of linear parts
2311  if (TestBit(kLinear)){
2312  ProcessLinear(chaine);
2313  }
2314 
2315  // see static function SetMaxima to change the gMAX.. default values
2316  fExpr = new TString[gMAXOP];
2317  fConst = new Double_t[gMAXCONST];
2318  fParams = new Double_t[gMAXPAR];
2319  fNames = new TString[gMAXPAR];
2320  fOper = new Int_t[gMAXOP];
2321  for (i=0; i<gMAXPAR; i++) {
2322  fParams[i] = 0;
2323  fNames[i] = "";
2324  }
2325  for (i=0; i<gMAXOP; i++) {
2326  fExpr[i] = "";
2327  fOper[i] = 0;
2328  }
2329  for (i=0; i<gMAXCONST; i++)
2330  fConst[i] = 0;
2331 
2332  // Substitution of some operators to C++ style
2333  Bool_t inString = false;
2334  for (i=1; i<=chaine.Length(); i++) {
2335  lc =chaine.Length();
2336  if (chaine(i-1,1) == "\"") inString = !inString;
2337  if (inString) continue;
2338  if (chaine(i-1,2) == "**") {
2339  chaine = chaine(0,i-1) + "^" + chaine(i+1,lc-i-1);
2340  i=0;
2341  } else if (chaine(i-1,2) == "++") {
2342  chaine = chaine(0,i) + chaine(i+1,lc-i-1);
2343  i=0;
2344  } else if (chaine(i-1,2) == "+-" || chaine(i-1,2) == "-+") {
2345  chaine = chaine(0,i-1) + "-" + chaine(i+1,lc-i-1);
2346  i=0;
2347  } else if (chaine(i-1,2) == "--") {
2348  chaine = chaine(0,i-1) + "+" + chaine(i+1,lc-i-1);
2349  i=0;
2350  } else if (chaine(i-1,2) == "->") {
2351  chaine = chaine(0,i-1) + "." + chaine(i+1,lc-i-1);
2352  i=0;
2353  } else if (chaine(i-1,1) == "[") {
2354  for (j=1;j<=chaine.Length()-i;j++) {
2355  if (chaine(j+i-1,1) == "]" || j+i > chaine.Length()) break;
2356  }
2357  ctemp = chaine(i,j-1);
2358  valeur=0;
2359  sscanf(ctemp.Data(),"%d",&valeur);
2360  if (valeur >= fNpar) fNpar = valeur+1;
2361  } else if (chaine(i-1,1) == " ") {
2362  chaine = chaine(0,i-1)+chaine(i,lc-i);
2363  i=0;
2364  }
2365  }
2366  err = 0;
2367  Analyze((const char*)chaine,err);
2368 
2369  // if no parameters delete arrays fParams and fNames
2370  if (!fNpar) {
2371  delete [] fParams; fParams = 0;
2372  delete [] fNames; fNames = 0;
2373  }
2374 
2375  // if no errors, copy local parameters to formula objects
2376  if (!err) {
2377  if (fNdim <= 0) fNdim = 1;
2378  if (chaine.Length() > 4)
2379  {
2380  if ( GetNumber() != 400 &&
2381  GetNumber() != 410 &&
2382  GetNumber() != 110 )
2383  SetNumber(0);
2384  else if ( GetNumber() == 110 && chaine.Length() > 6 )
2385  SetNumber(0);
2386  else if ( GetNumber() == 410 && chaine.Length() > 8 )
2387  SetNumber(0);
2388  }
2389  // if formula is a gaussian, set parameter names
2390  if (GetNumber() == 100) {
2391  SetParName(0,"Constant");
2392  SetParName(1,"Mean");
2393  SetParName(2,"Sigma");
2394  }
2395  // if formula is a 2D gaussian, set parameter names
2396  if (GetNumber() == 110){
2397  SetParName(0,"Constant");
2398  SetParName(1,"MeanX");
2399  SetParName(2,"SigmaX");
2400  SetParName(3,"MeanY");
2401  SetParName(4,"SigmaY");
2402  }
2403  // if formula is an exponential, set parameter names
2404  if (GetNumber() == 200) {
2405  SetParName(0,"Constant");
2406  SetParName(1,"Slope");
2407  }
2408  // if formula is a polynom, set parameter names
2409  if (GetNumber() == 300+fNpar) {
2410  for (i=0;i<fNpar;i++) SetParName(i,Form("p%d",i));
2411  }
2412  // if formula is a landau, set parameter names
2413  if (GetNumber() == 400) {
2414  SetParName(0,"Constant");
2415  SetParName(1,"MPV");
2416  SetParName(2,"Sigma");
2417  }
2418  // if formula is a 2D landau, set parameter names
2419  if (GetNumber() == 410) {
2420  SetParName(0,"Constant");
2421  SetParName(1,"MPVX");
2422  SetParName(2,"SigmaX");
2423  SetParName(3,"MPVY");
2424  SetParName(4,"SigmaY");
2425  }
2426  }
2427 
2428  // Here we shrink the arrays allocated like this:
2429  // fExpr = new TString[gMAXOP];
2430  // fConst = new Double_t[gMAXCONST];
2431  // fParams = new Double_t[gMAXPAR];
2432  // fNames = new TString[gMAXPAR];
2433  // fOper = new Int_t[gMAXOP];
2434  // fParams and fNames may be already 0, so we have to check.
2435  if (!err){
2436  ResizeArrayIfAllocated(fExpr, fNoper);
2437  ResizeArrayIfAllocated(fConst, fNconst);
2438  ResizeArrayIfAllocated(fParams, fNpar);
2439  ResizeArrayIfAllocated(fNames, fNpar);
2440  ResizeArrayIfAllocated(fOper, fNoper);
2441  }
2442 
2443 
2444  if (err) { fNdim = 0; return 1; }
2445  // Convert(5);
2446  //
2447  //MI change
2448  if (!IsA()->GetBaseClass("TTreeFormula")) {
2449  Optimize();
2450  }
2451  //
2452  return 0;
2453 }
2454 
2455 ////////////////////////////////////////////////////////////////////////////////
2456 /// Copy this formula.
2457 
2458 void TFormula::Copy(TObject &obj) const
2459 {
2460  Int_t i;
2461  ((TFormula&)obj).ClearFormula();
2462  TNamed::Copy(obj);
2463  ((TFormula&)obj).fNdim = fNdim;
2464  ((TFormula&)obj).fNpar = fNpar;
2465  ((TFormula&)obj).fNoper = fNoper;
2466  ((TFormula&)obj).fNconst = fNconst;
2467  ((TFormula&)obj).fNumber = fNumber;
2468  ((TFormula&)obj).fNval = fNval;
2469  ((TFormula&)obj).fExpr = 0;
2470  ((TFormula&)obj).fConst = 0;
2471  ((TFormula&)obj).fParams = 0;
2472  ((TFormula&)obj).fNames = 0;
2473  if (fExpr && fNoper) {
2474  ((TFormula&)obj).fExpr = new TString[fNoper];
2475  for (i=0;i<fNoper;i++) ((TFormula&)obj).fExpr[i] = fExpr[i];
2476  }
2477  if (fOper && fNoper) {
2478  ((TFormula&)obj).fOper = new Int_t[fNoper];
2479  for (i=0;i<fNoper;i++) ((TFormula&)obj).fOper[i] = fOper[i];
2480  }
2481  if (fConst && fNconst) {
2482  ((TFormula&)obj).fConst = new Double_t[fNconst];
2483  for (i=0;i<fNconst;i++) ((TFormula&)obj).fConst[i] = fConst[i];
2484  }
2485  if (fParams && fNpar) {
2486  ((TFormula&)obj).fParams = new Double_t[fNpar];
2487  for (i=0;i<fNpar;i++) ((TFormula&)obj).fParams[i] = fParams[i];
2488  }
2489  if (fNames && fNpar) {
2490  ((TFormula&)obj).fNames = new TString[fNpar];
2491  for (i=0;i<fNpar;i++) ((TFormula&)obj).fNames[i] = fNames[i];
2492  }
2493 
2494  TIter next(&fFunctions);
2495  TObject *fobj;
2496  while ( (fobj = next()) ) {
2497  ((TFormula&)obj).fFunctions.Add( fobj->Clone() );
2498  }
2499  //
2500  // MI change
2501  //
2502  //
2503  if (fNoper) {
2504  if(fExprOptimized) {
2505  ((TFormula&)obj).fExprOptimized = new TString[fNoper];
2506  for (i=0;i<fNoper;i++) ((TFormula&)obj).fExprOptimized[i] = fExprOptimized[i];
2507  }
2508  if (fOperOptimized) {
2509  ((TFormula&)obj).fOperOptimized = new Int_t[fNoper];
2510  for (i=0;i<fNoper;i++) ((TFormula&)obj).fOperOptimized[i] = fOperOptimized[i];
2511  }
2512  if (fPredefined) {
2513  ((TFormula&)obj).fPredefined = new ROOT::v5::TFormulaPrimitive*[fNoper];
2514  for (i=0;i<fNoper;i++) {((TFormula&)obj).fPredefined[i] = fPredefined[i];}
2515  }
2516  if (fOperOffset) {
2517  ((TFormula&)obj).fOperOffset = new TOperOffset[fNoper];
2518  for (i=0;i<fNoper;i++) {((TFormula&)obj).fOperOffset[i] = fOperOffset[i];}
2519  }
2520  }
2521  ((TFormula&)obj).fNOperOptimized = fNOperOptimized;
2522  ((TFormula&)obj).fOptimal = fOptimal;
2523 
2524 }
2525 
2526 ////////////////////////////////////////////////////////////////////////////////
2527 /// Return address of string corresponding to special code.
2528 ///
2529 /// This member function is inactive in the TFormula class.
2530 /// It may be redefined in derived classes.
2531 ///
2532 /// If you overload this member function, you also HAVE TO
2533 /// never call the constructor:
2534 ///
2535 /// ~~~ {.cpp}
2536 /// TFormula::TFormula(const char *name,const char *expression)
2537 /// ~~~
2538 ///
2539 /// and write your own constructor
2540 ///
2541 /// ~~~ {.cpp}
2542 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2543 /// ~~~
2544 ///
2545 /// which has to call the TFormula default constructor and whose implementation
2546 /// should be similar to the implementation of the normal TFormula constructor
2547 ///
2548 /// This is necessary because the normal TFormula constructor call indirectly
2549 /// the virtual member functions Analyze, DefaultString, DefaultValue
2550 /// and DefaultVariable.
2551 
2553 {
2554  return 0;
2555 }
2556 
2557 ////////////////////////////////////////////////////////////////////////////////
2558 /// Return value corresponding to special code.
2559 ///
2560 /// This member function is inactive in the TFormula class.
2561 /// It may be redefined in derived classes.
2562 ///
2563 /// If you overload this member function, you also HAVE TO
2564 /// never call the constructor:
2565 ///
2566 /// ~~~ {.cpp}
2567 /// TFormula::TFormula(const char *name,const char *expression)
2568 /// ~~~
2569 ///
2570 /// and write your own constructor
2571 ///
2572 /// ~~~ {.cpp}
2573 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2574 /// ~~~
2575 ///
2576 /// which has to call the TFormula default constructor and whose implementation
2577 /// should be similar to the implementation of the normal TFormula constructor
2578 ///
2579 /// This is necessary because the normal TFormula constructor call indirectly
2580 /// the virtual member functions Analyze, DefaultString, DefaultValue
2581 /// and DefaultVariable.
2582 
2584 {
2585  return 0;
2586 }
2587 
2588 ////////////////////////////////////////////////////////////////////////////////
2589 /// Check if expression is in the list of defined variables.
2590 ///
2591 /// This member function can be overloaded in derived classes
2592 ///
2593 /// If you overload this member function, you also HAVE TO
2594 /// never call the constructor:
2595 ///
2596 /// ~~~ {.cpp}
2597 /// TFormula::TFormula(const char *name,const char *expression)
2598 /// ~~~
2599 ///
2600 /// and write your own constructor
2601 ///
2602 /// ~~~ {.cpp}
2603 /// MyClass::MyClass(const char *name,const char *expression) : TFormula()
2604 /// ~~~
2605 ///
2606 /// which has to call the TFormula default constructor and whose implementation
2607 /// should be similar to the implementation of the normal TFormula constructor
2608 ///
2609 /// This is necessary because the normal TFormula constructor call indirectly
2610 /// the virtual member functions Analyze, DefaultString, DefaultValue
2611 /// and DefaultVariable.
2612 ///
2613 /// The expected returns values are
2614 /// - -2 : the name has been recognized but won't be usable
2615 /// - -1 : the name has not been recognized
2616 /// - >=0 : the name has been recognized, return the action parameter.
2617 
2619 {
2620  action = kVariable;
2621  if (chaine == "x") {
2622  if (fNdim < 1) fNdim = 1;
2623  return 0;
2624  } else if (chaine == "y") {
2625  if (fNdim < 2) fNdim = 2;
2626  return 1;
2627  } else if (chaine == "z") {
2628  if (fNdim < 3) fNdim = 3;
2629  return 2;
2630  } else if (chaine == "t") {
2631  if (fNdim < 4) fNdim = 4;
2632  return 3;
2633  }
2634  // MI change
2635  // extended defined variable (MI)
2636  //
2637  if (chaine.Data()[0]=='x'){
2638  if (chaine.Data()[1]=='[' && chaine.Data()[3]==']'){
2639  const char ch0 = '0';
2640  Int_t dim = chaine.Data()[2]-ch0;
2641  if (dim<0) return -1;
2642  if (dim>9) return -1;
2643  if (fNdim<=dim) fNdim = dim+1;
2644  return dim;
2645  }
2646  if (chaine.Data()[1]=='[' && chaine.Data()[4]==']'){
2647  const char ch0 = '0';
2648  Int_t dim = (chaine.Data()[2]-ch0)*10+(chaine.Data()[3]-ch0);
2649  if (dim<0) return -1;
2650  if (dim>99) return -1;
2651  if (fNdim<=dim) fNdim = dim+1;
2652  return dim;
2653  }
2654  }
2655  return -1;
2656 }
2657 
2658 ////////////////////////////////////////////////////////////////////////////////
2659 /// Evaluate this formula.
2660 ///
2661 /// The current value of variables x,y,z,t is passed through x, y, z and t.
2662 /// The parameters used will be the ones in the array params if params is given
2663 /// otherwise parameters will be taken from the stored data members fParams
2664 
2666 {
2667  Double_t xx[4];
2668  xx[0] = x;
2669  xx[1] = y;
2670  xx[2] = z;
2671  xx[3] = t;
2672  return ((TFormula*)this)->EvalPar(xx);
2673 }
2674 
2675 ////////////////////////////////////////////////////////////////////////////////
2676 /// Evaluate this formula.
2677 ///
2678 /// The current value of variables x,y,z,t is passed through the pointer x.
2679 /// The parameters used will be the ones in the array params if params is given
2680 /// otherwise parameters will be taken from the stored data members fParams
2681 ///
2682 /// \image html TFormula_eval.png
2683 
2685 {
2686  Int_t i,j;
2687  // coverity[uninit] the tab value of tab is guaranteed to be set properly by the control flow.
2688  Double_t tab[kMAXFOUND];
2689  const char *stringStack[gMAXSTRINGFOUND];
2690  Double_t param_calc[kMAXFOUND];
2691  char *string_calc[gMAXSTRINGFOUND];
2692  Int_t precalculated = 0;
2693  Int_t precalculated_str = 0;
2694  Double_t *params;
2695 
2696  if (uparams) {
2697  params = const_cast<Double_t*>(uparams);
2698  } else {
2699  params = fParams;
2700  }
2701  UInt_t pos = 0;
2702  UInt_t strpos = 0;
2703 
2704  for (i=0; i<fNoper; ++i) {
2705 
2706  const int oper = fOper[i];
2707  const int opcode = oper >> kTFOperShift;
2708 
2709  switch(opcode) {
2710 
2711  case kParameter : { pos++; tab[pos-1] = params[ oper & kTFOperMask ]; continue; }
2712  case kConstant : { pos++; tab[pos-1] = fConst[ oper & kTFOperMask ]; continue; }
2713  case kVariable : { pos++; tab[pos-1] = x[ oper & kTFOperMask ]; continue; }
2714  case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExpr[i].Data(); pos++; tab[pos-1] = 0; continue; }
2715 
2716  case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
2717  case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
2718  case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
2719  case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
2720  else tab[pos-1] /= tab[pos];
2721  continue;
2722  case kModulo : {pos--;
2723  Long64_t int1((Long64_t)tab[pos-1]);
2724  Long64_t int2((Long64_t)tab[pos]);
2725  tab[pos-1] = Double_t(int1%int2);
2726  continue;}
2727 
2728  case kcos : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
2729  case ksin : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
2730  case ktan : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
2731  else tab[pos-1] = TMath::Tan(tab[pos-1]);
2732  continue;
2733  case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2734  else tab[pos-1] = TMath::ACos(tab[pos-1]);
2735  continue;
2736  case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2737  else tab[pos-1] = TMath::ASin(tab[pos-1]);
2738  continue;
2739  case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
2740  case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
2741  case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
2742  case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
2743  else tab[pos-1] = TMath::TanH(tab[pos-1]);
2744  continue;
2745  case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} // indetermination
2746  else tab[pos-1] = TMath::ACosH(tab[pos-1]);
2747  continue;
2748  case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
2749  case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
2750  else tab[pos-1] = TMath::ATanH(tab[pos-1]);
2751  continue;
2752  case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
2753 
2754  case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
2755  case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
2756  case ksq : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
2757  case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
2758 
2759  case kstrstr : strpos -= 2; pos-=2; pos++;
2760  if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
2761  else tab[pos-1]=0;
2762  continue;
2763 
2764  case kmin : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); continue;
2765  case kmax : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); continue;
2766 
2767  case klog : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
2768  else {tab[pos-1] = 0;} //{indetermination }
2769  continue;
2770  case kexp : { Double_t dexp = tab[pos-1];
2771  if (dexp < -700) {tab[pos-1] = 0; continue;}
2772  if (dexp > 700) {tab[pos-1] = TMath::Exp(700); continue;}
2773  tab[pos-1] = TMath::Exp(dexp); continue; }
2774  case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
2775  else {tab[pos-1] = 0;} //{indetermination }
2776  continue;
2777 
2778  case kpi : pos++; tab[pos-1] = TMath::ACos(-1); continue;
2779 
2780  case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
2781  case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
2782  case kint : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
2783 
2784  case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
2785 
2786  case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
2787 
2788  case kAnd : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
2789  else tab[pos-1]=0;
2790  continue;
2791  case kOr : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
2792  else tab[pos-1]=0;
2793  continue;
2794  case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
2795  else tab[pos-1]=0;
2796  continue;
2797  case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
2798  else tab[pos-1]=0;
2799  continue;
2800  case kLess : pos--; if (tab[pos-1] < tab[pos]) tab[pos-1]=1;
2801  else tab[pos-1]=0;
2802  continue;
2803  case kGreater : pos--; if (tab[pos-1] > tab[pos]) tab[pos-1]=1;
2804  else tab[pos-1]=0;
2805  continue;
2806 
2807  case kLessThan: pos--; if (tab[pos-1]<=tab[pos]) tab[pos-1]=1;
2808  else tab[pos-1]=0;
2809  continue;
2810  case kGreaterThan: pos--; if (tab[pos-1]>=tab[pos]) tab[pos-1]=1;
2811  else tab[pos-1]=0;
2812  continue;
2813  case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1;
2814  continue;
2815 
2816  case kStringEqual : strpos -= 2; pos -=2 ; pos++;
2817  if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
2818  else tab[pos-1]=0;
2819  continue;
2820  case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
2821  if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
2822  else tab[pos-1]=0;
2823  continue;
2824 
2825  case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
2826  case kBitOr : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
2827  case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
2828  case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
2829 
2830  case kJump : i = (oper & kTFOperMask); continue;
2831  case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
2832 
2833  case kBoolOptimize: {
2834  // boolean operation optimizer
2835 
2836  int param = (oper & kTFOperMask);
2837  Bool_t skip = kFALSE;
2838  int op = param % 10; // 1 is && , 2 is ||
2839 
2840  if (op == 1 && (!tab[pos-1]) ) {
2841  // &&: skip the right part if the left part is already false
2842 
2843  skip = kTRUE;
2844 
2845  // Preserve the existing behavior (i.e. the result of a&&b is
2846  // either 0 or 1)
2847  tab[pos-1] = 0;
2848 
2849  } else if (op == 2 && tab[pos-1] ) {
2850  // ||: skip the right part if the left part is already true
2851 
2852  skip = kTRUE;
2853 
2854  // Preserve the existing behavior (i.e. the result of a||b is
2855  // either 0 or 1)
2856  tab[pos-1] = 1;
2857 
2858  }
2859 
2860  if (skip) {
2861  int toskip = param / 10;
2862  i += toskip;
2863  }
2864  continue;
2865  }
2866 
2867  }
2868 
2869  switch(opcode) {
2870 
2871  #define R__EXPO(var) \
2872  { \
2873  pos++; int param = (oper & kTFOperMask); \
2874  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]); \
2875  continue; \
2876  }
2877  // case kexpo:
2878  case kxexpo: R__EXPO(0);
2879  case kyexpo: R__EXPO(1);
2880  case kzexpo: R__EXPO(2);
2881  case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
2882  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
2883  continue; }
2884 
2885  #define R__GAUS(var) \
2886  { \
2887  pos++; int param = (oper & kTFOperMask); \
2888  tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1],params[param+2],IsNormalized()); \
2889  continue; \
2890  }
2891 
2892  // case kgaus:
2893  case kxgaus: R__GAUS(0);
2894  case kygaus: R__GAUS(1);
2895  case kzgaus: R__GAUS(2);
2896  case kxygaus: {pos++; int param = (oper & kTFOperMask);
2897  Double_t intermede1;
2898  if (params[param+2] == 0) {
2899  intermede1=1e10;
2900  } else {
2901  intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
2902  }
2903  Double_t intermede2;
2904  if (params[param+4] == 0) {
2905  intermede2=1e10;
2906  } else {
2907  intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
2908  }
2909  tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
2910  continue; }
2911 
2912  #define R__LANDAU(var) \
2913  { \
2914  pos++; const int param = (oper & kTFOperMask); \
2915  tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
2916  continue; \
2917  }
2918  // case klandau:
2919  case kxlandau: R__LANDAU(0);
2920  case kylandau: R__LANDAU(1);
2921  case kzlandau: R__LANDAU(2);
2922  case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
2923  Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
2924  Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
2925  tab[pos-1] = params[param]*intermede1*intermede2;
2926  continue;
2927  }
2928 
2929  #define R__POLY(var) \
2930  { \
2931  pos++; int param = (oper & kTFOperMask); \
2932  tab[pos-1] = 0; Double_t intermede = 1; \
2933  Int_t inter = param/100; /* arrondit */ \
2934  Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
2935  for (j=0 ;j<inter+1;j++) { \
2936  tab[pos-1] += intermede*params[j+int1]; \
2937  intermede *= x[var]; \
2938  } \
2939  continue; \
2940  }
2941  // case kpol:
2942  case kxpol: R__POLY(0);
2943  case kypol: R__POLY(1);
2944  case kzpol: R__POLY(2);
2945 
2946  case kDefinedVariable : {
2947  if (!precalculated) {
2948  precalculated = 1;
2949  for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
2950  }
2951  pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
2952  continue;
2953  }
2954 
2955  case kDefinedString : {
2956  int param = (oper & kTFOperMask);
2957  if (!precalculated_str) {
2958  precalculated_str=1;
2959  for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
2960  }
2961  strpos++; stringStack[strpos-1] = string_calc[param];
2962  pos++; tab[pos-1] = 0;
2963  continue;
2964  }
2965 
2966  case kFunctionCall: {
2967  // an external function call
2968 
2969  int param = (oper & kTFOperMask);
2970  int fno = param / 1000;
2971  int nargs = param % 1000;
2972 
2973  // Retrieve the function
2974  TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
2975 
2976  // Set the arguments
2977  method->ResetParam();
2978  if (nargs) {
2979  UInt_t argloc = pos-nargs;
2980  for(j=0;j<nargs;j++,argloc++,pos--) {
2981  method->SetParam(tab[argloc]);
2982  }
2983  }
2984  pos++;
2985  Double_t ret;
2986  method->Execute(ret);
2987  tab[pos-1] = ret; // check for the correct conversion!
2988 
2989  continue;
2990  };
2991  }
2992  if (!TestBit(kOptimizationError)) {
2994  Warning("EvalParOld","Found an unsupported opcode (%d)",oper >> kTFOperShift);
2995  }
2996  }
2997  Double_t result0 = tab[0];
2998  return result0;
2999 
3000 }
3001 
3002 ////////////////////////////////////////////////////////////////////////////////
3003 /// Reconstruct the formula expression from the internal TFormula member variables
3004 ///
3005 /// This function uses the internal member variables of TFormula to
3006 /// construct the mathematical expression associated with the TFormula
3007 /// instance. This function can be used to get an expanded version of the
3008 /// expression originally assigned to the TFormula instance, i.e. that
3009 /// the string returned by GetExpFormula() doesn't depend on other
3010 /// TFormula object names.
3011 ///
3012 /// if option contains "p" the returned string will contain the formula
3013 /// expression with symbolic parameters, eg [0] replaced by the actual value
3014 /// of the parameter. Example:
3015 /// if expression in formula is: "[0]*(x>-[1])+[2]*exp(-[3]*x)"
3016 /// and parameters are 3.25,-4.01,4.44,-0.04, GetExpFormula("p") will return:
3017 /// "(3.25*(x>+4.01))+(4.44*exp(+0.04*x))"
3018 
3020 {
3021  if (fNoper>0) {
3022  TString* tab=new TString[fNoper];
3023  Bool_t* ismulti=new Bool_t[fNoper];
3024  Int_t spos=0;
3025 
3026  ismulti[0]=kFALSE;
3027  Int_t optype;
3028  Int_t j;
3029  Int_t ternaryend = -1;
3030  for(Int_t i=0;i<fNoper;i++){
3031  optype = GetAction(i);
3032 
3033  if (ternaryend==i) {
3034  // The ? and : have been added to tab[spos-2]
3035  if(ismulti[spos-1]){
3036  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3037  } else {
3038  tab[spos-2]=tab[spos-2]+tab[spos-1];
3039  }
3040  spos--;
3041  // Do not call continue since we need to
3042  // do the rest of the loop.
3043  }
3044 
3045  // Boolean optimization breakpoint
3046  if (optype==kBoolOptimize) { // -3) {
3047  continue;
3048  }
3049 
3050  //Sign inversion
3051  if (optype==kSignInv) { // -1) {
3052  tab[spos-1]="-("+tab[spos-1]+")";
3053  // i++;
3054  continue;
3055  }
3056 
3057  //Simple name (parameter,pol0,landau, etc)
3058  if (kexpo<=optype && optype<=kzpol) { // >=0) {
3059  tab[spos]=fExpr[i];
3060  ismulti[spos]=kFALSE;
3061  spos++;
3062  continue;
3063  }
3064 
3065  //constants, variables x,y,z,t, pi
3066  if ((optype<=151 && optype>=140 && optype!=145) || (optype == 40)) {
3067  tab[spos]=fExpr[i];
3068  ismulti[spos]=kFALSE;
3069  spos++;
3070  continue;
3071  }
3072 
3073  //Basic operators (+,-,*,/,==,^,etc)
3074  if(((optype>0 && optype<6) || optype==20 ||
3075  (((optype>59 && optype<69) || (optype >75 && optype<82)) && spos>=2))) {
3076  // if(optype==-20 && spos>=2){
3077  if(ismulti[spos-2]){
3078  tab[spos-2]="("+tab[spos-2]+")";
3079  }
3080  if(ismulti[spos-1]){
3081  tab[spos-2]+=fExpr[i]+("("+tab[spos-1]+")");
3082  }else{
3083  tab[spos-2]+=fExpr[i]+tab[spos-1];
3084  }
3085  ismulti[spos-2]=kTRUE;
3086  spos--;
3087  continue;
3088  }
3089  //Ternary condition
3090  if (optype==kJumpIf) {
3091  if(ismulti[spos-1]){
3092  tab[spos-1]="("+tab[spos-1]+")?";
3093  } else {
3094  tab[spos-1]=tab[spos-1]+"?";
3095  }
3096  continue;
3097  }
3098  if (optype==kJump) {
3099  if(ismulti[spos-1]){
3100  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+"):";
3101  } else {
3102  tab[spos-2]=tab[spos-2]+tab[spos-1]+":";
3103  }
3104  ternaryend = GetActionParam(i) + 1;
3105  spos--;
3106  continue;
3107  }
3108 
3109  //Functions
3110  int offset = 0;
3111  TString funcname = fExpr[i];
3112  if((optype>9 && optype<16) ||
3113  (optype>20 && optype<23) ||
3114  (optype>29 && optype<34) ||
3115  (optype>40 && optype<44) ||
3116  (optype>69 && optype<76) ||
3117  (optype==145)) {
3118  //Functions with the format func(x)
3119  offset = -1;
3120  }
3121 
3122  if((optype>15 && optype<20) ||
3123  (optype>22 && optype<26)) {
3124  //Functions with the format func(x,y)
3125  offset = -2;
3126  }
3127  if(optype==145) {
3128  int param = (fOper[i] & kTFOperMask);
3129  //int fno = param / 1000;
3130  int nargs = param % 1000;
3131  offset = -nargs;
3132  // The function name contains return type and parameters types we need
3133  // to trim them.
3134  int depth;
3135  for(j=0, depth=0;j<funcname.Length();++j) {
3136  switch (funcname[j]) {
3137  case '<':
3138  ++depth; break;
3139  case '>':
3140  --depth; break;
3141  case ' ':
3142  if (depth==0) {
3143  funcname.Remove(0,j+1);
3144  j = funcname.Length();
3145  break;
3146  }
3147  }
3148  }
3149  Ssiz_t ind = funcname.First('(');
3150  funcname.Remove(ind);
3151  }
3152  if (offset > 0) {
3153  Error("GetExpFormula","Internal error, number of argument found is %d",-offset);
3154  } else if (offset == 0) {
3155  tab[spos]=funcname+"()";
3156  ismulti[spos]=kFALSE;
3157  spos += 1;
3158  continue;
3159  } else if (offset<=0 && (spos+offset>=0)) {
3160  tab[spos+offset]=funcname+("("+tab[spos+offset]);
3161  for (j=offset+1; j<0; j++){
3162  tab[spos+offset]+=","+tab[spos+j];
3163  }
3164  tab[spos+offset]+=")";
3165  ismulti[spos+offset]=kFALSE;
3166  spos += offset+1;
3167  continue;
3168  }
3169  }
3170  if (ternaryend==fNoper) {
3171  // The ? and : have been added to tab[spos-2]
3172  if(ismulti[spos-1]){
3173  tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
3174  } else {
3175  tab[spos-2]=tab[spos-2]+tab[spos-1];
3176  }
3177  spos--;
3178  }
3179 
3180  TString ret = "";
3181  if (spos > 0) ret = tab[spos-1];
3182  delete[] tab;
3183  delete[] ismulti;
3184 
3185  //if option "p" is specified, return the real values of parameters instead of [0]
3186  TString opt = option;
3187  opt.ToLower();
3188  if (opt.Contains("p")) {
3189  char pb[13];
3190  char pbv[100];
3191  for (j=0;j<fNpar;j++) {
3192  snprintf(pb,sizeof(pb),"[%d]",j);
3193  snprintf(pbv,100,"%g",fParams[j]);
3194  ret.ReplaceAll(pb,pbv);
3195  }
3196  ret.ReplaceAll("--","+");
3197  ret.ReplaceAll("+-","-");
3198  }
3199  return ret;
3200  } else{
3201  TString ret="";
3202  return ret;
3203  }
3204 }
3205 
3206 ////////////////////////////////////////////////////////////////////////////////
3207 /// Return linear part.
3208 
3210 {
3211  if (!fLinearParts.IsEmpty())
3212  return fLinearParts.UncheckedAt(i);
3213  return 0;
3214 }
3215 
3216 ////////////////////////////////////////////////////////////////////////////////
3217 /// Return value of parameter number ipar.
3218 
3220 {
3221  if (ipar <0 || ipar >= fNpar) return 0;
3222  return fParams[ipar];
3223 }
3224 
3225 ////////////////////////////////////////////////////////////////////////////////
3226 /// Return value of parameter named parName.
3227 
3228 Double_t TFormula::GetParameter(const char *parName) const
3229 {
3230  const Double_t kNaN = 1e-300;
3231  Int_t index = GetParNumber(parName);
3232  if (index==-1) {
3233  Error("TFormula", "Parameter %s not found", parName);
3234  return kNaN;
3235  }
3236  return GetParameter(index);
3237 }
3238 
3239 ////////////////////////////////////////////////////////////////////////////////
3240 /// Return name of one parameter.
3241 
3242 const char *TFormula::GetParName(Int_t ipar) const
3243 {
3244  if (ipar <0 || ipar >= fNpar) return "";
3245  if (fNames[ipar].Length() > 0) return (const char*)fNames[ipar];
3246  return Form("p%d",ipar);
3247 }
3248 
3249 ////////////////////////////////////////////////////////////////////////////////
3250 /// Return parameter number by name.
3251 
3252 Int_t TFormula::GetParNumber(const char *parName) const
3253 {
3254  if (!parName)
3255  return -1;
3256 
3257  for (Int_t i=0; i<fNpar; i++) {
3258  if (!strcmp(GetParName(i),parName)) return i;
3259  }
3260  return -1;
3261 }
3262 
3263 ////////////////////////////////////////////////////////////////////////////////
3264 /// Return true if the expression at the index 'oper' has to be treated as a string
3265 
3267 {
3268  return GetAction(oper) == kStringConst;
3269 }
3270 
3271 ////////////////////////////////////////////////////////////////////////////////
3272 /// Dump this formula with its attributes.
3273 
3275 {
3276  Int_t i;
3277  Printf(" %20s : %s Ndim= %d, Npar= %d, Noper= %d",GetName(),GetTitle(), fNdim,fNpar,fNoper);
3278  for (i=0;i<fNoper;i++) {
3279  Printf(" fExpr[%d] = %s action = %d action param = %d ",
3280  i,(const char*)fExpr[i],GetAction(i),GetActionParam(i));
3281  }
3282  //MI change
3283  //
3284  if (fNOperOptimized>0){
3285  Printf("Optimized expression");
3286  for (i=0;i<fNOperOptimized;i++) {
3287  Printf(" fExpr[%d] = %s\t\t action = %d action param = %d ",
3289  }
3290  }
3291 
3292  if (!fNames) return;
3293  if (!fParams) return;
3294  for (i=0;i<fNpar;i++) {
3295  Printf(" Par%3d %20s = %g",i,GetParName(i),fParams[i]);
3296  }
3297 }
3298 
3299 ////////////////////////////////////////////////////////////////////////////////
3300 /// If the formula is for linear fitting, change the title to
3301 /// normal and fill the LinearParts array
3302 
3304 {
3305  TString formula2(formula);
3306  char repl[20];
3307  char *pch;
3308  Int_t nf, offset, replsize;
3309  //replace "++" with "+[i]*"
3310  pch= (char*)strstr(formula.Data(), "++");
3311  if (pch)
3312  formula.Insert(0, "[0]*(");
3313  pch= (char*)strstr(formula.Data(), "++");
3314  if (pch){
3315  //if there are "++", replaces them with +[i]*
3316  nf = 1;
3317  while (pch){
3318  snprintf(repl,20, ")+[%d]*(", nf);
3319  offset = pch-formula.Data();
3320  if (nf<10) replsize = 7;
3321  else if (nf<100) replsize = 8;
3322  else replsize = 9;
3323  formula.Replace(pch-formula.Data(), 2, repl, replsize);
3324  pch = (char*)strstr(formula.Data()+offset, "++");
3325  nf++;
3326  }
3327  formula.Append(')', 1);
3328  } else {
3329  //if there are no ++, create a new string with ++ instead of +[i]*
3330  formula2=formula2(4, formula2.Length()-4);
3331  pch= (char*)strchr(formula2.Data(), '[');
3332  snprintf(repl,20, "++");
3333  nf = 1;
3334  while (pch){
3335  offset = pch-formula2.Data()-1;
3336  if (nf<10) replsize = 5;
3337  else replsize = 6;
3338  formula2.Replace(pch-formula2.Data()-1, replsize, repl, 2);
3339  pch = (char*)strchr(formula2.Data()+offset, '[');
3340  nf++;
3341  }
3342  }
3343 
3344  fLinearParts.Expand(nf);
3345  //break up the formula and fill the array of linear parts
3346  TString replaceformula;
3347  formula2 = formula2.ReplaceAll("++", 2, "|", 1);
3348  TObjArray *oa = formula2.Tokenize("|");
3349  TString replaceformula_name;
3350  for (Int_t i=0; i<nf; i++) {
3351  replaceformula = ((TObjString *)oa->UncheckedAt(i))->GetString();
3352  replaceformula_name = "f_linear_";
3353  replaceformula_name.Append(replaceformula);
3354  TFormula *f = new TFormula(replaceformula_name.Data(), replaceformula.Data());
3355  if (!f) {
3356  Error("TFormula", "f_linear not allocated");
3357  return;
3358  }
3359  {
3361  gROOT->GetListOfFunctions()->Remove(f);
3362  }
3363  f->SetBit(kNotGlobal, 1);
3364  fLinearParts.Add(f);
3365  }
3366  oa->Delete();
3367 }
3368 
3369 ////////////////////////////////////////////////////////////////////////////////
3370 /// Initialize parameter number ipar.
3371 
3372 void TFormula::SetParameter(const char *name, Double_t value)
3373 {
3374  Int_t ipar = GetParNumber(name);
3375  if (ipar <0 || ipar >= fNpar) return;
3376  fParams[ipar] = value;
3377  Update();
3378 }
3379 
3380 ////////////////////////////////////////////////////////////////////////////////
3381 /// Initialize parameter number ipar.
3382 
3384 {
3385  if (ipar <0 || ipar >= fNpar) return;
3386  fParams[ipar] = value;
3387  Update();
3388 }
3389 
3390 ////////////////////////////////////////////////////////////////////////////////
3391 /// Initialize array of all parameters.
3392 /// See also the next function with the same name.
3393 
3395 {
3396  for (Int_t i=0; i<fNpar;i++) {
3397  fParams[i] = params[i];
3398  }
3399  Update();
3400 }
3401 
3402 ////////////////////////////////////////////////////////////////////////////////
3403 /// Initialize up to 11 parameters
3404 /// All arguments except THE FIRST TWO are optional
3405 /// In case of a function with only one parameter, call this function with p1=0.
3406 /// Minimum two arguments are required to differentiate this function
3407 /// from the SetParameters(cont Double_t *params)
3408 
3410  ,Double_t p5,Double_t p6,Double_t p7,Double_t p8,Double_t p9,Double_t p10)
3411 {
3412  if (fNpar > 0) fParams[0] = p0;
3413  if (fNpar > 1) fParams[1] = p1;
3414  if (fNpar > 2) fParams[2] = p2;
3415  if (fNpar > 3) fParams[3] = p3;
3416  if (fNpar > 4) fParams[4] = p4;
3417  if (fNpar > 5) fParams[5] = p5;
3418  if (fNpar > 6) fParams[6] = p6;
3419  if (fNpar > 7) fParams[7] = p7;
3420  if (fNpar > 8) fParams[8] = p8;
3421  if (fNpar > 9) fParams[9] = p9;
3422  if (fNpar >10) fParams[10]= p10;
3423  Update();
3424 }
3425 
3426 ////////////////////////////////////////////////////////////////////////////////
3427 /// Set name of parameter number ipar
3428 
3429 void TFormula::SetParName(Int_t ipar, const char *name)
3430 {
3431  if (ipar <0 || ipar >= fNpar) return;
3432  fNames[ipar] = name;
3433 }
3434 
3435 ////////////////////////////////////////////////////////////////////////////////
3436 /// Set up to 11 parameter names.
3437 
3438 void TFormula::SetParNames(const char*name0,const char*name1,const char*name2,const char*name3,const char*name4,
3439  const char*name5,const char*name6,const char*name7,const char*name8,const char*name9,const char*name10)
3440 {
3441  if (fNpar > 0) fNames[0] = name0;
3442  if (fNpar > 1) fNames[1] = name1;
3443  if (fNpar > 2) fNames[2] = name2;
3444  if (fNpar > 3) fNames[3] = name3;
3445  if (fNpar > 4) fNames[4] = name4;
3446  if (fNpar > 5) fNames[5] = name5;
3447  if (fNpar > 6) fNames[6] = name6;
3448  if (fNpar > 7) fNames[7] = name7;
3449  if (fNpar > 8) fNames[8] = name8;
3450  if (fNpar > 9) fNames[9] = name9;
3451  if (fNpar >10) fNames[10]= name10;
3452 }
3453 
3454 ////////////////////////////////////////////////////////////////////////////////
3455 /// Stream a class object.
3456 
3457 void TFormula::Streamer(TBuffer &b, const TClass *onfile_class)
3458 {
3459  if (b.IsReading()) {
3460  UInt_t R__s, R__c;
3461  Version_t v = b.ReadVersion(&R__s, &R__c);
3462  if (v==6) {
3463  Error("Streamer","version 6 is not supported");
3464  return;
3465  }
3466  Streamer(b, v, R__s, R__c, onfile_class);
3467 
3468  } else {
3470  }
3471 }
3472 
3473 ////////////////////////////////////////////////////////////////////////////////
3474 /// Stream a class object.
3475 
3477 {
3478  if (b.IsReading()) {
3479  UInt_t R__s, R__c;
3480  Version_t v = b.ReadVersion(&R__s, &R__c);
3481  if (v==6) {
3482  Error("Streamer","version 6 is not supported");
3483  return;
3484  }
3485  Streamer(b, v, R__s, R__c, nullptr);
3486 
3487  } else {
3489  }
3490 }
3491 
3492 ////////////////////////////////////////////////////////////////////////////////
3493 /// specialized streamer function being able to read old TF1 versions as TF1Old in memory
3494 
3495 void TFormula::Streamer(TBuffer &b, Int_t v, UInt_t R__s, UInt_t R__c, const TClass *onfile_class)
3496 {
3497 
3498  //printf("Reading TFormula - version %d \n",v);
3499  if (v > 3 ) {
3500  b.ReadClassBuffer(TFormula::Class(), this, v, R__s, R__c, onfile_class);
3501  if (!TestBit(kNotGlobal)) {
3503  gROOT->GetListOfFunctions()->Add(this);
3504  }
3505 
3506  // We need to reinstate (if possible) the TMethodCall.
3507  if (fFunctions.GetLast()>=0) {
3508  // Compiles will reset the parameter values so we need
3509  // to temporarily keep them
3510  Double_t *param = fParams;
3511  TString *names = fNames;
3512  Int_t npar = fNpar;
3513  fParams = 0;
3514  fNames = 0;
3515  if (Compile()) {
3516  Error("Streamer","error compiling formula");
3517  return;
3518  }
3519  for (Int_t i = 0; i<npar && i<fNpar; ++i) fParams[i] = param[i];
3520  delete [] param;
3521  delete [] fNames;
3522  fNames = names;
3523  } else if (v<6) {
3524  Convert(v);
3525  }
3526  Optimize();
3527  return;
3528  }
3529  // version smaller or equal to 3
3530  // process old versions before automatic schema evolution
3531  TNamed::Streamer(b);
3532  b >> fNdim;
3533  b >> fNumber;
3534  if (v > 1) b >> fNval;
3535  if (v > 2) b >> fNstring;
3536  fNpar = b.ReadArray(fParams);
3537  fOper = new Int_t[gMAXOP];
3538  fNoper = b.ReadArray(fOper);
3539  fNconst = b.ReadArray(fConst);
3540  if (fNoper) {
3541  fExpr = new TString[fNoper];
3542  }
3543  if (fNpar) {
3544  fNames = new TString[fNpar];
3545  }
3546  Int_t i;
3547  for (i=0;i<fNoper;i++) fExpr[i].Streamer(b);
3548  for (i=0;i<fNpar;i++) fNames[i].Streamer(b);
3549  {
3551  if (gROOT->GetListOfFunctions()->FindObject(GetName())) return;
3552  gROOT->GetListOfFunctions()->Add(this);
3553  }
3554  b.CheckByteCount(R__s, R__c, TFormula::IsA());
3555 
3556  Convert(v);
3557  // end of old versions
3558 
3559 }
3560 
3561 void TFormula::Convert(UInt_t /* fromVersion */)
3562 {
3563  // Convert the fOper of a TFormula version fromVersion to the current in memory version
3564 
3565  enum {
3566  kOldexpo = 1000,
3567  kOldgaus = 2000,
3568  kOldlandau = 4000,
3569  kOldxylandau = 4500,
3570  kOldConstants = 50000,
3571  kOldStrings = 80000,
3572  kOldVariable = 100000,
3573  kOldTreeString = 105000,
3574  kOldFormulaVar = 110000,
3575  kOldBoolOptimize = 120000,
3576  kOldFunctionCall = 200000
3577  };
3578  int i,j;
3579 
3580  for (i=0,j=0; i<fNoper; ++i,++j) {
3581  Int_t action = fOper[i];
3582  Int_t newActionCode = 0;
3583  Int_t newActionParam = 0;
3584 
3585  if ( action == 0) {
3586  // Sign Inversion
3587 
3588  newActionCode = kSignInv;
3589 
3590  Float_t aresult = 99.99;
3591  sscanf((const char*)fExpr[i],"%g",&aresult);
3592  R__ASSERT((aresult+1)<0.001);
3593 
3594  ++i; // skip the implied multiplication.
3595 
3596  // For consistency and for Optimize to work correctly
3597  // we need to remove the "-1" string in fExpr
3598  for (int z=i; z<fNoper; ++z) {
3599  fExpr[z-1] = fExpr[z];
3600  }
3601 
3602  } else if ( action < 100 ) {
3603  // basic operators and mathematical library
3604 
3605  newActionCode = action;
3606 
3607  } else if (action >= kOldFunctionCall) {
3608  // Function call
3609 
3610  newActionCode = kFunctionCall;
3611  newActionParam = action-kOldFunctionCall;
3612 
3613  } else if (action >= kOldBoolOptimize) {
3614  // boolean operation optimizer
3615 
3616  newActionCode = kBoolOptimize;
3617  newActionParam = action-kOldBoolOptimize;
3618 
3619  } else if (action >= kOldFormulaVar) {
3620  // a variable
3621 
3622  newActionCode = kVariable;
3623  newActionParam = action-kOldFormulaVar;
3624 
3625  } else if (action >= kOldTreeString) {
3626  // a tree string
3627 
3628  newActionCode = kDefinedString;
3629  newActionParam = action-kOldTreeString;
3630 
3631  } else if (action >= kOldVariable) {
3632  // a tree variable
3633 
3634  newActionCode = kDefinedVariable;
3635  newActionParam = action-kOldVariable;
3636 
3637  } else if (action == kOldStrings) {
3638  // String
3639 
3640  newActionCode = kStringConst;
3641 
3642  } else if (action >= kOldConstants) {
3643  // numerical value
3644 
3645  newActionCode = kConstant;
3646  newActionParam = action-kOldConstants;
3647 
3648  } else if (action > 10000 && action < kOldConstants) {
3649  // Polynomial
3650 
3651  int var = action/10000; //arrondit
3652  newActionCode = kpol + (var-1);
3653  newActionParam = action - var*10000;
3654 
3655  } else if (action >= 4600) {
3656 
3657  Error("Convert","Unsupported value %d",action);
3658 
3659  } else if (action > kOldxylandau) {
3660  // xylandau
3661 
3662  newActionCode = kxylandau;
3663  newActionParam = action - (kOldxylandau+1);
3664 
3665  } else if (action > kOldlandau) {
3666  // landau, xlandau, ylandau or zlandau
3667 
3668  newActionCode = klandau;
3669  int var = action/100-40;
3670  if (var) newActionCode += var;
3671  newActionParam = action - var*100 - (kOldlandau+1);
3672 
3673  } else if (action > 2500 && action < 2600) {
3674  // xygaus
3675 
3676  newActionCode = kxygaus;
3677  newActionParam = action-2501;
3678 
3679  } else if (action > 2000 && action < 2500) {
3680  // gaus, xgaus, ygaus or zgaus
3681 
3682  newActionCode = kgaus;
3683  int var = action/100-20;
3684  if (var) newActionCode += var;
3685  newActionParam = action - var*100 - (kOldgaus+1);
3686 
3687  } else if (action > 1500 && action < 1600) {
3688  // xyexpo
3689 
3690  newActionCode = kxyexpo;
3691  newActionParam = action-1501;
3692 
3693  } else if (action > 1000 && action < 1500) {
3694  // expo or xexpo or yexpo or zexpo
3695 
3696  newActionCode = kexpo;
3697  int var = action/100-10;
3698  if (var) newActionCode += var;
3699  newActionParam = action - var*100 - (kOldexpo+1);
3700 
3701  } if (action > 100 && action < 200) {
3702  // Parameter substitution
3703 
3704  newActionCode = kParameter;
3705  newActionParam = action - 101;
3706  }
3707 
3708  SetAction( j, newActionCode, newActionParam );
3709 
3710  }
3711  if (i!=j) {
3712  fNoper -= (i-j);
3713  }
3714 
3715 }
3716 
3717 ////////////////////////////////////////////////////////////////////////////////
3718 /// TOper offset - helper class for TFormula*
3719 /// specify type of operand
3720 /// fTypeX = kVariable
3721 /// = kParameter
3722 /// = kConstant
3723 /// fOffestX = offset in corresponding array
3724 
3726 {
3727  fType0=0;
3728  fType1=0;
3729  fType2=0;
3730  fType3=0;
3731  fOffset0=0;
3732  fOffset1=0;
3733  fOffset2=0;
3734  fOffset3=0;
3735  fOldAction=0;
3736  fToJump=0;
3737 }
3738 
3739 ////////////////////////////////////////////////////////////////////////////////
3740 /// MakePrimitive
3741 /// find TFormulaPrimitive replacement for some operands
3742 
3743 void TFormula::MakePrimitive(const char *expr, Int_t pos)
3744 {
3745  TString cbase(expr);
3746  cbase.ReplaceAll("Double_t ","");
3747  int paran = cbase.First("(");
3748  // int nargs = 0;
3749  if (paran>0) {
3750  //nargs = 1;
3751  cbase[paran]=0;
3752  }
3753 
3754  if (cbase=="<") cbase="XlY";
3755  if (cbase=="<=") cbase="XleY";
3756  if (cbase==">") cbase="XgY";
3757  if (cbase==">=") cbase="XgeY";
3758  if (cbase=="==" && GetActionOptimized(pos)!=kStringEqual) cbase="XeY";
3759  if (cbase=="!=" && GetActionOptimized(pos)!=kStringNotEqual) cbase="XneY";
3760 
3761  ROOT::v5::TFormulaPrimitive *prim = ROOT::v5::TFormulaPrimitive::FindFormula(cbase ,paran>0 ? cbase.Data() + paran + 1 : (const char*)0);
3762  if (prim) {
3763  fPredefined[pos] = prim;
3764  if (prim->fType==10) {
3765  SetActionOptimized(pos, kFD1);
3766  }
3767  if (prim->fType==110) {
3768  SetActionOptimized(pos, kFD2);
3769  }
3770  if (prim->fType==1110) {
3771  SetActionOptimized(pos, kFD3);
3772  }
3773  if (prim->fType==-1) {
3774  SetActionOptimized(pos, kFDM);
3775  }
3776  if (prim->fType==0){
3778  fConst[fNconst] = prim->Eval(0);
3779  fNconst++;
3780  }
3781  return;
3782  }
3783 }
3784 
3785 ////////////////////////////////////////////////////////////////////////////////
3786 /// MI include
3787 ///
3788 /// Optimize formula
3789 /// - Minimize the number of operands
3790 /// 1. several operands are glued together
3791 /// 2. some primitive functions glued together - exemp. (x+y) => PlusXY(x,y)
3792 /// 3. maximize number of standard calls minimizing number of jumps in Eval cases
3793 /// 4. variables, parameters and constants are mapped - using fOperOfssets0
3794 /// Eval procedure use direct acces to data (only one corresponding case statement in eval procedure)
3795 /// ~~~ {.cpp}
3796 /// pdata[operand={Var,Par,Const}][offset]
3797 /// pdata[fOperOffsets0[i]][fOperOffset1[i+1]]
3798 /// ~~~
3799 /// - The fastest evaluation function is chosen at the end
3800 /// 1. fOptimal := pointer to the fastest function for given evaluation string
3801 /// ~~~ {.cpp}
3802 /// switch(GetActionOptimized(0)){
3803 /// case kData : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
3804 /// case kUnary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
3805 /// case kBinary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
3806 /// case kThree : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
3807 /// case kFDM : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
3808 /// }
3809 /// ~~~
3810 /// 2. ex.
3811 /// - fOptimal = ::EvalPrimitive0 - if it return only variable, constant or parameter
3812 /// - = ::EvalParameter1 - if only one unary operation
3813 /// - = ::EvalPrimitive2 - if only one binary operation
3814 
3816 {
3817  //
3818  // Initialize data members
3819  //
3820 
3821  Int_t i;
3822 
3823  if (fPredefined) { delete [] fPredefined; fPredefined = 0;}
3824  if (fOperOffset) { delete [] fOperOffset; fOperOffset = 0;}
3825  if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
3826  if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
3827 
3828  fExprOptimized = new TString[fNoper];
3829  fOperOptimized = new Int_t[fNoper];
3832  for (i=0; i<fNoper; i++) {
3833  fExprOptimized[i] = fExpr[i] ;
3834  fOperOptimized[i] = fOper[i];
3835  fPredefined[i]= 0;
3836  }
3837 
3838  //
3839  //Make primitives
3840  //
3841  for (i=0;i<fNoper;i++){
3842  if (fExprOptimized[i].Data()) {
3844  }
3845  }
3846  //
3847  Int_t maxfound = fNoper+1;
3848  Int_t *offset = new Int_t[maxfound*16];
3849  Int_t *optimized = new Int_t[maxfound];
3850  //
3851  //
3852  ROOT::v5::TFormulaPrimitive* primitive[10];
3853  primitive[0] = ROOT::v5::TFormulaPrimitive::FindFormula("PlusXY");
3854  primitive[1] = ROOT::v5::TFormulaPrimitive::FindFormula("MinusXY");
3855  primitive[2] = ROOT::v5::TFormulaPrimitive::FindFormula("MultXY");
3856  primitive[3] = ROOT::v5::TFormulaPrimitive::FindFormula("DivXY");
3857  primitive[4] = ROOT::v5::TFormulaPrimitive::FindFormula("XpYpZ");
3858  primitive[5] = ROOT::v5::TFormulaPrimitive::FindFormula("XxYxZ");
3859  primitive[6] = ROOT::v5::TFormulaPrimitive::FindFormula("XxYpZ");
3860  primitive[7] = ROOT::v5::TFormulaPrimitive::FindFormula("XpYxZ");
3861  primitive[8] = ROOT::v5::TFormulaPrimitive::FindFormula("Pow2");
3862  primitive[9] = ROOT::v5::TFormulaPrimitive::FindFormula("Pow3");
3863  //
3864  // set data pointers
3865  //
3866  for (i=0;i<fNoper;i++) optimized[i]=0;
3867  //
3868  for (i=0;i<fNoper;i++){
3869  Int_t actionparam = GetActionParamOptimized(i);
3870  Int_t action = GetActionOptimized(i);
3871 
3872  if (action==kBoolOptimize){
3873  //
3874  // optimize booleans
3875  //
3876  fOperOffset[i].fType1 = actionparam/10; // operands to skip
3877  fOperOffset[i].fOffset0 = actionparam%10; // 1 is && , 2 is || - operand
3878  fOperOffset[i].fToJump = i+fOperOffset[i].fType1; // where we should jump
3879  continue;
3880  }
3881  if (action==kJump || action==kJumpIf) {
3882  // Ternary conditional operator
3883  fOperOffset[i].fType1 = action;
3884  fOperOffset[i].fToJump = actionparam;
3885  }
3886  //
3887  if (action==kConstant&&i<fNoper-2){
3888  //
3889  // get offsets for kFDM operands
3890  //
3892  optimized[i]=1;
3893  optimized[i+1]=1;
3894  i+=2;
3895  fOperOffset[i].fType0=actionparam;
3897  Int_t offset2 = int(fConst[fOperOffset[i].fOffset0]+0.4);
3898  fOperOffset[i].fOffset0=offset2;
3899  Int_t nparmax = offset2+fPredefined[i]->fNParameters;
3900  if (nparmax>fNpar){ // increase expected number of parameters
3901  fNpar=nparmax;
3902  }
3903  continue;
3904  }
3905  }
3906  switch(action){
3907  case kVariable : {action=kData; fOperOffset[i].fType0=0; break;}
3908  case kParameter: {action=kData; fOperOffset[i].fType0=1; break;}
3909  case kConstant : {action=kData; fOperOffset[i].fType0=2; break;}
3910  }
3911  //
3913  SetActionOptimized(i,action, actionparam); //set common data option
3914  }
3915  //
3916  //
3918  //
3919  for (i=0; i<fNoper; ++i)
3920  {
3921  //
3922  if (!(GetActionOptimized(i)== kData)) continue;
3923  offset[0] = fOperOffset[i].fType0; //
3924  offset[1] = fOperOptimized[i] & kTFOperMask; // offset
3925 
3926  if ((i+1) >= fNoper) continue;
3927 
3928  if (GetActionOptimized(i+1)==kFD1){
3929  optimized[i] = 1; // to be optimized
3930  i++;
3931  fOperOffset[i].fType0 = offset[0];
3932  fOperOffset[i].fOffset0 = offset[1];
3934  continue;
3935  }
3936  if (GetActionOptimized(i+1)==kAdd){
3937  optimized[i] = 1; // to be optimized
3938  i++;
3939  fOperOffset[i].fType0 = offset[0];
3940  fOperOffset[i].fOffset0 = offset[1];
3942  continue;
3943  }
3944  if (GetActionOptimized(i+1)==kMultiply){
3945  optimized[i] = 1; // to be optimized
3946  i++;
3947  fOperOffset[i].fType0 = offset[0];
3948  fOperOffset[i].fOffset0 = offset[1];
3950  continue;
3951  }
3952 
3953  if ((i+2) >= fNoper) continue;
3954 
3955  //
3956  //Binary operators
3957  if (!(GetActionOptimized(i+1)== kData)) continue;
3958  offset[2] = fOperOffset[i+1].fType0;
3959  offset[3] = fOperOptimized[i+1] & kTFOperMask; // offset
3960  //
3963 
3964  optimized[i] = 1; // to be optimized
3965  optimized[i+1] = 1; // to be optimized
3966  i+=2;
3967  //
3968  fOperOffset[i].fType0 = offset[0];
3969  fOperOffset[i].fOffset0 = offset[1];
3970  fOperOffset[i].fType1 = offset[2];
3971  fOperOffset[i].fOffset1 = offset[3];
3972  fOperOffset[i].fType2 = GetActionOptimized(i); //remember old action
3973  if (GetActionOptimized(i)==kAdd) {fPredefined[i] = primitive[0];}
3974  if (GetActionOptimized(i)==kSubstract) {fPredefined[i] = primitive[1];}
3975  if (GetActionOptimized(i)==kMultiply) {
3976  fPredefined[i]=primitive[2];
3977  if (offset[0]==offset[2]&&offset[1]==offset[3]) {
3978  fPredefined[i] = primitive[8];
3980  continue;
3981  }
3982  }
3983  if (GetActionOptimized(i)==kDivide) {
3984  fPredefined[i] = primitive[3];
3985  }
3987  continue;
3988  }
3989 
3990  if ((i+3) >= fNoper) continue;
3991 
3992  //
3993  //operator 3
3994  //
3995  if (!(GetActionOptimized(i+2)== kData)) continue;
3996  offset[4] = fOperOffset[i+2].fType0;
3997  offset[5] = fOperOptimized[i+2] & kTFOperMask; // offset
3998  //
4001  optimized[i+0] = 1; // to be optimized
4002  optimized[i+1] = 1; // to be optimized
4003  optimized[i+2] = 1; // to be optimized
4004  i+=3;
4005  //
4006  fOperOffset[i].fType0 = offset[0];
4007  fOperOffset[i].fOffset0 = offset[1];
4008  fOperOffset[i].fType1 = offset[2];
4009  fOperOffset[i].fOffset1 = offset[3];
4010  fOperOffset[i].fType2 = offset[4];
4011  fOperOffset[i].fOffset2 = offset[5];
4012  //
4013  fOperOffset[i].fOldAction = GetActionOptimized(i); //remember old action
4014  if (GetActionOptimized(i)==kFD3) {
4016  continue;
4017  }
4018  Int_t action=0;
4019  Int_t action2=kThree;
4020  if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kAdd) action=4;
4022  action=5;
4023  if (offset[0]==offset[2]&&offset[1]==offset[3]&&offset[0]==offset[4]&&offset[1]==offset[5]){
4024  fPredefined[i]=primitive[9];
4025  action2=kUnary;
4026  action =9;
4027  }
4028  }
4029  if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kMultiply) action=6;
4030  if (GetActionOptimized(i)==kMultiply&&GetActionOptimized(i+1)==kAdd) action=7;
4031  //
4032  optimized[i]=1;
4033  i++;
4034  fOperOffset[i].fType0 = offset[0];
4035  fOperOffset[i].fOffset0 = offset[1];
4036  fOperOffset[i].fType1 = offset[2];
4037  fOperOffset[i].fOffset1 = offset[3];
4038  fOperOffset[i].fType2 = offset[4];
4039  fOperOffset[i].fOffset2 = offset[5];
4040  fPredefined[i]=primitive[action];
4041  SetActionOptimized(i,action2);
4042  continue;
4043  }
4044  }
4045  //
4046  //
4047  Int_t operO=0;
4048  TString expr="";
4049  Int_t *map0 = new Int_t[maxfound]; //remapping of the operands
4050  Int_t *map1 = new Int_t[maxfound]; //remapping of the operands
4051  for (i=0;i<fNoper;i++){
4052  map0[i] = operO;
4053  map1[operO] = i;
4054  fOperOptimized[operO] = fOperOptimized[i];
4055  fPredefined[operO] = fPredefined[i];
4056  fOperOffset[operO] = fOperOffset[i];
4057  expr += fExprOptimized[i];
4058  if (optimized[i]==0){
4059  fExprOptimized[operO] = expr;
4060  expr = "";
4061  operO++;
4062  }else{
4063  expr += ",";
4064  }
4065  }
4066  //
4067  // Recalculate long jump for Boolean optimize
4068  //
4069  for (i=0; i<fNOperOptimized; i++){
4070  Int_t optaction = GetActionOptimized(i);
4071  if (optaction==kBoolOptimize){
4072  Int_t oldpos = fOperOffset[i].fToJump;
4073  Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
4074  fOperOffset[i].fToJump = newpos; // new position to jump
4075  Int_t actionop = GetActionParamOptimized(i) % 10;
4076  switch (actionop) {
4077  case 1: SetActionOptimized(i,kBoolOptimizeAnd,newpos); break;
4078  case 2: SetActionOptimized(i,kBoolOptimizeOr,newpos); break;
4079  }
4080  } else if (optaction==kJump || optaction==kJumpIf) {
4081  Int_t oldpos = fOperOffset[i].fToJump;
4082  Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
4083  fOperOffset[i].fToJump = newpos; // new position to jump
4084  SetActionOptimized(i,optaction,newpos);
4085  }
4086  }
4087 
4088 
4089  fNOperOptimized = operO;
4090  //
4092  if (fNOperOptimized==1) {
4093  switch(GetActionOptimized(0)){
4099  }
4100  }
4101 
4102  delete [] map1;
4103  delete [] map0;
4104  delete [] offset;
4105  delete [] optimized;
4106 }
4107 
4108 ////////////////////////////////////////////////////////////////////////////////
4109 /// Evaluate primitive formula
4110 
4112 {
4113  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4115  switch((fOperOptimized[0] >> kTFOperShift)) {
4116  case kData : return result;
4117  case kUnary : return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4118  case kBinary :return (fPredefined[0]->fFunc110)(result,
4120 
4121  case kThree :return (fPredefined[0]->fFunc1110)(result, pdata[fOperOffset->fType1][fOperOffset->fOffset1],
4123  case kFDM : return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4124  (Double_t*)&params[fOperOffset->fOffset0]);
4125  }
4126  return 0;
4127 }
4128 
4129 ////////////////////////////////////////////////////////////////////////////////
4130 /// Evaluate primitive formula
4131 
4133 {
4134  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4135  return pdata[fOperOffset->fType0][fOperOffset->fOffset0];
4136 }
4137 
4138 ////////////////////////////////////////////////////////////////////////////////
4139 /// Evaluate primitive formula
4140 
4142 {
4143  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4144  return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
4145 }
4146 
4147 ////////////////////////////////////////////////////////////////////////////////
4148 /// Evaluate primitive formula
4149 
4151 {
4152  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4153  return (fPredefined[0]->fFunc110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0],
4155 }
4156 
4157 ////////////////////////////////////////////////////////////////////////////////
4158 /// Evaluate primitive formula
4159 
4161 {
4162  const Double_t *pdata[3] = {x,(params!=0)?params:fParams, fConst};
4163  return (fPredefined[0]->fFunc1110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0], pdata[fOperOffset->fType1][fOperOffset->fOffset1],
4165 }
4166 
4167 ////////////////////////////////////////////////////////////////////////////////
4168 /// Evaluate primitive formula
4169 
4171 {
4172  const Double_t *par = (params!=0)?params:fParams;
4173  return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
4174  (Double_t*)&par[fOperOffset->fOffset0]);
4175 }
4176 
4177 ////////////////////////////////////////////////////////////////////////////////
4178 /// Evaluate this formula.
4179 ///
4180 /// The current value of variables x,y,z,t is passed through the pointer x.
4181 /// The parameters used will be the ones in the array params if params is given
4182 /// otherwise parameters will be taken from the stored data members fParams
4183 ///
4184 /// \image html TFormula_eval.png
4185 
4187 {
4188  const Double_t *pdata[3] = {x,(uparams!=0)?uparams:fParams, fConst};
4189  //
4190  Int_t i,j;
4191  Double_t tab[kMAXFOUND];
4192  const char *stringStack[gMAXSTRINGFOUND];
4193  Double_t param_calc[kMAXFOUND];
4194  char *string_calc[gMAXSTRINGFOUND];
4195  Int_t precalculated = 0;
4196  Int_t precalculated_str = 0;
4197 
4198  Double_t *params;
4199 
4200  if (uparams) {
4201  //for (j=0;j<fNpar;j++) fParams[j] = params[j];
4202  params = const_cast<Double_t*>(uparams);
4203  } else {
4204  params = fParams;
4205  }
4206 
4207  //if (params) {
4208  // for (j=0;j<fNpar;j++) fParams[j] = params[j];
4209  //}
4210  UInt_t pos = 0;
4211  UInt_t strpos = 0;
4212  // for (i=0; i<fNoper; ++i) {
4213  for (i=0; i<fNOperOptimized; ++i) {
4214  //
4215  const int oper = fOperOptimized[i];
4216  const int opcode = oper >> kTFOperShift;
4217 
4218  switch(opcode) { // FREQUENTLY USED OPERATION
4219  case kData : tab[pos] = pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; pos++;continue;
4220  case kPlusD : tab[pos-1]+= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4221  case kMultD : tab[pos-1]*= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
4222  case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4223  case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4224  case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4225  case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4226  else tab[pos-1] /= tab[pos];
4227  continue;
4228  case kUnary : tab[pos] = (fPredefined[i]->fFunc10)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]); pos++;continue;
4229  case kBinary : tab[pos] = (fPredefined[i]->fFunc110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4230  pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1]);pos++;continue;
4231 
4232  case kThree : tab[pos] = (fPredefined[i]->fFunc1110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
4233  pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1],
4234  pdata[fOperOffset[i].fType2][fOperOffset[i].fOffset2]); pos++; continue;
4235 
4236  case kFDM : tab[pos] = (fPredefined[i]->fFuncG)(&x[fOperOffset[i].fType0],&params[fOperOffset[i].fOffset0]); pos++;continue;
4237  case kFD1 : tab[pos-1] =(fPredefined[i]->fFunc10)(tab[pos-1]); continue;
4238  case kFD2 : pos--; tab[pos-1] = (fPredefined[i]->fFunc110)(tab[pos-1],tab[pos]); continue;
4239  case kFD3 : pos-=2; tab[pos-1] = (fPredefined[i]->fFunc1110)(tab[pos-1],tab[pos],tab[pos+1]); continue;
4240  }
4241  //
4242  switch(opcode) {
4243  case kBoolOptimizeAnd: {
4244  if (!tab[pos-1]) i=fOperOffset[i].fToJump;
4245  continue;
4246  }
4247  case kBoolOptimizeOr: {
4248  if (tab[pos-1]) i=fOperOffset[i].fToJump;
4249  continue;
4250  }
4251  case kAnd : pos--; tab[pos-1] = (bool)tab[pos]; continue; // use the fact that other were check before - see bool optimize
4252  case kOr : pos--; tab[pos-1] = (bool)tab[pos]; continue;
4253  }
4254  switch(opcode) {
4255  // case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4256  case kabs : if (tab[pos-1]<0) tab[pos-1]=-tab[pos-1]; continue;
4257  case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
4258  case kint : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
4259  case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4260 
4261  case kModulo : {pos--;
4262  Long64_t int1((Long64_t)tab[pos-1]);
4263  Long64_t int2((Long64_t)tab[pos]);
4264  tab[pos-1] = Double_t(int1%int2);
4265  continue;}
4266 
4267 
4268  case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExprOptimized[i].Data(); pos++; tab[pos-1] = 0; continue; }
4269  case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
4270 
4271  case kstrstr : strpos -= 2; pos-=2; pos++;
4272  if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
4273  else tab[pos-1]=0;
4274  continue;
4275  case kpi : pos++; tab[pos-1] = TMath::ACos(-1); continue;
4276 
4277 
4278  case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4279 
4280  case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
4281 
4282 
4283  case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
4284  else tab[pos-1]=0;
4285  continue;
4286  case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
4287  else tab[pos-1]=0;
4288  continue;
4289  case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1;
4290  continue;
4291 
4292  case kStringEqual : strpos -= 2; pos -=2 ; pos++;
4293  if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4294  else tab[pos-1]=0;
4295  continue;
4296  case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
4297  if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
4298  else tab[pos-1]=0;
4299  continue;
4300 
4301  case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
4302  case kBitOr : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
4303  case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
4304  case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
4305 
4306  case kJump : i = (oper & kTFOperMask); continue;
4307  case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
4308 
4309  case kBoolOptimize: {
4310  // boolean operation optimizer
4311 
4312  int param = (oper & kTFOperMask);
4313  int op = param % 10; // 1 is && , 2 is ||
4314 
4315  if (op == 1 && (!tab[pos-1]) ) {
4316  // &&: skip the right part if the left part is already false
4317 
4318  i += param / 10;
4319 
4320  // Preserve the existing behavior (i.e. the result of a&&b is
4321  // either 0 or 1)
4322  tab[pos-1] = 0;
4323 
4324  } else if (op == 2 && tab[pos-1] ) {
4325  // ||: skip the right part if the left part is already true
4326 
4327  i += param / 10;
4328 
4329  // Preserve the existing behavior (i.e. the result of a||b is
4330  // either 0 or 1)
4331  tab[pos-1] = 1;
4332 
4333  }
4334 
4335  continue;
4336  }
4337 
4338  }
4339  switch(opcode) {
4340 
4341 #define R__EXPO(var) \
4342  { \
4343  pos++; int param = (oper & kTFOperMask); \
4344  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]); \
4345  continue; \
4346  }
4347  // case kexpo:
4348  case kxexpo: R__EXPO(0);
4349  case kyexpo: R__EXPO(1);
4350  case kzexpo: R__EXPO(2);
4351  case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
4352  tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
4353  continue; }
4354 #ifdef R__GAUS
4355 #undef R__GAUS
4356 #endif
4357 #define R__GAUS(var) \
4358  { \
4359  pos++; int param = (oper & kTFOperMask); \
4360  tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1], \
4361  params[param+2],IsNormalized()); \
4362  continue; \
4363  }
4364 
4365  // case kgaus:
4366  case kxgaus: R__GAUS(0);
4367  case kygaus: R__GAUS(1);
4368  case kzgaus: R__GAUS(2);
4369  case kxygaus: { pos++; int param = (oper & kTFOperMask);
4370  Double_t intermede1;
4371  if (params[param+2] == 0) {
4372  intermede1=1e10;
4373  } else {
4374  intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
4375  }
4376  Double_t intermede2;
4377  if (params[param+4] == 0) {
4378  intermede2=1e10;
4379  } else {
4380  intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
4381  }
4382  tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
4383  continue; }
4384 
4385 #define R__LANDAU(var) \
4386  { \
4387  pos++; const int param = (oper & kTFOperMask); \
4388  tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
4389  continue; \
4390  }
4391  // case klandau:
4392  case kxlandau: R__LANDAU(0);
4393  case kylandau: R__LANDAU(1);
4394  case kzlandau: R__LANDAU(2);
4395  case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
4396  Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
4397  Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
4398  tab[pos-1] = params[param]*intermede1*intermede2;
4399  continue;
4400  }
4401 
4402 #define R__POLY(var) \
4403  { \
4404  pos++; int param = (oper & kTFOperMask); \
4405  tab[pos-1] = 0; Double_t intermede = 1; \
4406  Int_t inter = param/100; /* arrondit */ \
4407  Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
4408  for (j=0 ;j<inter+1;j++) { \
4409  tab[pos-1] += intermede*params[j+int1]; \
4410  intermede *= x[var]; \
4411  } \
4412  continue; \
4413  }
4414  // case kpol:
4415  case kxpol: R__POLY(0);
4416  case kypol: R__POLY(1);
4417  case kzpol: R__POLY(2);
4418 
4419  case kDefinedVariable : {
4420  if (!precalculated) {
4421  precalculated = 1;
4422  for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
4423  }
4424  pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
4425  continue;
4426  }
4427 
4428  case kDefinedString : {
4429  int param = (oper & kTFOperMask);
4430  if (!precalculated_str) {
4431  precalculated_str=1;
4432  for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
4433  }
4434  strpos++; stringStack[strpos-1] = string_calc[param];
4435  pos++; tab[pos-1] = 0;
4436  continue;
4437  }
4438 
4439  case kFunctionCall: {
4440  // an external function call
4441 
4442  int param = (oper & kTFOperMask);
4443  int fno = param / 1000;
4444  int nargs = param % 1000;
4445 
4446  // Retrieve the function
4447  TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
4448 
4449  // Set the arguments
4450  method->ResetParam();
4451  if (nargs) {
4452  UInt_t argloc = pos-nargs;
4453  for(j=0;j<nargs;j++,argloc++,pos--) {
4454  method->SetParam(tab[argloc]);
4455  }
4456  }
4457  pos++;
4458  Double_t ret;
4459  method->Execute(ret);
4460  tab[pos-1] = ret; // check for the correct conversion!
4461 
4462  continue;
4463  };
4464  }
4465  if (!TestBit(kOptimizationError)) {
4467  Warning("EvalParFast","Found an unsupported optmized opcode (%d)",oper >> kTFOperShift);
4468  }
4469  }
4470  Double_t result0 = tab[0];
4471  return result0;
4472 
4473 }
4474 
4475 ////////////////////////////////////////////////////////////////////////////////
4476 /// Pre compile function
4477 
4479 {
4480  TString str = fTitle;
4481  if (str.Length()<3) return 1;
4482  if (str[str.Length()-1]!='+'&&str[str.Length()-2]!='+') return 1;
4483  str[str.Length()-2]=0;
4484  TString funName("preformula_");
4485  funName += fName;
4486  if (ROOT::v5::TFormulaPrimitive::FindFormula(funName)) return 0;
4487  TString fileName;
4488  fileName.Form("/tmp/%s.C",funName.Data());
4489 
4490  FILE *hf;
4491  hf = fopen(fileName.Data(),"w");
4492  if (hf == 0) {
4493  Error("PreCompile","Unable to open the file %s for writing.",fileName.Data());
4494  return 1;
4495  }
4496  fprintf(hf, "/////////////////////////////////////////////////////////////////////////\n");
4497  fprintf(hf, "// This code has been automatically generated \n");
4498  //
4499  fprintf(hf, "Double_t %s(Double_t *x, Double_t *p){",funName.Data());
4500  fprintf(hf, "return (%s);\n}",str.Data());
4501 
4502  // fprintf("ROOT::v5::TFormulaPrimitive::AddFormula(new ROOT::v5::TFormulaPrimitive(\"%s::%s\",\"%s::%s\",(ROOT::v5::TFormulaPrimitive::GenFunc0)%s::%s));\n",
4503  // clname,method->GetName(),clname,method->GetName(),clname,method->GetName());
4504  fclose(hf);
4505 
4506  return 0;
4507 
4508 
4509 }
4510 
4511 ////////////////////////////////////////////////////////////////////////////////
4512 /// static function to set the maximum value of 3 parameters
4513 ///
4514 /// - maxop : maximum number of operations
4515 /// - maxpar : maximum number of parameters
4516 /// - maxconst : maximum number of constants
4517 ///
4518 /// None of these parameters cannot be less than 10 (default is 1000)
4519 /// call this function to increase one or all maxima when processing
4520 /// very complex formula, eg TFormula::SetMaxima(100000,1000,1000000);
4521 /// If you process many functions with a small number of operations/parameters
4522 /// you may gain some memory and performance by decreasing these values.
4523 
4524 void TFormula::SetMaxima(Int_t maxop, Int_t maxpar, Int_t maxconst)
4525 {
4526  gMAXOP = TMath::Max(10,maxop);
4527  gMAXPAR = TMath::Max(10,maxpar);
4528  gMAXCONST = TMath::Max(10,maxconst);
4529 }
4530 
4531 ////////////////////////////////////////////////////////////////////////////////
4532 /// static function to get the maximum value of 3 parameters
4533 /// -maxop : maximum number of operations
4534 /// -maxpar : maximum number of parameters
4535 /// -maxconst : maximum number of constants
4536 
4537 void TFormula::GetMaxima(Int_t& maxop, Int_t& maxpar, Int_t& maxconst)
4538 {
4539  maxop = gMAXOP;
4540  maxpar = gMAXPAR;
4541  maxconst = gMAXCONST;
4542 }
4543 
4544  } // end namespace v5
4545 
4546 } // end namespace ROOT
TString fTitle
Definition: TNamed.h:33
TOperOffset()
TOper offset - helper class for TFormula* specify type of operand fTypeX = kVariable = kParameter = k...
Double_t ACosH(Double_t)
Definition: TMath.cxx:80
virtual Bool_t IsString(Int_t oper) const
Return true if the expression at the index &#39;oper&#39; has to be treated as a string.
Int_t fNOperOptimized
cache for information
Definition: TFormula.h:91
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
double par[1]
Definition: unuranDistr.cxx:38
Bool_t IsReading() const
Definition: TBuffer.h:81
void Streamer(TBuffer &b, const TClass *onfile_class)
Stream a class object.
#define R__EXPO(var)
Double_t Landau(Double_t x, Double_t mpv=0, Double_t sigma=1, Bool_t norm=kFALSE)
The LANDAU function.
Definition: TMath.cxx:472
virtual void Update()
Definition: TFormula.h:263
An array of TObjects.
Definition: TObjArray.h:37
virtual Bool_t StringToNumber(Int_t code)
Try to &#39;demote&#39; a string into an array bytes.
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
virtual void Analyze(const char *schain, Int_t &err, Int_t offset=0)
Analyze a sub-expression in one formula.
Double_t TanH(Double_t)
Definition: TMath.h:563
long long Long64_t
Definition: RtypesCore.h:69
static double p3(double t, double a, double b, double c, double d)
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Double_t Log(Double_t x)
Definition: TMath.h:649
short Version_t
Definition: RtypesCore.h:61
Collectable string class.
Definition: TObjString.h:28
float Float_t
Definition: RtypesCore.h:53
static const EReturnType kOther
Definition: TMethodCall.h:46
const char Option_t
Definition: RtypesCore.h:62
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:329
virtual Int_t DefinedVariable(TString &variable, Int_t &action)
Check if expression is in the list of defined variables.
double T(double x)
Definition: ChebyshevPol.h:34
Double_t EvalPrimitive(const Double_t *x, const Double_t *params)
Evaluate primitive formula.
Int_t PreCompile()
pointer to optimal function
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:640
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
#define BIT(n)
Definition: Rtypes.h:75
static Int_t gMAXCONST
Definition: TFormula_v5.cxx:32
GenFunc10 fFunc10
pointer to the function
virtual void Print(Option_t *option="") const
Dump this formula with its attributes.
virtual void Convert(UInt_t fromVersion)
TBits fAlreadyFound
Definition: TFormula.h:88
Double_t EvalPrimitive3(const Double_t *x, const Double_t *params)
Evaluate primitive formula.
virtual char * DefinedString(Int_t code)
Return address of string corresponding to special code.
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
#define R__ASSERT(e)
Definition: TError.h:96
#define R__LANDAU(var)
virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss)=0
#define gROOT
Definition: TROOT.h:375
Basic string class.
Definition: TString.h:129
virtual void SetNumber(Int_t number)
Definition: TFormula.h:251
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1099
Bool_t IsEmpty() const
Definition: TObjArray.h:70
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
#define gInterpreter
Definition: TInterpreter.h:499
virtual void ProcessLinear(TString &replaceformula)
If the formula is for linear fitting, change the title to normal and fill the LinearParts array...
const Int_t kTFOperMask
Definition: TFormula.h:32
Double_t * fParams
Definition: TFormula.h:83
virtual Int_t Compile(const char *expression="")
Compile expression already stored in fTitle.
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
void SetAction(Int_t code, Int_t value, Int_t param=0)
Definition: TFormula.h:107
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:597
const Int_t gMAXSTRINGFOUND
Definition: TFormula_v5.cxx:33
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
#define R__GAUS(var)
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:628
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:687
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:630
void SetActionOptimized(Int_t code, Int_t value, Int_t param=0)
Definition: TFormula.h:115
The Formula Primitive class.
Double_t x[n]
Definition: legend1.C:17
TObjArray fFunctions
Definition: TFormula.h:85
virtual const TObject * GetLinearPart(Int_t i)
Return linear part.
void Class()
Definition: Class.C:29
virtual ~TFormula()
Formula default destructor.
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
void MakePrimitive(const char *expr, Int_t pos)
MakePrimitive find TFormulaPrimitive replacement for some operands.
Double_t ASinH(Double_t)
Definition: TMath.cxx:67
Double_t Log10(Double_t x)
Definition: TMath.h:652
static double p2(double t, double a, double b, double c)
TString & Append(const char *cs)
Definition: TString.h:497
Double_t EvalParFast(const Double_t *x, const Double_t *params)
Evaluate this formula.
std::vector< std::vector< double > > Data
static void SetMaxima(Int_t maxop=1000, Int_t maxpar=1000, Int_t maxconst=1000)
static function to set the maximum value of 3 parameters
ClassInfo_t * GetClassInfo() const
Definition: TClass.h:381
virtual Bool_t CheckOperands(Int_t operation, Int_t &err)
Check whether the operand at &#39;oper-1&#39; is compatible with the operation at &#39;oper&#39;. ...
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:477
Double_t ATan2(Double_t, Double_t)
Definition: TMath.h:581
const Int_t kMAXFOUND
Definition: TFormula.h:31
virtual void Clear(Option_t *option="")
Resets the objects.
Method or function calling interface.
Definition: TMethodCall.h:37
Bool_t TestBitNumber(UInt_t bitnumber) const
Definition: TBits.h:219
virtual Bool_t IsNormalized() const
Definition: TFormula.h:248
Double_t GetParameter(Int_t ipar) const
Return value of parameter number ipar.
Double_t EvalPrimitive0(const Double_t *x, const Double_t *params)
Evaluate primitive formula.
TFormula & operator=(const TFormula &rhs)
Operator =.
virtual Double_t Rndm()
Machine independent random number generator.
Definition: TRandom.cxx:512
Double_t Eval(Double_t *x)
Eval primitive function at point x.
static void GetMaxima(Int_t &maxop, Int_t &maxpar, Int_t &maxconst)
static function to get the maximum value of 3 parameters -maxop : maximum number of operations -maxpa...
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:528
virtual void Copy(TObject &formula) const
Copy this formula.
#define R__POLY(var)
void ClearFormula(Option_t *option="")
Resets the objects.
virtual Bool_t AnalyzeFunction(TString &chaine, Int_t &err, Int_t offset=0)
Check if the chain as function call.
virtual 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")
Set up to 11 parameter names.
TFormulaPrimitive ** fPredefined
[fNOperOptimized] Offsets of operrands
Definition: TFormula.h:95
SVector< double, 2 > v
Definition: Dict.h:5
virtual void SetParName(Int_t ipar, const char *name)
Set name of parameter number ipar.
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
Evaluate this formula.
Double_t * fConst
Definition: TFormula.h:82
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2332
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
char * Form(const char *fmt,...)
Ssiz_t Length() const
Definition: TString.h:388
virtual const char * GetParName(Int_t ipar) const
Return name of one parameter.
static Int_t gMAXOP
Definition: TFormula_v5.cxx:32
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:71
Double_t ACos(Double_t)
Definition: TMath.h:572
static double p1(double t, double a, double b)
const UChar_t kTFOperShift
Definition: TFormula.h:33
virtual Int_t GetNpar() const
Definition: TFormula.h:238
R__EXTERN TRandom * gRandom
Definition: TRandom.h:62
TString fName
Definition: TNamed.h:32
TString & String()
Definition: TObjString.h:49
Bool_t IsValid() const
Return true if the method call has been properly initialized and is usable.
#define Printf
Definition: TGeoToOCC.h:18
TString * fNames
Definition: TFormula.h:84
Double_t Cos(Double_t)
Definition: TMath.h:551
#define R__LOCKGUARD2(mutex)
const Bool_t kFALSE
Definition: RtypesCore.h:92
virtual Double_t DefinedValue(Int_t code)
Return value corresponding to special code.
TString & Remove(Ssiz_t pos)
Definition: TString.h:621
long Long_t
Definition: RtypesCore.h:50
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
int Ssiz_t
Definition: RtypesCore.h:63
Double_t EvalPrimitive4(const Double_t *x, const Double_t *params)
Evaluate primitive formula.
TFunction * GetMethod()
Returns the TMethod describing the method to be executed.
virtual void SetParameter(const char *name, Double_t parvalue)
Initialize parameter number ipar.
Double_t Exp(Double_t x)
Definition: TMath.h:622
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2251
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
void ResetParam()
Reset parameter list. To be used before the first call the SetParam().
double Double_t
Definition: RtypesCore.h:55
The FORMULA class (ROOT version 5)
Definition: TFormula.h:65
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:875
unsigned long ULong_t
Definition: RtypesCore.h:51
Double_t y[n]
Definition: legend1.C:17
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
Definition: TObjArray.cxx:370
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:572
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
virtual const char * GetPrototype() const
Returns the prototype of a function as defined by CINT, or 0 in case of error.
Definition: TFunction.cxx:245
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:2885
TCanvas * slash()
Definition: slash.C:1
Mother of all ROOT objects.
Definition: TObject.h:37
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:151
Double_t(TObject::* TFuncG)(const Double_t *, const Double_t *) const
you should not use this method at all Int_t Int_t z
Definition: TRolke.cxx:630
Short_t GetActionOptimized(Int_t code) const
Definition: TFormula.h:112
Double_t EvalPrimitive1(const Double_t *x, const Double_t *params)
Evaluate primitive formula.
virtual void Copy(TObject &named) const
Copy this to obj.
Definition: TNamed.cxx:85