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