File indexing completed on 2025-01-18 10:10:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef ROOT_Math_WrappedMultiTF1
0014 #define ROOT_Math_WrappedMultiTF1
0015
0016
0017 #include "Math/IParamFunction.h"
0018
0019 #include "TF1.h"
0020 #include <string>
0021 #include <vector>
0022 #include <algorithm>
0023
0024 namespace ROOT {
0025
0026 namespace Math {
0027
0028 namespace Internal {
0029 double DerivPrecision(double eps);
0030 TF1 *CopyTF1Ptr(const TF1 *funcToCopy);
0031 };
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 template<class T>
0048 class WrappedMultiTF1Templ: virtual public ROOT::Math::IParametricGradFunctionMultiDimTempl<T> {
0049
0050 public:
0051
0052 typedef ROOT::Math::IParametricGradFunctionMultiDimTempl<T> BaseParamFunc;
0053 typedef typename ROOT::Math::IParametricFunctionMultiDimTempl<T>::BaseFunc BaseFunc;
0054
0055
0056
0057
0058
0059
0060
0061 WrappedMultiTF1Templ(TF1 &f, unsigned int dim = 0);
0062
0063
0064
0065
0066 ~WrappedMultiTF1Templ() override
0067 {
0068 if (fOwnFunc && fFunc) delete fFunc;
0069 }
0070
0071
0072
0073
0074 WrappedMultiTF1Templ(const WrappedMultiTF1Templ<T> &rhs);
0075
0076
0077
0078
0079 WrappedMultiTF1Templ &operator = (const WrappedMultiTF1Templ<T> &rhs);
0080
0081
0082
0083
0084
0085
0086 IMultiGenFunctionTempl<T> *Clone() const override
0087 {
0088 return new WrappedMultiTF1Templ<T>(*this);
0089 }
0090
0091
0092
0093
0094 unsigned int NDim() const override
0095 {
0096 return fDim;
0097 }
0098
0099
0100 const double *Parameters() const override
0101 {
0102
0103 return fFunc->GetParameters();
0104 }
0105
0106
0107 void SetParameters(const double *p) override
0108 {
0109
0110 fFunc->SetParameters(p);
0111 }
0112
0113
0114 unsigned int NPar() const override
0115 {
0116
0117 return fFunc->GetNpar();
0118 }
0119
0120
0121 std::string ParameterName(unsigned int i) const override {
0122 return std::string(fFunc->GetParName(i));
0123 }
0124
0125
0126 void ParameterGradient(const T *x, const double *par, T *grad) const override;
0127
0128
0129 bool ParameterHessian(const T *x, const double *par, T *h) const override;
0130
0131
0132 bool HasParameterHessian() const override;
0133
0134
0135 bool ParameterG2(const T *, const double *, T *) const override {
0136 return false;
0137 }
0138
0139
0140
0141 static void SetDerivPrecision(double eps);
0142
0143
0144 static double GetDerivPrecision();
0145
0146
0147 const TF1 *GetFunction() const
0148 {
0149 return fFunc;
0150 }
0151
0152
0153
0154 void SetAndCopyFunction(const TF1 *f = nullptr);
0155
0156 private:
0157
0158 T DoEvalPar(const T *x, const double *p) const override
0159 {
0160 return fFunc->EvalPar(x, p);
0161 }
0162
0163
0164
0165 T DoEvalVec(const T *x) const
0166 {
0167 return fFunc->EvalPar(x, 0);
0168 }
0169
0170
0171
0172 T DoEval(const T *x) const override
0173 {
0174
0175
0176
0177
0178 return fFunc->EvalPar(x, nullptr);
0179 }
0180
0181
0182 T DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const override;
0183
0184 bool fLinear;
0185 bool fPolynomial;
0186 bool fOwnFunc;
0187 TF1 *fFunc;
0188 unsigned int fDim;
0189
0190
0191 };
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 template <class T>
0203 struct GeneralLinearFunctionDerivation {
0204 static T DoParameterDerivative(const WrappedMultiTF1Templ<T> *, const T *, unsigned int)
0205 {
0206 Error("DoParameterDerivative", "The vectorized implementation of DoParameterDerivative does not support"
0207 "general linear functions built in TFormula with ++");
0208
0209 return TMath::SignalingNaN();
0210 }
0211 };
0212
0213 template <>
0214 struct GeneralLinearFunctionDerivation<double> {
0215 static double
0216 DoParameterDerivative(const WrappedMultiTF1Templ<double> *wrappedFunc, const double *x, unsigned int ipar)
0217 {
0218 const TFormula *df = dynamic_cast<const TFormula *>(wrappedFunc->GetFunction()->GetLinearPart(ipar));
0219 assert(df != nullptr);
0220 return (const_cast<TFormula *>(df))->EvalPar(x);
0221
0222 }
0223 };
0224
0225
0226 template<class T>
0227 WrappedMultiTF1Templ<T>::WrappedMultiTF1Templ(TF1 &f, unsigned int dim) :
0228 fLinear(false),
0229 fPolynomial(false),
0230 fOwnFunc(false),
0231 fFunc(&f),
0232 fDim(dim)
0233
0234 {
0235
0236
0237
0238 if (fDim == 0) fDim = fFunc->GetNdim();
0239
0240
0241
0242
0243 if (fFunc->IsLinear()) {
0244 int ip = 0;
0245 fLinear = true;
0246 while (fLinear && ip < fFunc->GetNpar()) {
0247 fLinear &= (fFunc->GetLinearPart(ip) != nullptr);
0248 ip++;
0249 }
0250 }
0251
0252 if (fDim == 1 && fFunc->GetNumber() >= 300 && fFunc->GetNumber() < 310) {
0253 fLinear = true;
0254 fPolynomial = true;
0255 }
0256 }
0257
0258 template<class T>
0259 WrappedMultiTF1Templ<T>::WrappedMultiTF1Templ(const WrappedMultiTF1Templ<T> &rhs) :
0260 BaseParamFunc(rhs),
0261 fLinear(rhs.fLinear),
0262 fPolynomial(rhs.fPolynomial),
0263 fOwnFunc(rhs.fOwnFunc),
0264 fFunc(rhs.fFunc),
0265 fDim(rhs.fDim)
0266
0267 {
0268
0269 if (fOwnFunc) SetAndCopyFunction(rhs.fFunc);
0270 }
0271
0272 template<class T>
0273 WrappedMultiTF1Templ<T> &WrappedMultiTF1Templ<T>::operator= (const WrappedMultiTF1Templ<T> &rhs)
0274 {
0275
0276 if (this == &rhs) return *this;
0277 fLinear = rhs.fLinear;
0278 fPolynomial = rhs.fPolynomial;
0279 fOwnFunc = rhs.fOwnFunc;
0280 fDim = rhs.fDim;
0281
0282 return *this;
0283 }
0284
0285 template <class T>
0286 void WrappedMultiTF1Templ<T>::ParameterGradient(const T *x, const double *par, T *grad) const
0287 {
0288
0289
0290
0291
0292
0293 if (!fLinear) {
0294
0295 fFunc->SetParameters(par);
0296
0297 double prec = this->GetDerivPrecision();
0298 fFunc->GradientPar(x, grad, prec);
0299 } else {
0300 unsigned int np = NPar();
0301 for (unsigned int i = 0; i < np; ++i)
0302 grad[i] = DoParameterDerivative(x, par, i);
0303 }
0304 }
0305
0306
0307 template <class T>
0308 struct GeneralHessianCalc {
0309 static bool Hessian(TF1 *, const T *, const double *, T *)
0310 {
0311 Error("Hessian", "The vectorized implementation of ParameterHessian is not supported");
0312 return false;
0313 }
0314 static bool IsAvailable(TF1 * ) { return false;}
0315 };
0316
0317 template <>
0318 struct GeneralHessianCalc<double> {
0319 static bool Hessian(TF1 * func, const double *x, const double * par, double * h)
0320 {
0321
0322 unsigned int np = func->GetNpar();
0323 auto formula = func->GetFormula();
0324 if (!formula) return false;
0325 std::vector<double> h2(np*np);
0326 func->SetParameters(par);
0327 formula->HessianPar(x,h2);
0328 for (unsigned int i = 0; i < np; i++) {
0329 for (unsigned int j = 0; j <= i; j++) {
0330 unsigned int ih = j + i *(i+1)/2;
0331 unsigned int im = i*np + j;
0332 h[ih] = h2[im];
0333 }
0334 }
0335 return true;
0336 }
0337 static bool IsAvailable(TF1 * func) {
0338 auto formula = func->GetFormula();
0339 if (!formula) return false;
0340 return formula->GenerateHessianPar();
0341 }
0342 };
0343
0344
0345
0346 template <class T>
0347 bool WrappedMultiTF1Templ<T>::ParameterHessian(const T *x, const double *par, T *h) const
0348 {
0349 if (fLinear) {
0350 std::fill(h, h + NPar()*(NPar()+1)/2, 0.0);
0351 return true;
0352 }
0353 return GeneralHessianCalc<T>::Hessian(fFunc, x, par, h);
0354 }
0355
0356 template <class T>
0357 bool WrappedMultiTF1Templ<T>::HasParameterHessian() const
0358 {
0359 return GeneralHessianCalc<T>::IsAvailable(fFunc);
0360 }
0361
0362 template <class T>
0363 T WrappedMultiTF1Templ<T>::DoParameterDerivative(const T *x, const double *p, unsigned int ipar) const
0364 {
0365
0366
0367 if (!fLinear) {
0368 fFunc->SetParameters(p);
0369 double prec = this->GetDerivPrecision();
0370 return fFunc->GradientPar(ipar, x, prec);
0371 }
0372 if (fPolynomial) {
0373
0374 assert(fDim == 1);
0375 if (ipar == 0) return 1.0;
0376 #ifdef R__HAS_VECCORE
0377 return vecCore::math::Pow(x[0], static_cast<T>(ipar));
0378 #else
0379 return std::pow(x[0], static_cast<int>(ipar));
0380 #endif
0381 } else {
0382
0383 return GeneralLinearFunctionDerivation<T>::DoParameterDerivative(this, x, ipar);
0384 }
0385 }
0386 template<class T>
0387 void WrappedMultiTF1Templ<T>::SetDerivPrecision(double eps)
0388 {
0389 ::ROOT::Math::Internal::DerivPrecision(eps);
0390 }
0391
0392 template<class T>
0393 double WrappedMultiTF1Templ<T>::GetDerivPrecision()
0394 {
0395 return ::ROOT::Math::Internal::DerivPrecision(-1);
0396 }
0397
0398 template<class T>
0399 void WrappedMultiTF1Templ<T>::SetAndCopyFunction(const TF1 *f)
0400 {
0401 const TF1 *funcToCopy = (f) ? f : fFunc;
0402 fFunc = ::ROOT::Math::Internal::CopyTF1Ptr(funcToCopy);
0403 fOwnFunc = true;
0404 }
0405
0406 using WrappedMultiTF1 = WrappedMultiTF1Templ<double>;
0407
0408 }
0409
0410 }
0411
0412
0413 #endif