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