00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "Math/GSLNLSMinimizer.h"
00014
00015 #include "Math/MinimTransformFunction.h"
00016 #include "Math/MultiNumGradFunction.h"
00017
00018 #include "Math/Error.h"
00019 #include "GSLMultiFit.h"
00020 #include "gsl/gsl_errno.h"
00021
00022
00023 #include "Math/FitMethodFunction.h"
00024
00025
00026 #include <iostream>
00027 #include <iomanip>
00028 #include <cassert>
00029 #include <memory>
00030
00031 namespace ROOT {
00032
00033 namespace Math {
00034
00035
00036
00037
00038
00039 class FitTransformFunction : public FitMethodFunction {
00040
00041 public:
00042
00043 FitTransformFunction(const FitMethodFunction & f, const std::vector<EMinimVariableType> & types, const std::vector<double> & values,
00044 const std::map<unsigned int, std::pair<double, double> > & bounds) :
00045 FitMethodFunction( f.NDim(), f.NPoints() ),
00046 fFunc(f),
00047 fTransform(new MinimTransformFunction( new MultiNumGradFunction(f), types, values, bounds) ),
00048 fGrad( std::vector<double>(f.NDim() ) )
00049 {
00050
00051
00052
00053 }
00054
00055 ~FitTransformFunction() {
00056 assert(fTransform);
00057 delete fTransform;
00058 }
00059
00060
00061 virtual double DataElement(const double * x, unsigned i, double * g = 0) const {
00062
00063 const double * xExt = fTransform->Transformation(x);
00064 if ( g == 0) return fFunc.DataElement( xExt, i );
00065
00066 double val = fFunc.DataElement( xExt, i, &fGrad[0]);
00067
00068 fTransform->GradientTransformation( x, &fGrad.front(), g);
00069 return val;
00070 }
00071
00072
00073 IMultiGenFunction * Clone() const {
00074
00075 return 0;
00076 }
00077
00078
00079 unsigned int NDim() const {
00080 return fTransform->NDim();
00081 }
00082
00083 unsigned int NTot() const {
00084 return fTransform->NTot();
00085 }
00086
00087
00088 const double * Transformation( const double * x) const { return fTransform->Transformation(x); }
00089
00090
00091
00092 void InvTransformation(const double * xext, double * xint) const { fTransform->InvTransformation(xext,xint); }
00093
00094
00095 void InvStepTransformation(const double * x, const double * sext, double * sint) const { fTransform->InvStepTransformation(x,sext,sint); }
00096
00097
00098 void GradientTransformation(const double * x, const double *gext, double * gint) const { fTransform->GradientTransformation(x,gext,gint); }
00099
00100 void MatrixTransformation(const double * x, const double *cint, double * cext) const { fTransform->MatrixTransformation(x,cint,cext); }
00101
00102 private:
00103
00104 double DoEval(const double * x) const {
00105 return fFunc( fTransform->Transformation(x) );
00106 }
00107
00108 const FitMethodFunction & fFunc;
00109 MinimTransformFunction * fTransform;
00110 mutable std::vector<double> fGrad;
00111
00112 };
00113
00114
00115
00116
00117
00118
00119 GSLNLSMinimizer::GSLNLSMinimizer( int ) :
00120 fDim(0),
00121 fNFree(0),
00122 fSize(0),
00123 fObjFunc(0),
00124 fMinVal(0)
00125 {
00126
00127 fGSLMultiFit = new GSLMultiFit( );
00128 fValues.reserve(10);
00129 fNames.reserve(10);
00130 fSteps.reserve(10);
00131
00132 fEdm = -1;
00133 fLSTolerance = 0.0001;
00134 SetMaxIterations(100);
00135 SetPrintLevel(1);
00136 }
00137
00138 GSLNLSMinimizer::~GSLNLSMinimizer () {
00139 assert(fGSLMultiFit != 0);
00140 delete fGSLMultiFit;
00141
00142 }
00143
00144 bool GSLNLSMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) {
00145
00146
00147 if (ivar > fValues.size() ) return false;
00148 if (ivar == fValues.size() ) {
00149 fValues.push_back(val);
00150 fNames.push_back(name);
00151 fSteps.push_back(step);
00152 fVarTypes.push_back(kDefault);
00153 }
00154 else {
00155 fValues[ivar] = val;
00156 fNames[ivar] = name;
00157 fSteps[ivar] = step;
00158 fVarTypes[ivar] = kDefault;
00159
00160
00161 std::map<unsigned int, std::pair<double, double> >::iterator iter = fBounds.find(ivar);
00162 if ( iter != fBounds.end() ) fBounds.erase (iter);
00163
00164 }
00165 return true;
00166 }
00167
00168 bool GSLNLSMinimizer::SetLowerLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower) {
00169
00170 bool ret = SetVariable(ivar, name, val, step);
00171 if (!ret) return false;
00172 fBounds[ivar] = std::make_pair( lower, lower);
00173 fVarTypes[ivar] = kLowBound;
00174 return true;
00175 }
00176 bool GSLNLSMinimizer::SetUpperLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double upper) {
00177
00178 bool ret = SetVariable(ivar, name, val, step);
00179 if (!ret) return false;
00180 fBounds[ivar] = std::make_pair( upper, upper);
00181 fVarTypes[ivar] = kUpBound;
00182 return true;
00183 }
00184 bool GSLNLSMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper ) {
00185
00186 bool ret = SetVariable(ivar, name, val, step);
00187 if (!ret) return false;
00188 fBounds[ivar] = std::make_pair( lower, upper);
00189 fVarTypes[ivar] = kBounds;
00190 return true;
00191 }
00192
00193 bool GSLNLSMinimizer::SetFixedVariable(unsigned int ivar , const std::string & name , double val ) {
00194
00195 bool ret = SetVariable(ivar, name, val, 0.);
00196 if (!ret) return false;
00197 fVarTypes[ivar] = kFix;
00198 return true;
00199 }
00200
00201 bool GSLNLSMinimizer::SetVariableValue(unsigned int ivar, double val) {
00202
00203
00204 if (ivar > fValues.size() ) return false;
00205 fValues[ivar] = val;
00206 return true;
00207 }
00208
00209 bool GSLNLSMinimizer::SetVariableValues( const double * x) {
00210
00211 if (x == 0) return false;
00212 std::copy(x,x+fValues.size(), fValues.begin() );
00213 return true;
00214 }
00215
00216
00217
00218 void GSLNLSMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) {
00219
00220
00221
00222
00223 const ROOT::Math::FitMethodFunction * chi2Func = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
00224 if (chi2Func == 0) {
00225 if (PrintLevel() > 0) std::cout << "GSLNLSMinimizer: Invalid function set - only Chi2Func supported" << std::endl;
00226 return;
00227 }
00228 fSize = chi2Func->NPoints();
00229 fDim = chi2Func->NDim();
00230 fNFree = fDim;
00231
00232
00233 fResiduals.reserve(fSize);
00234 for (unsigned int i = 0; i < fSize; ++i) {
00235 fResiduals.push_back( LSResidualFunc(*chi2Func, i) );
00236 }
00237
00238 fObjFunc = chi2Func;
00239 }
00240
00241 void GSLNLSMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func ) {
00242
00243
00244 return SetFunction(static_cast<const ROOT::Math::IMultiGenFunction &>(func) );
00245 }
00246
00247
00248 bool GSLNLSMinimizer::Minimize() {
00249
00250 int debugLevel = PrintLevel();
00251
00252
00253 assert (fGSLMultiFit != 0);
00254 if (fResiduals.size() != fSize || fObjFunc == 0) {
00255 MATH_ERROR_MSG("GSLNLSMinimizer::Minimize","Function has not been set");
00256 return false;
00257 }
00258
00259 unsigned int npar = fValues.size();
00260 if (npar == 0 || npar < fDim) {
00261 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize","Wrong number of parameters",npar);
00262 return false;
00263 }
00264
00265
00266
00267 bool doTransform = (fBounds.size() > 0);
00268 unsigned int ivar = 0;
00269 while (!doTransform && ivar < fVarTypes.size() ) {
00270 doTransform = (fVarTypes[ivar++] != kDefault );
00271 }
00272 std::vector<double> startValues(fValues.begin(), fValues.end() );
00273
00274 std::auto_ptr<FitTransformFunction> trFunc;
00275
00276
00277
00278 if (doTransform) {
00279 trFunc.reset(new FitTransformFunction ( *fObjFunc, fVarTypes, fValues, fBounds ) );
00280 for (unsigned int ires = 0; ires < fResiduals.size(); ++ires) {
00281 fResiduals[ires] = LSResidualFunc(*trFunc, ires);
00282 }
00283
00284 trFunc->InvTransformation(&fValues.front(), &startValues[0]);
00285 fNFree = trFunc->NDim();
00286 assert(fValues.size() == trFunc->NTot() );
00287 startValues.resize( fNFree );
00288 }
00289
00290 if (debugLevel >=1 ) std::cout <<"Minimize using GSLNLSMinimizer " << fGSLMultiFit->Name() << std::endl;
00291
00292
00293
00294
00295
00296
00297
00298 int iret = fGSLMultiFit->Set( fResiduals, &startValues.front() );
00299 if (iret) {
00300 MATH_ERROR_MSGVAL("GSLNLSMinimizer::Minimize","Error setting the residual functions ",iret);
00301 return false;
00302 }
00303
00304 if (debugLevel >=1 ) std::cout <<"GSLNLSMinimizer: Start iterating......... " << std::endl;
00305
00306
00307 unsigned int iter = 0;
00308 int status;
00309 bool minFound = false;
00310 do {
00311 status = fGSLMultiFit->Iterate();
00312
00313 if (debugLevel >=1) {
00314 std::cout << "----------> Iteration " << iter << " / " << MaxIterations() << " status " << gsl_strerror(status) << std::endl;
00315 const double * x = fGSLMultiFit->X();
00316 if (trFunc.get()) x = trFunc->Transformation(x);
00317 int pr = std::cout.precision(18);
00318 std::cout << " FVAL = " << (*fObjFunc)(x) << std::endl;
00319 std::cout.precision(pr);
00320 std::cout << " X Values : ";
00321 for (unsigned int i = 0; i < fDim; ++i)
00322 std::cout << " " << fNames[i] << " = " << x[i];
00323 std::cout << std::endl;
00324 }
00325
00326 if (status) break;
00327
00328
00329 status = fGSLMultiFit->TestDelta( Tolerance(), Tolerance() );
00330 if (status == GSL_SUCCESS) {
00331 minFound = true;
00332 }
00333
00334
00335 int status2 = fGSLMultiFit->TestGradient( Tolerance() );
00336 if ( minFound && status2 != GSL_SUCCESS) {
00337
00338 fEdm = fGSLMultiFit->Edm();
00339 if (fEdm > Tolerance() ) {
00340
00341 status = status2;
00342 minFound = false;
00343 }
00344 }
00345
00346 if (debugLevel >=1) {
00347 std::cout << " after Gradient and Delta tests: " << gsl_strerror(status);
00348 if (fEdm > 0) std::cout << ", edm is: " << fEdm;
00349 std::cout << std::endl;
00350 }
00351
00352 iter++;
00353
00354 }
00355 while (status == GSL_CONTINUE && iter < MaxIterations() );
00356
00357
00358 fEdm = fGSLMultiFit->Edm();
00359 if ( fEdm < Tolerance() ) {
00360 minFound = true;
00361 }
00362
00363
00364 const double * x = fGSLMultiFit->X();
00365 if (x == 0) return false;
00366
00367
00368 if (trFunc.get() != 0) {
00369 const double * xtrans = trFunc->Transformation(x);
00370 std::copy(xtrans, xtrans + trFunc->NTot(), fValues.begin() );
00371 }
00372 else {
00373 std::copy(x, x +fDim, fValues.begin() );
00374 }
00375
00376 fMinVal = (*fObjFunc)(&fValues.front() );
00377 fStatus = status;
00378
00379 fErrors.resize(fDim);
00380
00381
00382 if (fGSLMultiFit->CovarMatrix() ) fCovMatrix.resize(fDim*fDim);
00383
00384 if (minFound) {
00385
00386 if (trFunc.get() != 0) {
00387 trFunc->MatrixTransformation(x, fGSLMultiFit->CovarMatrix(), &fCovMatrix[0] );
00388 }
00389 else {
00390 const double * m = fGSLMultiFit->CovarMatrix();
00391 std::copy(m, m+ fDim*fDim, fCovMatrix.begin() );
00392 }
00393
00394 for (unsigned int i = 0; i < fDim; ++i)
00395 fErrors[i] = std::sqrt(fCovMatrix[i*fDim + i]);
00396
00397 if (debugLevel >=1 ) {
00398 std::cout << "GSLNLSMinimizer: Minimum Found" << std::endl;
00399 int pr = std::cout.precision(18);
00400 std::cout << "FVAL = " << fMinVal << std::endl;
00401 std::cout << "Edm = " << fEdm << std::endl;
00402 std::cout.precision(pr);
00403 std::cout << "NIterations = " << iter << std::endl;
00404 std::cout << "NFuncCalls = " << fObjFunc->NCalls() << std::endl;
00405 for (unsigned int i = 0; i < fDim; ++i)
00406 std::cout << std::setw(12) << fNames[i] << " = " << std::setw(12) << fValues[i] << " +/- " << std::setw(12) << fErrors[i] << std::endl;
00407 }
00408
00409 return true;
00410 }
00411 else {
00412 if (debugLevel >=1 ) {
00413 std::cout << "GSLNLSMinimizer: Minimization did not converge" << std::endl;
00414 std::cout << "FVAL = " << fMinVal << std::endl;
00415 std::cout << "Edm = " << fGSLMultiFit->Edm() << std::endl;
00416 std::cout << "Niterations = " << iter << std::endl;
00417 }
00418 return false;
00419 }
00420 return false;
00421 }
00422
00423 const double * GSLNLSMinimizer::MinGradient() const {
00424
00425 return fGSLMultiFit->Gradient();
00426 }
00427
00428
00429 double GSLNLSMinimizer::CovMatrix(unsigned int i , unsigned int j ) const {
00430
00431 if ( fCovMatrix.size() == 0) return 0;
00432 if (i > fDim || j > fDim) return 0;
00433 return fCovMatrix[i*fDim + j];
00434 }
00435
00436 int GSLNLSMinimizer::CovMatrixStatus( ) const {
00437
00438
00439 if ( fCovMatrix.size() == 0) return 0;
00440
00441 if (fStatus != GSL_SUCCESS) return 1;
00442 return 3;
00443 }
00444
00445
00446 }
00447
00448 }
00449