Logo ROOT  
Reference Guide
 
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 double DataElement(const double *x, unsigned i, double *g = nullptr, double * = nullptr, bool = false) const override
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 IMultiGenFunction *Clone() const override
67 {
68 // not supported
69 return nullptr;
70 }
71
72 // dimension (this is number of free dimensions)
73 unsigned int NDim() const override { return fTransform->NDim(); }
74
75 unsigned int NTot() const { return fTransform->NTot(); }
76
77 typename FMFunc::Type_t Type() const override { 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 double DoEval(const double *x) const override { return fFunc(fTransform->Transformation(x)); }
108
109 double DoDerivative(const double * /* x */, unsigned int /*icoord*/) const override
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 LSResidualFunc(const Func &func, unsigned int i) : fIndex(i), fChi2(&func) {}
138
139 // copy ctor
141
142 // assignment
144 {
145 fIndex = rhs.fIndex;
146 fChi2 = rhs.fChi2;
147 return *this;
148 }
149
150 IMultiGenFunction *Clone() const override { return new LSResidualFunc<Func>(*fChi2, fIndex); }
151
152 unsigned int NDim() const override { return fChi2->NDim(); }
153
154 void Gradient(const double *x, double *g) const override
155 {
156 double f0 = 0;
157 FdF(x, f0, g);
158 }
159
160 bool IsLSType() const { return fChi2->Type() == fChi2->kLeastSquare; }
161
162 void FdF(const double *x, double &f, double *g) const override { f = fChi2->DataElement(x, fIndex, g); }
163
164private:
165 double DoEval(const double *x) const override { return fChi2->DataElement(x, fIndex, nullptr); }
166
167 double DoDerivative(const double * /* x */, unsigned int /* icoord */) const override
168 {
169 // this function should not be called by GSL
170 throw std::runtime_error("LSRESidualFunc::DoDerivative");
171 return 0;
172 }
173
174 unsigned int fIndex;
175 const Func *fChi2;
176};
177
178int GetTypeFromName(const char *name)
179{
180 std::string tName(name);
181 if (tName.empty())
182 return 0;
183 if (tName == "lms_old")
184 return 1;
185 if (tName == "lm_old")
186 return 2;
187 if (tName == "trust")
188 return 3;
189 if (tName == "trust_lm")
190 return 4;
191 if (tName == "trust_lmaccel")
192 return 5;
193 if (tName == "trust_dogleg")
194 return 6;
195 if (tName == "trust_ddogleg")
196 return 7;
197 if (tName == "trust_subspace2D" || tName == "trust_2D")
198 return 8;
199 return 0;
200}
201
202// GSLNLSMinimizer implementation
204
206{
207 // Constructor implementation : create GSLMultiFit wrapper object
208 const gsl_multifit_fdfsolver_type *gsl_old_type = nullptr; // use default type defined in GSLMultiFit
209 if (type == 1)
210 gsl_old_type = gsl_multifit_fdfsolver_lmsder; // scaled lmder version
211 if (type == 2)
212 gsl_old_type = gsl_multifit_fdfsolver_lmder; // unscaled version
213
214 // const gsl_multifit_nlinear_type * gsl_new_type = nullptr; //
215 // if (type == 3) gsl_new_type = gsl_multifit_nlinear_trust; // trust region default
216
217 if (gsl_old_type)
219 else
221
222 fEdm = -1;
223
224 // default tolerance and max iterations
226 if (niter <= 0)
227 niter = 100;
229
231 if (fLSTolerance <= 0)
232 fLSTolerance = 0.0001; // default internal value
233
235
236 // set the default options
237 if (fGSLMultiFit2) {
239 if (type == 0 || type == 3)
241
242 fOptions.ExtraOptions()->SetValue("scale", "marquardt");
243 }
244}
245
247{
248 if (fGSLMultiFit)
249 delete fGSLMultiFit;
250 if (fGSLMultiFit2)
251 delete fGSLMultiFit2;
252}
253
255{
256 // set the function to minimizer
257 // need to create vector of functions to be passed to GSL multifit
258
259 // call base class method. It will clone the function and set number of dimensions
261 fNFree = NDim();
263}
264
266{
267
268 if (ObjFunction() == nullptr) {
269 MATH_ERROR_MSG("GSLNLSMinimizer::Minimize", "Function has not been set");
270 return false;
271 }
272 // check type of function (if it provides gradient)
273 auto fitFunc = (!fUseGradFunction) ? dynamic_cast<const ROOT::Math::FitMethodFunction *>(ObjFunction()) : nullptr;
274 auto fitGradFunc =
275 (fUseGradFunction) ? dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(ObjFunction()) : nullptr;
276 if (fitFunc == nullptr && fitGradFunc == nullptr) {
277 if (PrintLevel() > 0)
278 std::cout << "GSLNLSMinimizer: Invalid function set - only FitMethodFunction types are supported" << std::endl;
279 return false;
280 }
281
282 if (fGSLMultiFit) {
283
284 if (PrintLevel() > 0)
285 std::cout << "GLSNLSMinimizer::Minimize - Using old GSLMultiFit with method " << fOptions.MinimizerAlgorithm()
286 << std::endl;
287
288 if (fitGradFunc)
290 else
292 }
293 if (fGSLMultiFit2) {
294
295 // set specific minimizer parameters
297
298 if (PrintLevel() > 0)
299 std::cout << "GLSNLSMinimizer::Minimize - Using new GSLMultiFit with trs method " << fOptions.MinimizerAlgorithm()
300 << std::endl;
301
302 if (fitGradFunc)
304 else
306 }
307 return false;
308}
309
310template <class Func, class FitterType>
312{
313
314 unsigned int size = fitFunc.NPoints();
315 fNCalls = 0; // reset number of function calls
316
317 std::vector<LSResidualFunc<Func>> residualFuncs;
318 residualFuncs.reserve(size);
319
320 // set initial parameters of the minimizer
321 int debugLevel = PrintLevel();
322
323 unsigned int npar = NPar();
324 unsigned int ndim = NDim();
325 if (npar == 0 || npar < ndim) {
326 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize", "Wrong number of parameters", npar);
327 return false;
328 }
329
330 // set residual functions and check if a transformation is needed
331 std::vector<double> startValues;
332
333 // transformation need a grad function.
334 std::unique_ptr<MultiNumGradFunction> gradFunction;
335 std::unique_ptr<MinimTransformFunction> trFuncRaw;
336 if (!fUseGradFunction) {
337 gradFunction = std::make_unique<MultiNumGradFunction>(fitFunc);
339 } else {
340 // use pointer stored in BasicMinimizer
342 }
343 // need to transform in a FitTransformFunction which is set in the residual functions
344 std::unique_ptr<FitTransformFunction<Func>> trFunc;
345 if (trFuncRaw) {
346 // pass ownership of trFuncRaw to FitTransformFunction
347 trFunc = std::make_unique<FitTransformFunction<Func>>(fitFunc, std::move(trFuncRaw));
348 assert(npar == trFunc->NTot());
349 for (unsigned int ires = 0; ires < size; ++ires) {
351 }
352 } else {
353 for (unsigned int ires = 0; ires < size; ++ires) {
355 }
356 }
357
358 if (debugLevel >= 1)
359 std::cout << "Minimize using GSLNLSMinimizer " << std::endl;
360
361 int iret = fitter->Set(residualFuncs, &startValues.front());
362
363 if (iret) {
364 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize", "Error setting the residual functions ", iret);
365 return false;
366 }
367
368 int status = 0;
369 bool minFound = false;
370 unsigned int iter = 0;
371 if (fGSLMultiFit) {
372 // case of using old solver
373
374 if (debugLevel >= 1)
375 std::cout << "GSLNLSMinimizer: " << fGSLMultiFit->Name() << " - start iterating......... " << std::endl;
376
377 // start iteration
378 do {
379 status = fitter->Iterate();
380
381 if (debugLevel >= 1) {
382 std::cout << "----------> Iteration " << iter << " / " << MaxIterations() << " status "
383 << gsl_strerror(status) << std::endl;
384 const double *x = fitter->X();
385 if (trFunc)
386 x = trFunc->Transformation(x);
387 int pr = std::cout.precision(18);
388 std::cout << " FVAL = " << (fitFunc)(x) << std::endl;
389 std::cout.precision(pr);
390 std::cout << " X Values : ";
391 for (unsigned int i = 0; i < NDim(); ++i)
392 std::cout << " " << VariableName(i) << " = " << x[i];
393 std::cout << std::endl;
394 }
395
396 if (status)
397 break;
398
399 // check also the delta in X()
400 status = fitter->TestDelta(Tolerance(), Tolerance());
401 if (status == GSL_SUCCESS) {
402 minFound = true;
403 }
404
405 // double-check with the gradient
406 int status2 = fitter->TestGradient(Tolerance());
407 if (minFound && status2 != GSL_SUCCESS) {
408 // check now edm
409 fEdm = fitter->Edm();
410 if (fEdm > Tolerance()) {
411 // continue the iteration
412 status = status2;
413 minFound = false;
414 }
415 }
416
417 if (debugLevel >= 1) {
418 std::cout << " after Gradient and Delta tests: " << gsl_strerror(status);
419 if (fEdm > 0)
420 std::cout << ", edm is: " << fEdm;
421 std::cout << std::endl;
422 }
423
424 iter++;
425
426 } while (status == GSL_CONTINUE && iter < MaxIterations());
427
428 // check edm
429 fEdm = fitter->Edm();
430 if (fEdm < Tolerance()) {
431 minFound = true;
432 }
433
434 } else if (fGSLMultiFit2) {
435 // case using new solver and given driver
436 status = fGSLMultiFit2->Solve();
437 if (status == GSL_SUCCESS)
438 minFound = true;
439 iter = fGSLMultiFit2->NIter();
440 }
441
442 // save state with values and function value
443 const double *x = fitter->X();
444 if (x == nullptr)
445 return false;
446 // apply transformation outside SetFinalValues(..)
447 // because trFunc is not a MinimTransformFunction but a FitTransFormFunction
448 if (trFunc)
449 x = trFunc->Transformation(x);
451
453 fStatus = status;
454 fNCalls = fitFunc.NCalls();
455 fErrors.resize(NDim());
456
457 // get errors from cov matrix
458 const double *cov = fitter->CovarMatrix();
459 if (cov) {
460
461 fCovMatrix.resize(ndim * ndim);
462
463 if (trFunc) {
464 trFunc->MatrixTransformation(x, fitter->CovarMatrix(), fCovMatrix.data());
465 } else {
466 std::copy(cov, cov + fCovMatrix.size(), fCovMatrix.begin());
467 }
468
469 for (unsigned int i = 0; i < ndim; ++i)
470 fErrors[i] = std::sqrt(fCovMatrix[i * ndim + i]);
471 }
472
473 if (minFound) {
474
475 if (debugLevel >= 1) {
476 std::cout << "GSLNLSMinimizer: Minimum Found" << std::endl;
477 int pr = std::cout.precision(18);
478 std::cout << "FVAL = " << MinValue() << std::endl;
479 std::cout << "Edm = " << fEdm << std::endl;
480 std::cout.precision(pr);
481 std::cout << "NIterations = " << iter << std::endl;
482 std::cout << "NFuncCalls = " << fitFunc.NCalls() << std::endl;
483 for (unsigned int i = 0; i < NDim(); ++i)
484 std::cout << std::setw(12) << VariableName(i) << " = " << std::setw(12) << X()[i] << " +/- "
485 << std::setw(12) << fErrors[i] << std::endl;
486 }
487
488 return true;
489 } else {
490 if (debugLevel >= 0) {
491 std::cout << "GSLNLSMinimizer: Minimization did not converge: " << std::endl;
492 if (status == GSL_ENOPROG) // case status 27
493 std::cout << "\t iteration is not making progress towards solution" << std::endl;
494 else
495 std::cout << "\t failed with status " << status << std::endl;
496 }
497 if (debugLevel >= 1) {
498 std::cout << "FVAL = " << MinValue() << std::endl;
499 std::cout << "Edm = " << fitter->Edm() << std::endl;
500 std::cout << "Niterations = " << iter << std::endl;
501 }
502 return false;
503 }
504 return false;
505}
506
507const double *GSLNLSMinimizer::MinGradient() const
508{
509 // return gradient (internal values) - only when using old fitter
510 return (fGSLMultiFit) ? fGSLMultiFit->Gradient() : nullptr;
511}
512
513double GSLNLSMinimizer::CovMatrix(unsigned int i, unsigned int j) const
514{
515 // return covariance matrix element
516 unsigned int ndim = NDim();
517 if (fCovMatrix.empty())
518 return 0;
519 if (i > ndim || j > ndim)
520 return 0;
521 return fCovMatrix[i * ndim + j];
522}
523
525{
526 // return covariance matrix status = 0 not computed,
527 // 1 computed but is approximate because minimum is not valid, 3 is fine
528 if (fCovMatrix.empty())
529 return 0;
530 // case minimization did not finished correctly
531 if (fStatus != GSL_SUCCESS)
532 return 1;
533 return 3;
534}
535
536} // end namespace Math
537
538} // 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
unsigned int NDim() const override
void InvTransformation(const double *xext, double *xint) const
inverse transformation (external -> internal)
FMFunc::Type_t Type() const override
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
double DoDerivative(const double *, unsigned int) const override
double DataElement(const double *x, unsigned i, double *g=nullptr, double *=nullptr, bool=false) const override
IMultiGenFunction * Clone() const override
double DoEval(const double *x) const override
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
FitTransformFunction(const FMFunc &f, std::unique_ptr< MinimTransformFunction > transFunc)
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:239
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:317
void SetMaxIterations(unsigned int maxiter)
Set maximum iterations (one iteration can have many function calls).
Definition Minimizer.h:351
int fStatus
status of minimizer
Definition Minimizer.h:388
unsigned int MaxIterations() const
Max iterations.
Definition Minimizer.h:314
void SetPrintLevel(int level)
Set print level.
Definition Minimizer.h:345
MinimizerOptions fOptions
minimizer options
Definition Minimizer.h:387
int PrintLevel() const
Set print level.
Definition Minimizer.h:308
Double_t x[n]
Definition legend1.C:17
Namespace for new Math classes and functions.
int GetTypeFromName(const char *name)