Logo ROOT   6.12/07
Reference Guide
WrappedMultiTF1.h
Go to the documentation of this file.
1 // @(#)root/mathmore:$Id$
2 // Author: L. Moneta Wed Sep 6 09:52:26 2006
3 
4 /**********************************************************************
5  * *
6  * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7  * *
8  * *
9  **********************************************************************/
10 
11 // Header file for class WrappedTFunction
12 
13 #ifndef ROOT_Math_WrappedMultiTF1
14 #define ROOT_Math_WrappedMultiTF1
15 
16 
17 #include "Math/IParamFunction.h"
18 
19 #include "TF1.h"
20 
21 namespace ROOT {
22 
23  namespace Math {
24 
25  namespace Internal {
26  double DerivPrecision(double eps);
27  TF1 *CopyTF1Ptr(const TF1 *funcToCopy);
28  };
29 
30  /**
31  Class to Wrap a ROOT Function class (like TF1) in a IParamMultiFunction interface
32  of multi-dimensions to be used in the ROOT::Math numerical algorithm.
33  This wrapper class does not own the TF1 pointer, so it assumes it exists during the wrapper lifetime.
34  The class copy the TF1 pointer only when it owns it.
35 
36  The class from ROOT version 6.03 does not contain anymore a copy of the parameters. The parameters are
37  stored in the TF1 class.
38 
39  @ingroup CppFunctions
40  */
41 
42  //LM note: are there any issues when cloning the class for the parameters that are not copied anymore ??
43 
44  template<class T>
46 
47  public:
48 
51 
52  /**
53  constructor from a function pointer to a TF1
54  If dim = 0 dimension is taken from TF1::GetNdim().
55  IN case of multi-dimensional function created using directly TF1 object the dimension
56  returned by TF1::GetNdim is always 1. The user must then pass the correct value of dim
57  */
58  WrappedMultiTF1Templ(TF1 &f, unsigned int dim = 0);
59 
60  /**
61  Destructor (no operations). Function pointer is not owned
62  */
64  {
65  if (fOwnFunc && fFunc) delete fFunc;
66  }
67 
68  /**
69  Copy constructor
70  */
72 
73  /**
74  Assignment operator
75  */
77 
78  /** @name interface inherited from IParamFunction */
79 
80  /**
81  Clone the wrapper but not the original function
82  */
84  {
85  return new WrappedMultiTF1Templ<T>(*this);
86  }
87 
88  /**
89  Retrieve the dimension of the function
90  */
91  unsigned int NDim() const
92  {
93  return fDim;
94  }
95 
96  /// get the parameter values (return values from TF1)
97  const double *Parameters() const
98  {
99  //return (fParams.size() > 0) ? &fParams.front() : 0;
100  return fFunc->GetParameters();
101  }
102 
103  /// set parameter values (only the cached one in this class,leave unchanges those of TF1)
104  void SetParameters(const double *p)
105  {
106  //std::copy(p,p+fParams.size(),fParams.begin());
107  fFunc->SetParameters(p);
108  }
109 
110  /// return number of parameters
111  unsigned int NPar() const
112  {
113  // return fParams.size();
114  return fFunc->GetNpar();
115  }
116 
117  /// return parameter name (from TF1)
118  std::string ParameterName(unsigned int i) const {
119  return std::string(fFunc->GetParName(i));
120  }
121 
122  // evaluate the derivative of the function with respect to the parameters
123  void ParameterGradient(const T *x, const double *par, T *grad) const;
124 
125  /// precision value used for calculating the derivative step-size
126  /// h = eps * |x|. The default is 0.001, give a smaller in case function changes rapidly
127  static void SetDerivPrecision(double eps);
128 
129  /// get precision value used for calculating the derivative step-size
130  static double GetDerivPrecision();
131 
132  /// method to retrieve the internal function pointer
133  const TF1 *GetFunction() const
134  {
135  return fFunc;
136  }
137 
138  /// method to set a new function pointer and copy it inside.
139  /// By calling this method the class manages now the passed TF1 pointer
140  void SetAndCopyFunction(const TF1 *f = 0);
141 
142  private:
143  /// evaluate function passing coordinates x and vector of parameters
144  T DoEvalPar(const T *x, const double *p) const
145  {
146  return fFunc->EvalPar(x, p);
147  }
148 
149  /// evaluate function using the cached parameter values (of TF1)
150  /// re-implement for better efficiency
151  T DoEvalVec(const T *x) const
152  {
153  return fFunc->EvalPar(x, 0);
154  }
155 
156  /// evaluate function using the cached parameter values (of TF1)
157  /// re-implement for better efficiency
158  T DoEval(const T *x) const
159  {
160  // no need to call InitArg for interpreted functions (done in ctor)
161 
162  //const double * p = (fParams.size() > 0) ? &fParams.front() : 0;
163  return fFunc->EvalPar(x, 0);
164  }
165 
166  /// evaluate the partial derivative with respect to the parameter
167  T DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const;
168 
169  bool fLinear; // flag for linear functions
170  bool fPolynomial; // flag for polynomial functions
171  bool fOwnFunc; // flag to indicate we own the TF1 function pointer
172  TF1 *fFunc; // pointer to ROOT function
173  unsigned int fDim; // cached value of dimension
174  //std::vector<double> fParams; // cached vector with parameter values
175 
176  };
177 
178  /**
179  * Auxiliar class to bypass the (provisional) lack of vectorization in TFormula::EvalPar.
180  *
181  * WrappedMultiTF1Templ::DoParameterDerivation calls TFormula::EvalPar in the case of a general linear function
182  * built with TFormula using ++; as EvalPar is not vectorized, in order to generalize DoParameterDerivative with
183  * a general type T, we use this auxiliar class to branch the code in compile time with the double
184  * specialization (that can call EvalPar) and the general implementation (that throws an error in the case of
185  * general linear function).
186  */
187  template <class T>
189  static T DoParameterDerivative(const WrappedMultiTF1Templ<T> *, const T *, unsigned int)
190  {
191  Error("DoParameterDerivative", "The vectorized implementation of DoParameterDerivative does not support"
192  "general linear functions built in TFormula with ++");
193 
194  return TMath::SignalingNaN();
195  }
196  };
197 
198  template <>
200  static double
201  DoParameterDerivative(const WrappedMultiTF1Templ<double> *wrappedFunc, const double *x, unsigned int ipar)
202  {
203  const TFormula *df = dynamic_cast<const TFormula *>(wrappedFunc->GetFunction()->GetLinearPart(ipar));
204  assert(df != 0);
205  return (const_cast<TFormula *>(df))->EvalPar(x); // derivatives should not depend on parameters since
206  // function is linear
207  }
208  };
209 
210  // implementations for WrappedMultiTF1Templ<T>
211  template<class T>
213  fLinear(false),
214  fPolynomial(false),
215  fOwnFunc(false),
216  fFunc(&f),
217  fDim(dim)
218  //fParams(f.GetParameters(),f.GetParameters()+f.GetNpar())
219  {
220  // constructor of WrappedMultiTF1Templ<T>
221  // pass a dimension if dimension specified in TF1 does not correspond to real dimension
222  // for example in case of multi-dimensional TF1 objects defined as TF1 (i.e. for functions with dims > 3 )
223  if (fDim == 0) fDim = fFunc->GetNdim();
224 
225  // check that in case function is linear the linear terms are not zero
226  // function is linear when is a TFormula created with "++"
227  // hyperplane are not yet existing in TFormula
228  if (fFunc->IsLinear()) {
229  int ip = 0;
230  fLinear = true;
231  while (fLinear && ip < fFunc->GetNpar()) {
232  fLinear &= (fFunc->GetLinearPart(ip) != 0) ;
233  ip++;
234  }
235  }
236  // distinguish case of polynomial functions and linear functions
237  if (fDim == 1 && fFunc->GetNumber() >= 300 && fFunc->GetNumber() < 310) {
238  fLinear = true;
239  fPolynomial = true;
240  }
241  }
242 
243  template<class T>
245  BaseFunc(),
246  BaseParamFunc(),
247  fLinear(rhs.fLinear),
249  fOwnFunc(rhs.fOwnFunc),
250  fFunc(rhs.fFunc),
251  fDim(rhs.fDim)
252  //fParams(rhs.fParams)
253  {
254  // copy constructor
256  }
257 
258  template<class T>
260  {
261  // Assignment operator
262  if (this == &rhs) return *this; // time saving self-test
263  fLinear = rhs.fLinear;
264  fPolynomial = rhs.fPolynomial;
265  fOwnFunc = rhs.fOwnFunc;
266  fDim = rhs.fDim;
267  //fParams = rhs.fParams;
268  return *this;
269  }
270 
271  template <class T>
272  void WrappedMultiTF1Templ<T>::ParameterGradient(const T *x, const double *par, T *grad) const
273  {
274  // evaluate the gradient of the function with respect to the parameters
275  //IMPORTANT NOTE: TF1::GradientPar returns 0 for fixed parameters to avoid computing useless derivatives
276  // BUT the TLinearFitter wants to have the derivatives also for fixed parameters.
277  // so in case of fLinear (or fPolynomial) a non-zero value will be returned for fixed parameters
278 
279  if (!fLinear) {
280  // need to set parameter values
281  fFunc->SetParameters(par);
282  // no need to call InitArgs (it is called in TF1::GradientPar)
283  double prec = this->GetDerivPrecision();
284  fFunc->GradientPar(x, grad, prec);
285  } else { // case of linear functions
286  unsigned int np = NPar();
287  for (unsigned int i = 0; i < np; ++i)
288  grad[i] = DoParameterDerivative(x, par, i);
289  }
290  }
291 
292  template <class T>
293  T WrappedMultiTF1Templ<T>::DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const
294  {
295  // evaluate the derivative of the function with respect to parameter ipar
296  // see note above concerning the fixed parameters
297  if (!fLinear) {
298  fFunc->SetParameters(p);
299  double prec = this->GetDerivPrecision();
300  return fFunc->GradientPar(ipar, x, prec);
301  }
302  if (fPolynomial) {
303  // case of polynomial function (no parameter dependency) (case for dim = 1)
304  assert(fDim == 1);
305  if (ipar == 0) return 1.0;
306 #ifdef R__HAS_VECCORE
307  return vecCore::math::Pow(x[0], static_cast<T>(ipar));
308 #else
309  return std::pow(x[0], static_cast<int>(ipar));
310 #endif
311  } else {
312  // case of general linear function (built in TFormula with ++ )
314  }
315  }
316  template<class T>
318  {
320  }
321 
322  template<class T>
324  {
326  }
327 
328  template<class T>
330  {
331  const TF1 *funcToCopy = (f) ? f : fFunc;
333  fOwnFunc = true;
334  }
335 
337 
338  } // end namespace Math
339 
340 } // end namespace ROOT
341 
342 
343 #endif /* ROOT_Fit_WrappedMultiTF1 */
Auxiliar class to bypass the (provisional) lack of vectorization in TFormula::EvalPar.
static T DoParameterDerivative(const WrappedMultiTF1Templ< T > *, const T *, unsigned int)
virtual void SetParameters(const Double_t *params)
Definition: TF1.h:628
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
double T(double x)
Definition: ChebyshevPol.h:34
static double DoParameterDerivative(const WrappedMultiTF1Templ< double > *wrappedFunc, const double *x, unsigned int ipar)
const TF1 * GetFunction() const
method to retrieve the internal function pointer
Interface (abstract class) for parametric gradient multi-dimensional functions providing in addition ...
void ParameterGradient(const T *x, const double *par, T *grad) const
Evaluate the all the derivatives (gradient vector) of the function with respect to the parameters at ...
void SetParameters(const double *p)
set parameter values (only the cached one in this class,leave unchanges those of TF1) ...
T DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const
evaluate the partial derivative with respect to the parameter
Double_t x[n]
Definition: legend1.C:17
static double GetDerivPrecision()
get precision value used for calculating the derivative step-size
unsigned int NPar() const
return number of parameters
Class to Wrap a ROOT Function class (like TF1) in a IParamMultiFunction interface of multi-dimensions...
double pow(double, double)
virtual Int_t GetNdim() const
Definition: TF1.h:469
virtual Double_t GradientPar(Int_t ipar, const Double_t *x, Double_t eps=0.01)
Compute the gradient (derivative) wrt a parameter ipar.
Definition: TF1.cxx:2327
ROOT::Math::IParametricGradFunctionMultiDimTempl< T > BaseParamFunc
Documentation for the abstract class IBaseFunctionMultiDim.
Definition: IFunction.h:62
TF1 * CopyTF1Ptr(const TF1 *funcToCopy)
Definition: WrappedTF1.cxx:33
std::string ParameterName(unsigned int i) const
return parameter name (from TF1)
T DoEvalVec(const T *x) const
evaluate function using the cached parameter values (of TF1) re-implement for better efficiency ...
The Formula class.
Definition: TFormula.h:83
virtual const TObject * GetLinearPart(Int_t i) const
Definition: TF1.h:449
T DoEvalPar(const T *x, const double *p) const
evaluate function passing coordinates x and vector of parameters
virtual Bool_t IsLinear() const
Definition: TF1.h:586
Double_t SignalingNaN()
Definition: TMath.h:790
WrappedMultiTF1Templ(TF1 &f, unsigned int dim=0)
constructor from a function pointer to a TF1 If dim = 0 dimension is taken from TF1::GetNdim().
IMultiGenFunctionTempl< T > * Clone() const
Clone the wrapper but not the original function.
static void SetDerivPrecision(double eps)
precision value used for calculating the derivative step-size h = eps * |x|.
ROOT::Math::IParametricFunctionMultiDimTempl< T >::BaseFunc BaseFunc
double DerivPrecision(double eps)
Definition: WrappedTF1.cxx:25
~WrappedMultiTF1Templ()
Destructor (no operations).
Namespace for new Math classes and functions.
Binding & operator=(OUT(*fun)(void))
unsigned int NDim() const
Retrieve the dimension of the function.
T DoEval(const T *x) const
evaluate function using the cached parameter values (of TF1) re-implement for better efficiency ...
1-Dim function class
Definition: TF1.h:211
WrappedMultiTF1Templ & operator=(const WrappedMultiTF1Templ< T > &rhs)
Assignment operator.
const double * Parameters() const
get the parameter values (return values from TF1)
virtual Int_t GetNumber() const
Definition: TF1.h:482
void SetAndCopyFunction(const TF1 *f=0)
method to set a new function pointer and copy it inside.
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.