Logo ROOT   6.18/05
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
21namespace 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());
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 BaseParamFunc(rhs),
246 fLinear(rhs.fLinear),
247 fPolynomial(rhs.fPolynomial),
248 fOwnFunc(rhs.fOwnFunc),
249 fFunc(rhs.fFunc),
250 fDim(rhs.fDim)
251 //fParams(rhs.fParams)
252 {
253 // copy constructor
255 }
256
257 template<class T>
259 {
260 // Assignment operator
261 if (this == &rhs) return *this; // time saving self-test
262 fLinear = rhs.fLinear;
263 fPolynomial = rhs.fPolynomial;
264 fOwnFunc = rhs.fOwnFunc;
265 fDim = rhs.fDim;
266 //fParams = rhs.fParams;
267 return *this;
268 }
269
270 template <class T>
271 void WrappedMultiTF1Templ<T>::ParameterGradient(const T *x, const double *par, T *grad) const
272 {
273 // evaluate the gradient of the function with respect to the parameters
274 //IMPORTANT NOTE: TF1::GradientPar returns 0 for fixed parameters to avoid computing useless derivatives
275 // BUT the TLinearFitter wants to have the derivatives also for fixed parameters.
276 // so in case of fLinear (or fPolynomial) a non-zero value will be returned for fixed parameters
277
278 if (!fLinear) {
279 // need to set parameter values
280 fFunc->SetParameters(par);
281 // no need to call InitArgs (it is called in TF1::GradientPar)
282 double prec = this->GetDerivPrecision();
283 fFunc->GradientPar(x, grad, prec);
284 } else { // case of linear functions
285 unsigned int np = NPar();
286 for (unsigned int i = 0; i < np; ++i)
287 grad[i] = DoParameterDerivative(x, par, i);
288 }
289 }
290
291 template <class T>
292 T WrappedMultiTF1Templ<T>::DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const
293 {
294 // evaluate the derivative of the function with respect to parameter ipar
295 // see note above concerning the fixed parameters
296 if (!fLinear) {
297 fFunc->SetParameters(p);
298 double prec = this->GetDerivPrecision();
299 return fFunc->GradientPar(ipar, x, prec);
300 }
301 if (fPolynomial) {
302 // case of polynomial function (no parameter dependency) (case for dim = 1)
303 assert(fDim == 1);
304 if (ipar == 0) return 1.0;
305#ifdef R__HAS_VECCORE
306 return vecCore::math::Pow(x[0], static_cast<T>(ipar));
307#else
308 return std::pow(x[0], static_cast<int>(ipar));
309#endif
310 } else {
311 // case of general linear function (built in TFormula with ++ )
313 }
314 }
315 template<class T>
317 {
319 }
320
321 template<class T>
323 {
325 }
326
327 template<class T>
329 {
330 const TF1 *funcToCopy = (f) ? f : fFunc;
331 fFunc = ::ROOT::Math::Internal::CopyTF1Ptr(funcToCopy);
332 fOwnFunc = true;
333 }
334
336
337 } // end namespace Math
338
339} // end namespace ROOT
340
341
342#endif /* ROOT_Fit_WrappedMultiTF1 */
#define f(i)
Definition: RSha256.hxx:104
void Error(const char *location, const char *msgfmt,...)
double pow(double, double)
Documentation for the abstract class IBaseFunctionMultiDim.
Definition: IFunction.h:62
Interface (abstract class) for parametric gradient multi-dimensional functions providing in addition ...
Class to Wrap a ROOT Function class (like TF1) in a IParamMultiFunction interface of multi-dimensions...
void SetParameters(const double *p)
set parameter values (only the cached one in this class,leave unchanges those of TF1)
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 ...
unsigned int NDim() const
Retrieve the dimension of the function.
T DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const
evaluate the partial derivative with respect to the parameter
void SetAndCopyFunction(const TF1 *f=0)
method to set a new function pointer and copy it inside.
unsigned int NPar() const
return number of parameters
static void SetDerivPrecision(double eps)
precision value used for calculating the derivative step-size h = eps * |x|.
const double * Parameters() const
get the parameter values (return values from TF1)
static double GetDerivPrecision()
get precision value used for calculating the derivative step-size
ROOT::Math::IParametricGradFunctionMultiDimTempl< T > BaseParamFunc
WrappedMultiTF1Templ & operator=(const WrappedMultiTF1Templ< T > &rhs)
Assignment operator.
T DoEval(const T *x) const
evaluate function using the cached parameter values (of TF1) re-implement for better efficiency
T DoEvalPar(const T *x, const double *p) const
evaluate function passing coordinates x and vector of parameters
std::string ParameterName(unsigned int i) const
return parameter name (from TF1)
const TF1 * GetFunction() const
method to retrieve the internal function pointer
ROOT::Math::IParametricFunctionMultiDimTempl< T >::BaseFunc BaseFunc
T DoEvalVec(const T *x) const
evaluate function using the cached parameter values (of TF1) re-implement for better efficiency
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.
~WrappedMultiTF1Templ()
Destructor (no operations).
1-Dim function class
Definition: TF1.h:211
virtual Int_t GetNumber() const
Definition: TF1.h:492
virtual Int_t GetNpar() const
Definition: TF1.h:475
virtual Double_t * GetParameters() const
Definition: TF1.h:514
virtual Double_t EvalPar(const Double_t *x, const Double_t *params=0)
Evaluate function with given coordinates and parameters.
Definition: TF1.cxx:1458
virtual const char * GetParName(Int_t ipar) const
Definition: TF1.h:523
virtual Bool_t IsLinear() const
Definition: TF1.h:596
virtual void SetParameters(const Double_t *params)
Definition: TF1.h:638
virtual Int_t GetNdim() const
Definition: TF1.h:479
virtual const TObject * GetLinearPart(Int_t i) const
Definition: TF1.h:459
The Formula class.
Definition: TFormula.h:84
Double_t x[n]
Definition: legend1.C:17
Namespace for new Math classes and functions.
double T(double x)
Definition: ChebyshevPol.h:34
double DerivPrecision(double eps)
Definition: WrappedTF1.cxx:25
TF1 * CopyTF1Ptr(const TF1 *funcToCopy)
Definition: WrappedTF1.cxx:33
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Double_t SignalingNaN()
Returns a signaling NaN as defined by IEEE 754](http://en.wikipedia.org/wiki/NaN#Signaling_NaN)
Definition: TMath.h:896
static double DoParameterDerivative(const WrappedMultiTF1Templ< double > *wrappedFunc, const double *x, unsigned int ipar)
Auxiliar class to bypass the (provisional) lack of vectorization in TFormula::EvalPar.
static T DoParameterDerivative(const WrappedMultiTF1Templ< T > *, const T *, unsigned int)