TFormula.cxx

Go to the documentation of this file.
00001 // @(#)root/hist:$Id: TFormula.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Nicolas Brun   19/08/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include <math.h>
00013 
00014 #include "Riostream.h"
00015 #include "TROOT.h"
00016 #include "TClass.h"
00017 #include "TFormula.h"
00018 #include "TMath.h"
00019 #include "TRandom.h"
00020 #include "TFunction.h"
00021 #include "TMethodCall.h"
00022 #include "TObjString.h"
00023 #include "TError.h"
00024 #include "TFormulaPrimitive.h"
00025 
00026 #ifdef WIN32
00027 #pragma optimize("",off)
00028 #endif
00029 
00030 static Int_t gMAXOP=1000,gMAXPAR=1000,gMAXCONST=1000;
00031 const Int_t  gMAXSTRINGFOUND = 10;
00032 const UInt_t kOptimizationError = BIT(19);
00033 
00034 ClassImp(TFormula)
00035 
00036 //______________________________________________________________________________
00037 //*-*-*-*-*-*-*-*-*-*-*The  F O R M U L A  class*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
00038 //*-*                  =========================
00039 //*-*
00040 //*-*   This class has been implemented by begin_html <a href="http://pcbrun.cern.ch/nicolas/index.html">Nicolas Brun</a> end_html(age 18).
00041 //*-*   ========================================================
00042 //Begin_Html
00043 /*
00044 <img src="gif/tformula_classtree.gif">
00045 */
00046 //End_Html
00047 //*-*
00048 //*-*  Example of valid expressions:
00049 //*-*     -  sin(x)/x
00050 //*-*     -  [0]*sin(x) + [1]*exp(-[2]*x)
00051 //*-*     -  x + y**2
00052 //*-*     -  x^2 + y^2
00053 //*-*     -  [0]*pow([1],4)
00054 //*-*     -  2*pi*sqrt(x/y)
00055 //*-*     -  gaus(0)*expo(3)  + ypol3(5)*x
00056 //*-*     -  gausn(0)*expo(3) + ypol3(5)*x
00057 //*-*
00058 //*-*  In the last example above:
00059 //*-*     gaus(0) is a substitute for [0]*exp(-0.5*((x-[1])/[2])**2)
00060 //*-*        and (0) means start numbering parameters at 0
00061 //*-*     gausn(0) is a substitute for [0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))
00062 //*-*        and (0) means start numbering parameters at 0
00063 //*-*     expo(3) is a substitute for exp([3]+[4]*x)
00064 //*-*     pol3(5) is a substitute for par[5]+par[6]*x+par[7]*x**2+par[8]*x**3
00065 //*-*         (here Pol3 stands for Polynomial of degree 3)
00066 //*-*
00067 //*-*   TMath functions can be part of the expression, eg:
00068 //*-*     -  TMath::Landau(x)*sin(x)
00069 //*-*     -  TMath::Erf(x)
00070 //*-*
00071 //*-*   Comparisons operators are also supported (&&, ||, ==, <=, >=, !)
00072 //*-*   Examples:
00073 //*-*      sin(x*(x<0.5 || x>1))
00074 //*-*   If the result of a comparison is TRUE, the result is 1, otherwise 0.
00075 //*-*
00076 //*-*   Already predefined names can be given. For example, if the formula
00077 //*-*     TFormula old(sin(x*(x<0.5 || x>1))) one can assign a name to the formula. By default
00078 //*-*     the name of the object = title = formula itself.
00079 //*-*     old.SetName("old").
00080 //*-*     then, old can be reused in a new expression.
00081 //*-*     TFormula new("x*old") is equivalent to:
00082 //*-*     TFormula new("x*sin(x*(x<0.5 || x>1))")
00083 //*-*
00084 //*-*   Up to 4 dimensions are supported (indicated by x, y, z, t)
00085 //*-*   An expression may have 0 parameters or a list of parameters
00086 //*-*   indicated by the sequence [par_number]
00087 //*-*
00088 //*-*   A graph showing the logic to compile and analyze a formula
00089 //*-*   is shown in TFormula::Compile and TFormula::Analyze.
00090 //*-*   Once a formula has been compiled, it can be evaluated for a given
00091 //*-*   set of parameters. see graph in TFormula::EvalPar.
00092 //*-*
00093 //*-*   This class is the base class for the function classes TF1,TF2 and TF3.
00094 //*-*   It is also used by the ntuple selection mechanism TNtupleFormula.
00095 //*-*
00096 //*-*   In version 7 of TFormula, the usage of fOper has been changed
00097 //*-*   to improve the performance of TFormula::EvalPar.
00098 //*-*   Conceptually, fOper was changed from a simple array of Int_t
00099 //*-*   to an array of composite values.
00100 //*-*   For example a 'ylandau(5)' operation used to be encoded as 4105;
00101 //*-*   it is now encoded as (klandau >> kTFOperShit) + 5
00102 //*-*   Any class inheriting from TFormula and using directly fOper (which
00103 //*-*   is now a private data member), needs to be updated to take this
00104 //*-*   in consideration.  The member functions recommended to set and
00105 //*-*   access fOper are:  SetAction, GetAction, GetActionParam
00106 //*-*   For more performant access to the information, see the implementation
00107 //*-*   TFormula::EvalPar
00108 //*-*
00109 //*-*   CHANGING DEFAULT SETTINGS
00110 //*-*   =========================
00111 //*-*   When creating complex formula , it may be necessary to increase
00112 //*-*   some default parameters. see static function TFormula::SetMaxima
00113 //*-*
00114 //*-*   WHY TFormula CANNOT ACCEPT A CLASS MEMBER FUNCTION ?
00115 //*-*   ====================================================
00116 //*-* This is a frequently asked question.
00117 //*-* C++ is a strongly typed language. There is no way for TFormula (without
00118 //*-* recompiling this class) to know about all possible user defined data types.
00119 //*-* This also apply to the case of a static class function.
00120 //*-* Because TMath is a special and frequent case, TFormula is aware
00121 //*-* of all TMath functions.
00122 //*-*
00123 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
00124 
00125 
00126 //______________________________________________________________________________
00127 TFormula::TFormula(): TNamed()
00128 {
00129 //*-*-*-*-*-*-*-*-*-*-*Formula default constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
00130 //*-*                  ============================
00131 
00132    fNdim   = 0;
00133    fNpar   = 0;
00134    fNoper  = 0;
00135    fNconst = 0;
00136    fNumber = 0;
00137    fExpr   = 0;
00138    fOper   = 0;
00139    fConst  = 0;
00140    fParams = 0;
00141    fNstring= 0;
00142    fNames  = 0;
00143    fNval   = 0;
00144    //
00145    //MI change
00146    fNOperOptimized = 0;
00147    fExprOptimized  = 0;
00148    fOperOptimized  = 0;
00149    fOperOffset     = 0;
00150    fPredefined     = 0;
00151    fOptimal        = (TFormulaPrimitive::TFuncG)&TFormula::EvalParOld;
00152 }
00153 
00154 //______________________________________________________________________________
00155 TFormula::TFormula(const char *name,const char *expression) :
00156    TNamed(name,expression)
00157 {
00158 //*-*-*-*-*-*-*-*-*-*-*Normal Formula constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
00159 //*-*                  ==========================
00160 
00161    fNdim   = 0;
00162    fNpar   = 0;
00163    fNoper  = 0;
00164    fNconst = 0;
00165    fNumber = 0;
00166    fExpr   = 0;
00167    fOper   = 0;
00168    fConst  = 0;
00169    fParams = 0;
00170    fNstring= 0;
00171    fNames  = 0;
00172    fNval   = 0;
00173    //
00174    //MI change
00175    fNOperOptimized = 0;
00176    fExprOptimized  = 0;
00177    fOperOptimized  = 0;
00178    fOperOffset     = 0;
00179    fPredefined     = 0;
00180    fOptimal        = (TFormulaPrimitive::TFuncG)&TFormula::EvalParOld;
00181 
00182    if (!expression || !*expression) {
00183       Error("TFormula", "expression may not be 0 or have 0 length");
00184       return;
00185    }
00186 
00187    //eliminate blanks in expression
00188    Int_t i,j,nch;
00189    nch = strlen(expression);
00190    char *expr = new char[nch+1];
00191    j = 0;
00192    for (i=0;i<nch;i++) {
00193       if (expression[i] == ' ') continue;
00194       if (i > 0 && (expression[i] == '*') && (expression[i-1] == '*')) {
00195          expr[j-1] = '^';
00196          continue;
00197       }
00198       expr[j] = expression[i]; j++;
00199    }
00200    expr[j] = 0;
00201    Bool_t gausNorm   = kFALSE;
00202    Bool_t landauNorm = kFALSE;
00203    Bool_t linear = kFALSE;
00204 
00205    if (j) {
00206       TString chaine = expr;
00207       //special case for functions for linear fitting
00208       if (chaine.Contains("++"))
00209          linear = kTRUE;
00210       // special case for normalized gaus
00211       if (chaine.Contains("gausn")) {
00212          gausNorm = kTRUE;
00213          chaine.ReplaceAll("gausn","gaus");
00214       }
00215       // special case for normalized landau
00216       if (chaine.Contains("landaun")) {
00217          landauNorm = kTRUE;
00218          chaine.ReplaceAll("landaun","landau");
00219       }
00220       SetTitle(chaine.Data());
00221    }
00222    delete [] expr;
00223 
00224    if (linear)    SetBit(kLinear);
00225 
00226    if (Compile()) return;
00227 
00228    if (gausNorm)   SetBit(kNormalized);
00229    if (landauNorm) SetBit(kNormalized);
00230 
00231 //*-*- Store formula in linked list of formula in ROOT
00232 
00233    TFormula *old = (TFormula*)gROOT->GetListOfFunctions()->FindObject(name);
00234    if (old) {
00235       gROOT->GetListOfFunctions()->Remove(old);
00236    }
00237    if (strcmp(name,"x")==0 || strcmp(name,"y")==0 ||
00238        strcmp(name,"z")==0 || strcmp(name,"t")==0 )
00239    {
00240       Error("TFormula","The name \'%s\' is reserved as a TFormula variable name.\n"
00241          "\tThis function will not be registered in the list of functions",name);
00242    } else {
00243       gROOT->GetListOfFunctions()->Add(this);
00244    }
00245 }
00246 
00247 //______________________________________________________________________________
00248 TFormula::TFormula(const TFormula &formula) : TNamed()
00249 {
00250    // Default constructor.
00251 
00252    fNdim   = 0;
00253    fNpar   = 0;
00254    fNoper  = 0;
00255    fNconst = 0;
00256    fNumber = 0;
00257    fExpr   = 0;
00258    fOper   = 0;
00259    fConst  = 0;
00260    fParams = 0;
00261    fNstring= 0;
00262    fNames  = 0;
00263    fNval   = 0;
00264    fNOperOptimized = 0;
00265    fPredefined     = 0;
00266    fOperOffset     = 0;
00267    fExprOptimized  = 0;
00268    fOperOptimized  = 0;
00269 
00270    ((TFormula&)formula).TFormula::Copy(*this);
00271 }
00272 
00273 //______________________________________________________________________________
00274 TFormula& TFormula::operator=(const TFormula &rhs)
00275 {
00276    // Operator =
00277 
00278    if (this != &rhs) {
00279       rhs.Copy(*this);
00280    }
00281    return *this;
00282 }
00283 
00284 //______________________________________________________________________________
00285 TFormula::~TFormula()
00286 {
00287 //*-*-*-*-*-*-*-*-*-*-*Formula default destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
00288 //*-*                  ===========================
00289 
00290    if (gROOT) gROOT->GetListOfFunctions()->Remove(this);
00291 
00292    ClearFormula();
00293 }
00294 
00295 //______________________________________________________________________________
00296 Bool_t TFormula::AnalyzeFunction(TString &chaine, Int_t &err, Int_t offset)
00297 {
00298 //*-*-*-*-*-*-*-*-*Check if the chain as function call *-*-*-*-*-*-*-*-*-*-*
00299 //*-*              =======================================
00300 //*-*
00301 //*-*   If you overload this member function, you also HAVE TO
00302 //*-*   never call the constructor:
00303 //*-*
00304 //*-*     TFormula::TFormula(const char *name,const char *expression)
00305 //*-*
00306 //*-*   and write your own constructor
00307 //*-*
00308 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
00309 //*-*
00310 //*-*   which has to call the TFormula default constructor and whose implementation
00311 //*-*   should be similar to the implementation of the normal TFormula constructor
00312 //*-*
00313 //*-*   This is necessary because the normal TFormula constructor call indirectly
00314 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
00315 //*-*   and DefaultVariable.
00316 //*-*
00317 
00318    int i,j;
00319 
00320    // We have to decompose the chain is 3 potential components:
00321    //   namespace::functionName( args )
00322 
00323    Ssiz_t argStart = chaine.First('(');
00324    if (argStart<0) return false;
00325 
00326    TString functionName = chaine(0,argStart);
00327 
00328    // This does not support template yet (where the scope operator might be in
00329    // one of the template arguments
00330    Ssiz_t scopeEnd = functionName.Last(':');
00331    TString spaceName;
00332    if (scopeEnd>0 && functionName[scopeEnd-1]==':') {
00333       spaceName = functionName(0,scopeEnd-1);
00334       functionName.Remove(0,scopeEnd+1);
00335    }
00336 
00337    // Now we need to count and decompose the actual arguments, we could also check the type
00338    // of the arguments
00339    if (chaine[chaine.Length()-1] != ')') {
00340       Error("AnalyzeFunction","We thought we had a function but we dont (in %s)\n",chaine.Data());
00341    }
00342 
00343    TString args = chaine(argStart+1,chaine.Length()-2-argStart);
00344    TObjArray argArr;
00345    argArr.SetOwner(kTRUE);
00346    //fprintf(stderr,"args are '%s'\n",args.Data());
00347 
00348    Bool_t inString = false;
00349    int paran = 0;
00350    int brack = 0;
00351    int prevComma = 0;
00352    int nargs = 0;
00353    for(i=0; i<args.Length(); i++) {
00354       if (args[i]=='"') inString = !inString;
00355       if (inString) continue;
00356 
00357       Bool_t foundArg = false;
00358       switch(args[i]) {
00359 
00360          case '(': paran++; break;
00361          case ')': paran--; break;
00362          case '[': brack++; break;
00363          case ']': brack--; break;
00364 
00365          case ',': if (paran==0 && brack==0) { foundArg = true; } break;
00366       }
00367       if ((i+1)==args.Length()) {
00368          foundArg = true; i++;
00369       }
00370       if (foundArg) {
00371          TString arg = args(prevComma,i-prevComma);
00372 
00373          // Here we could
00374          //   a) check the type
00375          //fprintf(stderr,"found #%d arg %s\n",nargs,arg.Data());
00376 
00377          // We register the arg for later usage
00378          argArr.Add(new TObjString(arg));
00379          nargs++;
00380 
00381          prevComma = i+1;
00382       };
00383    }
00384 
00385    if (nargs>999) {
00386       err = 7;
00387       return false;
00388    }
00389 
00390    // Now we need to lookup the function and check its arguments.
00391 
00392    // We have 2 choice ... parse more and replace x, y, z and [?] by 0.0 or
00393    // or do the following silly thing:
00394    TString proto;
00395    for(j=0; j<nargs; j++) {
00396       proto += "0.0,";
00397    }
00398    if (nargs) proto.Remove(proto.Length()-1);
00399 
00400 
00401    TClass *ns = (spaceName.Length()) ? TClass::GetClass(spaceName) : 0;
00402    TMethodCall *method = new TMethodCall();
00403    if (ns) {
00404       method->Init(ns,functionName,proto);
00405    } else {
00406       method->Init(functionName,proto);
00407    }
00408 
00409    if (method->IsValid()) {
00410       if (method->ReturnType() == TMethodCall::kOther) {
00411          /*
00412            Error("Compile",
00413                "TFormula can only call interpreted and compiled function that returns a numerical type %s returns a %s\n",
00414                method->GetMethodName(), method->GetMethod()->GetReturnTypeName());
00415          */
00416          err=29;
00417 
00418       } else {
00419 
00420          // Analyze the arguments
00421          TIter next(&argArr);
00422          TObjString *objstr;
00423          while ( (objstr=(TObjString*)next()) ) {
00424             Analyze(objstr->String(),err,offset);
00425          }
00426 
00427          fFunctions.Add(method);
00428          fExpr[fNoper] = method->GetMethod()->GetPrototype();
00429          SetAction(fNoper, kFunctionCall, fFunctions.GetLast()*1000 + nargs);
00430          fNoper++;
00431          return true;
00432       }
00433    }
00434 
00435    delete method;
00436    //
00437    // MI change - extended space of functions
00438    // not forward compatible change
00439    //
00440    TString cbase(chaine);
00441    Int_t args_paran = cbase.First("(");
00442    if (args_paran>0){
00443       cbase[args_paran]=0;
00444    }
00445 
00446    TFormulaPrimitive *prim = TFormulaPrimitive::FindFormula(cbase, args_paran>0 ? cbase.Data() + args_paran + 1 : (const char*)0);
00447    if (prim &&   (!IsA()->GetBaseClass("TTreeFormula"))) {
00448       // TO BE DONE ALSO IN TTREFORMULA - temporary fix MI
00449       // Analyze the arguments
00450       TIter next(&argArr);
00451       TObjString *objstr;
00452       while ( (objstr=(TObjString*)next()) ) {
00453          Analyze(objstr->String(),err,offset); if (err) return kFALSE;
00454       }
00455       if (nargs!=prim->fNArguments) {
00456          Error("Compile",        "%s requires %d arguments",
00457             prim->GetName(), prim->fNArguments);
00458          return kFALSE;
00459       }
00460       fExpr[fNoper] = prim->GetName();
00461       if (prim->fType==10){
00462          SetAction(fNoper, kFD1);
00463       }
00464       if (prim->fType==110){
00465          SetAction(fNoper, kFD2);
00466       }
00467       if (prim->fType==1110){
00468          SetAction(fNoper, kFD3);
00469       }
00470       if (prim->fType==-1){
00471          SetAction(fNoper, kFDM);
00472          if (fNpar<prim->fNParameters) fNpar+=prim->fNParameters;
00473       }
00474 
00475       fNoper++;
00476       return kTRUE;
00477    }
00478 
00479    return kFALSE;
00480 }
00481 
00482 
00483 //______________________________________________________________________________
00484 void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset)
00485 {
00486 //*-*-*-*-*-*-*-*-*Analyze a sub-expression in one formula*-*-*-*-*-*-*-*-*-*-*
00487 //*-*              =======================================
00488 //*-*
00489 //*-*   Expressions in one formula are recursively analyzed.
00490 //*-*   Result of analysis is stored in the object tables.
00491 //*-*
00492 //*-*                  Table of function codes and errors
00493 //*-*                  ==================================
00494 //*-*
00495 //*-*   * functions :
00496 //*-*
00497 //*-*     +           1                   pow          20
00498 //*-*     -           2                   sq           21
00499 //*-*     *           3                   sqrt         22
00500 //*-*     /           4                   strstr       23
00501 //*-*     %           5                   min          24
00502 //*-*                                     max          25
00503 //*-*                                     log          30
00504 //*-*     cos         10                  exp          31
00505 //*-*     sin         11                  log10        32
00506 //*-*     tan         12
00507 //*-*     acos        13                  abs          41
00508 //*-*     asin        14                  sign         42
00509 //*-*     atan        15                  int          43
00510 //*-*     atan2       16
00511 //*-*     fmod        17                  rndm         50
00512 //*-*
00513 //*-*     cosh        70                  acosh        73
00514 //*-*     sinh        71                  asinh        74
00515 //*-*     tanh        72                  atanh        75
00516 //*-*
00517 //*-*     expo       100                  gaus        110     gausn  (see note below)
00518 //*-*     expo(0)    100 0                gaus(0)     110 0   gausn(0)
00519 //*-*     expo(1)    100 1                gaus(1)     110 1   gausn(1)
00520 //*-*     xexpo      100 x                xgaus       110 x   xgausn
00521 //*-*     yexpo      101 x                ygaus       111 x   ygausn
00522 //*-*     zexpo      102 x                zgaus       112 x   zgausn
00523 //*-*     xyexpo     105 x                xygaus      115 x   xygausn
00524 //*-*     yexpo(5)   102 5                ygaus(5)    111 5   ygausn(5)
00525 //*-*     xyexpo(2)  105 2                xygaus(2)   115 2   xygausn(2)
00526 //*-*
00527 //*-*     landau      120 x   landaun (see note below)
00528 //*-*     landau(0)   120 0   landaun(0)
00529 //*-*     landau(1)   120 1   landaun(1)
00530 //*-*     xlandau     120 x   xlandaun
00531 //*-*     ylandau     121 x   ylandaun
00532 //*-*     zlandau     122 x   zlandaun
00533 //*-*     xylandau    125 x   xylandaun
00534 //*-*     ylandau(5)  121 5   ylandaun(5)
00535 //*-*     xylandau(2) 125 2   xylandaun(2)
00536 //*-*
00537 //*-*     pol0        130 x               pol1        130 1xx
00538 //*-*     pol0(0)     130 0               pol1(0)     130 100
00539 //*-*     pol0(1)     130 1               pol1(1)     130 101
00540 //*-*     xpol0       130 x               xpol1       130 101
00541 //*-*     ypol0       131 x               ypol1       131 101
00542 //*-*     zpol0       132 x               zpol1       132 1xx
00543 //*-*     ypol0(5)    131 5               ypol1(5)    131 105
00544 //*-*
00545 //*-*     pi          40
00546 //*-*
00547 //*-*     &&          60                  <            64
00548 //*-*     ||          61                  >            65
00549 //*-*     ==          62                  <=           66
00550 //*-*     !=          63                  =>           67
00551 //*-*     !           68
00552 //*-*     ==(string)  76                  &            78
00553 //*-*     !=(string)  77                  |            79
00554 //*-*     <<(shift)   80                  >>(shift)    81
00555 //*_*     ? :         82
00556 //*-*
00557 //*-*   * constants (kConstants) :
00558 //*-*
00559 //*-*    c0  141 1      c1  141 2  etc..
00560 //*-*
00561 //*-*   * strings (kStringConst):
00562 //*-*
00563 //*-*    sX  143 x
00564 //*-*
00565 //*-*   * variables (kFormulaVar) :
00566 //*-*
00567 //*-*     x    144 0      y    144 1      z    144 2      t    144 3
00568 //*-*
00569 //*-*   * parameters :
00570 //*-*
00571 //*-*     [1]        140 1
00572 //*-*     [2]        140 2
00573 //*-*     etc.
00574 //*-*
00575 //*-*   special cases for normalized gaussian or landau distributions
00576 //*-*   =============================================================
00577 //*-*   the expression "gaus" is a substitute for
00578 //*-*     [0]*exp(-0.5*((x-[1])/[2])**2)
00579 //*-*   to obtain a standard normalized gaussian, use "gausn" instead of "gaus"
00580 //*-*   the expression "gausn" is a substitute for
00581 //*-*     [0]*exp(-0.5*((x-[1])/[2])**2)/(sqrt(2*pi)*[2]))
00582 //*-*   WARNING: gaus and gausn are mutually exclusive in the same expression.
00583 //*-*
00584 //*-*   In the same way the expression "landau" is a substitute for
00585 //*-*     [0]*TMath::Landau(x,[1],[2],kFALSE)
00586 //*-*   to obtain a standard normalized landau, use "landaun" instead of "landau"
00587 //*-*   the expression "landaun" is a substitute for
00588 //*-*     [0]*TMath::Landau(x,[1],[2],kTRUE)
00589 //*-*   WARNING: landau and landaun are mutually exclusive in the same expression.
00590 //*-*
00591 //*-*   boolean optimization (kBoolOptmize) :
00592 //*-*   =====================================
00593 //*-*
00594 //*-*     Those pseudo operation are used to implement lazy evaluation of
00595 //*-*     && and ||.  When the left hand of the expression if false
00596 //*-*     (respectively true), the evaluation of the right is entirely skipped
00597 //*-*     (since it would not change the value of the expreession).
00598 //*-*
00599 //*-*     &&   142 11 (one operation on right) 142 21 (2 operations on right)
00600 //*-*     ||   142 12 (one operation on right) 142 22 (2 operations on right)
00601 //*-*
00602 //*-*   * functions calls (kFunctionCall) :
00603 //*-*
00604 //*-*    f0 145  0  f1 145  1  etc..
00605 //*-*
00606 //*-*   errors :
00607 //*-*   ========
00608 //*-*
00609 //*-*     1  : Division By Zero
00610 //*-*     2  : Invalid Floating Point Operation
00611 //*-*     4  : Empty String
00612 //*-*     5  : invalid syntax
00613 //*-*     6  : Too many operators
00614 //*-*     7  : Too many parameters
00615 //*-*    10  : z specified but not x and y
00616 //*-*    11  : z and y specified but not x
00617 //*-*    12  : y specified but not x
00618 //*-*    13  : z and x specified but not y
00619 //*-*    20  : non integer value for parameter number
00620 //*-*    21  : atan2 requires two arguments
00621 //*-*    22  : pow requires two arguments
00622 //*-*    23  : degree of polynomial not specified
00623 //*-*    24  : Degree of polynomial must be positive
00624 //*-*    25  : Degree of polynomial must be less than 20
00625 //*-*    26  : Unknown name
00626 //*-*    27  : Too many constants in expression
00627 //*-*    28  : strstr requires two arguments
00628 //*-*    29  : interpreted or compiled function have to return a numerical type
00629 //*-*    30  : Bad numerical expression
00630 //*-*    31  : Part of the variable exist but some of it is not accessible or useable
00631 //*-*    40  : '(' is expected
00632 //*-*    41  : ')' is expected
00633 //*-*    42  : '[' is expected
00634 //*-*    43  : ']' is expected
00635 //Begin_Html
00636 /*
00637 <img src="gif/analyze.gif">
00638 */
00639 //End_Html
00640 //*-*
00641 //*-*  Special functions
00642 //*-*  -----------------
00643 //*-*  By default, the formula is assigned fNumber=0. However, the following
00644 //*-*  formula built with simple functions are assigned  fNumber:
00645 //*-*    "gaus"      100  (or gausn)
00646 //*-*    "xygaus"    110
00647 //*-*    "expo"      200
00648 //*-*    "polN"      300+N
00649 //*-*    "landau"    400
00650 //*-*    "xylandau"  410
00651 //*-*  Note that expressions like gaus(0), expo(1) will force fNumber=0
00652 //*-*
00653 //*-*  Warning when deriving a class from TFormula
00654 //*-*  -------------------------------------------
00655 //*-*   If you overload this member function, you also HAVE TO
00656 //*-*   never call the constructor:
00657 //*-*
00658 //*-*     TFormula::TFormula(const char *name,const char *expression)
00659 //*-*
00660 //*-*   and write your own constructor
00661 //*-*
00662 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
00663 //*-*
00664 //*-*   which has to call the TFormula default constructor and whose implementation
00665 //*-*   should be similar to the implementation of the normal TFormula constructor
00666 //*-*
00667 //*-*   This is necessary because the normal TFormula constructor call indirectly
00668 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
00669 //*-*   and DefaultVariable.
00670 //*-*
00671 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
00672 
00673 
00674    Int_t valeur,find,n,i,j,k,lchain,nomb,virgule,inter,nest;
00675    Int_t compt,compt2,compt3,compt4;
00676    Bool_t inString;
00677    Double_t vafConst;
00678    ULong_t vafConst2;
00679    Bool_t parenthese;
00680    TString s,chaine_error,chaine1ST;
00681    TString s1,s2,s3,ctemp;
00682 
00683    TString chaine = schain;
00684    TFormula *oldformula;
00685    Int_t modulo,plus,puiss10,puiss10bis,moins,multi,divi,puiss,et,ou,petit,grand,egal,diff,peteg,grdeg,etx,oux,rshift,lshift,tercond,terelse;
00686    char t;
00687    TString slash("/"), escapedSlash("\\/");
00688    Int_t inter2 = 0;
00689    SetNumber(0);
00690    Int_t actionCode,actionParam;
00691    Int_t err_hint = 0;
00692 
00693 //*-*- Verify correct matching of parenthesis and remove unnecessary parenthesis.
00694 //*-*  ========================================================================
00695    lchain = chaine.Length();
00696    //if (chaine(lchain-2,2) == "^2") chaine = "sq(" + chaine(0,lchain-2) + ")";
00697    parenthese = kTRUE;
00698    lchain = chaine.Length();
00699    while (parenthese && lchain>0 && err==0){
00700       compt  = 0;
00701       compt2 = 0;
00702       inString = false;
00703       lchain = chaine.Length();
00704       if (lchain==0) err=4;
00705       else {
00706          for (i=1; i<=lchain; ++i) {
00707             if (chaine(i-1,1) == "\"") inString = !inString;
00708             if (!inString) {
00709                if (chaine(i-1,1) == "[") compt2++;
00710                if (chaine(i-1,1) == "]") compt2--;
00711                if (chaine(i-1,1) == "(") compt++;
00712                if (chaine(i-1,1) == ")") compt--;
00713             }
00714             if (compt < 0) err = 40; // more open parentheses than close parentheses
00715             if (compt2< 0) err = 42; // more ] than [
00716             if (compt==0 && (i!=lchain || lchain==1)) parenthese = kFALSE;
00717             // if (lchain<3 && chaine(0,1)!="(" && chaine(lchain-1,1)!=")") parenthese = kFALSE;
00718          }
00719          if (compt > 0) err = 41; // more ( than )
00720          if (compt2> 0) err = 43; // more [ than ]
00721          if (parenthese) chaine = chaine(1,lchain-2);
00722       }
00723    } // while parantheses
00724 
00725    if (lchain==0) err=4; // empty string
00726    modulo=plus=moins=multi=divi=puiss=et=ou=petit=grand=egal=diff=peteg=grdeg=etx=oux=rshift=lshift=tercond=terelse=0;
00727 
00728 //*-*- Look for simple operators
00729 //*-*  =========================
00730 
00731    if (err==0) {
00732       compt = compt2 = compt3 = compt4 = 0;puiss10=0;puiss10bis = 0;
00733       inString = false;
00734       j = lchain;
00735       Bool_t isdecimal = 1; // indicates whether the left part is decimal.
00736 
00737       for (i=1;i<=lchain; i++) {
00738 
00739          puiss10=puiss10bis=0;
00740          if (i>2) {
00741             t = chaine[i-3];
00742             isdecimal = isdecimal && (strchr("0123456789.",t)!=0);
00743             if (isdecimal) {
00744                if ( chaine[i-2] == 'e' || chaine[i-2] == 'E' ) puiss10 = 1;
00745             } else if ( strchr("+-/[]()&|><=!*/%^\\",t) ) {
00746                isdecimal = 1; // reset after delimiter
00747             }
00748          }
00749          if (j>2) {
00750             if (chaine[j-2] == 'e' || chaine[j-2] == 'E') {
00751                Bool_t isrightdecimal = 1;
00752 
00753                for(k=j-3; k>=0 && isrightdecimal; --k) {
00754                   t = chaine[k];
00755                   isrightdecimal = isrightdecimal && (strchr("0123456789.",t)!=0);
00756                   if (!isrightdecimal) {
00757                      if (strchr("+-/[]()&|><=!*/%^\\",t)!=0) {
00758                         puiss10bis = 1;
00759                      }
00760                   }
00761                }
00762                if (k<0 && isrightdecimal)  puiss10bis = 1;
00763             }
00764          }
00765          if (puiss10 && (i<=lchain)) {
00766             t = chaine[i];
00767             puiss10 = (strchr("0123456789.",t)!=0);
00768          }
00769          if (puiss10bis && (j<=lchain)) {
00770             t = chaine[j];
00771             puiss10bis = (strchr("0123456789.",t)!=0);
00772          }
00773 
00774          if (chaine(i-1,1) == "\"") inString = !inString;
00775          if (inString) continue;
00776          if (chaine(i-1,1) == "[") compt2++;
00777          if (chaine(i-1,1) == "]") compt2--;
00778          if (chaine(i-1,1) == "(") compt++;
00779          if (chaine(i-1,1) == ")") compt--;
00780          if (chaine(j-1,1) == "[") compt3++;
00781          if (chaine(j-1,1) == "]") compt3--;
00782          if (chaine(j-1,1) == "(") compt4++;
00783          if (chaine(j-1,1) == ")") compt4--;
00784          if (chaine(i-1,2)=="&&" && !inString && compt==0 && compt2==0 && et==0) {et=i;puiss=0;}
00785          if (chaine(i-1,2)=="||" && compt==0 && compt2==0 && ou==0) {puiss10=0; ou=i;}
00786          if (chaine(i-1,1)=="&"  && compt==0 && compt2==0 && etx==0) {etx=i;puiss=0;}
00787          if (chaine(i-1,1)=="|"  && compt==0 && compt2==0 && oux==0) {puiss10=0; oux=i;}
00788          if (chaine(i-1,2)==">>" && compt==0 && compt2==0 && rshift==0) {puiss10=0; rshift=i;}
00789          if (chaine(i-1,1)==">"  && compt==0 && compt2==0 && rshift==0 && grand==0)
00790             {puiss10=0; grand=i;}
00791          if (chaine(i-1,2)=="<<" && compt==0 && compt2==0 && lshift==0) {puiss10=0; lshift=i;}
00792          if (chaine(i-1,1)=="<"  && compt==0 && compt2==0 && lshift==0 && petit==0)
00793             {puiss10=0; petit=i;
00794             // Check whether or not we have a template names! (actually this can
00795             // only happen in TTreeFormula.
00796             for(int ip = i,depth=0; ip < lchain; ++ip) {
00797                char c = chaine(ip);
00798                // The characteres allowed in the template parameter are alpha-numerical characters,
00799                // underscores, comma, <, > and scope operator.
00800                if (isalnum(c) || c=='_' || c==',') continue;
00801                if (c==':' && chaine(ip+1)==':') { ++ip; continue; }
00802                if (c=='<') { ++depth; continue; }
00803                if (c=='>') {
00804                   if (depth) { --depth; continue; }
00805                   else {
00806                      // We reach the end of the template parameter.
00807                      petit = 0;
00808                      i = ip+1;
00809                      break;
00810                   }
00811                }
00812                // Character not authorized within a template parameter
00813                break;
00814             }
00815             if (petit==0) {
00816                // We found a template parameter and modified i
00817                continue; // the for(int i ,...)
00818             }
00819          }
00820          if ((chaine(i-1,2)=="<=" || chaine(i-1,2)=="=<") && compt==0 && compt2==0
00821             && peteg==0) {peteg=i; puiss10=0; petit=0;}
00822          if ((chaine(i-1,2)=="=>" || chaine(i-1,2)==">=") && compt==0 && compt2==0
00823             && grdeg==0) {puiss10=0; grdeg=i; grand=0;}
00824          if (chaine(i-1,2) == "==" && compt == 0 && compt2 == 0 && egal == 0) {puiss10=0; egal=i;}
00825          if (chaine(i-1,2) == "!=" && compt == 0 && compt2 == 0 && diff == 0) {puiss10=0; diff=i;}
00826          if (i>1 && chaine(i-1,1) == "+" && compt == 0 && compt2 == 0 && puiss10==0) plus=i;
00827          if (chaine(j-1,1) == "-" && chaine(j-2,1) != "*" && chaine(j-2,1) != "/"
00828             && chaine(j-2,1)!="^" && compt3==0 && compt4==0 && moins==0 && puiss10bis==0) moins=j;
00829          if (chaine(i-1,1)=="%" && compt==0 && compt2==0 && modulo==0) {puiss10=0; modulo=i;}
00830          if (chaine(i-1,1)=="*" && compt==0 && compt2==0 && multi==0)  {puiss10=0; multi=i;}
00831          if (chaine(j-1,1)=="/" && chaine(j-2,1)!="\\"
00832             && compt4==0 && compt3==0 && divi==0)
00833          {
00834             puiss10=0; divi=j;
00835          }
00836          if (chaine(j-1)=='^' && compt4==0 && compt3==0 && puiss==0) {puiss10=0; puiss=j;}
00837          if (chaine(i-1)=='?' && compt == 0 && compt2 == 0 && tercond == 0) {puiss10=0; tercond=i;}
00838          if (chaine(i-1)==':' && tercond && compt == 0 && compt2 == 0 && terelse == 0) {
00839             if (i>2 && chaine(i-2)!=':' && chaine(i)!=':') {
00840                puiss10=0; terelse=i;
00841             }
00842          }
00843 
00844          j--;
00845       }
00846 
00847 //*-*- If operator found, analyze left and right part of the statement
00848 //*-*  ===============================================================
00849 
00850       enum { kIsCharacter = BIT(12) };
00851       actionParam = 0;
00852       if (tercond && terelse) {
00853          if (tercond == 1 || terelse == lchain || tercond == (terelse-1) ) {
00854             err = 5;
00855             chaine_error = "?:";
00856          } else {
00857             // Condition
00858             ctemp = chaine(0,tercond-1);
00859             Analyze(ctemp.Data(),err,offset); if (err) return;
00860 
00861             fExpr[fNoper] = "?: condition jump";
00862             actionCode = kJumpIf;
00863             actionParam = 0;
00864             SetAction(fNoper,actionCode, actionParam);
00865             Int_t optloc = fNoper++;
00866 
00867             // Expression executed if condition is true.
00868             ctemp = chaine(tercond,terelse-tercond-1);
00869             Analyze(ctemp.Data(),err,offset); if (err) return;
00870             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
00871             SetAction(optloc, actionCode, actionParam);
00872 
00873             fExpr[fNoper] = "?: else jump";
00874             actionCode = kJump;
00875             actionParam = 0;
00876             // Set jump target.
00877             SetAction(fNoper,actionCode, actionParam);
00878             optloc = fNoper++;
00879 
00880             // Expression executed if condition is false.
00881             ctemp = chaine(terelse,lchain-terelse);
00882             Analyze(ctemp.Data(),err,offset); if (err) return;
00883             // Set jump target.
00884             actionParam = fNoper - 1; // We need to not skip the next instruction, so we compensate for the ++i in the eval loop
00885             SetAction(optloc, actionCode, actionParam);
00886 
00887             if (IsString(optloc-1) != IsString(fNoper-1)) {
00888                err = 45;
00889                chaine_error = "?:";
00890             }
00891          }
00892       } else if (ou != 0) {    //check for ||
00893          if (ou==1 || ou==lchain-1) {
00894             err=5;
00895             chaine_error="||";
00896          }
00897          else {
00898             ctemp = chaine(0,ou-1);
00899             Analyze(ctemp.Data(),err,offset); if (err) return;
00900 
00901             fExpr[fNoper] = "|| checkpoint";
00902             actionCode = kBoolOptimize;
00903             actionParam = 2;
00904             SetAction(fNoper,actionCode, actionParam);
00905             Int_t optloc = fNoper++;
00906 
00907             ctemp = chaine(ou+1,lchain-ou-1);
00908             Analyze(ctemp.Data(),err,offset); if (err) return;
00909             fExpr[fNoper] = "||";
00910             actionCode = kOr;
00911             SetAction(fNoper,actionCode, 0);
00912 
00913             SetAction( optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
00914             fNoper++;
00915             if (!CheckOperands(optloc-1,fNoper-1,err)) return;
00916          }
00917       } else if (et!=0) {
00918          if (et==1 || et==lchain-1) {
00919             err=5;
00920             chaine_error="&&";
00921          }
00922          else {
00923             ctemp = chaine(0,et-1);
00924             Analyze(ctemp.Data(),err,offset); if (err) return;
00925 
00926             fExpr[fNoper] = "&& checkpoint";
00927             actionCode = kBoolOptimize;
00928             actionParam = 1;
00929             SetAction(fNoper,actionCode,actionParam);
00930 
00931             Int_t optloc = fNoper++;
00932 
00933             ctemp = chaine(et+1,lchain-et-1);
00934             Analyze(ctemp.Data(),err,offset); if (err) return;
00935             fExpr[fNoper] = "&&";
00936             actionCode = kAnd;
00937             SetAction(fNoper,actionCode,0);
00938 
00939             SetAction(optloc, GetAction(optloc), GetActionParam(optloc) + (fNoper-optloc) * 10);
00940             fNoper++;
00941             if (!CheckOperands(optloc-1,fNoper-1,err)) return;
00942          }
00943       } else if (oux!=0) {
00944          if (oux==1 || oux==lchain) {
00945             err=5;
00946             chaine_error="|";
00947          }
00948          else {
00949             ctemp = chaine(0,oux-1);
00950             Analyze(ctemp.Data(),err,offset); if (err) return;
00951             UInt_t leftopr = fNoper-1;
00952             ctemp = chaine(oux,lchain-oux);
00953             Analyze(ctemp.Data(),err,offset); if (err) return;
00954             fExpr[fNoper] = "|";
00955             actionCode = kBitOr;
00956             SetAction(fNoper,actionCode,actionParam);
00957             fNoper++;
00958             if (!CheckOperands(leftopr,fNoper-1,err)) return;
00959          }
00960       } else if (etx!=0) {
00961          if (etx==1 || etx==lchain) {
00962             err=5;
00963             chaine_error="&";
00964          }
00965          else {
00966             ctemp = chaine(0,etx-1);
00967             Analyze(ctemp.Data(),err,offset); if (err) return;
00968             UInt_t leftopr = fNoper-1;
00969             ctemp = chaine(etx,lchain-etx);
00970             Analyze(ctemp.Data(),err,offset); if (err) return;
00971             fExpr[fNoper] = "&";
00972             actionCode = kBitAnd;
00973             SetAction(fNoper,actionCode,actionParam);
00974             fNoper++;
00975             if (!CheckOperands(leftopr,fNoper-1,err)) return;
00976          }
00977       } else if (petit != 0) {
00978          if (petit==1 || petit==lchain) {
00979             err=5;
00980             chaine_error="<";
00981          }
00982          else {
00983             ctemp = chaine(0,petit-1);
00984             Analyze(ctemp.Data(),err,offset); if (err) return;
00985             UInt_t leftopr = fNoper-1;
00986             ctemp = chaine(petit,lchain-petit);
00987             Analyze(ctemp.Data(),err,offset); if (err) return;
00988             fExpr[fNoper] = "<";
00989             actionCode = kLess;
00990             SetAction(fNoper,actionCode,actionParam);
00991             fNoper++;
00992             if (!CheckOperands(leftopr,fNoper-1,err)) return;
00993          }
00994       } else if (grand != 0) {
00995          if (grand==1 || grand==lchain) {
00996             err=5;
00997             chaine_error=">";
00998          }
00999          else {
01000             ctemp = chaine(0,grand-1);
01001             Analyze(ctemp.Data(),err,offset); if (err) return;
01002             UInt_t leftopr = fNoper-1;
01003             ctemp = chaine(grand,lchain-grand);
01004             Analyze(ctemp.Data(),err,offset); if (err) return;
01005             fExpr[fNoper] = ">";
01006             actionCode = kGreater;
01007             SetAction(fNoper,actionCode,actionParam);
01008             fNoper++;
01009             if (!CheckOperands(leftopr,fNoper-1,err)) return;
01010          }
01011       } else if (peteg != 0) {
01012          if (peteg==1 || peteg==lchain-1) {
01013             err=5;
01014             chaine_error="<=";
01015          }
01016          else {
01017             ctemp = chaine(0,peteg-1);
01018             Analyze(ctemp.Data(),err,offset); if (err) return;
01019             ctemp = chaine(peteg+1,lchain-peteg-1);
01020             UInt_t leftopr = fNoper-1;
01021             Analyze(ctemp.Data(),err,offset); if (err) return;
01022             fExpr[fNoper] = "<=";
01023             actionCode = kLessThan;
01024             SetAction(fNoper,actionCode,actionParam);
01025             fNoper++;
01026             if (!CheckOperands(leftopr,fNoper-1,err)) return;
01027          }
01028       } else if (grdeg != 0) {
01029          if (grdeg==1 || grdeg==lchain-1) {
01030             err=5;
01031             chaine_error="=>";
01032          }
01033          else {
01034             ctemp = chaine(0,grdeg-1);
01035             Analyze(ctemp.Data(),err,offset); if (err) return;
01036             UInt_t leftopr = fNoper-1;
01037             ctemp = chaine(grdeg+1,lchain-grdeg-1);
01038             Analyze(ctemp.Data(),err,offset); if (err) return;
01039             fExpr[fNoper] = ">=";
01040             actionCode = kGreaterThan;
01041             SetAction(fNoper,actionCode,actionParam);
01042             fNoper++;
01043             if (!CheckOperands(leftopr,fNoper-1,err)) return;
01044          }
01045       } else if (egal != 0) {
01046          if (egal==1 || egal==lchain-1) {
01047             err=5;
01048             chaine_error="==";
01049          }
01050          else {
01051             ctemp = chaine(0,egal-1);
01052             Analyze(ctemp.Data(),err,offset); if (err) return;
01053             Int_t optloc = fNoper-1;
01054 
01055             ctemp = chaine(egal+1,lchain-egal-1);
01056             Analyze(ctemp.Data(),err,offset); if (err) return;
01057             fExpr[fNoper] = "==";
01058             actionCode = kEqual;
01059 
01060             Bool_t isstring = IsString(fNoper-1);
01061             if (IsString(optloc) != isstring) {
01062                err = 45;
01063                chaine_error = "==";
01064             } else if (isstring) {
01065                actionCode = kStringEqual;
01066                SetBit(kIsCharacter);
01067             }
01068             SetAction(fNoper,actionCode,actionParam);
01069             fNoper++;
01070          }
01071       } else if (diff != 0) {
01072          if (diff==1 || diff==lchain-1) {
01073             err=5;
01074             chaine_error = "!=";
01075          }
01076          else {
01077             ctemp = chaine(0,diff-1);
01078             Analyze(ctemp.Data(),err,offset); if (err) return;
01079             Int_t optloc = fNoper-1;
01080 
01081             ctemp = chaine(diff+1,lchain-diff-1);
01082             Analyze(ctemp.Data(),err,offset); if (err) return;
01083             fExpr[fNoper] = "!=";
01084             actionCode = kNotEqual;
01085 
01086             Bool_t isstring = IsString(fNoper-1);
01087             if (IsString(optloc) != isstring) {
01088                err = 45;
01089                chaine_error = "!=";
01090             } else if (isstring) {
01091                actionCode = kStringNotEqual;
01092                SetBit(kIsCharacter);
01093             }
01094             SetAction(fNoper,actionCode,actionParam);
01095             fNoper++;
01096          }
01097       } else if (plus != 0) {
01098          if (plus==lchain) {
01099             err=5;
01100             chaine_error = "+";
01101          }
01102          else {
01103             ctemp = chaine(0,plus-1);
01104             Analyze(ctemp.Data(),err,offset); if (err) return;
01105             UInt_t leftopr = fNoper-1;
01106             ctemp = chaine(plus,lchain-plus);
01107             Analyze(ctemp.Data(),err,offset); if (err) return;
01108             fExpr[fNoper] = "+";
01109             actionCode = kAdd;
01110             SetAction(fNoper,actionCode,actionParam);
01111             fNoper++;
01112             if (!CheckOperands(leftopr,fNoper-1,err)) return;
01113          }
01114       } else {
01115          if (moins != 0) {
01116             if (moins == 1) {
01117                ctemp = chaine(moins,lchain-moins);
01118                Analyze(ctemp.Data(),err,offset); if (err) return;
01119                fExpr[fNoper] = "-";
01120                actionCode = kSignInv;
01121                SetAction(fNoper,actionCode,actionParam);
01122                ++fNoper;
01123                if (!CheckOperands(fNoper-1,err)) return;
01124             } else {
01125                if (moins == lchain) {
01126                   err=5;
01127                   chaine_error = "-";
01128                } else {
01129                   ctemp = chaine(0,moins-1);
01130                   Analyze(ctemp.Data(),err,offset); if (err) return;
01131                   UInt_t leftopr = fNoper-1;
01132                   ctemp = chaine(moins,lchain-moins);
01133                   Analyze(ctemp.Data(),err,offset); if (err) return;
01134                   fExpr[fNoper] = "-";
01135                   actionCode = kSubstract;
01136                   SetAction(fNoper,actionCode,actionParam);
01137                   fNoper++;
01138                   if (!CheckOperands(leftopr,fNoper-1,err)) return;
01139                }
01140             }
01141          } else if (modulo != 0) {
01142             if (modulo == 1 || modulo == lchain) {
01143                err=5;
01144                chaine_error="%";
01145             } else {
01146                ctemp = chaine(0,modulo-1);
01147                Analyze(ctemp.Data(),err,offset); if (err) return;
01148                UInt_t leftopr = fNoper-1;
01149                ctemp = chaine(modulo,lchain-modulo);
01150                Analyze(ctemp.Data(),err,offset); if (err) return;
01151                fExpr[fNoper] = "%";
01152                actionCode = kModulo;
01153                SetAction(fNoper,actionCode,actionParam);
01154                fNoper++;
01155                if (!CheckOperands(leftopr,fNoper-1,err)) return;
01156             }
01157          } else if (rshift != 0) {
01158             if (rshift == 1 || rshift == lchain) {
01159                err=5;
01160                chaine_error=">>";
01161             } else {
01162                ctemp = chaine(0,rshift-1);
01163                Analyze(ctemp.Data(),err,offset); if (err) return;
01164                UInt_t leftopr = fNoper-1;
01165                ctemp = chaine(rshift+1,lchain-rshift-1);
01166                Analyze(ctemp.Data(),err,offset); if (err) return;
01167                fExpr[fNoper] = ">>";
01168                actionCode = kRightShift;
01169                SetAction(fNoper,actionCode,actionParam);
01170                fNoper++;
01171                if (!CheckOperands(leftopr,fNoper-1,err)) return;
01172             }
01173          } else if (lshift != 0) {
01174             if (lshift == 1 || lshift == lchain) {
01175                err=5;
01176                chaine_error=">>";
01177             } else {
01178                ctemp = chaine(0,lshift-1);
01179                Analyze(ctemp.Data(),err,offset); if (err) return;
01180                UInt_t leftopr = fNoper-1;
01181                ctemp = chaine(lshift+1,lchain-lshift-1);
01182                Analyze(ctemp.Data(),err,offset); if (err) return;
01183                fExpr[fNoper] = ">>";
01184                actionCode = kLeftShift;
01185                SetAction(fNoper,actionCode,actionParam);
01186                fNoper++;
01187                if (!CheckOperands(leftopr,fNoper-1,err)) return;
01188             }
01189          } else {
01190             if (multi != 0) {
01191                if (multi == 1 || multi == lchain) {
01192                err=5;
01193                chaine_error="*";
01194             }
01195             else {
01196                ctemp = chaine(0,multi-1);
01197                Analyze(ctemp.Data(),err,offset); if (err) return;
01198                UInt_t leftopr = fNoper-1;
01199                ctemp = chaine(multi,lchain-multi);
01200                Analyze(ctemp.Data(),err,offset); if (err) return;
01201                fExpr[fNoper] = "*";
01202                actionCode = kMultiply;
01203                SetAction(fNoper,actionCode,actionParam);
01204                fNoper++;
01205                if (!CheckOperands(leftopr,fNoper-1,err)) return;
01206             }
01207          } else {
01208             if (divi != 0) {
01209                if (divi == 1 || divi == lchain) {
01210                   err=5;
01211                   chaine_error = "/";
01212                }
01213                else {
01214                   ctemp = chaine(0,divi-1);
01215                   Analyze(ctemp.Data(),err,offset); if (err) return;
01216                   UInt_t leftopr = fNoper-1;
01217                   ctemp = chaine(divi,lchain-divi);
01218                   Analyze(ctemp.Data(),err,offset); if (err) return;
01219                   fExpr[fNoper] = "/";
01220                   actionCode = kDivide;
01221                   SetAction(fNoper,actionCode,actionParam);
01222                   fNoper++;
01223                   if (!CheckOperands(leftopr,fNoper-1,err)) return;
01224                }
01225             } else {
01226                if (puiss != 0) {
01227                   if (puiss == 1 || puiss == lchain) {
01228                      err = 5;
01229                      chaine_error = "**";
01230                   }
01231                   else {
01232                      if (chaine(lchain-2,2) == "^2") {
01233                         ctemp = "sq(" + chaine(0,lchain-2) + ")";
01234                         Analyze(ctemp.Data(),err,offset); if (err) return;
01235                      } else {
01236                         ctemp = chaine(0,puiss-1);
01237                         Analyze(ctemp.Data(),err,offset); if (err) return;
01238                         UInt_t leftopr = fNoper-1;
01239                         ctemp = chaine(puiss,lchain-puiss);
01240                         Analyze(ctemp.Data(),err,offset); if (err) return;
01241                         fExpr[fNoper] = "^";
01242                         actionCode = kpow;
01243                         SetAction(fNoper,actionCode,actionParam);
01244                         fNoper++;
01245                         if (!CheckOperands(leftopr,fNoper-1,err)) return;
01246                      }
01247                   }
01248                } else {
01249 
01250                   find=0;
01251 
01252 //*-*- Check for a numerical expression
01253                   {
01254                      Bool_t hasDot = kFALSE;
01255                      Bool_t isHexa = kFALSE;
01256                      Bool_t hasExpo= kFALSE;
01257                      if ((chaine(0,2)=="0x")||(chaine(0,2)=="0X")) isHexa=kTRUE;
01258                      for (j=0; j<chaine.Length() && err==0; j++) {
01259                         t=chaine[j];
01260                         if (!isHexa) {
01261                            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-")) {
01262                               if (hasExpo) {
01263                                  err=26;
01264                                  chaine_error=chaine;
01265                               }
01266                               hasExpo = kTRUE;
01267                               // The previous implementation allowed a '.' in the exponent.
01268                               // That information was ignored (by sscanf), we now make it an error
01269                               // hasDot = kFALSE;
01270                               hasDot = kTRUE;  // forbid any additional '.'
01271                               if (chaine(j,2)=="e+" || chaine(j,2)=="e-" || chaine(j,2)=="E+" || chaine(j,2)=="E-") j++;
01272                            }
01273                            else {
01274                               if (chaine(j,1) == "." && !hasDot) hasDot = kTRUE; // accept only one '.' in the number
01275                               else {
01276                                  // The previous implementation was allowing ANYTHING after the '.' and thus
01277                                  // made legal code like '2.3 and fpx' and was just silently ignoring the
01278                                  // 'and fpx'.
01279                                  if (!strchr("0123456789",t) && (chaine(j,1)!="+" || j!=0)) {
01280                                     err = 30;
01281                                     chaine_error=chaine;
01282                                  }
01283                               }
01284                            }
01285                         }
01286                         else {
01287                            if (!strchr("0123456789abcdefABCDEF",t) && (j>1)) {
01288                               err = 30;
01289                               chaine_error=chaine;
01290                            }
01291                         }
01292                      }
01293                      if (fNconst >= gMAXCONST) err = 27;
01294                      if (!err) {
01295                         if (!isHexa) {if (sscanf((const char*)chaine,"%lg",&vafConst) > 0) err = 0; else err =1;}
01296                         else {if (sscanf((const char*)chaine,"%lx",&vafConst2) > 0) err = 0; else err=1;
01297                         vafConst = (Double_t) vafConst2;}
01298                         fExpr[fNoper] = chaine;
01299                         k = -1;
01300                         for (j=0;j<fNconst;j++) {
01301                            if (vafConst == fConst[j] ) k= j;
01302                         }
01303                         if ( k < 0) {  k = fNconst; fNconst++; fConst[k] = vafConst; }
01304                         actionCode = kConstant;
01305                         actionParam = k;
01306                         SetAction(fNoper,actionCode,actionParam);
01307                         fNoper++;
01308                      }
01309                      if (err==30) err=0;
01310                      else find = kTRUE;
01311                   }
01312 
01313 
01314 //*-*- Look for an already defined expression
01315                   if (find==0) {
01316                      oldformula = (TFormula*)gROOT->GetListOfFunctions()->FindObject((const char*)chaine);
01317                      if (oldformula && strcmp(schain,oldformula->GetTitle())) {
01318                         Int_t nprior = fNpar;
01319                         Analyze(oldformula->GetExpFormula(),err,fNpar);
01320 
01321                         if (err) return; // changes fNpar
01322                         fNpar = nprior;
01323                         find=1;
01324                         if (!err) {
01325                            Int_t npold = oldformula->GetNpar();
01326                            fNpar += npold;
01327                            for (Int_t ipar=0;ipar<npold;ipar++) {
01328                               fParams[ipar+fNpar-npold] = oldformula->GetParameter(ipar);
01329                            }
01330                         }
01331                      }
01332                   }
01333                   if (find == 0) {
01334 //*-*- Check if chaine is a defined variable.
01335 //*-*- Note that DefinedVariable can be overloaded
01336                      ctemp = chaine;
01337                      ctemp.ReplaceAll(escapedSlash, slash);
01338                      Int_t action;
01339                      k = DefinedVariable(ctemp,action);
01340                      if (k==-3) {
01341                         // Error message already issued
01342                         err = 1;
01343                      } if (k==-2) {
01344                         err = 31;
01345                         chaine_error = ctemp;
01346                      } else if ( k >= 0 ) {
01347                         fExpr[fNoper] = ctemp;
01348                         actionCode = action;
01349                         actionParam = k;
01350                         SetAction(fNoper,actionCode,actionParam);
01351                         if (action==kDefinedString) fNstring++;
01352                         else if (k <kMAXFOUND && !fAlreadyFound.TestBitNumber(k)) {
01353                            fAlreadyFound.SetBitNumber(k);
01354                            fNval++;
01355                         }
01356                         fNoper++;
01357                      } else if (chaine(0,1) == "!") {
01358                         ctemp = chaine(1,lchain-1);
01359                         Analyze(ctemp.Data(),err,offset); if (err) return;
01360                         fExpr[fNoper] = "!";
01361                         actionCode = kNot;
01362                         SetAction(fNoper,actionCode,actionParam);
01363                         fNoper++;
01364                         if (!CheckOperands(fNoper-1,err)) return;
01365                      } else if (chaine(0,1)=="\"" && chaine(chaine.Length()-1,1)=="\"") {
01366                         //*-* It is a string !!!
01367                         fExpr[fNoper] = chaine(1,chaine.Length()-2);
01368                         actionCode = kStringConst;
01369                         SetAction(fNoper,actionCode,actionParam);
01370                         fNoper++;
01371                      } else if (chaine(0,4) == "cos(") {
01372                         ctemp = chaine(3,lchain-3);
01373                         Analyze(ctemp.Data(),err,offset); if (err) return;
01374                         fExpr[fNoper] = "cos";
01375                         actionCode = kcos;
01376                         SetAction(fNoper,actionCode,actionParam);
01377                         fNoper++;
01378                         if (!CheckOperands(fNoper-1,err)) return;
01379                      } else if (chaine(0,4) == "sin(") {
01380                         ctemp = chaine(3,lchain-3);
01381                         Analyze(ctemp.Data(),err,offset); if (err) return;
01382                         fExpr[fNoper] = "sin";
01383                         actionCode = ksin;
01384                         SetAction(fNoper,actionCode,actionParam);
01385                         fNoper++;
01386                         if (!CheckOperands(fNoper-1,err)) return;
01387                      } else if (chaine(0,4) == "tan(") {
01388                         ctemp = chaine(3,lchain-3);
01389                         Analyze(ctemp.Data(),err,offset); if (err) return;
01390                         fExpr[fNoper] = "tan";
01391                         actionCode = ktan;
01392                         SetAction(fNoper,actionCode,actionParam);
01393                         fNoper++;
01394                         if (!CheckOperands(fNoper-1,err)) return;
01395                      } else if (chaine(0,5) == "acos(") {
01396                         ctemp = chaine(4,lchain-4);
01397                         Analyze(ctemp.Data(),err,offset); if (err) return;
01398                         fExpr[fNoper] = "acos";
01399                         actionCode = kacos;
01400                         SetAction(fNoper,actionCode,actionParam);
01401                         fNoper++;
01402                         if (!CheckOperands(fNoper-1,err)) return;
01403                      } else if (chaine(0,5) == "asin(") {
01404                         ctemp = chaine(4,lchain-4);
01405                         Analyze(ctemp.Data(),err,offset); if (err) return;
01406                         fExpr[fNoper] = "asin";
01407                         actionCode = kasin;
01408                         SetAction(fNoper,actionCode,actionParam);
01409                         fNoper++;
01410                         if (!CheckOperands(fNoper-1,err)) return;
01411                      } else if (chaine(0,5) == "atan(") {
01412                         ctemp = chaine(4,lchain-4);
01413                         Analyze(ctemp.Data(),err,offset); if (err) return;
01414                         fExpr[fNoper] = "atan";
01415                         actionCode = katan;
01416                         SetAction(fNoper,actionCode,actionParam);
01417                         fNoper++;
01418                         if (!CheckOperands(fNoper-1,err)) return;
01419                      } else if (chaine(0,5) == "cosh(") {
01420                         ctemp = chaine(4,lchain-4);
01421                         Analyze(ctemp.Data(),err,offset); if (err) return;
01422                         fExpr[fNoper] = "cosh";
01423                         actionCode = kcosh;
01424                         SetAction(fNoper,actionCode,actionParam);
01425                         fNoper++;
01426                         if (!CheckOperands(fNoper-1,err)) return;
01427                      } else if (chaine(0,5) == "sinh(") {
01428                         ctemp = chaine(4,lchain-4);
01429                         Analyze(ctemp.Data(),err,offset); if (err) return;
01430                         fExpr[fNoper] = "sinh";
01431                         actionCode = ksinh;
01432                         SetAction(fNoper,actionCode,actionParam);
01433                         fNoper++;;
01434                         if (!CheckOperands(fNoper-1,err)) return;
01435                      } else if (chaine(0,5) == "tanh(") {
01436                         ctemp = chaine(4,lchain-4);
01437                         Analyze(ctemp.Data(),err,offset); if (err) return;
01438                         fExpr[fNoper] = "tanh";
01439                         actionCode = ktanh;
01440                         SetAction(fNoper,actionCode,actionParam);
01441                         fNoper++;;
01442                         if (!CheckOperands(fNoper-1,err)) return;
01443                      } else if (chaine(0,6) == "acosh(") {
01444                         ctemp = chaine(5,lchain-5);
01445                         Analyze(ctemp.Data(),err,offset); if (err) return;
01446                         fExpr[fNoper] = "acosh";
01447                         actionCode = kacosh;
01448                         SetAction(fNoper,actionCode,actionParam);
01449                         fNoper++;;
01450                         if (!CheckOperands(fNoper-1,err)) return;
01451                      } else if (chaine(0,6) == "asinh(") {
01452                         ctemp = chaine(5,lchain-5);
01453                         Analyze(ctemp.Data(),err,offset); if (err) return;
01454                         fExpr[fNoper] = "asinh";
01455                         actionCode = kasinh;
01456                         SetAction(fNoper,actionCode,actionParam);
01457                         fNoper++;;
01458                         if (!CheckOperands(fNoper-1,err)) return;
01459                      } else if (chaine(0,6) == "atanh(") {
01460                         ctemp = chaine(5,lchain-5);
01461                         Analyze(ctemp.Data(),err,offset); if (err) return;
01462                         fExpr[fNoper] = "atanh";
01463                         actionCode = katanh;
01464                         SetAction(fNoper,actionCode,actionParam);
01465                         fNoper++;;
01466                         if (!CheckOperands(fNoper-1,err)) return;
01467                      } else if (chaine(0,3) == "sq(") {
01468                         ctemp = chaine(2,lchain-2);
01469                         Analyze(ctemp.Data(),err,offset); if (err) return;
01470                         fExpr[fNoper] = "sq";
01471                         actionCode = ksq;
01472                         SetAction(fNoper,actionCode,actionParam);
01473                         fNoper++;;
01474                         if (!CheckOperands(fNoper-1,err)) return;
01475                      } else if (chaine(0,4) == "log(") {
01476                         ctemp = chaine(3,lchain-3);
01477                         Analyze(ctemp.Data(),err,offset); if (err) return;
01478                         fExpr[fNoper] = "log";
01479                         actionCode = klog;
01480                         SetAction(fNoper,actionCode,actionParam);
01481                         fNoper++;;
01482                         if (!CheckOperands(fNoper-1,err)) return;
01483                      } else if (chaine(0,6) == "log10(") {
01484                         ctemp = chaine(5,lchain-5);
01485                         Analyze(ctemp.Data(),err,offset); if (err) return;
01486                         fExpr[fNoper] = "log10";
01487                         actionCode = klog10;
01488                         SetAction(fNoper,actionCode,actionParam);
01489                         fNoper++;;
01490                         if (!CheckOperands(fNoper-1,err)) return;
01491                      } else if (chaine(0,4) == "exp(") {
01492                         ctemp = chaine(3,lchain-3);
01493                         Analyze(ctemp.Data(),err,offset); if (err) return;
01494                         fExpr[fNoper] = "exp";
01495                         actionCode = kexp;
01496                         SetAction(fNoper,actionCode,actionParam);
01497                         fNoper++;;
01498                         if (!CheckOperands(fNoper-1,err)) return;
01499                      } else if (chaine(0,4) == "abs(") {
01500                         ctemp = chaine(3,lchain-3);
01501                         Analyze(ctemp.Data(),err,offset); if (err) return;
01502                         fExpr[fNoper] = "abs";
01503                         actionCode = kabs;
01504                         SetAction(fNoper,actionCode,actionParam);
01505                         fNoper++;;
01506                         if (!CheckOperands(fNoper-1,err)) return;
01507                      } else if (chaine(0,5) == "sign(") {
01508                         ctemp = chaine(4,lchain-4);
01509                         Analyze(ctemp.Data(),err,offset); if (err) return;
01510                         fExpr[fNoper] = "sign";
01511                         actionCode = ksign;
01512                         SetAction(fNoper,actionCode,actionParam);
01513                         fNoper++;;
01514                         if (!CheckOperands(fNoper-1,err)) return;
01515                      } else if (chaine(0,4) == "int(") {
01516                         ctemp = chaine(3,lchain-3);
01517                         Analyze(ctemp.Data(),err,offset); if (err) return;
01518                         fExpr[fNoper] = "int";
01519                         actionCode = kint;
01520                         SetAction(fNoper,actionCode,actionParam);
01521                         fNoper++;;
01522                         if (!CheckOperands(fNoper-1,err)) return;
01523                      } else if (chaine == "rndm" || chaine(0,5) == "rndm(") {
01524                         fExpr[fNoper] = "rndm";
01525                         actionCode = krndm;
01526                         SetAction(fNoper,actionCode,actionParam);
01527                         fNoper++;;
01528                      } else if (chaine(0,5) == "sqrt(") {
01529                         ctemp = chaine(4,lchain-4);
01530                         Analyze(ctemp.Data(),err,offset); if (err) return;
01531                         fExpr[fNoper] = "sqrt";
01532                         actionCode = ksqrt;
01533                         SetAction(fNoper,actionCode,actionParam);
01534                         fNoper++;;
01535                         if (!CheckOperands(fNoper-1,err)) return;
01536 
01537 //*-*- Look for an exponential
01538 //*-*  =======================
01539                      } else if ( chaine == "expo" || chaine(0,5)=="expo("
01540                             || (lchain==5 && chaine(1,4)=="expo")
01541                             || (lchain==6 && chaine(2,4)=="expo")
01542                             || chaine(1,5)=="expo(" || chaine(2,5)=="expo(" ) {
01543                         chaine1ST=chaine;
01544                         if (chaine(1,4) == "expo") {
01545                            ctemp=chaine(0,1);
01546                            if (ctemp=="x") {
01547                               inter2=0;
01548                               if (fNdim < 1) fNdim = 1; }
01549                            else if (ctemp=="y") {
01550                               inter2=1;
01551                               if (fNdim < 2) fNdim = 2; }
01552                            else if (ctemp=="z") {
01553                               inter2=2;
01554                               if (fNdim < 3) fNdim = 3; }
01555                            else if (ctemp=="t") {
01556                               inter2=3;
01557                               if (fNdim < 4) fNdim = 4; }
01558                            else {
01559                               err=26; // unknown name;
01560                               chaine_error=chaine1ST;
01561                            }
01562                            chaine=chaine(1,lchain-1);
01563                            lchain=chaine.Length();
01564                         } else inter2=0;
01565                         if (chaine(2,4) == "expo") {
01566                            if (chaine(0,2) != "xy") {
01567                               err=26; // unknown name
01568                               chaine_error=chaine1ST;
01569                            }
01570                            else {
01571                               inter2=5;
01572                               if (fNdim < 2) fNdim = 2;
01573                               chaine=chaine(2,lchain-2);
01574                               lchain=chaine.Length();
01575                            }
01576                         }
01577                         if (lchain == 4) {
01578                            if (fNpar>=gMAXPAR) err=7; // too many parameters
01579                            if (!err) {
01580                               fExpr[fNoper] = chaine1ST;
01581                               actionCode = kexpo + inter2;
01582                               actionParam = offset;
01583                               SetAction(fNoper,actionCode,actionParam);
01584                               if (inter2 == 5+offset && fNpar < 3+offset) fNpar = 3+offset;
01585                               if (fNpar < 2+offset) fNpar = 2+offset;
01586                               if (fNpar>=gMAXPAR) err=7; // too many parameters
01587                               if (!err) {
01588                                  fNoper++;
01589                                  if (fNdim < 1) fNdim = 1;
01590                                  if (fNpar == 2) SetNumber(200);
01591                               }
01592                            }
01593                         } else if (chaine(4,1) == "(") {
01594                            ctemp = chaine(5,lchain-6);
01595                            fExpr[fNoper] = chaine1ST;
01596                            for (j=0; j<ctemp.Length(); j++) {
01597                               t=ctemp[j];
01598                               if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
01599                                  err=20;
01600                                  chaine_error=chaine1ST;
01601                               }
01602                            }
01603                            if (err==0) {
01604                               sscanf(ctemp.Data(),"%d",&inter);
01605                               if (inter>=0) {
01606                                  inter += offset;
01607                                  actionCode = kexpo + inter2;
01608                                  actionParam = inter;
01609                                  SetAction(fNoper,actionCode,actionParam);
01610                                  if (inter2 == 5) inter++;
01611                                  if (inter+2>fNpar) fNpar = inter+2;
01612                                  if (fNpar>=gMAXPAR) err=7; // too many parameters
01613                                  if (!err) fNoper++;
01614                                  if (fNpar == 2) SetNumber(200);
01615                               } else err=20;
01616                            } else err = 20; // non integer value for parameter number
01617                         } else {
01618                            err=26; // unknown name
01619                            chaine_error=chaine;
01620                         }
01621 //*-*- Look for gaus, xgaus,ygaus,xygaus
01622 //*-*  =================================
01623                      } else if (chaine=="gaus"
01624                             || (lchain==5 && chaine(1,4)=="gaus")
01625                             || (lchain==6 && chaine(2,4)=="gaus")
01626                             || chaine(0,5)=="gaus(" || chaine(1,5)=="gaus(" || chaine(2,5)=="gaus(") {
01627                         chaine1ST=chaine;
01628                         if (chaine(1,4) == "gaus") {
01629                            ctemp=chaine(0,1);
01630                            if (ctemp=="x") {
01631                               inter2=0;
01632                               if (fNdim < 1) fNdim = 1; }
01633                            else if (ctemp=="y") {
01634                               inter2=1;
01635                               if (fNdim < 2) fNdim = 2; }
01636                            else if (ctemp=="z") {
01637                               inter2=2;
01638                               if (fNdim < 3) fNdim = 3; }
01639                            else if (ctemp=="t") {
01640                               inter2=3;
01641                               if (fNdim < 4) fNdim = 4; }
01642                            else {
01643                               err=26; // unknown name
01644                               chaine_error=chaine1ST;
01645                            }
01646                            chaine=chaine(1,lchain-1);
01647                            lchain=chaine.Length();
01648                         } else inter2=0;
01649                         if (chaine(2,4) == "gaus") {
01650                            if (chaine(0,2) != "xy") {
01651                               err=26; // unknown name
01652                               chaine_error=chaine1ST;
01653                            }
01654                            else {
01655                               inter2=5;
01656                               if (fNdim < 2) fNdim = 2;
01657                               chaine=chaine(2,lchain-2);
01658                               lchain=chaine.Length();
01659                               SetNumber(110); // xygaus
01660                            }
01661                         }
01662                         if (lchain == 4 && err==0) {
01663                            if (fNpar>=gMAXPAR) err=7; // too many parameters
01664                            if (!err) {
01665                               fExpr[fNoper] = chaine1ST;
01666                               actionCode = kgaus + inter2;
01667                               actionParam = offset;
01668                               SetAction(fNoper,actionCode,actionParam);
01669                               if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
01670                               if (3+offset>fNpar) fNpar = 3+offset;
01671                               if (fNpar>=gMAXPAR) err=7; // too many parameters
01672                               if (!err) {
01673                                  fNoper++;
01674                                  if (fNdim < 1) fNdim = 1;
01675                                  if (fNpar == 3) SetNumber(100);
01676                               }
01677                            }
01678                         } else if (chaine(4,1) == "(" && err==0) {
01679                            ctemp = chaine(5,lchain-6);
01680                            fExpr[fNoper] = chaine1ST;
01681                            for (j=0; j<ctemp.Length(); j++) {
01682                               t=ctemp[j];
01683                               if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
01684                                  err=20;
01685                                  chaine_error=chaine1ST;
01686                               }
01687                            }
01688                            if (err==0) {
01689                               sscanf(ctemp.Data(),"%d",&inter);
01690                               if (inter >= 0) {
01691                                  inter += offset;
01692                                  actionCode = kgaus + inter2;
01693                                  actionParam = inter;
01694                                  SetAction(fNoper,actionCode,actionParam);
01695                                  if (inter2 == 5) inter += 2;
01696                                  if (inter+3>fNpar) fNpar = inter+3;
01697                                  if (fNpar>=gMAXPAR) err=7; // too many parameters
01698                                  if (!err) fNoper++;
01699                                  if(fNpar == 3) SetNumber(100);
01700                               } else err = 20; // non integer value for parameter number
01701                            }
01702                         } else if (err==0) {
01703                            err=26; // unknown name
01704                            chaine_error=chaine1ST;
01705                         }
01706 //*-*- Look for landau, xlandau,ylandau,xylandau
01707 //*-*  =================================
01708                      } else if (chaine=="landau" || (lchain==7 && chaine(1,6)=="landau")
01709                             || (lchain==8 && chaine(2,6)=="landau")
01710                             || chaine(0,7)=="landau(" || chaine(1,7)=="landau(" || chaine(2,7)=="landau(") {
01711                         chaine1ST=chaine;
01712                         if (chaine(1,6) == "landau") {
01713                            ctemp=chaine(0,1);
01714                            if (ctemp=="x") {
01715                               inter2=0;
01716                               if (fNdim < 1) fNdim = 1; }
01717                            else if (ctemp=="y") {
01718                               inter2=1;
01719                               if (fNdim < 2) fNdim = 2; }
01720                            else if (ctemp=="z") {
01721                               inter2=2;
01722                               if (fNdim < 3) fNdim = 3; }
01723                            else if (ctemp=="t") {
01724                               inter2=3;
01725                               if (fNdim < 4) fNdim = 4; }
01726                            else {
01727                               err=26; // unknown name
01728                               chaine_error=chaine1ST;
01729                            }
01730                            chaine=chaine(1,lchain-1);
01731                            lchain=chaine.Length();
01732                         } else inter2=0;
01733                         if (chaine(2,6) == "landau") {
01734                            if (chaine(0,2) != "xy") {
01735                               err=26; // unknown name
01736                               chaine_error=chaine1ST;
01737                            }
01738                            else {
01739                               inter2=5;
01740                               if (fNdim < 2) fNdim = 2;
01741                               chaine=chaine(2,lchain-2);
01742                               lchain=chaine.Length();
01743                               SetNumber(410);
01744                            }
01745                         }
01746                         if (lchain == 6 && err==0) {
01747                            if (fNpar>=gMAXPAR) err=7; // too many parameters
01748                            if (!err) {
01749                               fExpr[fNoper] = chaine1ST;
01750                               actionCode = klandau + inter2;
01751                               actionParam = offset;
01752                               SetAction(fNoper,actionCode,actionParam);
01753                               if (inter2 == 5+offset && fNpar < 5+offset) fNpar = 5+offset;
01754                               if (3+offset>fNpar) fNpar = 3+offset;
01755                               if (fNpar>=gMAXPAR) err=7; // too many parameters
01756                               if (!err) {
01757                                  fNoper++;
01758                                  if (fNdim < 1) fNdim = 1;
01759                                  if (fNpar == 3) SetNumber(400);
01760                               }
01761                            }
01762                         } else if (chaine(6,1) == "(" && err==0) {
01763                            ctemp = chaine(7,lchain-8);
01764                            fExpr[fNoper] = chaine1ST;
01765                            for (j=0; j<ctemp.Length(); j++) {
01766                               t=ctemp[j];
01767                               if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
01768                                  err=20;
01769                                  chaine_error=chaine1ST;
01770                               }
01771                            }
01772                            if (err==0) {
01773                               sscanf(ctemp.Data(),"%d",&inter);
01774                               if (inter >= 0) {
01775                                  inter += offset;
01776                                  actionCode = klandau + inter2;
01777                                  actionParam = inter;
01778                                  SetAction(fNoper,actionCode,actionParam);
01779                                  if (inter2 == 5) inter += 2;
01780                                  if (inter+3>fNpar) fNpar = inter+3;
01781                                  if (fNpar>=gMAXPAR) err=7; // too many parameters
01782                                  if (!err) fNoper++;
01783                                  if (fNpar == 3) SetNumber(400);
01784                               } else err = 20; // non integer value for parameter number
01785                            }
01786                         } else if (err==0) {
01787                            err=26; // unknown name
01788                            chaine_error=chaine1ST;
01789                         }
01790 //*-*- Look for a polynomial
01791 //*-*  =====================
01792                      } else if (chaine(0,3) == "pol" || chaine(1,3) == "pol") {
01793                         chaine1ST=chaine;
01794                         if (chaine(1,3) == "pol") {
01795                            ctemp=chaine(0,1);
01796                            if (ctemp=="x") {
01797                               inter2=1;
01798                               if (fNdim < 1) fNdim = 1; }
01799                            else if (ctemp=="y") {
01800                               inter2=2;
01801                               if (fNdim < 2) fNdim = 2; }
01802                            else if (ctemp=="z") {
01803                               inter2=3;
01804                               if (fNdim < 3) fNdim = 3; }
01805                            else if (ctemp=="t") {
01806                               inter2=4;
01807                               if (fNdim < 4) fNdim = 4; }
01808                            else {
01809                               err=26; // unknown name;
01810                               chaine_error=chaine1ST;
01811                            }
01812                            chaine=chaine(1,lchain-1);
01813                            lchain=chaine.Length();
01814                         } else inter2=1;
01815                         if (chaine(lchain-1,1) == ")") {
01816                            nomb = 0;
01817                            for (j=3;j<lchain;j++) if (chaine(j,1)=="(" && nomb == 0) nomb = j;
01818                            if (nomb == 3) err = 23; // degree of polynomial not specified
01819                            if (nomb == 0) err = 40; // '(' is expected
01820                            ctemp = chaine(nomb+1,lchain-nomb-2);
01821                            for (j=0; j<ctemp.Length(); j++) {
01822                               t=ctemp[j];
01823                               if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
01824                                  err=20;
01825                                  chaine_error=chaine1ST;
01826                               }
01827                            }
01828                            if (!err) {
01829                               sscanf(ctemp.Data(),"%d",&inter);
01830                               if (inter < 0) err = 20;
01831                            }
01832                         }
01833                         else {
01834                            nomb = lchain;
01835                            inter = 0;
01836                         }
01837                         if (!err) {
01838                            inter--;
01839                            ctemp = chaine(3,nomb-3);
01840                            if (sscanf(ctemp.Data(),"%d",&n) > 0) {
01841                               if (n < 0  ) err = 24; //Degree of polynomial must be positive
01842                               if (n >= 20) err = 25; //Degree of polynomial must be less than 20
01843                            } else err = 20;
01844                         }
01845                         if (!err) {
01846                            fExpr[fNoper] = chaine1ST;
01847                            actionCode = kpol+(inter2-1);
01848                            actionParam = n*100+inter+2;
01849                            SetAction(fNoper,actionCode,actionParam);
01850                            if (inter+n+1>=fNpar) fNpar = inter + n + 2;
01851                            if (fNpar>=gMAXPAR) err=7; // too many parameters
01852                            if (!err) {
01853                               fNoper++;
01854                               if (fNdim < 1) fNdim = 1;
01855                               SetNumber(300+n);
01856                            }
01857                         }
01858 //*-*- Look for pow,atan2,etc
01859 //*-*  ======================
01860                      } else if (chaine(0,4) == "pow(") {
01861                         compt = 4; nomb = 0; virgule = 0; nest=0;
01862                         while(compt != lchain) {
01863                            compt++;
01864                            if (chaine(compt-1,1) == "(") nest++;
01865                            else if (chaine(compt-1,1) == ")") nest--;
01866                            else if (chaine(compt-1,1) == "," && nest==0) {
01867                               nomb++;
01868                               if (nomb == 1 && virgule == 0) virgule = compt;
01869                            }
01870                         }
01871                         if (nomb != 1) err = 22; // There are plus or minus than 2 arguments for pow
01872                         else {
01873                            ctemp = chaine(4,virgule-5);
01874                            Analyze(ctemp.Data(),err,offset); if (err) return;
01875                            UInt_t leftopr = fNoper-1;
01876                            ctemp = chaine(virgule,lchain-virgule-1);
01877                            Analyze(ctemp.Data(),err,offset); if (err) return;
01878                            fExpr[fNoper] = "^";
01879                            actionCode = kpow;
01880                            SetAction(fNoper,actionCode,actionParam);
01881                            fNoper++;
01882                            if (!CheckOperands(leftopr,fNoper-1,err)) return;
01883                         }
01884                      } else if (chaine(0,7) == "strstr(") {
01885                         compt = 7; nomb = 0; virgule = 0; nest=0;
01886                         inString = false;
01887                         while(compt != lchain) {
01888                            compt++;
01889                            if (chaine(compt-1,1) == "\"") {
01890                               inString = !inString;
01891                            }  else if (!inString) {
01892                               if (chaine(compt-1,1) == "(") nest++;
01893                               else if (chaine(compt-1,1) == ")") nest--;
01894                               else if (chaine(compt-1,1) == "," && nest==0) {
01895                                  nomb++;
01896                                  if (nomb == 1 && virgule == 0) virgule = compt;
01897                               }
01898                            }
01899                         }
01900                         if (nomb != 1) err = 28; // There are plus or minus than 2 arguments for strstr
01901                         else {
01902                            ctemp = chaine(7,virgule-8);
01903                            Analyze(ctemp.Data(),err,offset); if (err) return;
01904                            Int_t optloc = fNoper-1;
01905 
01906                            ctemp = chaine(virgule,lchain-virgule-1);
01907                            Analyze(ctemp.Data(),err,offset); if (err) return;
01908                            fExpr[fNoper] = "strstr";
01909                            actionCode = kstrstr;
01910                            SetAction(fNoper,actionCode,actionParam);
01911                            fNoper++;
01912 
01913                            if ( !IsString(optloc) || !IsString(fNoper-2) ) {
01914                               err = 46;
01915                               chaine_error = "strstr";
01916                            }
01917                         }
01918                      } else if (chaine(0,4) == "min(") {
01919                         compt = 4; nomb = 0; virgule = 0; nest=0;
01920                         while(compt != lchain) {
01921                            compt++;
01922                            if (chaine(compt-1,1) == "(") nest++;
01923                            else if (chaine(compt-1,1) == ")") nest--;
01924                            else if (chaine(compt-1,1) == "," && nest==0) {
01925                               nomb++;
01926                               if (nomb == 1 && virgule == 0) virgule = compt;
01927                            }
01928                         }
01929                         if (nomb != 1) {
01930                            err = 44; // There are plus or minus than 2 arguments for min
01931                            err_hint = 3;
01932                         }
01933                         else {
01934                            ctemp = chaine(4,virgule-5);
01935                            Analyze(ctemp.Data(),err,offset); if (err) return;
01936                            UInt_t leftopr = fNoper-1;
01937                            ctemp = chaine(virgule,lchain-virgule-1);
01938                            Analyze(ctemp.Data(),err,offset); if (err) return;
01939                            fExpr[fNoper] = "min";
01940                            actionCode = kmin;
01941                            SetAction(fNoper,actionCode,actionParam);
01942                            fNoper++;
01943                            if (!CheckOperands(leftopr,fNoper-1,err)) return;
01944                         }
01945                      } else if (chaine(0,4) == "max(") {
01946                         compt = 4; nomb = 0; virgule = 0; nest=0;
01947                         while(compt != lchain) {
01948                            compt++;
01949                            if (chaine(compt-1,1) == "(") nest++;
01950                            else if (chaine(compt-1,1) == ")") nest--;
01951                            else if (chaine(compt-1,1) == "," && nest==0) {
01952                               nomb++;
01953                               if (nomb == 1 && virgule == 0) virgule = compt;
01954                            }
01955                         }
01956                         if (nomb != 1) {
01957                            err = 44; // There are plus or minus than 2 arguments for min
01958                            err_hint = 3;
01959                         }
01960                         else {
01961                            ctemp = chaine(4,virgule-5);
01962                            Analyze(ctemp.Data(),err,offset); if (err) return;
01963                            UInt_t leftopr = fNoper-1;
01964                            ctemp = chaine(virgule,lchain-virgule-1);
01965                            Analyze(ctemp.Data(),err,offset); if (err) return;
01966                            fExpr[fNoper] = "max";
01967                            actionCode = kmax;
01968                            SetAction(fNoper,actionCode,actionParam);
01969                            fNoper++;
01970                            if (!CheckOperands(leftopr,fNoper-1,err)) return;
01971                         }
01972 
01973                      } else if (chaine(0,6) == "atan2(") {
01974                         compt = 6; nomb = 0; virgule = 0; nest=0;
01975                         while(compt != lchain) {
01976                            compt++;
01977                            if (chaine(compt-1,1) == "(") nest++;
01978                            else if (chaine(compt-1,1) == ")") nest--;
01979                            else if (chaine(compt-1,1) == "," && nest==0) {
01980                               nomb++;
01981                               if (nomb == 1 && virgule == 0) virgule = compt;
01982                            }
01983                         }
01984                         if (nomb != 1) err = 21;  //{ There are plus or minus than 2 arguments for atan2
01985                         else {
01986                            ctemp = chaine(6,virgule-7);
01987                            Analyze(ctemp.Data(),err,offset); if (err) return;
01988                            UInt_t leftopr = fNoper-1;
01989                            ctemp = chaine(virgule,lchain-virgule-1);
01990                            Analyze(ctemp.Data(),err,offset); if (err) return;
01991                            fExpr[fNoper] = "atan2";
01992                            actionCode = katan2;
01993                            SetAction(fNoper,actionCode,actionParam);
01994                            fNoper++;
01995                            if (!CheckOperands(leftopr,fNoper-1,err)) return;
01996                         }
01997                      } else if (chaine(0,5) == "fmod(") {
01998                         compt = 5; nomb = 0; virgule = 0; nest=0;
01999                         while(compt != lchain) {
02000                            compt++;
02001                            if (chaine(compt-1,1) == "(") nest++;
02002                            else if (chaine(compt-1,1) == ")") nest--;
02003                            else if (chaine(compt-1,1) == "," && nest==0) {
02004                               nomb++;
02005                               if (nomb == 1 && virgule == 0) virgule = compt;
02006                            }
02007                         }
02008                         if (nomb != 1) {
02009                            err = 44; // There are plus or minus than 2 arguments for fmod
02010                            err_hint = 4;
02011                         }
02012                         else {
02013                            ctemp = chaine(5,virgule-6);
02014                            Analyze(ctemp.Data(),err,offset); if (err) return;
02015                            UInt_t leftopr = fNoper-1;
02016                            ctemp = chaine(virgule,lchain-virgule-1);
02017                            Analyze(ctemp.Data(),err,offset); if (err) return;
02018                            fExpr[fNoper] = "fmod";
02019                            actionCode = kfmod;
02020                            SetAction(fNoper,actionCode,actionParam);
02021                            fNoper++;
02022                            if (!CheckOperands(leftopr,fNoper-1,err)) return;
02023                         }
02024                      } else if (AnalyzeFunction(chaine,err,offset) || err) { // The '||err' is to grab an error coming from AnalyzeFunction
02025                         if (err) {
02026                            chaine_error = chaine;
02027                         } else {
02028                            // We have a function call. Note that all the work was already,
02029                            // eventually done in AnalyzeFunction
02030                            //fprintf(stderr,"We found a foreign function in %s\n",chaine.Data());
02031                         }
02032                      } else if (chaine(0,1) == "[" && chaine(lchain-1,1) == "]") {
02033                         fExpr[fNoper] = chaine;
02034                         fNoper++;
02035                         ctemp = chaine(1,lchain-2);
02036                         for (j=0; j<ctemp.Length(); j++) {
02037                            t=ctemp[j];
02038                            if (strchr("0123456789",t)==0 && (ctemp(j,1)!="+" || j!=0)) {
02039                               err=20;
02040                               chaine_error=chaine1ST; // le numero ? de par[?] n'est pas un entier }
02041                            }
02042                         }
02043                         if (!err) {
02044                            sscanf(ctemp.Data(),"%d",&valeur);
02045                            actionCode = kParameter;
02046                            actionParam = offset + valeur;
02047                            SetAction(fNoper-1, actionCode, actionParam);
02048                            fExpr[fNoper-1] = "[";
02049                            fExpr[fNoper-1] = (fExpr[fNoper-1] + (long int)(valeur+offset)) + "]";
02050                         }
02051                      } else if (chaine == "pi") {
02052                         fExpr[fNoper] = "pi";
02053                         actionCode = kpi;
02054                         SetAction(fNoper,actionCode,actionParam);
02055                         fNoper++;
02056                      }
02057                      else {
02058 //*-*- None of the above.
02059 //*-*  ==================
02060                         err = 30;
02061                      }
02062                   }
02063                }
02064             }
02065          }
02066       }
02067    }
02068 
02069 //   Test  * si y existe :  que x existe
02070 //         * si z existe :  que x et y existent
02071 
02072 //     nomb = 1;
02073 //     for (i=1; i<=fNoper; i++) {
02074 //         if (fOper[i-1] == 97 && nomb > 0) nomb *= -1;
02075 //         if (fOper[i-1] == 98 && TMath::Abs(nomb) != 2) nomb *= 2;
02076 //         if (fOper[i-1] == 99 && TMath::Abs(nomb) != 20 && TMath::Abs(nomb) != 10) nomb *= 10;
02077 //     }
02078 //     if (nomb == 10)  err = 10; //{variable z sans x et y }
02079 //     if (nomb == 20)  err = 11; //{variables z et y sans x }
02080 //     if (nomb == 2)   err = 12; //{variable y sans x }
02081 //     if (nomb == -10) err = 13; //{variables z et x sans y }
02082 
02083    //*-*- Overflows
02084    if (fNoper>=gMAXOP) err=6; // too many operators
02085 
02086    }
02087 
02088 //*-*- errors!
02089    if (err>1) {
02090       TString er = "";
02091       chaine_error = "\""+chaine_error+"\"";
02092       switch(err) {
02093          case  2 : er = " Invalid Floating Point Operation"; break;
02094          case  4 : er = " Empty String"; break;
02095          case  5 : er = " Invalid Syntax " + chaine_error; break;
02096          case  6 : er = " Too many operators !"; break;
02097          case  7 : er = " Too many parameters !"; break;
02098          case 10 : er = " z specified but not x and y"; break;
02099          case 11 : er = " z and y specified but not x"; break;
02100          case 12 : er = " y specified but not x"; break;
02101          case 13 : er = " z and x specified but not y"; break;
02102          case 20 : er = " Non integer value for parameter number : " + chaine_error; break;
02103          case 21 : er = " ATAN2 requires two arguments"; break;
02104          case 22 : er = " POW requires two arguments"; break;
02105          case 23 : er = " Degree of polynomial not specified"; break;
02106          case 24 : er = " Degree of polynomial must be positive"; break;
02107          case 25 : er = " Degree of polynomial must be less than 20"; break;
02108          case 26 : er = " Unknown name : " + chaine_error; break;
02109          case 27 : er = " Too many constants in expression"; break;
02110          case 28 : er = " strstr requires two arguments"; break;
02111          case 29 : er = " TFormula can only call interpreted and compiled functions that return a numerical type: " + chaine_error; break;
02112          case 30 : er = " Bad numerical expression : " + chaine_error; break;
02113          case 31 : er = " Part of the Variable " + chaine_error; er += " exists but some of it is not accessible or useable"; break;
02114          case 40 : er = " '(' is expected"; break;
02115          case 41 : er = " ')' is expected"; break;
02116          case 42 : er = " '[' is expected"; break;
02117          case 43 : er = " ']' is expected"; break;
02118          case 44 : er = " The function '" + chaine(0,err_hint) + "' requires two arguments."; break;
02119          case 45 : er = "The operator " + chaine_error + " requires a numerical operand."; break;
02120          case 46 : er = "Both operands of the operator " + chaine_error + " have to be either numbers or strings."; break;
02121          case 47 : er = chaine_error + " requires 2 string arguments"; break;
02122       }
02123       Error("Compile", "%s", er.Data());
02124       err=1;
02125    }
02126 
02127 }
02128 
02129 //______________________________________________________________________________
02130 Bool_t TFormula::CheckOperands(Int_t oper, Int_t &err)
02131 {
02132    // Check whether the operand at 'oper-1' is compatible with the operation at 'oper'.
02133 
02134    if ( IsString(oper-1) && !StringToNumber(oper-1) ) {
02135       Error("Compile","\"%s\" requires a numerical operand.",fExpr[oper].Data());
02136       err = 45;
02137       return kFALSE;
02138    }
02139    return kTRUE;
02140 }
02141 
02142 //______________________________________________________________________________
02143 Bool_t TFormula::CheckOperands(Int_t leftoper, Int_t oper, Int_t &err)
02144 {
02145    // Check whether the operands at 'leftoper' and 'oper-1' are compatible with the operation at 'oper'.
02146 
02147    if ( IsString(oper-1) || IsString(leftoper) ) {
02148       if (IsString(oper-1) && StringToNumber(oper-1)) {
02149           return kTRUE;
02150       }
02151       if (IsString(leftoper) && StringToNumber(leftoper)) {
02152          return kTRUE;
02153       }
02154       Error("Compile","\"%s\" requires two numerical operands.",fExpr[oper].Data());
02155       err = 46;
02156       return kFALSE;
02157    }
02158    return kTRUE;
02159 }
02160 
02161 //______________________________________________________________________________
02162 Bool_t TFormula::StringToNumber(Int_t /* code */)
02163 {
02164    // Try to 'demote' a string into an array bytes.  If this is not possible,
02165    // return false.
02166 
02167    // In TFormula proper, we can not handle array of bytes ...
02168    return kFALSE;
02169 }
02170 
02171 //______________________________________________________________________________
02172 void TFormula::Clear(Option_t * /*option*/ )
02173 {
02174 //*-*-*-*-*-*-*-*-*Resets the objects*-*-*-*-*-*-*-*-*-*-*
02175 //*-*              ==================
02176 //*-*
02177 //*-* Resets the object to its state before compilation.
02178 //*-*
02179 
02180    ClearFormula();
02181 }
02182 
02183 //______________________________________________________________________________
02184 void TFormula::ClearFormula(Option_t * /*option*/ )
02185 {
02186 //*-*-*-*-*-*-*-*-*Resets the objects*-*-*-*-*-*-*-*-*-*-*
02187 //*-*              ==================
02188 //*-*
02189 //*-* Resets the object to its state before compilation.
02190 //*-*
02191 
02192    fNdim   = 0;
02193    fNpar   = 0;
02194    fNoper  = 0;
02195    fNconst = 0;
02196    fNumber = 0;
02197    fNstring= 0;
02198    fNval   = 0;
02199 
02200    if (fExpr)   { delete [] fExpr;   fExpr   = 0;}
02201    if (fNames)  { delete [] fNames;  fNames  = 0;}
02202    if (fOper)   { delete [] fOper;   fOper   = 0;}
02203    if (fConst)  { delete [] fConst;  fConst  = 0;}
02204    if (fParams) { delete [] fParams; fParams = 0;}
02205    fFunctions.Delete();
02206    fLinearParts.Delete();
02207    //
02208    //MI change
02209    if (fPredefined)    { delete [] fPredefined;    fPredefined    = 0;}
02210    if (fOperOffset)    { delete [] fOperOffset;    fOperOffset    = 0;}
02211    if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
02212    if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
02213    // should we also remove the object from the list?
02214    // gROOT->GetListOfFunctions()->Remove(this);
02215    // if we don't, what happens if it fails the new compilation?
02216 }
02217 
02218 //______________________________________________________________________________
02219 Int_t TFormula::Compile(const char *expression)
02220 {
02221 //*-*-*-*-*-*-*-*-*-*-*Compile expression already stored in fTitle*-*-*-*-*-*
02222 //*-*                  ===========================================
02223 //*-*
02224 //*-*   Loop on all subexpressions of formula stored in fTitle
02225 //*-*
02226 //*-*   If you overload this member function, you also HAVE TO
02227 //*-*   never call the constructor:
02228 //*-*
02229 //*-*     TFormula::TFormula(const char *name,const char *expression)
02230 //*-*
02231 //*-*   and write your own constructor
02232 //*-*
02233 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
02234 //*-*
02235 //*-*   which has to call the TFormula default constructor and whose implementation
02236 //*-*   should be similar to the implementation of the normal TFormula constructor
02237 //*-*
02238 //*-*   This is necessary because the normal TFormula constructor call indirectly
02239 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
02240 //*-*   and DefaultVariable.
02241 //*-*
02242 //Begin_Html
02243 /*
02244 <img src="gif/compile.gif">
02245 */
02246 //End_Html
02247 //*-*
02248 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02249 
02250    Int_t i,j,lc,valeur,err;
02251    TString ctemp;
02252 
02253    ClearFormula();
02254 
02255 //*-*- If expression is not empty, take it, otherwise take the title
02256    if (strlen(expression)) SetTitle(expression);
02257 
02258    TString chaine = GetTitle();
02259 
02260    if (chaine.Contains(";")) {
02261       char *sctemp = new char[chaine.Length()+1];
02262       strlcpy(sctemp,chaine.Data(),chaine.Length()+1);
02263       char *semicol = (char*)strstr(sctemp,";");
02264       if (semicol) *semicol = 0;
02265       chaine = sctemp;
02266       delete [] sctemp;
02267    }
02268 //  chaine.ToLower();
02269 
02270 //if the function is linear, process it and fill the array of linear parts
02271    if (TestBit(kLinear)){
02272       ProcessLinear(chaine);
02273    }
02274 
02275      // see static function SetMaxima to change the gMAX.. default values
02276    fExpr   = new TString[gMAXOP];
02277    fConst  = new Double_t[gMAXCONST];
02278    fParams = new Double_t[gMAXPAR];
02279    fNames  = new TString[gMAXPAR];
02280    fOper   = new Int_t[gMAXOP];
02281    for (i=0; i<gMAXPAR; i++) {
02282       fParams[i] = 0;
02283       fNames[i] = "";
02284    }
02285    for (i=0; i<gMAXOP; i++) {
02286       fExpr[i] = "";
02287       fOper[i] = 0;
02288    }
02289    for (i=0; i<gMAXCONST; i++)
02290       fConst[i] = 0;
02291 
02292 //*-*- Substitution of some operators to C++ style
02293 //*-*  ===========================================
02294    Bool_t inString = false;
02295    for (i=1; i<=chaine.Length(); i++) {
02296       lc =chaine.Length();
02297       if (chaine(i-1,1) == "\"") inString = !inString;
02298       if (inString) continue;
02299       if (chaine(i-1,2) == "**") {
02300          chaine = chaine(0,i-1) + "^" + chaine(i+1,lc-i-1);
02301          i=0;
02302       } else if (chaine(i-1,2) == "++") {
02303          chaine = chaine(0,i) + chaine(i+1,lc-i-1);
02304          i=0;
02305       } else if (chaine(i-1,2) == "+-" || chaine(i-1,2) == "-+") {
02306          chaine = chaine(0,i-1) + "-" + chaine(i+1,lc-i-1);
02307          i=0;
02308       } else if (chaine(i-1,2) == "--") {
02309          chaine = chaine(0,i-1) + "+" + chaine(i+1,lc-i-1);
02310          i=0;
02311       } else if (chaine(i-1,2) == "->") {
02312          chaine = chaine(0,i-1) + "." + chaine(i+1,lc-i-1);
02313          i=0;
02314       } else if (chaine(i-1,1) == "[") {
02315          for (j=1;j<=chaine.Length()-i;j++) {
02316             if (chaine(j+i-1,1) == "]" || j+i > chaine.Length()) break;
02317          }
02318          ctemp = chaine(i,j-1);
02319          valeur=0;
02320          sscanf(ctemp.Data(),"%d",&valeur);
02321          if (valeur >= fNpar) fNpar = valeur+1;
02322       } else if (chaine(i-1,1) == " ") {
02323          chaine = chaine(0,i-1)+chaine(i,lc-i);
02324          i=0;
02325       }
02326    }
02327    err = 0;
02328    Analyze((const char*)chaine,err);
02329 
02330    // if no parameters delete arrays fParams and fNames
02331    if (!fNpar) {
02332       delete [] fParams; fParams = 0;
02333       delete [] fNames;  fNames = 0;
02334    }
02335 
02336    //*-*- if no errors, copy local parameters to formula objects
02337    if (!err) {
02338       if (fNdim <= 0) fNdim = 1;
02339       if (chaine.Length() > 4)
02340       {
02341          if ( GetNumber() != 400 &&
02342               GetNumber() != 410 &&
02343               GetNumber() != 110 )
02344             SetNumber(0);
02345          else if ( GetNumber() == 110 && chaine.Length() > 6 )
02346             SetNumber(0);
02347          else if ( GetNumber() == 410 && chaine.Length() > 8 )
02348             SetNumber(0);
02349       }
02350       //*-*- if formula is a gaussian, set parameter names
02351       if (GetNumber() == 100) {
02352          SetParName(0,"Constant");
02353          SetParName(1,"Mean");
02354          SetParName(2,"Sigma");
02355       }
02356       //*-*- if formula is a 2D gaussian, set parameter names
02357       if (GetNumber() == 110){
02358          SetParName(0,"Constant");
02359          SetParName(1,"MeanX");
02360          SetParName(2,"SigmaX");
02361          SetParName(3,"MeanY");
02362          SetParName(4,"SigmaY");
02363       }
02364       //*-*- if formula is an exponential, set parameter names
02365       if (GetNumber() == 200) {
02366          SetParName(0,"Constant");
02367          SetParName(1,"Slope");
02368       }
02369       //*-*- if formula is a polynome, set parameter names
02370       if (GetNumber() == 300+fNpar) {
02371          for (i=0;i<fNpar;i++) SetParName(i,Form("p%d",i));
02372       }
02373       //*-*- if formula is a landau, set parameter names
02374       if (GetNumber() == 400) {
02375          SetParName(0,"Constant");
02376          SetParName(1,"MPV");
02377          SetParName(2,"Sigma");
02378       }
02379       //*-*- if formula is a 2D landau, set parameter names
02380       if (GetNumber() == 410) {
02381          SetParName(0,"Constant");
02382          SetParName(1,"MPVX");
02383          SetParName(2,"SigmaX");
02384          SetParName(3,"MPVY");
02385          SetParName(4,"SigmaY");
02386       }
02387    }
02388 
02389    if (err) { fNdim = 0; return 1; }
02390    //   Convert(5);
02391    //
02392    //MI change
02393    if (!IsA()->GetBaseClass("TTreeFormula")) {
02394       Optimize();
02395    }
02396    //
02397    return 0;
02398 }
02399 
02400 //______________________________________________________________________________
02401 void TFormula::Copy(TObject &obj) const
02402 {
02403 //*-*-*-*-*-*-*-*-*-*-*Copy this formula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02404 //*-*                  =================
02405 
02406    Int_t i;
02407    ((TFormula&)obj).ClearFormula();
02408    TNamed::Copy(obj);
02409    ((TFormula&)obj).fNdim   = fNdim;
02410    ((TFormula&)obj).fNpar   = fNpar;
02411    ((TFormula&)obj).fNoper  = fNoper;
02412    ((TFormula&)obj).fNconst = fNconst;
02413    ((TFormula&)obj).fNumber = fNumber;
02414    ((TFormula&)obj).fNval   = fNval;
02415    ((TFormula&)obj).fExpr   = 0;
02416    ((TFormula&)obj).fConst  = 0;
02417    ((TFormula&)obj).fParams = 0;
02418    ((TFormula&)obj).fNames  = 0;
02419    if (fExpr && fNoper) {
02420       ((TFormula&)obj).fExpr = new TString[fNoper];
02421       for (i=0;i<fNoper;i++)  ((TFormula&)obj).fExpr[i]   = fExpr[i];
02422    }
02423    if (fOper && fNoper) {
02424      ((TFormula&)obj).fOper = new Int_t[fNoper];
02425       for (i=0;i<fNoper;i++)  ((TFormula&)obj).fOper[i]   = fOper[i];
02426    }
02427    if (fConst && fNconst) {
02428       ((TFormula&)obj).fConst = new Double_t[fNconst];
02429       for (i=0;i<fNconst;i++) ((TFormula&)obj).fConst[i]  = fConst[i];
02430    }
02431    if (fParams && fNpar) {
02432       ((TFormula&)obj).fParams = new Double_t[fNpar];
02433       for (i=0;i<fNpar;i++)   ((TFormula&)obj).fParams[i] = fParams[i];
02434    }
02435    if (fNames && fNpar) {
02436       ((TFormula&)obj).fNames = new TString[fNpar];
02437       for (i=0;i<fNpar;i++)   ((TFormula&)obj).fNames[i]  = fNames[i];
02438    }
02439 
02440    TIter next(&fFunctions);
02441    TObject *fobj;
02442    while ( (fobj = next()) ) {
02443       ((TFormula&)obj).fFunctions.Add( fobj->Clone() );
02444    }
02445    //
02446    // MI change
02447    //
02448    //
02449    if (fNoper) {
02450       if(fExprOptimized) {
02451          ((TFormula&)obj).fExprOptimized   = new TString[fNoper];
02452          for (i=0;i<fNoper;i++)  ((TFormula&)obj).fExprOptimized[i]   = fExprOptimized[i];
02453       }
02454       if (fOperOptimized) {
02455          ((TFormula&)obj).fOperOptimized   = new Int_t[fNoper];
02456          for (i=0;i<fNoper;i++)  ((TFormula&)obj).fOperOptimized[i]   = fOperOptimized[i];
02457       }
02458       if (fPredefined) {
02459          ((TFormula&)obj).fPredefined      = new TFormulaPrimitive*[fNoper];
02460          for (i=0;i<fNoper;i++) {((TFormula&)obj).fPredefined[i] = fPredefined[i];}
02461       }
02462       if (fOperOffset) {
02463          ((TFormula&)obj).fOperOffset         = new TOperOffset[fNoper];
02464          for (i=0;i<fNoper;i++) {((TFormula&)obj).fOperOffset[i] = fOperOffset[i];}
02465       }
02466    }
02467    ((TFormula&)obj).fNOperOptimized = fNOperOptimized;
02468    ((TFormula&)obj).fOptimal = fOptimal;
02469 
02470 }
02471 
02472 //______________________________________________________________________________
02473 char *TFormula::DefinedString(Int_t)
02474 {
02475 //*-*-*-*-*-*Return address of string corresponding to special code*-*-*-*-*-*
02476 //*-*        ======================================================
02477 //*-*
02478 //*-*   This member function is inactive in the TFormula class.
02479 //*-*   It may be redefined in derived classes.
02480 //*-*
02481 //*-*   If you overload this member function, you also HAVE TO
02482 //*-*   never call the constructor:
02483 //*-*
02484 //*-*     TFormula::TFormula(const char *name,const char *expression)
02485 //*-*
02486 //*-*   and write your own constructor
02487 //*-*
02488 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
02489 //*-*
02490 //*-*   which has to call the TFormula default constructor and whose implementation
02491 //*-*   should be similar to the implementation of the normal TFormula constructor
02492 //*-*
02493 //*-*   This is necessary because the normal TFormula constructor call indirectly
02494 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
02495 //*-*   and DefaultVariable.
02496 //*-*
02497 ///*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02498    return 0;
02499 }
02500 
02501 //______________________________________________________________________________
02502 Double_t TFormula::DefinedValue(Int_t)
02503 {
02504 //*-*-*-*-*-*Return value corresponding to special code*-*-*-*-*-*-*-*-*
02505 //*-*        ==========================================
02506 //*-*
02507 //*-*   This member function is inactive in the TFormula class.
02508 //*-*   It may be redefined in derived classes.
02509 //*-*
02510 //*-*   If you overload this member function, you also HAVE TO
02511 //*-*   never call the constructor:
02512 //*-*
02513 //*-*     TFormula::TFormula(const char *name,const char *expression)
02514 //*-*
02515 //*-*   and write your own constructor
02516 //*-*
02517 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
02518 //*-*
02519 //*-*   which has to call the TFormula default constructor and whose implementation
02520 //*-*   should be similar to the implementation of the normal TFormula constructor
02521 //*-*
02522 //*-*   This is necessary because the normal TFormula constructor call indirectly
02523 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
02524 //*-*   and DefaultVariable.
02525 //*-*
02526 ///*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02527    return 0;
02528 }
02529 
02530 //______________________________________________________________________________
02531 Int_t TFormula::DefinedVariable(TString &chaine,Int_t &action)
02532 {
02533 //*-*-*-*-*-*Check if expression is in the list of defined variables*-*-*-*-*
02534 //*-*        =======================================================
02535 //*-*
02536 //*-*   This member function can be overloaded in derived classes
02537 //*-*
02538 //*-*   If you overload this member function, you also HAVE TO
02539 //*-*   never call the constructor:
02540 //*-*
02541 //*-*     TFormula::TFormula(const char *name,const char *expression)
02542 //*-*
02543 //*-*   and write your own constructor
02544 //*-*
02545 //*-*     MyClass::MyClass(const char *name,const char *expression) : TFormula()
02546 //*-*
02547 //*-*   which has to call the TFormula default constructor and whose implementation
02548 //*-*   should be similar to the implementation of the normal TFormula constructor
02549 //*-*
02550 //*-*   This is necessary because the normal TFormula constructor call indirectly
02551 //*-*   the virtual member functions Analyze, DefaultString, DefaultValue
02552 //*-*   and DefaultVariable.
02553 //*-*
02554 //*-*   The expected returns values are
02555 //*-*     -2 :  the name has been recognized but won't be usable
02556 //*-*     -1 :  the name has not been recognized
02557 //*-*    >=0 :  the name has been recognized, return the action parameter.
02558 //*-*
02559 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02560 
02561    action = kVariable;
02562    if (chaine == "x") {
02563       if (fNdim < 1) fNdim = 1;
02564       return 0;
02565    } else if (chaine == "y") {
02566       if (fNdim < 2) fNdim = 2;
02567       return 1;
02568    } else if (chaine == "z") {
02569       if (fNdim < 3) fNdim = 3;
02570       return 2;
02571    } else if (chaine == "t") {
02572       if (fNdim < 4) fNdim = 4;
02573       return 3;
02574    }
02575    // MI change
02576    // extended defined variable (MI)
02577    //
02578    if (chaine.Data()[0]=='x'){
02579       if (chaine.Data()[1]=='[' && chaine.Data()[3]==']'){
02580          const char ch0 = '0';
02581          Int_t dim = chaine.Data()[2]-ch0;
02582          if (dim<0) return -1;
02583          if (dim>9) return -1;
02584          if (fNdim<=dim) fNdim = dim+1;
02585          return dim;
02586       }
02587       if (chaine.Data()[1]=='[' && chaine.Data()[4]==']'){
02588          const char ch0 = '0';
02589          Int_t dim = (chaine.Data()[2]-ch0)*10+(chaine.Data()[3]-ch0);
02590          if (dim<0) return -1;
02591          if (dim>99) return -1;
02592          if (fNdim<=dim) fNdim = dim+1;
02593          return dim;
02594       }
02595    }
02596    return -1;
02597 }
02598 
02599 //______________________________________________________________________________
02600 Double_t TFormula::Eval(Double_t x, Double_t y, Double_t z, Double_t t) const
02601 {
02602 //*-*-*-*-*-*-*-*-*-*-*Evaluate this formula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02603 //*-*                  =====================
02604 //*-*
02605 //*-*   The current value of variables x,y,z,t is passed through x, y, z and t.
02606 //*-*   The parameters used will be the ones in the array params if params is given
02607 //*-*    otherwise parameters will be taken from the stored data members fParams
02608 //*-*
02609 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02610 
02611    Double_t xx[4];
02612    xx[0] = x;
02613    xx[1] = y;
02614    xx[2] = z;
02615    xx[3] = t;
02616    return ((TFormula*)this)->EvalPar(xx);
02617 }
02618 
02619 //______________________________________________________________________________
02620 Double_t TFormula::EvalParOld(const Double_t *x, const Double_t *uparams)
02621 {
02622 //*-*-*-*-*-*-*-*-*-*-*Evaluate this formula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02623 //*-*                  =====================
02624 //*-*
02625 //*-*   The current value of variables x,y,z,t is passed through the pointer x.
02626 //*-*   The parameters used will be the ones in the array params if params is given
02627 //*-*    otherwise parameters will be taken from the stored data members fParams
02628 //Begin_Html
02629 /*
02630 <img src="gif/eval.gif">
02631 */
02632 //End_Html
02633 //*-*
02634 //*-*
02635 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
02636 
02637    Int_t i,j;
02638    Double_t tab[kMAXFOUND];
02639    const char *stringStack[gMAXSTRINGFOUND];
02640    Double_t param_calc[kMAXFOUND];
02641    char *string_calc[gMAXSTRINGFOUND];
02642    Int_t precalculated = 0;
02643    Int_t precalculated_str = 0;
02644    Double_t *params;
02645 
02646    if (uparams) {
02647       params = const_cast<Double_t*>(uparams);
02648    } else {
02649       params = fParams;
02650    }
02651    UInt_t pos    = 0;
02652    UInt_t strpos = 0;
02653 
02654    for (i=0; i<fNoper; ++i) {
02655 
02656       const int oper = fOper[i];
02657       const int opcode = oper >> kTFOperShift;
02658 
02659       switch(opcode) {
02660 
02661          case kParameter  : { pos++; tab[pos-1] = params[ oper & kTFOperMask ]; continue; }
02662          case kConstant   : { pos++; tab[pos-1] = fConst[ oper & kTFOperMask ]; continue; }
02663          case kVariable   : { pos++; tab[pos-1] = x[ oper & kTFOperMask ]; continue; }
02664          case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExpr[i].Data(); pos++; tab[pos-1] = 0; continue; }
02665 
02666          case kAdd        : pos--; tab[pos-1] += tab[pos]; continue;
02667          case kSubstract  : pos--; tab[pos-1] -= tab[pos]; continue;
02668          case kMultiply   : pos--; tab[pos-1] *= tab[pos]; continue;
02669          case kDivide     : pos--; if (tab[pos] == 0) tab[pos-1] = 0; //  division by 0
02670                            else               tab[pos-1] /= tab[pos];
02671                            continue;
02672          case kModulo     : {pos--;
02673                               Long64_t int1((Long64_t)tab[pos-1]);
02674                               Long64_t int2((Long64_t)tab[pos]);
02675                               tab[pos-1] = Double_t(int1%int2);
02676                               continue;}
02677 
02678          case kcos  : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
02679          case ksin  : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
02680          case ktan  : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
02681                         else tab[pos-1] = TMath::Tan(tab[pos-1]);
02682                         continue;
02683          case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
02684                         else tab[pos-1] = TMath::ACos(tab[pos-1]);
02685                         continue;
02686          case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} //  indetermination
02687                         else tab[pos-1] = TMath::ASin(tab[pos-1]);
02688                         continue;
02689          case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
02690          case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
02691          case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
02692          case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
02693                         else tab[pos-1] = TMath::TanH(tab[pos-1]);
02694                         continue;
02695          case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} //  indetermination
02696                         else tab[pos-1] = TMath::ACosH(tab[pos-1]);
02697                         continue;
02698          case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
02699          case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
02700                         else tab[pos-1] = TMath::ATanH(tab[pos-1]); continue;
02701          case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
02702 
02703          case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
02704          case kpow  : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
02705          case ksq   : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
02706          case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
02707 
02708          case kstrstr : strpos -= 2; pos-=2; pos++;
02709                         if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
02710                         else tab[pos-1]=0; continue;
02711 
02712          case kmin : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); continue;
02713          case kmax : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); continue;
02714 
02715          case klog  : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
02716                         else {tab[pos-1] = 0;} //{indetermination }
02717                         continue;
02718          case kexp  : { Double_t dexp = tab[pos-1];
02719                         if (dexp < -700) {tab[pos-1] = 0; continue;}
02720                         if (dexp >  700) {tab[pos-1] = TMath::Exp(700); continue;}
02721                         tab[pos-1] = TMath::Exp(dexp); continue;  }
02722          case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
02723                         else {tab[pos-1] = 0;} //{indetermination }
02724                         continue;
02725 
02726          case kpi   : pos++; tab[pos-1] = TMath::ACos(-1); continue;
02727 
02728          case kabs  : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
02729          case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
02730          case kint  : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
02731 
02732          case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
02733 
02734          case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;
02735 
02736          case kAnd  : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
02737                         else tab[pos-1]=0; continue;
02738          case kOr   : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
02739                         else tab[pos-1]=0; continue;
02740          case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
02741                         else tab[pos-1]=0; continue;
02742          case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
02743                         else tab[pos-1]=0; continue;
02744          case kLess     : pos--; if (tab[pos-1] < tab[pos]) tab[pos-1]=1;
02745                         else tab[pos-1]=0; continue;
02746          case kGreater  : pos--; if (tab[pos-1] > tab[pos]) tab[pos-1]=1;
02747                         else tab[pos-1]=0; continue;
02748 
02749          case kLessThan: pos--; if (tab[pos-1]<=tab[pos]) tab[pos-1]=1;
02750                         else tab[pos-1]=0; continue;
02751          case kGreaterThan: pos--; if (tab[pos-1]>=tab[pos]) tab[pos-1]=1;
02752                         else tab[pos-1]=0; continue;
02753          case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1; continue;
02754 
02755          case kStringEqual : strpos -= 2; pos -=2 ; pos++;
02756                         if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
02757                         else tab[pos-1]=0; continue;
02758          case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
02759                         if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
02760                         else tab[pos-1]=0; continue;
02761 
02762          case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
02763          case kBitOr  : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
02764          case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
02765          case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
02766 
02767          case kJump   : i = (oper & kTFOperMask); continue;
02768          case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
02769 
02770          case kBoolOptimize: {
02771             // boolean operation optimizer
02772 
02773             int param = (oper & kTFOperMask);
02774             Bool_t skip = kFALSE;
02775             int op = param % 10; // 1 is && , 2 is ||
02776 
02777             if (op == 1 && (!tab[pos-1]) ) {
02778                // &&: skip the right part if the left part is already false
02779 
02780                skip = kTRUE;
02781 
02782                // Preserve the existing behavior (i.e. the result of a&&b is
02783                // either 0 or 1)
02784                tab[pos-1] = 0;
02785 
02786             } else if (op == 2 && tab[pos-1] ) {
02787                // ||: skip the right part if the left part is already true
02788 
02789                skip = kTRUE;
02790 
02791                // Preserve the existing behavior (i.e. the result of a||b is
02792                // either 0 or 1)
02793                tab[pos-1] = 1;
02794 
02795             }
02796 
02797             if (skip) {
02798                int toskip = param / 10;
02799                i += toskip;
02800             }
02801             continue;
02802          }
02803 
02804       }
02805 
02806       switch(opcode) {
02807 
02808          #define R__EXPO(var)                                                 \
02809          {                                                                    \
02810             pos++; int param = (oper & kTFOperMask);                          \
02811             tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]);  \
02812             continue;                                                         \
02813          }
02814          // case kexpo:
02815          case kxexpo: R__EXPO(0);
02816          case kyexpo: R__EXPO(1);
02817          case kzexpo: R__EXPO(2);
02818          case kxyexpo:{ pos++; int param = (oper & kTFOperMask);
02819                         tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
02820                         continue;  }
02821 
02822          #define R__GAUS(var)                                                    \
02823          {                                                                       \
02824             pos++; int param = (oper & kTFOperMask);                             \
02825             tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1],params[param+2],IsNormalized()); \
02826             continue;                                                            \
02827          }
02828 
02829          // case kgaus:
02830          case kxgaus: R__GAUS(0);
02831          case kygaus: R__GAUS(1);
02832          case kzgaus: R__GAUS(2);
02833          case kxygaus: {pos++; int param = (oper & kTFOperMask);
02834                         Double_t intermede1;
02835                         if (params[param+2] == 0) {
02836                            intermede1=1e10;
02837                         } else {
02838                            intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
02839                         }
02840                         Double_t intermede2;
02841                         if (params[param+4] == 0) {
02842                            intermede2=1e10;
02843                         } else {
02844                            intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
02845                         }
02846                         tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
02847                         continue; }
02848 
02849          #define R__LANDAU(var)                                                                  \
02850          {                                                                                       \
02851             pos++; const int param = (oper & kTFOperMask);                                       \
02852             tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
02853             continue;                                                                            \
02854          }
02855          // case klandau:
02856          case kxlandau: R__LANDAU(0);
02857          case kylandau: R__LANDAU(1);
02858          case kzlandau: R__LANDAU(2);
02859          case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
02860                            Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
02861                            Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
02862                            tab[pos-1] = params[param]*intermede1*intermede2;
02863                            continue;
02864          }
02865 
02866          #define R__POLY(var)                                                  \
02867          {                                                                     \
02868             pos++; int param = (oper & kTFOperMask);                           \
02869             tab[pos-1] = 0; Double_t intermede = 1;                            \
02870             Int_t inter = param/100; /* arrondit */                            \
02871             Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
02872             for (j=0 ;j<inter+1;j++) {                                         \
02873                tab[pos-1] += intermede*params[j+int1];                        \
02874                intermede *= x[var];                                            \
02875             }                                                                  \
02876             continue;                                                          \
02877          }
02878          // case kpol:
02879          case kxpol: R__POLY(0);
02880          case kypol: R__POLY(1);
02881          case kzpol: R__POLY(2);
02882 
02883          case kDefinedVariable : {
02884             if (!precalculated) {
02885                precalculated = 1;
02886                for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
02887             }
02888             pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
02889             continue;
02890          }
02891 
02892          case kDefinedString : {
02893             int param = (oper & kTFOperMask);
02894             if (!precalculated_str) {
02895                precalculated_str=1;
02896                for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
02897             }
02898             strpos++; stringStack[strpos-1] = string_calc[param];
02899             pos++; tab[pos-1] = 0;
02900             continue;
02901          }
02902 
02903          case kFunctionCall: {
02904             // an external function call
02905 
02906             int param = (oper & kTFOperMask);
02907             int fno   = param / 1000;
02908             int nargs = param % 1000;
02909 
02910             // Retrieve the function
02911             TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
02912 
02913             // Set the arguments
02914             TString args;
02915             if (nargs) {
02916                UInt_t argloc = pos-nargs;
02917                for(j=0;j<nargs;j++,argloc++,pos--) {
02918                   if (TMath::IsNaN(tab[argloc])) {
02919                      // TString would add 'nan' this is not what we want
02920                      // so let's do somethign else
02921                      args += "(double)(0x8000000000000)";
02922                   } else {
02923                      args += tab[argloc];
02924                   }
02925                   args += ',';
02926                }
02927                args.Remove(args.Length()-1);
02928             }
02929             pos++;
02930             Double_t ret;
02931             method->Execute(args,ret);
02932             tab[pos-1] = ret; // check for the correct conversion!
02933 
02934             continue;
02935          };
02936       }
02937       if (!TestBit(kOptimizationError)) {
02938          SetBit(kOptimizationError);
02939          Warning("EvalParOld","Found an unsupported opcode (%d)",oper >> kTFOperShift);
02940       }
02941    }
02942    Double_t result0 = tab[0];
02943    return result0;
02944 
02945 }
02946 
02947 //------------------------------------------------------------------------------
02948 TString TFormula::GetExpFormula(Option_t *option) const
02949 {
02950 //*-*-*-*-*-*-*-*-*Reconstruct the formula expression from*-*-*-*-*-*-*-*-*-*-*
02951 //*-*              the internal TFormula member variables
02952 //*-*              =======================================
02953 //*-*
02954 //*-*   This function uses the internal member variables of TFormula to
02955 //*-*   construct the mathematical expression associated with the TFormula
02956 //*-*   instance. This function can be used to get an expanded version of the
02957 //*-*   expression originally assigned to the TFormula instance, i.e. that
02958 //*-*   the string returned by GetExpFormula() doesn't depend on other
02959 //*-*   TFormula object names.
02960 //*-*
02961 //*-*  if option contains "p" the returned string will contain the formula
02962 //*-*  expression with symbolic parameters, eg [0] replaced by the actual value
02963 //*-*  of the parameter. Example:
02964 //*-*  if expression in formula is: "[0]*(x>-[1])+[2]*exp(-[3]*x)"
02965 //*-*  and parameters are 3.25,-4.01,4.44,-0.04, GetExpFormula("p") will return:
02966 //*-*   "(3.25*(x>+4.01))+(4.44*exp(+0.04*x))"
02967 
02968    if (fNoper>0) {
02969       TString* tab=new TString[fNoper];
02970       Bool_t* ismulti=new Bool_t[fNoper];
02971       Int_t spos=0;
02972 
02973       ismulti[0]=kFALSE;
02974       Int_t optype;
02975       Int_t j;
02976       Int_t ternaryend = -1;
02977       for(Int_t i=0;i<fNoper;i++){
02978          optype = GetAction(i);
02979 
02980          if (ternaryend==i) {
02981             // The ? and : have been added to tab[spos-2]
02982             if(ismulti[spos-1]){
02983                tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
02984             } else {
02985                tab[spos-2]=tab[spos-2]+tab[spos-1];
02986             }
02987             spos--;
02988             // Do not call continue since we need to
02989             // do the rest of the loop.
02990          }
02991 
02992          // Boolean optimization breakpoint
02993          if (optype==kBoolOptimize) { // -3) {
02994             continue;
02995          }
02996 
02997          //Sign inversion
02998          if (optype==kSignInv) { // -1) {
02999             tab[spos-1]="-("+tab[spos-1]+")";
03000             // i++;
03001             continue;
03002          }
03003 
03004          //Simple name (parameter,pol0,landau, etc)
03005          if (kexpo<=optype && optype<=kzpol) { // >=0) {
03006             tab[spos]=fExpr[i];
03007             ismulti[spos]=kFALSE;
03008             spos++;
03009             continue;
03010          }
03011 
03012          //constants, variables x,y,z,t, pi
03013          if ((optype<=151 && optype>=140 && optype!=145) || (optype == 40)) {
03014             tab[spos]=fExpr[i];
03015             ismulti[spos]=kFALSE;
03016             spos++;
03017             continue;
03018          }
03019 
03020          //Basic operators (+,-,*,/,==,^,etc)
03021          if(((optype>0 && optype<6) || optype==20 ||
03022              (((optype>59 && optype<69) || (optype >75 && optype<82)) && spos>=2))) {
03023              // if(optype==-20 && spos>=2){
03024             if(ismulti[spos-2]){
03025                tab[spos-2]="("+tab[spos-2]+")";
03026             }
03027             if(ismulti[spos-1]){
03028                tab[spos-2]+=fExpr[i]+("("+tab[spos-1]+")");
03029             }else{
03030                tab[spos-2]+=fExpr[i]+tab[spos-1];
03031             }
03032             ismulti[spos-2]=kTRUE;
03033             spos--;
03034             continue;
03035          }
03036          //Ternary condition
03037          if (optype==kJumpIf) {
03038             if(ismulti[spos-1]){
03039                tab[spos-1]="("+tab[spos-1]+")?";
03040             } else {
03041                tab[spos-1]=tab[spos-1]+"?";
03042             }
03043             continue;
03044          }
03045          if (optype==kJump) {
03046             if(ismulti[spos-1]){
03047                tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+"):";
03048             } else {
03049                tab[spos-2]=tab[spos-2]+tab[spos-1]+":";
03050             }
03051             ternaryend = GetActionParam(i) + 1;
03052             spos--;
03053             continue;
03054          }
03055 
03056          //Functions
03057          int offset = 0;
03058          TString funcname = fExpr[i];
03059          if((optype>9  && optype<16) ||
03060             (optype>20 && optype<23) ||
03061             (optype>29 && optype<34) ||
03062             (optype>40 && optype<44) ||
03063             (optype>69 && optype<76) ||
03064             (optype==145)) {
03065             //Functions with the format func(x)
03066             offset = -1;
03067          }
03068 
03069          if((optype>15 && optype<20) ||
03070             (optype>22 && optype<26)) {
03071             //Functions with the format func(x,y)
03072             offset = -2;
03073          }
03074          if(optype==145) {
03075             int param = (fOper[i] & kTFOperMask);
03076             //int fno   = param / 1000;
03077             int nargs = param % 1000;
03078             offset = -nargs;
03079             // The function name contains return type and parameters types we need
03080             // to trim them.
03081             int depth;
03082             for(j=0, depth=0;j<funcname.Length();++j) {
03083                switch (funcname[j]) {
03084                   case '<':
03085                      ++depth; break;
03086                   case '>':
03087                      --depth; break;
03088                   case ' ':
03089                      if (depth==0) {
03090                         funcname.Remove(0,j+1);
03091                         j = funcname.Length();
03092                         break;
03093                      }
03094                }
03095             }
03096             Ssiz_t ind = funcname.First('(');
03097             funcname.Remove(ind);
03098          }
03099          if (offset<=0 && (spos+offset>=0)) {
03100             tab[spos+offset]=funcname+("("+tab[spos+offset]);
03101             for (j=offset+1; j<0; j++){
03102                tab[spos+offset]+=","+tab[spos+j];
03103             }
03104             tab[spos+offset]+=")";
03105             ismulti[spos+offset]=kFALSE;
03106             spos+=offset+1;
03107             continue;
03108          }
03109       }
03110       if (ternaryend==fNoper) {
03111          // The ? and : have been added to tab[spos-2]
03112          if(ismulti[spos-1]){
03113             tab[spos-2]=tab[spos-2]+"("+tab[spos-1]+")";
03114          } else {
03115             tab[spos-2]=tab[spos-2]+tab[spos-1];
03116          }
03117          spos--;
03118       }
03119 
03120       TString ret = "";
03121       if (spos > 0) ret = tab[spos-1];
03122       delete[] tab;
03123       delete[] ismulti;
03124 
03125       //if option "p" is specified, return the real values of parameters instead of [0]
03126       TString opt = option;
03127       opt.ToLower();
03128       if (opt.Contains("p")) {
03129          char pb[10];
03130          char pbv[100];
03131          for (j=0;j<fNpar;j++) {
03132             snprintf(pb,10,"[%d]",j);
03133             snprintf(pbv,100,"%g",fParams[j]);
03134             ret.ReplaceAll(pb,pbv);
03135          }
03136          ret.ReplaceAll("--","+");
03137          ret.ReplaceAll("+-","-");
03138       }
03139       return ret;
03140    } else{
03141       TString ret="";
03142       return ret;
03143    }
03144 }
03145 
03146 //______________________________________________________________________________
03147 const TObject* TFormula::GetLinearPart(Int_t i)
03148 {
03149    // Return linear part.
03150 
03151    if (!fLinearParts.IsEmpty())
03152       return fLinearParts.UncheckedAt(i);
03153    return 0;
03154 }
03155 
03156 //______________________________________________________________________________
03157 Double_t TFormula::GetParameter(Int_t ipar) const
03158 {
03159    //return value of parameter number ipar
03160 
03161    if (ipar <0 || ipar >= fNpar) return 0;
03162    return fParams[ipar];
03163 }
03164 
03165 //______________________________________________________________________________
03166 Double_t TFormula::GetParameter(const char *parName) const
03167 {
03168    //return value of parameter named parName
03169 
03170    const Double_t kNaN = 1e-300;
03171    Int_t index = GetParNumber(parName);
03172    if (index==-1) {
03173       Error("TFormula", "Parameter %s not found", parName);
03174       return kNaN;
03175    }
03176    return GetParameter(index);
03177 }
03178 
03179 //______________________________________________________________________________
03180 const char *TFormula::GetParName(Int_t ipar) const
03181 {
03182 //*-*-*-*-*-*-*-*Return name of one parameter*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
03183 //*-*            ============================
03184 
03185    if (ipar <0 || ipar >= fNpar) return "";
03186    if (fNames[ipar].Length() > 0) return (const char*)fNames[ipar];
03187    return Form("p%d",ipar);
03188 }
03189 
03190 //______________________________________________________________________________
03191 Int_t TFormula::GetParNumber(const char *parName) const
03192 {
03193    // return parameter number by name
03194 
03195    if (!parName)
03196       return -1;
03197 
03198    for (Int_t i=0; i<fNpar; i++) {
03199       if (!strcmp(GetParName(i),parName)) return i;
03200    }
03201    return -1;
03202 }
03203 
03204 //______________________________________________________________________________
03205 Bool_t TFormula::IsString(Int_t oper) const
03206 {
03207    // return true if the expression at the index 'oper' is to be treated as
03208    // as string
03209 
03210    return GetAction(oper) == kStringConst;
03211 }
03212 
03213 //______________________________________________________________________________
03214 void TFormula::Print(Option_t *) const
03215 {
03216 //*-*-*-*-*-*-*-*-*-*-*Dump this formula with its attributes*-*-*-*-*-*-*-*-*-*
03217 //*-*                  =====================================
03218    Int_t i;
03219    Printf(" %20s : %s Ndim= %d, Npar= %d, Noper= %d",GetName(),GetTitle(), fNdim,fNpar,fNoper);
03220    for (i=0;i<fNoper;i++) {
03221       Printf(" fExpr[%d] = %s  action = %d action param = %d ",
03222              i,(const char*)fExpr[i],GetAction(i),GetActionParam(i));
03223    }
03224    //MI change
03225    //
03226    if (fNOperOptimized>0){
03227       Printf("Optimized expression");
03228       for (i=0;i<fNOperOptimized;i++) {
03229          Printf(" fExpr[%d] = %s\t\t  action = %d action param = %d ",
03230             i,(const char*)fExprOptimized[i],GetActionOptimized(i),GetActionParamOptimized(i));
03231       }
03232    }
03233    //
03234    //
03235    if (!fNames) return;
03236    if (!fParams) return;
03237    for (i=0;i<fNpar;i++) {
03238       Printf(" Par%3d  %20s = %g",i,GetParName(i),fParams[i]);
03239    }
03240 }
03241 
03242 //______________________________________________________________________________
03243 void TFormula::ProcessLinear(TString &formula)
03244 {
03245    //if the formula is for linear fitting, change the title to
03246    //normal and fill the LinearParts array
03247 
03248    TString formula2(formula);
03249    char repl[20];
03250    char *pch;
03251    Int_t nf, offset, replsize;
03252    //replace "++" with "+[i]*"
03253    pch= (char*)strstr(formula.Data(), "++");
03254    if (pch)
03255       formula.Insert(0, "[0]*(");
03256    pch= (char*)strstr(formula.Data(), "++");
03257    if (pch){
03258       //if there are "++", replaces them with +[i]*
03259       nf = 1;
03260       while (pch){
03261          snprintf(repl,20, ")+[%d]*(", nf);
03262          offset = pch-formula.Data();
03263          if (nf<10) replsize = 7;
03264          else if (nf<100) replsize = 8;
03265          else replsize = 9;
03266          formula.Replace(pch-formula.Data(), 2, repl, replsize);
03267          pch = (char*)strstr(formula.Data()+offset, "++");
03268          nf++;
03269       }
03270       formula.Append(')', 1);
03271    } else {
03272       //if there are no ++, create a new string with ++ instead of +[i]*
03273       formula2=formula2(4, formula2.Length()-4);
03274       pch= (char*)strchr(formula2.Data(), '[');
03275       snprintf(repl,20, "++");
03276       nf = 1;
03277       while (pch){
03278          offset = pch-formula2.Data()-1;
03279          if (nf<10) replsize = 5;
03280          else replsize = 6;
03281          formula2.Replace(pch-formula2.Data()-1, replsize, repl, 2);
03282          pch = (char*)strchr(formula2.Data()+offset, '[');
03283          nf++;
03284       }
03285    }
03286 
03287    fLinearParts.Expand(nf);
03288    //break up the formula and fill the array of linear parts
03289    TString replaceformula;
03290    formula2 = formula2.ReplaceAll("++", 2, "|", 1);
03291    TObjArray *oa = formula2.Tokenize("|");
03292    for (Int_t i=0; i<nf; i++) {
03293       replaceformula = ((TObjString *)oa->UncheckedAt(i))->GetString();
03294       TFormula *f = new TFormula(replaceformula.Data(), replaceformula.Data());
03295       if (!f) {
03296          Error("TFormula", "f_linear not allocated");
03297          return;
03298       }
03299       gROOT->GetListOfFunctions()->Remove(f);
03300       f->SetBit(kNotGlobal, 1);
03301       fLinearParts.Add(f);
03302    }
03303    oa->Delete();
03304 }
03305 
03306 //______________________________________________________________________________
03307 void TFormula::SetParameter(const char *name, Double_t value)
03308 {
03309 //*-*-*-*-*-*-*-*Initialize parameter number ipar*-*-*-*-*-*-*-*-*-*-*-*-*
03310 //*-*            ================================
03311 
03312    Int_t ipar = GetParNumber(name);
03313    if (ipar <0 || ipar >= fNpar) return;
03314    fParams[ipar] = value;
03315    Update();
03316 }
03317 
03318 //______________________________________________________________________________
03319 void TFormula::SetParameter(Int_t ipar, Double_t value)
03320 {
03321 //*-*-*-*-*-*-*-*Initialize parameter number ipar*-*-*-*-*-*-*-*-*-*-*-*-*
03322 //*-*            ================================
03323 
03324    if (ipar <0 || ipar >= fNpar) return;
03325    fParams[ipar] = value;
03326    Update();
03327 }
03328 
03329 //______________________________________________________________________________
03330 void TFormula::SetParameters(const Double_t *params)
03331 {
03332 // Initialize array of all parameters
03333 // see also next function with same name
03334 
03335    for (Int_t i=0; i<fNpar;i++) {
03336       fParams[i] = params[i];
03337    }
03338    Update();
03339 }
03340 
03341 
03342 //______________________________________________________________________________
03343 void TFormula::SetParameters(Double_t p0,Double_t p1,Double_t p2,Double_t p3,Double_t p4
03344                        ,Double_t p5,Double_t p6,Double_t p7,Double_t p8,Double_t p9,Double_t p10)
03345 {
03346 // Initialize up to 10 parameters
03347 // All arguments except THE FIRST TWO are optional
03348 // In case of a function with only one parameter, call this function with p1=0.
03349 // Minimum two arguments are required to differentiate this function
03350 // from the SetParameters(cont Double_t *params)
03351 
03352    if (fNpar > 0) fParams[0] = p0;
03353    if (fNpar > 1) fParams[1] = p1;
03354    if (fNpar > 2) fParams[2] = p2;
03355    if (fNpar > 3) fParams[3] = p3;
03356    if (fNpar > 4) fParams[4] = p4;
03357    if (fNpar > 5) fParams[5] = p5;
03358    if (fNpar > 6) fParams[6] = p6;
03359    if (fNpar > 7) fParams[7] = p7;
03360    if (fNpar > 8) fParams[8] = p8;
03361    if (fNpar > 9) fParams[9] = p9;
03362    if (fNpar >10) fParams[10]= p10;
03363    Update();
03364 }
03365 
03366 //______________________________________________________________________________
03367 void TFormula::SetParName(Int_t ipar, const char *name)
03368 {
03369 // Set name of parameter number ipar
03370 
03371    if (ipar <0 || ipar >= fNpar) return;
03372    fNames[ipar] = name;
03373 }
03374 
03375 //______________________________________________________________________________
03376 void TFormula::SetParNames(const char*name0,const char*name1,const char*name2,const char*name3,const char*name4,
03377                      const char*name5,const char*name6,const char*name7,const char*name8,const char*name9,const char*name10)
03378 {
03379 //*-*-*-*-*-*-*-*-*-*Set up to 10 parameter names*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
03380 //*-*                ============================
03381 
03382    if (fNpar > 0) fNames[0] = name0;
03383    if (fNpar > 1) fNames[1] = name1;
03384    if (fNpar > 2) fNames[2] = name2;
03385    if (fNpar > 3) fNames[3] = name3;
03386    if (fNpar > 4) fNames[4] = name4;
03387    if (fNpar > 5) fNames[5] = name5;
03388    if (fNpar > 6) fNames[6] = name6;
03389    if (fNpar > 7) fNames[7] = name7;
03390    if (fNpar > 8) fNames[8] = name8;
03391    if (fNpar > 9) fNames[9] = name9;
03392    if (fNpar >10) fNames[10]= name10;
03393 }
03394 
03395 //______________________________________________________________________________
03396 void TFormula::Streamer(TBuffer &b)
03397 {
03398 //*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
03399 //*-*              =========================================
03400    if (b.IsReading()) {
03401       UInt_t R__s, R__c;
03402       Version_t v = b.ReadVersion(&R__s, &R__c);
03403       if (v > 3) {
03404 
03405          if (v==6) {
03406             Error("Streamer","version 6 is not supported");
03407             return;
03408          }
03409          b.ReadClassBuffer(TFormula::Class(), this, v, R__s, R__c);
03410          if (!TestBit(kNotGlobal)) gROOT->GetListOfFunctions()->Add(this);
03411 
03412          // We need to reinstate (if possible) the TMethodCall.
03413          if (fFunctions.GetLast()>=0) {
03414             // Compiles will reset the parameter values so we need
03415             // to temporarily keep them
03416             Double_t *param = fParams;
03417             TString *names = fNames;
03418             Int_t npar = fNpar;
03419             fParams = 0;
03420             fNames = 0;
03421             Compile();
03422             for (Int_t i = 0; i<npar && i<fNpar; ++i) fParams[i] = param[i];
03423             delete [] param;
03424             delete [] fNames;
03425             fNames = names;
03426          } else if (v<6) {
03427             Convert(v);
03428          }
03429          Optimize();
03430          return;
03431       }
03432       //====process old versions before automatic schema evolution
03433       TNamed::Streamer(b);
03434       b >> fNdim;
03435       b >> fNumber;
03436       if (v > 1) b >> fNval;
03437       if (v > 2) b >> fNstring;
03438       fNpar   = b.ReadArray(fParams);
03439       fOper = new Int_t[gMAXOP];
03440       fNoper  = b.ReadArray(fOper);
03441       fNconst = b.ReadArray(fConst);
03442       if (fNoper) {
03443          fExpr   = new TString[fNoper];
03444       }
03445       if (fNpar) {
03446          fNames  = new TString[fNpar];
03447       }
03448       Int_t i;
03449       for (i=0;i<fNoper;i++)  fExpr[i].Streamer(b);
03450       for (i=0;i<fNpar;i++)   fNames[i].Streamer(b);
03451       if (gROOT->GetListOfFunctions()->FindObject(GetName())) return;
03452       gROOT->GetListOfFunctions()->Add(this);
03453       b.CheckByteCount(R__s, R__c, TFormula::IsA());
03454 
03455       Convert(v);
03456       //====end of old versions
03457 
03458    } else {
03459       b.WriteClassBuffer(TFormula::Class(),this);
03460    }
03461 }
03462 
03463 void TFormula::Convert(UInt_t /* fromVersion */)
03464 {
03465    // Convert the fOper of a TFormula version fromVersion to the current in memory version
03466 
03467    enum {
03468       kOldexpo         =  1000,
03469       kOldgaus         =  2000,
03470       kOldlandau       =  4000,
03471       kOldxylandau     =  4500,
03472       kOldConstants    =  50000,
03473       kOldStrings      =  80000,
03474       kOldVariable     = 100000,
03475       kOldTreeString   = 105000,
03476       kOldFormulaVar   = 110000,
03477       kOldBoolOptimize = 120000,
03478       kOldFunctionCall = 200000
03479    };
03480    int i,j;
03481 
03482    for (i=0,j=0; i<fNoper; ++i,++j) {
03483       Int_t action = fOper[i];
03484       Int_t newActionCode = 0;
03485       Int_t newActionParam = 0;
03486 
03487       if ( action == 0) {
03488          // Sign Inversion
03489 
03490          newActionCode = kSignInv;
03491 
03492          Float_t aresult = 99.99;
03493          sscanf((const char*)fExpr[i],"%g",&aresult);
03494          R__ASSERT((aresult+1)<0.001);
03495 
03496          ++i; // skip the implied multiplication.
03497 
03498          // For consistency and for Optimize to work correctly
03499          // we need to remove the "-1" string in fExpr
03500          for (int z=i; z<fNoper; ++z) {
03501             fExpr[z-1] = fExpr[z];
03502          }
03503 
03504       } else  if ( action < 100 ) {
03505          // basic operators and mathematical library
03506 
03507          newActionCode = action;
03508 
03509       } else if (action >= kOldFunctionCall) {
03510          // Function call
03511 
03512          newActionCode = kFunctionCall;
03513          newActionParam = action-kOldFunctionCall;
03514 
03515       } else if (action >= kOldBoolOptimize) {
03516          // boolean operation optimizer
03517 
03518          newActionCode = kBoolOptimize;
03519          newActionParam = action-kOldBoolOptimize;
03520 
03521       } else if (action >= kOldFormulaVar) {
03522          // a variable
03523 
03524          newActionCode = kVariable;
03525          newActionParam = action-kOldFormulaVar;
03526 
03527       } else if (action >= kOldTreeString) {
03528          // a tree string
03529 
03530          newActionCode = kDefinedString;
03531          newActionParam = action-kOldTreeString;
03532 
03533       } else if (action >= kOldVariable) {
03534          // a tree variable
03535 
03536          newActionCode = kDefinedVariable;
03537          newActionParam = action-kOldVariable;
03538 
03539       } else if (action == kOldStrings) {
03540          // String
03541 
03542          newActionCode = kStringConst;
03543 
03544       } else if (action >= kOldConstants) {
03545          // numerical value
03546 
03547          newActionCode = kConstant;
03548          newActionParam = action-kOldConstants;
03549 
03550       } else if (action > 10000 && action < kOldConstants) {
03551          // Polynomial
03552 
03553          int var = action/10000; //arrondit
03554          newActionCode = kpol + (var-1);
03555          newActionParam = action - var*10000;
03556 
03557       } else if (action >= 4600) {
03558 
03559          Error("Convert","Unsupported value %d",action);
03560 
03561       } else if (action > kOldxylandau) {
03562          // xylandau
03563 
03564          newActionCode = kxylandau;
03565          newActionParam = action - (kOldxylandau+1);
03566 
03567       } else if (action > kOldlandau) {
03568          // landau, xlandau, ylandau or zlandau
03569 
03570          newActionCode = klandau;
03571          int var = action/100-40;
03572          if (var) newActionCode += var;
03573          newActionParam = action - var*100 - (kOldlandau+1);
03574 
03575       } else if (action > 2500 && action < 2600) {
03576          // xygaus
03577 
03578          newActionCode = kxygaus;
03579          newActionParam = action-2501;
03580 
03581       }  else if (action > 2000 && action < 2500) {
03582          //  gaus, xgaus, ygaus or zgaus
03583 
03584          newActionCode = kgaus;
03585          int var = action/100-20;
03586          if (var) newActionCode += var;
03587          newActionParam = action - var*100 - (kOldgaus+1);
03588 
03589       } else if (action > 1500 && action < 1600) {
03590          // xyexpo
03591 
03592          newActionCode = kxyexpo;
03593          newActionParam = action-1501;
03594 
03595       } else if (action > 1000 && action < 1500) {
03596          // expo or xexpo or yexpo or zexpo
03597 
03598          newActionCode = kexpo;
03599          int var = action/100-10;
03600          if (var) newActionCode += var;
03601          newActionParam = action - var*100 - (kOldexpo+1);
03602 
03603       } if (action > 100 && action < 200) {
03604          // Parameter substitution
03605 
03606          newActionCode = kParameter;
03607          newActionParam = action - 101;
03608       }
03609 
03610       SetAction( j, newActionCode, newActionParam );
03611 
03612    }
03613    if (i!=j) {
03614       fNoper -= (i-j);
03615    }
03616 
03617 }
03618 
03619 
03620 
03621 ///////////////////////////////////////////////////////////////////////////////////////
03622 ///////////////////////////////////////////////////////////////////////////////////////
03623 ///////////////////////////////////////////////////////////////////////////////////////
03624 ///////////////////////////////////////////////////////////////////////////////////////
03625 
03626 
03627 //______________________________________________________________________________
03628 TOperOffset::TOperOffset()
03629 {
03630    //  TOper offset  - helper class for TFormula*
03631    //                     specify type of operand
03632    //                     fTypeX   = kVariable
03633    //                              = kParameter
03634    //                              = kConstant
03635    //                     fOffestX = offset in corresponding array
03636    //*-*                  ============================
03637    fType0=0;
03638    fType1=0;
03639    fType2=0;
03640    fType3=0;
03641    fOffset0=0;
03642    fOffset1=0;
03643    fOffset2=0;
03644    fOffset3=0;
03645    fOldAction=0;
03646    fToJump=0;
03647 }
03648 
03649 //______________________________________________________________________________
03650 void  TFormula::MakePrimitive(const char *expr, Int_t pos)
03651 {
03652    //
03653    //  MakePrimitive
03654    //  find TFormulaPrimitive replacement for some operands
03655    //
03656    //
03657    TString cbase(expr);
03658    cbase.ReplaceAll("Double_t ","");
03659    int paran = cbase.First("(");
03660    int nargs = 0;
03661    if (paran>0) {
03662       nargs = 1;
03663       cbase[paran]=0;
03664    }
03665 
03666    if (cbase=="<") cbase="XlY";
03667    if (cbase=="<=") cbase="XleY";
03668    if (cbase==">") cbase="XgY";
03669    if (cbase==">=") cbase="XgeY";
03670    if (cbase=="==" && GetActionOptimized(pos)!=kStringEqual) cbase="XeY";
03671    if (cbase=="!=" && GetActionOptimized(pos)!=kStringNotEqual) cbase="XneY";
03672 
03673    TFormulaPrimitive *prim = TFormulaPrimitive::FindFormula(cbase ,paran>0 ? cbase.Data() + paran + 1 : (const char*)0);
03674    if (prim) {
03675       fPredefined[pos] = prim;
03676       if (prim->fType==10) {
03677          SetActionOptimized(pos, kFD1);
03678       }
03679       if (prim->fType==110) {
03680          SetActionOptimized(pos, kFD2);
03681       }
03682       if (prim->fType==1110) {
03683          SetActionOptimized(pos, kFD3);
03684       }
03685       if (prim->fType==-1) {
03686          SetActionOptimized(pos, kFDM);
03687       }
03688       if (prim->fType==0){
03689          SetActionOptimized(pos,kConstant,fNconst);
03690          fConst[fNconst] = prim->Eval(0);
03691          fNconst++;
03692       }
03693       return;
03694    }
03695 }
03696 
03697 //______________________________________________________________________________
03698 void TFormula::Optimize()
03699 {
03700    //
03701    // MI include
03702    //
03703    // Optimize formula
03704    // 1.) Minimize the number of operands
03705    //     a.)  several operanands are glued togther
03706    //     b.)  some primitive functions glued together - exemp. (x+y) => PlusXY(x,y)
03707    //     c.)  maximize number of standard calls minimizing number of jumps in Eval cases
03708    //     d.)  variables, parameters and constants are mapped - using fOperOfssets0
03709    //          Eval procedure use direct acces to data (only one corresponding case statement in eval procedure)
03710    //
03711    //          pdata[operand={Var,Par,Const}][offset]
03712    //          pdata[fOperOffsets0[i]][fOperOffset1[i+1]]
03713    // 2.) The fastest evaluation function is choosen at the end
03714    //     a.) fOptimal := pointer to the fastest function for given evaluation string
03715    //             switch(GetActionOptimized(0)){
03716    //               case kData : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
03717    //               case kUnary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
03718    //               case kBinary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
03719    //               case kThree : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
03720    //               case kFDM : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
03721    //             }
03722    //     b.) ex. fOptimal = ::EvalPrimitive0 - if it return only variable, constant or parameter
03723    //                      = ::EvalParameter1 - if only one unary operation
03724    //                      = ::EvalPrimitive2 - if only one binary operation
03725    //                        .......
03726 
03727    //
03728    // Initialize data members
03729    //
03730 
03731    Int_t i;
03732 
03733    if (fPredefined)    { delete [] fPredefined;    fPredefined    = 0;}
03734    if (fOperOffset)    { delete [] fOperOffset;    fOperOffset    = 0;}
03735    if (fExprOptimized) { delete [] fExprOptimized; fExprOptimized = 0;}
03736    if (fOperOptimized) { delete [] fOperOptimized; fOperOptimized = 0;}
03737 
03738    fExprOptimized   = new TString[fNoper];
03739    fOperOptimized   = new Int_t[fNoper];
03740    fPredefined      = new TFormulaPrimitive*[fNoper];
03741    fOperOffset      = new TOperOffset[fNoper];
03742    for (i=0; i<fNoper; i++) {
03743       fExprOptimized[i]   = fExpr[i] ;
03744       fOperOptimized[i]   = fOper[i];
03745       fPredefined[i]= 0;
03746    }
03747 
03748    //
03749    //Make primitives
03750    //
03751    for (i=0;i<fNoper;i++){
03752       if (fExprOptimized[i].Data()) {
03753          MakePrimitive(fExprOptimized[i].Data(), i);
03754       }
03755    }
03756    //
03757    Int_t maxfound   = fNoper+1;
03758    Int_t *offset    = new Int_t[maxfound*16];
03759    Int_t *optimized = new Int_t[maxfound];
03760    //
03761    //
03762    TFormulaPrimitive*  primitive[10];
03763    primitive[0] =  TFormulaPrimitive::FindFormula("PlusXY");
03764    primitive[1] =  TFormulaPrimitive::FindFormula("MinusXY");
03765    primitive[2] =  TFormulaPrimitive::FindFormula("MultXY");
03766    primitive[3] =  TFormulaPrimitive::FindFormula("DivXY");
03767    primitive[4] =  TFormulaPrimitive::FindFormula("XpYpZ");
03768    primitive[5] =  TFormulaPrimitive::FindFormula("XxYxZ");
03769    primitive[6] =  TFormulaPrimitive::FindFormula("XxYpZ");
03770    primitive[7] =  TFormulaPrimitive::FindFormula("XpYxZ");
03771    primitive[8] =  TFormulaPrimitive::FindFormula("Pow2");
03772    primitive[9] =  TFormulaPrimitive::FindFormula("Pow3");
03773    //
03774    // set data pointers
03775    //
03776    for (i=0;i<fNoper;i++) optimized[i]=0;
03777    //
03778    for (i=0;i<fNoper;i++){
03779       Int_t actionparam = GetActionParamOptimized(i);
03780       Int_t action = GetActionOptimized(i);
03781 
03782       if (action==kBoolOptimize){
03783          //
03784          // optimize booleans
03785          //
03786          fOperOffset[i].fType1     = actionparam/10;           //  operands to skip
03787          fOperOffset[i].fOffset0   = actionparam%10;           //  1 is && , 2 is ||   - operand
03788          fOperOffset[i].fToJump    = i+fOperOffset[i].fType1;  //  where we should  jump
03789          continue;
03790       }
03791       if (action==kJump || action==kJumpIf) {
03792          // Ternary condtional operator
03793          fOperOffset[i].fType1     = action;
03794          fOperOffset[i].fToJump    = actionparam;
03795       }
03796       //
03797       if (action==kConstant&&i<fNoper-2){
03798          //
03799          // get offsets for kFDM operands
03800          //
03801          if (GetActionOptimized(i+1)==kConstant && GetActionOptimized(i+2)==kFDM){
03802             optimized[i]=1;
03803             optimized[i+1]=1;
03804             i+=2;
03805             fOperOffset[i].fType0=actionparam;
03806             fOperOffset[i].fOffset0=GetActionParamOptimized(i-1);
03807             Int_t offset2 =  int(fConst[fOperOffset[i].fOffset0]+0.4);
03808             fOperOffset[i].fOffset0=offset2;
03809             Int_t nparmax = offset2+fPredefined[i]->fNParameters;
03810             if (nparmax>fNpar){ // increase expected number of parameters
03811                fNpar=nparmax;
03812             }
03813             continue;
03814          }
03815       }
03816       switch(action){
03817       case kVariable : {action=kData; fOperOffset[i].fType0=0; break;}
03818       case kParameter: {action=kData; fOperOffset[i].fType0=1; break;}
03819       case kConstant : {action=kData; fOperOffset[i].fType0=2; break;}
03820       }
03821       //
03822       fOperOffset[i].fOffset0 = GetActionParamOptimized(i);
03823       SetActionOptimized(i,action, actionparam);    //set common data option
03824    }
03825    //
03826    //
03827    fNOperOptimized = fNoper;
03828    //
03829    for (i=0; i<fNoper; ++i)
03830    {
03831       //
03832       if (!(GetActionOptimized(i)== kData)) continue;
03833       offset[0] = fOperOffset[i].fType0;       //
03834       offset[1] = fOperOptimized[i] & kTFOperMask;   // offset
03835 
03836       if ((i+1) >= fNoper) continue;
03837 
03838       if (GetActionOptimized(i+1)==kFD1){
03839          optimized[i] = 1; // to be optimized
03840          i++;
03841          fOperOffset[i].fType0   = offset[0];
03842          fOperOffset[i].fOffset0 = offset[1];
03843          SetActionOptimized(i  ,kUnary);
03844          continue;
03845       }
03846       if (GetActionOptimized(i+1)==kAdd){
03847          optimized[i] = 1; // to be optimized
03848          i++;
03849          fOperOffset[i].fType0   = offset[0];
03850          fOperOffset[i].fOffset0 = offset[1];
03851          SetActionOptimized(i  ,kPlusD);
03852          continue;
03853       }
03854       if (GetActionOptimized(i+1)==kMultiply){
03855          optimized[i] = 1; // to be optimized
03856          i++;
03857          fOperOffset[i].fType0   = offset[0];
03858          fOperOffset[i].fOffset0 = offset[1];
03859          SetActionOptimized(i,kMultD);
03860          continue;
03861       }
03862 
03863       if ((i+2) >= fNoper) continue;
03864 
03865       //
03866       //Binary operators
03867       if (!(GetActionOptimized(i+1)== kData))  continue;
03868       offset[2] = fOperOffset[i+1].fType0;
03869       offset[3] = fOperOptimized[i+1] & kTFOperMask;   // offset
03870       //
03871       if (GetActionOptimized(i+2)==kFD2 || GetActionOptimized(i+2)==kAdd ||GetActionOptimized(i+2)==kSubstract||
03872          GetActionOptimized(i+2)==kMultiply || GetActionOptimized(i+2)==kDivide){
03873 
03874          optimized[i] = 1; // to be optimized
03875          optimized[i+1] = 1; // to be optimized
03876          i+=2;
03877          //
03878          fOperOffset[i].fType0   = offset[0];
03879          fOperOffset[i].fOffset0 = offset[1];
03880          fOperOffset[i].fType1   = offset[2];
03881          fOperOffset[i].fOffset1 = offset[3];
03882          fOperOffset[i].fType2   = GetActionOptimized(i);  //remember old action
03883          if (GetActionOptimized(i)==kAdd)       {fPredefined[i] = primitive[0];}
03884          if (GetActionOptimized(i)==kSubstract) {fPredefined[i] = primitive[1];}
03885          if (GetActionOptimized(i)==kMultiply) {
03886             fPredefined[i]=primitive[2];
03887             if (offset[0]==offset[2]&&offset[1]==offset[3]) {
03888                fPredefined[i] = primitive[8];
03889                SetActionOptimized(i,kUnary);
03890                continue;
03891             }
03892          }
03893          if (GetActionOptimized(i)==kDivide) {
03894             fPredefined[i] = primitive[3];
03895          }
03896          SetActionOptimized(i,kBinary);
03897          continue;
03898       }
03899 
03900       if ((i+3) >= fNoper) continue;
03901 
03902       //
03903       //operator 3
03904       //
03905       if (!(GetActionOptimized(i+2)== kData))  continue;
03906       offset[4] = fOperOffset[i+2].fType0;
03907       offset[5] = fOperOptimized[i+2] & kTFOperMask;   // offset
03908       //
03909       if (GetActionOptimized(i+3)==kFD3|| (  (GetActionOptimized(i+3)==kAdd||GetActionOptimized(i+3)==kMultiply) &&
03910          (GetActionOptimized(i+4)==kAdd||GetActionOptimized(i+4)==kMultiply) ) ){
03911          optimized[i+0]   = 1; // to be optimized
03912          optimized[i+1] = 1; // to be optimized
03913          optimized[i+2] = 1; // to be optimized
03914          i+=3;
03915          //
03916          fOperOffset[i].fType0   = offset[0];
03917          fOperOffset[i].fOffset0 = offset[1];
03918          fOperOffset[i].fType1   = offset[2];
03919          fOperOffset[i].fOffset1 = offset[3];
03920          fOperOffset[i].fType2   = offset[4];
03921          fOperOffset[i].fOffset2 = offset[5];
03922          //
03923          fOperOffset[i].fOldAction = GetActionOptimized(i);  //remember old action
03924          if (GetActionOptimized(i)==kFD3) {
03925             SetActionOptimized(i,kThree);
03926             continue;
03927          }
03928          Int_t action=0;
03929          Int_t action2=kThree;
03930          if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kAdd)      action=4;
03931          if (GetActionOptimized(i)==kMultiply&&GetActionOptimized(i+1)==kMultiply) {
03932             action=5;
03933             if (offset[0]==offset[2]&&offset[1]==offset[3]&&offset[0]==offset[4]&&offset[1]==offset[5]){
03934                fPredefined[i]=primitive[9];
03935                action2=kUnary;
03936                action =9;
03937             }
03938          }
03939          if (GetActionOptimized(i)==kAdd&&GetActionOptimized(i+1)==kMultiply) action=6;
03940          if (GetActionOptimized(i)==kMultiply&&GetActionOptimized(i+1)==kAdd) action=7;
03941          //
03942          optimized[i]=1;
03943          i++;
03944          fOperOffset[i].fType0   = offset[0];
03945          fOperOffset[i].fOffset0 = offset[1];
03946          fOperOffset[i].fType1 = offset[2];
03947          fOperOffset[i].fOffset1 = offset[3];
03948          fOperOffset[i].fType2 = offset[4];
03949          fOperOffset[i].fOffset2 = offset[5];
03950          fPredefined[i]=primitive[action];
03951          SetActionOptimized(i,action2);
03952          continue;
03953       }
03954    }
03955    //
03956    //
03957    Int_t operO=0;
03958    TString expr="";
03959    Int_t *map0 = new Int_t[maxfound];   //remapping of the operands
03960    Int_t *map1 = new Int_t[maxfound];   //remapping of the operands
03961    for (i=0;i<fNoper;i++){
03962       map0[i]     =  operO;
03963       map1[operO] =  i;
03964       fOperOptimized[operO] = fOperOptimized[i];
03965       fPredefined[operO]    = fPredefined[i];
03966       fOperOffset[operO]    = fOperOffset[i];
03967       expr += fExprOptimized[i];
03968       if (optimized[i]==0){
03969          fExprOptimized[operO] = expr;
03970          expr = "";
03971          operO++;
03972       }else{
03973          expr += ",";
03974       }
03975    }
03976    //
03977    // Recalculate long jump for  Boolen optimize
03978    //
03979    for (i=0; i<fNOperOptimized; i++){
03980       Int_t optaction = GetActionOptimized(i);
03981       if (optaction==kBoolOptimize){
03982          Int_t oldpos = fOperOffset[i].fToJump;
03983          Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
03984          fOperOffset[i].fToJump = newpos;   // new position to jump
03985          Int_t actionop = GetActionParamOptimized(i) % 10;
03986          switch (actionop) {
03987             case 1: SetActionOptimized(i,kBoolOptimizeAnd,newpos);  break;
03988             case 2: SetActionOptimized(i,kBoolOptimizeOr,newpos); break;
03989          }
03990       } else if (optaction==kJump || optaction==kJumpIf) {
03991          Int_t oldpos = fOperOffset[i].fToJump;
03992          Int_t newpos = oldpos==fNoper ? fNOperOptimized : map0[oldpos];
03993          fOperOffset[i].fToJump = newpos;   // new position to jump
03994          SetActionOptimized(i,optaction,newpos);
03995       }
03996    }
03997 
03998 
03999    fNOperOptimized = operO;
04000    //
04001    fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalParFast;
04002    if (fNOperOptimized==1) {
04003       switch(GetActionOptimized(0)){
04004          case kData   : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive0; break;}
04005          case kUnary  : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive1; break;}
04006          case kBinary : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive2; break;}
04007          case kThree  : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive3; break;}
04008          case kFDM    : {fOptimal= (TFormulaPrimitive::TFuncG)&TFormula::EvalPrimitive4; break;}
04009       }
04010    }
04011 
04012    delete [] map1;
04013    delete [] map0;
04014    delete [] offset;
04015    delete [] optimized;
04016 }
04017 
04018 //______________________________________________________________________________
04019 Double_t TFormula::EvalPrimitive(const Double_t *x, const Double_t *params)
04020 {
04021    //
04022    //Evaluate primitive formula
04023    //
04024    const Double_t  *pdata[3] = {x,(params!=0)?params:fParams, fConst};
04025    Double_t result = pdata[fOperOffset->fType0][fOperOffset->fOffset0];
04026    switch((fOperOptimized[0] >> kTFOperShift)) {
04027       case kData          : return result;
04028       case kUnary         : return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
04029       case kBinary         :return (fPredefined[0]->fFunc110)(result,
04030                                pdata[fOperOffset->fType1][fOperOffset->fOffset1]);
04031 
04032       case kThree         :return (fPredefined[0]->fFunc1110)(result, pdata[fOperOffset->fType1][fOperOffset->fOffset1],
04033                               pdata[fOperOffset->fType2][fOperOffset->fOffset2]);
04034       case kFDM         : return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
04035                              (Double_t*)&params[fOperOffset->fOffset0]);
04036    }
04037    return 0;
04038 }
04039 
04040 //______________________________________________________________________________
04041 Double_t TFormula::EvalPrimitive0(const Double_t *x, const Double_t *params)
04042 {
04043    //
04044    //Evaluate primitive formula
04045    //
04046    const Double_t  *pdata[3] = {x,(params!=0)?params:fParams, fConst};
04047    return  pdata[fOperOffset->fType0][fOperOffset->fOffset0];
04048 }
04049 
04050 //______________________________________________________________________________
04051 Double_t TFormula::EvalPrimitive1(const Double_t *x, const Double_t *params)
04052 {
04053    //
04054    //Evaluate primitive formula
04055    //
04056    const Double_t  *pdata[3] = {x,(params!=0)?params:fParams, fConst};
04057    return (fPredefined[0]->fFunc10)(pdata[fOperOffset->fType0][fOperOffset->fOffset0]);
04058 }
04059 
04060 //______________________________________________________________________________
04061 Double_t TFormula::EvalPrimitive2(const Double_t *x, const Double_t *params)
04062 {
04063    //
04064    //Evaluate primitive formula
04065    //
04066    const Double_t  *pdata[3] = {x,(params!=0)?params:fParams, fConst};
04067    return (fPredefined[0]->fFunc110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0],
04068       pdata[fOperOffset->fType1][fOperOffset->fOffset1]);
04069 }
04070 
04071 //______________________________________________________________________________
04072 Double_t TFormula::EvalPrimitive3(const Double_t *x, const Double_t *params)
04073 {
04074    //
04075    //Evaluate primitive formula
04076    //
04077    const Double_t  *pdata[3] = {x,(params!=0)?params:fParams, fConst};
04078    return (fPredefined[0]->fFunc1110)(pdata[fOperOffset->fType0][fOperOffset->fOffset0], pdata[fOperOffset->fType1][fOperOffset->fOffset1],
04079       pdata[fOperOffset->fType2][fOperOffset->fOffset2]);
04080 }
04081 
04082 //______________________________________________________________________________
04083 Double_t TFormula::EvalPrimitive4(const Double_t *x, const Double_t *params)
04084 {
04085    //
04086    //Evaluate primitive formula
04087    //
04088    const Double_t *par = (params!=0)?params:fParams;
04089    return (fPredefined[0]->fFuncG)((Double_t*)&x[fOperOffset->fType0],
04090       (Double_t*)&par[fOperOffset->fOffset0]);
04091 }
04092 
04093 
04094 //______________________________________________________________________________
04095 Double_t TFormula::EvalParFast(const Double_t *x, const Double_t *uparams)
04096 {
04097    //*-*-*-*-*-*-*-*-*-*-*Evaluate this formula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
04098    //*-*                  =====================
04099    //*-*
04100    //*-*   The current value of variables x,y,z,t is passed through the pointer x.
04101    //*-*   The parameters used will be the ones in the array params if params is given
04102    //*-*    otherwise parameters will be taken from the stored data members fParams
04103    //Begin_Html
04104    /*
04105    <img src="gif/eval.gif">
04106    */
04107    //End_Html
04108    //*-*
04109    //*-*
04110    //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
04111    const Double_t  *pdata[3] = {x,(uparams!=0)?uparams:fParams, fConst};
04112    //
04113    Int_t i,j;
04114    Double_t tab[kMAXFOUND];
04115    const char *stringStack[gMAXSTRINGFOUND];
04116    Double_t param_calc[kMAXFOUND];
04117    char *string_calc[gMAXSTRINGFOUND];
04118    Int_t precalculated = 0;
04119    Int_t precalculated_str = 0;
04120 
04121    Double_t *params;
04122 
04123    if (uparams) {
04124       //for (j=0;j<fNpar;j++) fParams[j] = params[j];
04125       params = const_cast<Double_t*>(uparams);
04126    } else {
04127       params = fParams;
04128    }
04129 
04130    //if (params) {
04131    // for (j=0;j<fNpar;j++) fParams[j] = params[j];
04132    //}
04133    UInt_t pos    = 0;
04134    UInt_t strpos = 0;
04135    //   for (i=0; i<fNoper; ++i) {
04136    for (i=0; i<fNOperOptimized; ++i) {
04137       //
04138       const int oper = fOperOptimized[i];
04139       const int opcode = oper >> kTFOperShift;
04140 
04141       switch(opcode) {  // FREQUENTLY USED OPERATION
04142          case kData      : tab[pos] = pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; pos++;continue;
04143          case kPlusD     : tab[pos-1]+= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
04144          case kMultD     : tab[pos-1]*= pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]; continue;
04145          case kAdd       : pos--; tab[pos-1] += tab[pos]; continue;
04146          case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
04147          case kMultiply  : pos--; tab[pos-1] *= tab[pos]; continue;
04148          case kDivide    : pos--; if (tab[pos] == 0) tab[pos-1] = 0; //  division by 0
04149                               else     tab[pos-1] /= tab[pos];
04150                               continue;
04151          case kUnary     : tab[pos] = (fPredefined[i]->fFunc10)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0]); pos++;continue;
04152          case kBinary    : tab[pos] = (fPredefined[i]->fFunc110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
04153                               pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1]);pos++;continue;
04154 
04155          case kThree     : tab[pos]   = (fPredefined[i]->fFunc1110)(pdata[fOperOffset[i].fType0][fOperOffset[i].fOffset0],
04156                               pdata[fOperOffset[i].fType1][fOperOffset[i].fOffset1],
04157                               pdata[fOperOffset[i].fType2][fOperOffset[i].fOffset2]); pos++; continue;
04158 
04159          case kFDM       : tab[pos] = (fPredefined[i]->fFuncG)(&x[fOperOffset[i].fType0],&params[fOperOffset[i].fOffset0]); pos++;continue;
04160          case kFD1       : tab[pos-1]   =(fPredefined[i]->fFunc10)(tab[pos-1]); continue;
04161          case kFD2       :    pos--; tab[pos-1]   = (fPredefined[i]->fFunc110)(tab[pos-1],tab[pos]); continue;
04162          case kFD3       :    pos-=2; tab[pos-1]   = (fPredefined[i]->fFunc1110)(tab[pos-1],tab[pos],tab[pos+1]); continue;
04163       }
04164       //
04165       switch(opcode) {
04166          case kBoolOptimizeAnd: {
04167             if (!tab[pos-1]) i=fOperOffset[i].fToJump; continue;
04168          }
04169          case kBoolOptimizeOr: {
04170             if (tab[pos-1])  i=fOperOffset[i].fToJump; continue;
04171          }
04172          case kAnd  : pos--; tab[pos-1] = (bool)tab[pos];  continue;  // use the fact that other were check before - see bool optimize
04173          case kOr   : pos--; tab[pos-1] = (bool)tab[pos];  continue;
04174       }
04175       switch(opcode) {
04176          //    case kabs  : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
04177          case kabs  : if (tab[pos-1]<0) tab[pos-1]=-tab[pos-1]; continue;
04178          case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1; continue;
04179          case kint  : tab[pos-1] = Double_t(Int_t(tab[pos-1])); continue;
04180          case kpow  : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
04181 
04182          case kModulo     : {pos--;
04183             Long64_t int1((Long64_t)tab[pos-1]);
04184             Long64_t int2((Long64_t)tab[pos]);
04185             tab[pos-1] = Double_t(int1%int2);
04186             continue;}
04187 
04188 
04189          case kStringConst: { strpos++; stringStack[strpos-1] = (char*)fExprOptimized[i].Data(); pos++; tab[pos-1] = 0; continue; }
04190          case kfmod : pos--; tab[pos-1] = fmod(tab[pos-1],tab[pos]); continue;
04191 
04192          case kstrstr : strpos -= 2; pos-=2; pos++;
04193             if (strstr(stringStack[strpos],stringStack[strpos+1])) tab[pos-1]=1;
04194             else tab[pos-1]=0; continue;
04195          case kpi   : pos++; tab[pos-1] = TMath::ACos(-1); continue;
04196 
04197 
04198          case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
04199 
04200          case krndm : pos++; tab[pos-1] = gRandom->Rndm(1); continue;
04201 
04202 
04203          case kEqual: pos--; if (tab[pos-1] == tab[pos]) tab[pos-1]=1;
04204                         else tab[pos-1]=0; continue;
04205          case kNotEqual : pos--; if (tab[pos-1] != tab[pos]) tab[pos-1]=1;
04206                         else tab[pos-1]=0; continue;
04207          case kNot : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1; continue;
04208 
04209          case kStringEqual : strpos -= 2; pos -=2 ; pos++;
04210             if (!strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
04211             else tab[pos-1]=0; continue;
04212          case kStringNotEqual: strpos -= 2; pos -= 2; pos++;
04213             if (strcmp(stringStack[strpos+1],stringStack[strpos])) tab[pos-1]=1;
04214             else tab[pos-1]=0; continue;
04215 
04216          case kBitAnd : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); continue;
04217          case kBitOr  : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); continue;
04218          case kLeftShift : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) <<((Int_t) tab[pos]); continue;
04219          case kRightShift: pos--; tab[pos-1]= ((Int_t) tab[pos-1]) >>((Int_t) tab[pos]); continue;
04220 
04221          case kJump   : i = (oper & kTFOperMask); continue;
04222          case kJumpIf : pos--; if (!tab[pos]) i = (oper & kTFOperMask); continue;
04223 
04224          case kBoolOptimize: {
04225             // boolean operation optimizer
04226 
04227             int param = (oper & kTFOperMask);
04228             int op = param % 10; // 1 is && , 2 is ||
04229 
04230             if (op == 1 && (!tab[pos-1]) ) {
04231                // &&: skip the right part if the left part is already false
04232 
04233                i +=  param / 10;
04234 
04235                // Preserve the existing behavior (i.e. the result of a&&b is
04236                // either 0 or 1)
04237                tab[pos-1] = 0;
04238 
04239             } else if (op == 2 && tab[pos-1] ) {
04240                // ||: skip the right part if the left part is already true
04241 
04242                i +=  param / 10;
04243 
04244                // Preserve the existing behavior (i.e. the result of a||b is
04245                // either 0 or 1)
04246                tab[pos-1] = 1;
04247 
04248             }
04249 
04250             continue;
04251          }
04252 
04253       }
04254       switch(opcode) {
04255 
04256 #define R__EXPO(var)                                                         \
04257          {                                                                   \
04258            pos++; int param = (oper & kTFOperMask);                          \
04259            tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[var]);    \
04260            continue;                                                         \
04261          }
04262          // case kexpo:
04263          case kxexpo: R__EXPO(0);
04264          case kyexpo: R__EXPO(1);
04265          case kzexpo: R__EXPO(2);
04266          case kxyexpo:{  pos++; int param = (oper & kTFOperMask);
04267             tab[pos-1] = TMath::Exp(params[param]+params[param+1]*x[0]+params[param+2]*x[1]);
04268             continue;  }
04269 #ifdef R__GAUS
04270 #undef R__GAUS
04271 #endif
04272 #define R__GAUS(var)                                                                           \
04273                      {                                                                         \
04274                      pos++; int param = (oper & kTFOperMask);                                  \
04275                      tab[pos-1] = params[param]*TMath::Gaus(x[var],params[param+1],          \
04276                                                              params[param+2],IsNormalized()); \
04277                      continue;                                                                 \
04278                      }
04279 
04280                      // case kgaus:
04281          case kxgaus: R__GAUS(0);
04282          case kygaus: R__GAUS(1);
04283          case kzgaus: R__GAUS(2);
04284          case kxygaus: { pos++; int param = (oper & kTFOperMask);
04285             Double_t intermede1;
04286             if (params[param+2] == 0) {
04287                intermede1=1e10;
04288             } else {
04289                intermede1=Double_t((x[0]-params[param+1])/params[param+2]);
04290             }
04291             Double_t intermede2;
04292             if (params[param+4] == 0) {
04293                intermede2=1e10;
04294             } else {
04295                intermede2=Double_t((x[1]-params[param+3])/params[param+4]);
04296             }
04297             tab[pos-1] = params[param]*TMath::Exp(-0.5*(intermede1*intermede1+intermede2*intermede2));
04298             continue; }
04299 
04300 #define R__LANDAU(var)                                                                  \
04301                       {                                                                                       \
04302                       pos++; const int param = (oper & kTFOperMask);                                       \
04303                       tab[pos-1] = params[param]*TMath::Landau(x[var],params[param+1],params[param+2],IsNormalized()); \
04304                       continue;                                                                            \
04305                       }
04306                       // case klandau:
04307          case kxlandau: R__LANDAU(0);
04308          case kylandau: R__LANDAU(1);
04309          case kzlandau: R__LANDAU(2);
04310          case kxylandau: { pos++; int param = oper&0x7fffff /* ActionParams[i] */ ;
04311             Double_t intermede1=TMath::Landau(x[0], params[param+1], params[param+2],IsNormalized());
04312             Double_t intermede2=TMath::Landau(x[1], params[param+3], params[param+4],IsNormalized());
04313             tab[pos-1] = params[param]*intermede1*intermede2;
04314             continue;
04315                         }
04316 
04317 #define R__POLY(var)                                                                       \
04318                         {                                                                  \
04319                         pos++; int param = (oper & kTFOperMask);                           \
04320                         tab[pos-1] = 0; Double_t intermede = 1;                            \
04321                         Int_t inter = param/100; /* arrondit */                            \
04322                         Int_t int1= param-inter*100-1; /* aucune simplification ! (sic) */ \
04323                         for (j=0 ;j<inter+1;j++) {                                         \
04324                         tab[pos-1] += intermede*params[j+int1];                           \
04325                         intermede *= x[var];                                               \
04326                         }                                                                  \
04327                         continue;                                                          \
04328                         }
04329                         // case kpol:
04330          case kxpol: R__POLY(0);
04331          case kypol: R__POLY(1);
04332          case kzpol: R__POLY(2);
04333 
04334          case kDefinedVariable : {
04335             if (!precalculated) {
04336                precalculated = 1;
04337                for(j=0;j<fNval;j++) param_calc[j]=DefinedValue(j);
04338             }
04339             pos++; tab[pos-1] = param_calc[(oper & kTFOperMask)];
04340             continue;
04341             }
04342 
04343          case kDefinedString : {
04344             int param = (oper & kTFOperMask);
04345             if (!precalculated_str) {
04346                precalculated_str=1;
04347                for (j=0;j<fNstring;j++) string_calc[j]=DefinedString(j);
04348             }
04349             strpos++; stringStack[strpos-1] = string_calc[param];
04350             pos++; tab[pos-1] = 0;
04351             continue;
04352             }
04353 
04354          case kFunctionCall: {
04355             // an external function call
04356 
04357             int param = (oper & kTFOperMask);
04358             int fno   = param / 1000;
04359             int nargs = param % 1000;
04360 
04361             // Retrieve the function
04362             TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
04363 
04364             // Set the arguments
04365             TString args;
04366             if (nargs) {
04367                UInt_t argloc = pos-nargs;
04368                for(j=0;j<nargs;j++,argloc++,pos--) {
04369                   if (TMath::IsNaN(tab[argloc])) {
04370                      // TString would add 'nan' this is not what we want
04371                      // so let's do somethign else
04372                      args += "(double)(0x8000000000000)";
04373                   } else {
04374                      args += tab[argloc];
04375                   }
04376                   args += ',';
04377                }
04378                args.Remove(args.Length()-1);
04379             }
04380             pos++;
04381             Double_t ret;
04382             method->Execute(args,ret);
04383             tab[pos-1] = ret; // check for the correct conversion!
04384 
04385             continue;
04386          };
04387       }
04388       if (!TestBit(kOptimizationError)) {
04389          SetBit(kOptimizationError);
04390          Warning("EvalParFast","Found an unsupported optmized opcode (%d)",oper >> kTFOperShift);
04391       }
04392    }
04393    Double_t result0 = tab[0];
04394    return result0;
04395 
04396 }
04397 
04398 
04399 //______________________________________________________________________________
04400 Int_t TFormula::PreCompile()
04401 {
04402    //
04403    //Pre compile function
04404    //
04405    TString str = fTitle;
04406    if (str.Length()<3) return 1;
04407    if (str[str.Length()-1]!='+'&&str[str.Length()-2]!='+') return 1;
04408    str[str.Length()-2]=0;
04409    TString funName("preformula_");
04410    funName += fName;
04411    if (TFormulaPrimitive::FindFormula(funName)) return 0;
04412    TString fileName;
04413    fileName.Form("/tmp/%s.C",funName.Data());
04414 
04415    FILE *hf;
04416    hf = fopen(fileName.Data(),"w");
04417    if (hf == 0) {
04418       Error("PreCompile","Unable to open the file %s for writing.",fileName.Data());
04419       return 1;
04420    }
04421    fprintf(hf,   "/////////////////////////////////////////////////////////////////////////\n");
04422    fprintf(hf,   "//   This code has been automatically generated \n");
04423    //
04424    fprintf(hf,   "Double_t %s(Double_t *x, Double_t *p){",funName.Data());
04425    fprintf(hf,   "return (%s);\n}",str.Data());
04426 
04427    //   fprintf("TFormulaPrimitive::AddFormula(new TFormulaPrimitive(\"%s::%s\",\"%s::%s\",(TFormulaPrimitive::GenFunc0)%s::%s));\n",
04428    //             clname,method->GetName(),clname,method->GetName(),clname,method->GetName());
04429    fclose(hf);
04430 
04431    return 0;
04432 
04433 
04434 }
04435 
04436 
04437 //______________________________________________________________________________
04438 void TFormula::SetMaxima(Int_t maxop, Int_t maxpar, Int_t maxconst)
04439 {
04440    // static function to set the maximum value of 3 parameters
04441    //  -maxop    : maximum number of operations
04442    //  -maxpar   : maximum number of parameters
04443    //  -maxconst : maximum number of constants
04444    // None of these parameters cannot be less than 10 (default is 1000)
04445    // call this function to increase one or all maxima when processing
04446    // very complex formula, eg TFormula::SetMaxima(100000,1000,1000000);
04447    // If you process many functions with a small number of operations/parameters
04448    // you may gain some memory and performance by decreasing these values.
04449 
04450    gMAXOP    = TMath::Max(10,maxop);
04451    gMAXPAR   = TMath::Max(10,maxpar);
04452    gMAXCONST = TMath::Max(10,maxconst);
04453 }

Generated on Tue Jul 5 14:24:17 2011 for ROOT_528-00b_version by  doxygen 1.5.1