1 // @(#)root/mathcore:$Id$
2 // Authors: L. Moneta, J.T. Offermann, E.G.P. Bos    2013-2018
3 //
4 /**********************************************************************
5  *                                                                    *
6  * Copyright (c) 2013 , LCG ROOT MathLib Team                         *
7  *                                                                    *
8  **********************************************************************/
9 /*
10  * NumericalDerivator.h
11  *
12  *  Original version created on: Aug 14, 2013
13  *      Authors: L. Moneta, J. T. Offermann
14  *  Modified version created on: Sep 27, 2017
15  *      Author: E. G. P. Bos
16  */
17 
18 #ifndef ROOT_Minuit2_NumericalDerivator
19 #define ROOT_Minuit2_NumericalDerivator
20 
21 #include <Math/IFunctionfwd.h>
22 
23 #include <vector>
24 #include "Fit/ParameterSettings.h"
25 #include "Minuit2/SinParameterTransformation.h"
26 #include "Minuit2/SqrtUpParameterTransformation.h"
27 #include "Minuit2/SqrtLowParameterTransformation.h"
28 #include "Minuit2/MnMachinePrecision.h"
29 
30 namespace ROOT {
31 namespace Minuit2 {
32 
33 // Holds all necessary derivatives and associated numbers (per parameter) used in the NumericalDerivator class.
34 struct DerivatorElement {
35    double derivative;
36    double second_derivative;
37    double step_size;
38 };
39 
40 class NumericalDerivator {
41 public:
42    explicit NumericalDerivator(bool always_exactly_mimic_minuit2 = true);
43    NumericalDerivator(const NumericalDerivator &other);
44    NumericalDerivator(double step_tolerance, double grad_tolerance, unsigned int ncycles, double error_level,
45                       bool always_exactly_mimic_minuit2 = true);
46 
47    void SetupDifferentiate(const ROOT::Math::IBaseFunctionMultiDim *function, const double *cx,
48                            const std::vector<ROOT::Fit::ParameterSettings> &parameters);
49    std::vector<DerivatorElement> Differentiate(const ROOT::Math::IBaseFunctionMultiDim *function, const double *x,
50                                                const std::vector<ROOT::Fit::ParameterSettings> &parameters,
51                                                const std::vector<DerivatorElement> &previous_gradient);
52 
53    DerivatorElement PartialDerivative(const ROOT::Math::IBaseFunctionMultiDim *function, const double *x,
54                                       const std::vector<ROOT::Fit::ParameterSettings> &parameters,
55                                       unsigned int i_component, DerivatorElement previous);
56    DerivatorElement FastPartialDerivative(const ROOT::Math::IBaseFunctionMultiDim *function,
57                                           const std::vector<ROOT::Fit::ParameterSettings> &parameters,
58                                           unsigned int i_component, const DerivatorElement &previous);
59    DerivatorElement operator()(const ROOT::Math::IBaseFunctionMultiDim *function, const double *x,
60                                const std::vector<ROOT::Fit::ParameterSettings> &parameters, unsigned int i_component,
61                                const DerivatorElement &previous);
62 
GetValue()63    double GetValue() const { return fVal; }
SetStepTolerance(double value)64    inline void SetStepTolerance(double value) { fStepTolerance = value; }
SetGradTolerance(double value)65    inline void SetGradTolerance(double value) { fGradTolerance = value; }
SetNCycles(unsigned int value)66    inline void SetNCycles(unsigned int value) { fNCycles = value; }
SetErrorLevel(double value)67    inline void SetErrorLevel(double value) { fUp = value; }
68 
69    double Int2ext(const ROOT::Fit::ParameterSettings &parameter, double val) const;
70    double Ext2int(const ROOT::Fit::ParameterSettings &parameter, double val) const;
71    double DInt2Ext(const ROOT::Fit::ParameterSettings &parameter, double val) const;
72 
73    void SetInitialGradient(const ROOT::Math::IBaseFunctionMultiDim *function,
74                            const std::vector<ROOT::Fit::ParameterSettings> &parameters,
75                            std::vector<DerivatorElement> &gradient);
76 
AlwaysExactlyMimicMinuit2()77    inline bool AlwaysExactlyMimicMinuit2() const { return fAlwaysExactlyMimicMinuit2; }
SetAlwaysExactlyMimicMinuit2(bool flag)78    inline void SetAlwaysExactlyMimicMinuit2(bool flag) { fAlwaysExactlyMimicMinuit2 = flag; }
79 
80 private:
81    double fStepTolerance = 0.5;
82    double fGradTolerance = 0.1;
83    double fUp = 1;
84    double fVal = 0;
85 
86    std::vector<double> fVx;
87    std::vector<double> fVxExternal;
88    std::vector<double> fVxFValCache;
89    double fDfmin;
90    double fVrysml;
91 
92    // MODIFIED: Minuit2 determines machine precision in a slightly different way than
93    // std::numeric_limits<double>::epsilon()). We go with the Minuit2 one.
94    ROOT::Minuit2::MnMachinePrecision fPrecision;
95 
96    ROOT::Minuit2::SinParameterTransformation fDoubleLimTrafo;
97    ROOT::Minuit2::SqrtUpParameterTransformation fUpperLimTrafo;
98    ROOT::Minuit2::SqrtLowParameterTransformation fLowerLimTrafo;
99 
100    unsigned int fNCycles = 2;
101    bool fAlwaysExactlyMimicMinuit2;
102 
103 };
104 
105 std::ostream &operator<<(std::ostream &out, const DerivatorElement &value);
106 
107 } // namespace Minuit2
108 } // namespace ROOT
109 
110 #endif // ROOT_Minuit2_NumericalDerivator
111