Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
GSLNLSMinimizer.cxx
Go to the documentation of this file.
1// @(#)root/mathmore:$Id$
2// Author: L. Moneta Wed Dec 20 17:16:32 2006
3
4/**********************************************************************
5 * *
6 * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7 * *
8 * *
9 **********************************************************************/
10
11// Implementation file for class GSLNLSMinimizer
12
14
17#include "Math/GenAlgoOptions.h"
18
19#include "Math/Error.h"
20#include "GSLMultiFit.h"
21#include "GSLMultiFit2.h"
22#include "gsl/gsl_errno.h"
23
25// #include "Math/Derivator.h"
26
27#include <iostream>
28#include <iomanip>
29#include <cassert>
30
31namespace ROOT {
32
33namespace Math {
34
35/// Internal class used by GSLNLSMinimizer to implement the transformation of the chi2
36/// function used by GSL Non-linear Least-square fitting
37/// The class is template on the FitMethodFunction type to support both gradient and non
38/// gradient functions
39template <class FMFunc>
41
42public:
43 FitTransformFunction(const FMFunc &f, std::unique_ptr<MinimTransformFunction> transFunc)
44 : FMFunc(f.NDim(), f.NPoints()), fFunc(f), fTransform(std::move(transFunc)), fGrad(std::vector<double>(f.NDim()))
45 {
46 // constructor from a given FitMethodFunction and Transformation object.
47 // Ownership of the transformation object is passed to this class
48 }
49
51
52 // re-implement data element
53 virtual double DataElement(const double *x, unsigned i, double *g = nullptr, double * = nullptr, bool = false) const
54 {
55 // transform from x internal to x external
56 const double *xExt = fTransform->Transformation(x);
57 if (g == nullptr)
58 return fFunc.DataElement(xExt, i);
59 // use gradient
60 double val = fFunc.DataElement(xExt, i, &fGrad[0]);
61 // transform gradient
62 fTransform->GradientTransformation(x, &fGrad.front(), g);
63 return val;
64 }
65
66 virtual IMultiGenFunction *Clone() const
67 {
68 // not supported
69 return nullptr;
70 }
71
72 // dimension (this is number of free dimensions)
73 virtual unsigned int NDim() const { return fTransform->NDim(); }
74
75 unsigned int NTot() const { return fTransform->NTot(); }
76
77 virtual typename FMFunc::Type_t Type() const { return fFunc.Type(); }
78
79 // forward of transformation functions
80 const double *Transformation(const double *x) const { return fTransform->Transformation(x); }
81
82 /// inverse transformation (external -> internal)
83 void InvTransformation(const double *xext, double *xint) const { fTransform->InvTransformation(xext, xint); }
84
85 /// inverse transformation for steps (external -> internal) at external point x
86 void InvStepTransformation(const double *x, const double *sext, double *sint) const
87 {
88 fTransform->InvStepTransformation(x, sext, sint);
89 }
90
91 /// transform gradient vector (external -> internal) at internal point x
92 void GradientTransformation(const double *x, const double *gext, double *gint) const
93 {
94 fTransform->GradientTransformation(x, gext, gint);
95 }
96
97 void MatrixTransformation(const double *x, const double *cint, double *cext) const
98 {
99 fTransform->MatrixTransformation(x, cint, cext);
100 }
101
102private:
103 // objects of this class are not meant for copying or assignment
106
107 virtual double DoEval(const double *x) const { return fFunc(fTransform->Transformation(x)); }
108
109 virtual double DoDerivative(const double * /* x */, unsigned int /*icoord*/) const
110 {
111 // not used
112 throw std::runtime_error("FitTransformFunction::DoDerivative");
113 return 0;
114 }
115
117 const FMFunc &fFunc; // pointer to original fit method function
118 std::unique_ptr<MinimTransformFunction> fTransform; // pointer to transformation function
119 mutable std::vector<double> fGrad; // cached vector of gradient values
120};
121
122//________________________________________________________________________________
123/**
124 LSResidualFunc class description.
125 Internal class used for accessing the residuals of the Least Square function
126 and their derivatives which are estimated numerically using GSL numerical derivation.
127 The class contains a pointer to the fit method function and an index specifying
128 the i-th residual and wraps it in a multi-dim gradient function interface
129 ROOT::Math::IGradientFunctionMultiDim.
130 The class is used by ROOT::Math::GSLNLSMinimizer (GSL non linear least square fitter)
131
132 @ingroup MultiMin
133*/
134template <class Func>
136public:
137 // default ctor (required by CINT)
139
140 LSResidualFunc(const Func &func, unsigned int i) : fIndex(i), fChi2(&func) {}
141
142 // copy ctor
144
145 // assignment
147 {
148 fIndex = rhs.fIndex;
149 fChi2 = rhs.fChi2;
150 return *this;
151 }
152
153 IMultiGenFunction *Clone() const override { return new LSResidualFunc<Func>(*fChi2, fIndex); }
154
155 unsigned int NDim() const override { return fChi2->NDim(); }
156
157 void Gradient(const double *x, double *g) const override
158 {
159 double f0 = 0;
160 FdF(x, f0, g);
161 }
162
163 bool IsLSType() const { return fChi2->Type() == fChi2->kLeastSquare; }
164
165 void FdF(const double *x, double &f, double *g) const override { f = fChi2->DataElement(x, fIndex, g); }
166
167private:
168 double DoEval(const double *x) const override { return fChi2->DataElement(x, fIndex, nullptr); }
169
170 double DoDerivative(const double * /* x */, unsigned int /* icoord */) const override
171 {
172 // this function should not be called by GSL
173 throw std::runtime_error("LSRESidualFunc::DoDerivative");
174 return 0;
175 }
176
177 unsigned int fIndex;
178 const Func *fChi2;
179};
180
181int GetTypeFromName(const char *name)
182{
183 std::string tName(name);
184 if (tName.empty())
185 return 0;
186 if (tName == "lms_old")
187 return 1;
188 if (tName == "lm_old")
189 return 2;
190 if (tName == "trust")
191 return 3;
192 if (tName == "trust_lm")
193 return 4;
194 if (tName == "trust_lmaccel")
195 return 5;
196 if (tName == "trust_dogleg")
197 return 6;
198 if (tName == "trust_ddogleg")
199 return 7;
200 if (tName == "trust_subspace2D" || tName == "trust_2D")
201 return 8;
202 return 0;
203}
204
205// GSLNLSMinimizer implementation
207
209{
210 // Constructor implementation : create GSLMultiFit wrapper object
211 const gsl_multifit_fdfsolver_type *gsl_old_type = nullptr; // use default type defined in GSLMultiFit
212 if (type == 1)
213 gsl_old_type = gsl_multifit_fdfsolver_lmsder; // scaled lmder version
214 if (type == 2)
215 gsl_old_type = gsl_multifit_fdfsolver_lmder; // unscaled version
216
217 // const gsl_multifit_nlinear_type * gsl_new_type = nullptr; //
218 // if (type == 3) gsl_new_type = gsl_multifit_nlinear_trust; // trust region default
219
220 if (gsl_old_type)
222 else
224
225 fEdm = -1;
226
227 // default tolerance and max iterations
229 if (niter <= 0)
230 niter = 100;
232
234 if (fLSTolerance <= 0)
235 fLSTolerance = 0.0001; // default internal value
236
238
239 // set the default options
240 if (fGSLMultiFit2) {
242 if (type == 0 || type == 3)
244
245 fOptions.ExtraOptions()->SetValue("scale", "marquardt");
246 }
247}
248
250{
251 if (fGSLMultiFit)
252 delete fGSLMultiFit;
253 if (fGSLMultiFit2)
254 delete fGSLMultiFit2;
255}
256
258{
259 // set the function to minimizer
260 // need to create vector of functions to be passed to GSL multifit
261
262 // call base class method. It will clone the function and set number of dimensions
264 fNFree = NDim();
266}
267
269{
270
271 if (ObjFunction() == nullptr) {
272 MATH_ERROR_MSG("GSLNLSMinimizer::Minimize", "Function has not been set");
273 return false;
274 }
275 // check type of function (if it provides gradient)
276 auto fitFunc = (!fUseGradFunction) ? dynamic_cast<const ROOT::Math::FitMethodFunction *>(ObjFunction()) : nullptr;
277 auto fitGradFunc =
278 (fUseGradFunction) ? dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(ObjFunction()) : nullptr;
279 if (fitFunc == nullptr && fitGradFunc == nullptr) {
280 if (PrintLevel() > 0)
281 std::cout << "GSLNLSMinimizer: Invalid function set - only FitMethodFunction types are supported" << std::endl;
282 return false;
283 }
284
285 if (fGSLMultiFit) {
286
287 if (PrintLevel() > 0)
288 std::cout << "GLSNLSMinimizer::Minimize - Using old GSLMultiFit with method " << fOptions.MinimizerAlgorithm()
289 << std::endl;
290
291 if (fitGradFunc)
293 else
295 }
296 if (fGSLMultiFit2) {
297
298 // set specific minimizer parameters
300
301 if (PrintLevel() > 0)
302 std::cout << "GLSNLSMinimizer::Minimize - Using new GSLMultiFit with trs method " << fOptions.MinimizerAlgorithm()
303 << std::endl;
304
305 if (fitGradFunc)
307 else
309 }
310 return false;
311}
312
313template <class Func, class FitterType>
315{
316
317 unsigned int size = fitFunc.NPoints();
318 fNCalls = 0; // reset number of function calls
319
320 std::vector<LSResidualFunc<Func>> residualFuncs;
321 residualFuncs.reserve(size);
322
323 // set initial parameters of the minimizer
324 int debugLevel = PrintLevel();
325
326 unsigned int npar = NPar();
327 unsigned int ndim = NDim();
328 if (npar == 0 || npar < ndim) {
329 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize", "Wrong number of parameters", npar);
330 return false;
331 }
332
333 // set residual functions and check if a transformation is needed
334 std::vector<double> startValues;
335
336 // transformation need a grad function.
337 std::unique_ptr<MultiNumGradFunction> gradFunction;
338 std::unique_ptr<MinimTransformFunction> trFuncRaw;
339 if (!fUseGradFunction) {
340 gradFunction = std::make_unique<MultiNumGradFunction>(fitFunc);
342 } else {
343 // use pointer stored in BasicMinimizer
345 }
346 // need to transform in a FitTransformFunction which is set in the residual functions
347 std::unique_ptr<FitTransformFunction<Func>> trFunc;
348 if (trFuncRaw) {
349 // pass ownership of trFuncRaw to FitTransformFunction
350 trFunc = std::make_unique<FitTransformFunction<Func>>(fitFunc, std::move(trFuncRaw));
351 assert(npar == trFunc->NTot());
352 for (unsigned int ires = 0; ires < size; ++ires) {
354 }
355 } else {
356 for (unsigned int ires = 0; ires < size; ++ires) {
358 }
359 }
360
361 if (debugLevel >= 1)
362 std::cout << "Minimize using GSLNLSMinimizer " << std::endl;
363
364 int iret = fitter->Set(residualFuncs, &startValues.front());
365
366 if (iret) {
367 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize", "Error setting the residual functions ", iret);
368 return false;
369 }
370
371 int status = 0;
372 bool minFound = false;
373 unsigned int iter = 0;
374 if (fGSLMultiFit) {
375 // case of using old solver
376
377 if (debugLevel >= 1)
378 std::cout << "GSLNLSMinimizer: " << fGSLMultiFit->Name() << " - start iterating......... " << std::endl;
379
380 // start iteration
381 do {
382 status = fitter->Iterate();
383
384 if (debugLevel >= 1) {
385 std::cout << "----------> Iteration " << iter << " / " << MaxIterations() << " status "
386 << gsl_strerror(status) << std::endl;
387 const double *x = fitter->X();
388 if (trFunc)
389 x = trFunc->Transformation(x);
390 int pr = std::cout.precision(18);
391 std::cout << " FVAL = " << (fitFunc)(x) << std::endl;
392 std::cout.precision(pr);
393 std::cout << " X Values : ";
394 for (unsigned int i = 0; i < NDim(); ++i)
395 std::cout << " " << VariableName(i) << " = " << x[i];
396 std::cout << std::endl;
397 }
398
399 if (status)
400 break;
401
402 // check also the delta in X()
403 status = fitter->TestDelta(Tolerance(), Tolerance());
404 if (status == GSL_SUCCESS) {
405 minFound = true;
406 }
407
408 // double-check with the gradient
409 int status2 = fitter->TestGradient(Tolerance());
410 if (minFound && status2 != GSL_SUCCESS) {
411 // check now edm
412 fEdm = fitter->Edm();
413 if (fEdm > Tolerance()) {
414 // continue the iteration
415 status = status2;
416 minFound = false;
417 }
418 }
419
420 if (debugLevel >= 1) {
421 std::cout << " after Gradient and Delta tests: " << gsl_strerror(status);
422 if (fEdm > 0)
423 std::cout << ", edm is: " << fEdm;
424 std::cout << std::endl;
425 }
426
427 iter++;
428
429 } while (status == GSL_CONTINUE && iter < MaxIterations());
430
431 // check edm
432 fEdm = fitter->Edm();
433 if (fEdm < Tolerance()) {
434 minFound = true;
435 }
436
437 } else if (fGSLMultiFit2) {
438 // case using new solver and given driver
439 status = fGSLMultiFit2->Solve();
440 if (status == GSL_SUCCESS)
441 minFound = true;
442 iter = fGSLMultiFit2->NIter();
443 }
444
445 // save state with values and function value
446 const double *x = fitter->X();
447 if (x == nullptr)
448 return false;
449 // apply transformation outside SetFinalValues(..)
450 // because trFunc is not a MinimTransformFunction but a FitTransFormFunction
451 if (trFunc)
452 x = trFunc->Transformation(x);
454
456 fStatus = status;
457 fNCalls = fitFunc.NCalls();
458 fErrors.resize(NDim());
459
460 // get errors from cov matrix
461 const double *cov = fitter->CovarMatrix();
462 if (cov) {
463
464 fCovMatrix.resize(ndim * ndim);
465
466 if (trFunc) {
467 trFunc->MatrixTransformation(x, fitter->CovarMatrix(), fCovMatrix.data());
468 } else {
469 std::copy(cov, cov + fCovMatrix.size(), fCovMatrix.begin());
470 }
471
472 for (unsigned int i = 0; i < ndim; ++i)
473 fErrors[i] = std::sqrt(fCovMatrix[i * ndim + i]);
474 }
475
476 if (minFound) {
477
478 if (debugLevel >= 1) {
479 std::cout << "GSLNLSMinimizer: Minimum Found" << std::endl;
480 int pr = std::cout.precision(18);
481 std::cout << "FVAL = " << MinValue() << std::endl;
482 std::cout << "Edm = " << fEdm << std::endl;
483 std::cout.precision(pr);
484 std::cout << "NIterations = " << iter << std::endl;
485 std::cout << "NFuncCalls = " << fitFunc.NCalls() << std::endl;
486 for (unsigned int i = 0; i < NDim(); ++i)
487 std::cout << std::setw(12) << VariableName(i) << " = " << std::setw(12) << X()[i] << " +/- "
488 << std::setw(12) << fErrors[i] << std::endl;
489 }
490
491 return true;
492 } else {
493 if (debugLevel >= 0) {
494 std::cout << "GSLNLSMinimizer: Minimization did not converge: " << std::endl;
495 if (status == GSL_ENOPROG) // case status 27
496 std::cout << "\t iteration is not making progress towards solution" << std::endl;
497 else
498 std::cout << "\t failed with status " << status << std::endl;
499 }
500 if (debugLevel >= 1) {
501 std::cout << "FVAL = " << MinValue() << std::endl;
502 std::cout << "Edm = " << fitter->Edm() << std::endl;
503 std::cout << "Niterations = " << iter << std::endl;
504 }
505 return false;
506 }
507 return false;
508}
509
510const double *GSLNLSMinimizer::MinGradient() const
511{
512 // return gradient (internal values) - only when using old fitter
513 return (fGSLMultiFit) ? fGSLMultiFit->Gradient() : nullptr;
514}
515
516double GSLNLSMinimizer::CovMatrix(unsigned int i, unsigned int j) const
517{
518 // return covariance matrix element
519 unsigned int ndim = NDim();
520 if (fCovMatrix.empty())
521 return 0;
522 if (i > ndim || j > ndim)
523 return 0;
524 return fCovMatrix[i * ndim + j];
525}
526
528{
529 // return covariance matrix status = 0 not computed,
530 // 1 computed but is approximate because minimum is not valid, 3 is fine
531 if (fCovMatrix.empty())
532 return 0;
533 // case minimization did not finished correctly
534 if (fStatus != GSL_SUCCESS)
535 return 1;
536 return 3;
537}
538
539} // end namespace Math
540
541} // end namespace ROOT
#define MATH_ERROR_MSGVAL(loc, txt, x)
Definition Error.h:109
#define MATH_ERROR_MSG(loc, str)
Definition Error.h:83
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
FitMethodFunction class Interface for objective functions (like chi2 and likelihood used in the fit) ...
virtual unsigned int NPar() const
total number of parameter defined
unsigned int NDim() const override
number of dimensions
void SetFinalValues(const double *x, const MinimTransformFunction *func=nullptr)
double MinValue() const override
return minimum function value
MinimTransformFunction * CreateTransformation(std::vector< double > &startValues, const ROOT::Math::IMultiGradFunction *func=nullptr)
void SetFunction(const ROOT::Math::IMultiGenFunction &func) override
set the function to minimize
const ROOT::Math::IMultiGenFunction * ObjFunction() const
return pointer to used objective function
const double * X() const override
return pointer to X values at the minimum
std::string VariableName(unsigned int ivar) const override
get name of variables (override if minimizer support storing of variable names)
Internal class used by GSLNLSMinimizer to implement the transformation of the chi2 function used by G...
FitTransformFunction & operator=(const FitTransformFunction &rhs)=delete
virtual FMFunc::Type_t Type() const
void InvTransformation(const double *xext, double *xint) const
inverse transformation (external -> internal)
std::unique_ptr< MinimTransformFunction > fTransform
void InvStepTransformation(const double *x, const double *sext, double *sint) const
inverse transformation for steps (external -> internal) at external point x
virtual IMultiGenFunction * Clone() const
void MatrixTransformation(const double *x, const double *cint, double *cext) const
void GradientTransformation(const double *x, const double *gext, double *gint) const
transform gradient vector (external -> internal) at internal point x
FitTransformFunction(const FitTransformFunction &rhs)=delete
virtual double DoEval(const double *x) const
FitTransformFunction(const FMFunc &f, std::unique_ptr< MinimTransformFunction > transFunc)
virtual double DataElement(const double *x, unsigned i, double *g=nullptr, double *=nullptr, bool=false) const
virtual unsigned int NDim() const
virtual double DoDerivative(const double *, unsigned int) const
const double * Transformation(const double *x) const
GSLMultiFit2, internal class for implementing GSL non linear least square GSL fitting New class imple...
void SetParameters(const ROOT::Math::MinimizerOptions &minimOptions)
ROOT::Math::GenAlgoOptions GetDefaultOptions() const
GSLMultiFit, internal class for implementing GSL non linear least square GSL fitting.
Definition GSLMultiFit.h:53
const double * Gradient() const
gradient value at the minimum
std::string Name() const
GSLNLSMinimizer class for Non Linear Least Square fitting It Uses the Levemberg-Marquardt algorithm f...
double CovMatrix(unsigned int, unsigned int) const override
return covariance matrices elements if the variable is fixed the matrix is zero The ordering of the v...
int CovMatrixStatus() const override
return covariance matrix status
void SetFunction(const ROOT::Math::IMultiGenFunction &func) override
set the function to minimize
std::vector< double > fErrors
std::vector< double > fCovMatrix
~GSLNLSMinimizer() override
Destructor (no operations)
GSLNLSMinimizer(int type)
Constructor from a type.
bool DoMinimize(const Func &f, FitterType *fitter)
Internal method to perform minimization template on the type of method function.
bool Minimize() override
method to perform the minimization
const double * MinGradient() const override
return pointer to gradient values at the minimum
ROOT::Math::GSLMultiFit * fGSLMultiFit
ROOT::Math::GSLMultiFit2 * fGSLMultiFit2
Documentation for the abstract class IBaseFunctionMultiDim.
Definition IFunction.h:63
Interface (abstract class) for multi-dimensional functions providing a gradient calculation.
Definition IFunction.h:170
LSResidualFunc class description.
double DoEval(const double *x) const override
LSResidualFunc< Func > & operator=(const LSResidualFunc< Func > &rhs)
void FdF(const double *x, double &f, double *g) const override
LSResidualFunc(const LSResidualFunc< Func > &rhs)
void Gradient(const double *x, double *g) const override
double DoDerivative(const double *, unsigned int) const override
LSResidualFunc(const Func &func, unsigned int i)
IMultiGenFunction * Clone() const override
Clone a function.
unsigned int NDim() const override
Retrieve the dimension of the function.
const IOptions * ExtraOptions() const
return extra options (NULL pointer if they are not present)
const std::string & MinimizerAlgorithm() const
type of algorithm
void SetExtraOptions(const IOptions &opt)
set extra options (in this case pointer is cloned)
void SetMinimizerAlgorithm(const char *type)
set minimizer algorithm
double Tolerance() const
Absolute tolerance.
Definition Minimizer.h:314
void SetMaxIterations(unsigned int maxiter)
Set maximum iterations (one iteration can have many function calls).
Definition Minimizer.h:348
int fStatus
status of minimizer
Definition Minimizer.h:385
unsigned int MaxIterations() const
Max iterations.
Definition Minimizer.h:311
void SetPrintLevel(int level)
Set print level.
Definition Minimizer.h:342
MinimizerOptions fOptions
minimizer options
Definition Minimizer.h:384
int PrintLevel() const
Set print level.
Definition Minimizer.h:305
Double_t x[n]
Definition legend1.C:17
Namespace for new Math classes and functions.
int GetTypeFromName(const char *name)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...