// @(#)root/hist:$Id$
// Author: Maciej Zimnoch   30/09/2013

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
// ---------------------------------- TFormula.h
#ifndef ROOT_TFormula
#define ROOT_TFormula


#ifndef ROOT_TNamed
#include "TNamed.h"
#endif
 #ifndef ROOT_TBits
#include "TBits.h"
#endif
#ifndef ROOT_TObjArray
#include "TObjArray.h"
#endif
#include "TMethodCall.h"
#include "TInterpreter.h"
#include <vector>
#include <list>
#include <map>

class TFormulaFunction
{
public:
   TString  fName;
   TString  fBody;
   Int_t    fNargs;
   Bool_t   fFound;
   Bool_t   fFuncCall;
   const char *  GetName() const    { return fName.Data(); }
   const char *  GetBody() const    { return fBody.Data(); }
   Int_t    GetNargs() const   { return fNargs;}
   Bool_t   IsFuncCall() const { return fFuncCall;}
   TFormulaFunction(){}
   TFormulaFunction(const TString &name, const TString &body, int numArgs)
      : fName(name),fBody(body),fNargs(numArgs),fFound(false),fFuncCall(true) {}
   TFormulaFunction(const TString& name)
   : fName(name),fBody(""),fNargs(0),fFound(false),fFuncCall(false){}
   Bool_t operator<(const TFormulaFunction &rhv) const
   {
      // order by length - first the longer ones to avoid replacing wrong functions 
      if ( fName.Length() > rhv.fName.Length() )
         return true;
      else if ( fName.Length() > rhv.fName.Length() )
         return false;
      // case of equal length
      return fName < rhv.fName && fBody < rhv.fBody;
   }
   Bool_t operator==(const TFormulaFunction &rhv) const
   {
      return fName == rhv.fName && fBody == rhv.fBody && fNargs == rhv.fNargs;
   }
};

class TFormulaVariable
{
public:
   TString fName;
   Double_t fValue;
   Int_t fArrayPos;
   Bool_t fFound;
   const char * GetName() const     { return fName.Data(); }
   Double_t GetInitialValue() const    { return fValue; }
   Int_t    GetArrayPos() const { return fArrayPos; }
   TFormulaVariable():fName(""),fValue(-1),fArrayPos(-1),fFound(false){}
   TFormulaVariable(const TString &name, Double_t value, Int_t pos)
   : fName(name), fValue(value), fArrayPos(pos),fFound(false) {}
   Bool_t operator<(const TFormulaVariable &rhv) const
   {
      return fName < rhv.fName;
   }
};

struct TFormulaParamOrder {
   bool operator() (const TString& a, const TString& b) const;
};


class TFormula : public TNamed
{
private:

   // All data members are transient apart from the string defining the formula and the parameter values

   TString           fClingInput;           //! input function passed to Cling
   std::vector<Double_t>  fClingVariables;       //!  cached variables
   std::vector<Double_t>  fClingParameters;      //  parameter values
   Bool_t            fReadyToExecute;       //! trasient to force initialization
   Bool_t            fClingInitialized;  //!  transient to force re-initialization
   Bool_t            fAllParametersSetted;    // flag to control if all parameters are setted
   TMethodCall*      fMethod;        //! pointer to methocall
   TString           fClingName;     //! unique name passed to Cling to define the function ( double clingName(double*x, double*p) )

   TInterpreter::CallFuncIFacePtr_t::Generic_t fFuncPtr;   //!  function pointer
   void *   fLambdaPtr;                                    //!  pointer to the lambda function

   void     InputFormulaIntoCling();
   Bool_t   PrepareEvalMethod();
   void     FillDefaults();
   void     HandlePolN(TString &formula);
   void     HandleParametrizedFunctions(TString &formula);
   void     HandleExponentiation(TString &formula);
   void     HandleLinear(TString &formula);
   Bool_t   InitLambdaExpression(const char * formula);
   static Bool_t   IsDefaultVariableName(const TString &name);
protected:

   std::list<TFormulaFunction>         fFuncs;    //!
   std::map<TString,TFormulaVariable>  fVars;     //!  list of  variable names
   std::map<TString,Int_t,TFormulaParamOrder>   fParams;   //  list of  parameter names
   std::map<TString,Double_t>          fConsts;   //!
   std::map<TString,TString>           fFunctionsShortcuts;  //!
   TString                        fFormula;
   Int_t                          fNdim;  //!
   Int_t                          fNpar;  //!
   Int_t                          fNumber;  //!
   std::vector<TObject*>          fLinearParts;  // vector of linear functions

   static Bool_t IsOperator(const char c);
   static Bool_t IsBracket(const char c);
   static Bool_t IsFunctionNameChar(const char c);
   static Bool_t IsScientificNotation(const TString & formula, int ipos);
   static Bool_t IsHexadecimal(const TString & formula, int ipos);
   void   ExtractFunctors(TString &formula);
   void   PreProcessFormula(TString &formula);
   void   ProcessFormula(TString &formula);
   Bool_t PrepareFormula(TString &formula);
   void   ReplaceParamName(TString &formula, const TString & oldname, const TString & name);
   void   DoAddParameter(const TString &name, Double_t value, bool processFormula);
   void   DoSetParameters(const Double_t * p, Int_t size);
   void   SetPredefinedParamNames(); 

   Double_t       DoEval(const Double_t * x, const Double_t * p = nullptr) const;

public:

   enum {
      kNotGlobal     = BIT(10),    // don't store in gROOT->GetListOfFunction (it should be protected)
      kNormalized    = BIT(14),    // set to true if the TFormula (ex gausn) is normalized
      kLinear        = BIT(16),    //set to true if the TFormula is for linear fitting
      kLambda        = BIT(17)     // set to true if TFormula has been build with a lambda  
   };
                  TFormula();
   virtual        ~TFormula();
   TFormula&      operator=(const TFormula &rhs);
   TFormula(const char *name, const char * formula = "", bool addToGlobList = true);
   TFormula(const char *name, const char * formula, int ndim, int npar, bool addToGlobList = true);
                  TFormula(const TFormula &formula);
   //               TFormula(const char *name, Int_t nparams, Int_t ndims);

   void           AddParameter(const TString &name, Double_t value = 0) { DoAddParameter(name,value,true); }
   void           AddVariable(const TString &name, Double_t value = 0);
   void           AddVariables(const TString *vars, const Int_t size);
   Int_t          Compile(const char *expression="");
   virtual void   Copy(TObject &f1) const;
   virtual void   Clear(Option_t * option="");
   Double_t       Eval(Double_t x) const;
   Double_t       Eval(Double_t x, Double_t y) const;
   Double_t       Eval(Double_t x, Double_t y , Double_t z) const;
   Double_t       Eval(Double_t x, Double_t y , Double_t z , Double_t t ) const;
   Double_t       EvalPar(const Double_t *x, const Double_t *params=0) const;
   TString        GetExpFormula(Option_t *option="") const;
   const TObject *GetLinearPart(Int_t i) const;
   Int_t          GetNdim() const {return fNdim;}
   Int_t          GetNpar() const {return fNpar;}
   Int_t          GetNumber() const { return fNumber; }
   const char *   GetParName(Int_t ipar) const;
   Int_t          GetParNumber(const char * name) const;
   Double_t       GetParameter(const char * name) const;
   Double_t       GetParameter(Int_t param) const;
   Double_t*      GetParameters() const;
   void           GetParameters(Double_t *params) const;
   Double_t       GetVariable(const char *name) const;
   Int_t          GetVarNumber(const char *name) const;
   TString        GetVarName(Int_t ivar) const;
   Bool_t         IsValid() const { return fReadyToExecute && fClingInitialized; }
   Bool_t         IsLinear() const { return TestBit(kLinear); }
   void           Print(Option_t *option = "") const;
   void           SetName(const char* name);
   void           SetParameter(const char* name, Double_t value);
   void           SetParameter(Int_t param, Double_t value);
   void           SetParameters(const Double_t *params);
   //void           SetParameters(const pair<TString,Double_t> *params, const Int_t size);
   void           SetParameters(Double_t p0,Double_t p1,Double_t p2=0,Double_t p3=0,Double_t p4=0,
                                     Double_t p5=0,Double_t p6=0,Double_t p7=0,Double_t p8=0,
                                     Double_t p9=0,Double_t p10=0); // *MENU*
   void           SetParName(Int_t ipar, const char *name);
   void           SetParNames(const char *name0="p0",const char *name1="p1",const char
                             *name2="p2",const char *name3="p3",const char
                             *name4="p4", const char *name5="p5",const char *name6="p6",const char *name7="p7",const char
                             *name8="p8",const char *name9="p9",const char *name10="p10"); // *MENU*
   void           SetVariable(const TString &name, Double_t value);
   void           SetVariables(const std::pair<TString,Double_t> *vars, const Int_t size);

   ClassDef(TFormula,10)
};
#endif
 TFormula.h:1
 TFormula.h:2
 TFormula.h:3
 TFormula.h:4
 TFormula.h:5
 TFormula.h:6
 TFormula.h:7
 TFormula.h:8
 TFormula.h:9
 TFormula.h:10
 TFormula.h:11
 TFormula.h:12
 TFormula.h:13
 TFormula.h:14
 TFormula.h:15
 TFormula.h:16
 TFormula.h:17
 TFormula.h:18
 TFormula.h:19
 TFormula.h:20
 TFormula.h:21
 TFormula.h:22
 TFormula.h:23
 TFormula.h:24
 TFormula.h:25
 TFormula.h:26
 TFormula.h:27
 TFormula.h:28
 TFormula.h:29
 TFormula.h:30
 TFormula.h:31
 TFormula.h:32
 TFormula.h:33
 TFormula.h:34
 TFormula.h:35
 TFormula.h:36
 TFormula.h:37
 TFormula.h:38
 TFormula.h:39
 TFormula.h:40
 TFormula.h:41
 TFormula.h:42
 TFormula.h:43
 TFormula.h:44
 TFormula.h:45
 TFormula.h:46
 TFormula.h:47
 TFormula.h:48
 TFormula.h:49
 TFormula.h:50
 TFormula.h:51
 TFormula.h:52
 TFormula.h:53
 TFormula.h:54
 TFormula.h:55
 TFormula.h:56
 TFormula.h:57
 TFormula.h:58
 TFormula.h:59
 TFormula.h:60
 TFormula.h:61
 TFormula.h:62
 TFormula.h:63
 TFormula.h:64
 TFormula.h:65
 TFormula.h:66
 TFormula.h:67
 TFormula.h:68
 TFormula.h:69
 TFormula.h:70
 TFormula.h:71
 TFormula.h:72
 TFormula.h:73
 TFormula.h:74
 TFormula.h:75
 TFormula.h:76
 TFormula.h:77
 TFormula.h:78
 TFormula.h:79
 TFormula.h:80
 TFormula.h:81
 TFormula.h:82
 TFormula.h:83
 TFormula.h:84
 TFormula.h:85
 TFormula.h:86
 TFormula.h:87
 TFormula.h:88
 TFormula.h:89
 TFormula.h:90
 TFormula.h:91
 TFormula.h:92
 TFormula.h:93
 TFormula.h:94
 TFormula.h:95
 TFormula.h:96
 TFormula.h:97
 TFormula.h:98
 TFormula.h:99
 TFormula.h:100
 TFormula.h:101
 TFormula.h:102
 TFormula.h:103
 TFormula.h:104
 TFormula.h:105
 TFormula.h:106
 TFormula.h:107
 TFormula.h:108
 TFormula.h:109
 TFormula.h:110
 TFormula.h:111
 TFormula.h:112
 TFormula.h:113
 TFormula.h:114
 TFormula.h:115
 TFormula.h:116
 TFormula.h:117
 TFormula.h:118
 TFormula.h:119
 TFormula.h:120
 TFormula.h:121
 TFormula.h:122
 TFormula.h:123
 TFormula.h:124
 TFormula.h:125
 TFormula.h:126
 TFormula.h:127
 TFormula.h:128
 TFormula.h:129
 TFormula.h:130
 TFormula.h:131
 TFormula.h:132
 TFormula.h:133
 TFormula.h:134
 TFormula.h:135
 TFormula.h:136
 TFormula.h:137
 TFormula.h:138
 TFormula.h:139
 TFormula.h:140
 TFormula.h:141
 TFormula.h:142
 TFormula.h:143
 TFormula.h:144
 TFormula.h:145
 TFormula.h:146
 TFormula.h:147
 TFormula.h:148
 TFormula.h:149
 TFormula.h:150
 TFormula.h:151
 TFormula.h:152
 TFormula.h:153
 TFormula.h:154
 TFormula.h:155
 TFormula.h:156
 TFormula.h:157
 TFormula.h:158
 TFormula.h:159
 TFormula.h:160
 TFormula.h:161
 TFormula.h:162
 TFormula.h:163
 TFormula.h:164
 TFormula.h:165
 TFormula.h:166
 TFormula.h:167
 TFormula.h:168
 TFormula.h:169
 TFormula.h:170
 TFormula.h:171
 TFormula.h:172
 TFormula.h:173
 TFormula.h:174
 TFormula.h:175
 TFormula.h:176
 TFormula.h:177
 TFormula.h:178
 TFormula.h:179
 TFormula.h:180
 TFormula.h:181
 TFormula.h:182
 TFormula.h:183
 TFormula.h:184
 TFormula.h:185
 TFormula.h:186
 TFormula.h:187
 TFormula.h:188
 TFormula.h:189
 TFormula.h:190
 TFormula.h:191
 TFormula.h:192
 TFormula.h:193
 TFormula.h:194
 TFormula.h:195
 TFormula.h:196
 TFormula.h:197
 TFormula.h:198
 TFormula.h:199
 TFormula.h:200
 TFormula.h:201
 TFormula.h:202
 TFormula.h:203
 TFormula.h:204
 TFormula.h:205
 TFormula.h:206
 TFormula.h:207