00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "Math/GSLMinimizer.h"
00028
00029 #include "GSLMultiMinimizer.h"
00030
00031 #include "Math/MultiNumGradFunction.h"
00032 #include "Math/FitMethodFunction.h"
00033
00034 #include "Math/MinimTransformFunction.h"
00035
00036 #include <cassert>
00037
00038 #include <iostream>
00039 #include <cmath>
00040 #include <algorithm>
00041 #include <functional>
00042 #include <ctype.h>
00043 #include <limits>
00044
00045 namespace ROOT {
00046
00047 namespace Math {
00048
00049
00050 GSLMinimizer::GSLMinimizer( ROOT::Math::EGSLMinimizerType type) :
00051 fDim(0),
00052 fObjFunc(0),
00053 fMinVal(0)
00054 {
00055
00056
00057
00058 fGSLMultiMin = new GSLMultiMinimizer((ROOT::Math::EGSLMinimizerType) type);
00059 fValues.reserve(10);
00060 fNames.reserve(10);
00061 fSteps.reserve(10);
00062
00063 fLSTolerance = 0.1;
00064 int niter = ROOT::Math::MinimizerOptions::DefaultMaxIterations();
00065 if (niter <=0 ) niter = 1000;
00066 SetMaxIterations(niter);
00067 SetPrintLevel(ROOT::Math::MinimizerOptions::DefaultPrintLevel());
00068 }
00069
00070 GSLMinimizer::GSLMinimizer( const char * type) :
00071 fDim(0),
00072 fObjFunc(0),
00073 fMinVal(0)
00074 {
00075
00076 std::string algoname(type);
00077 std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower );
00078
00079 ROOT::Math::EGSLMinimizerType algo = kVectorBFGS2;
00080
00081 if (algoname == "conjugatefr") algo = kConjugateFR;
00082 if (algoname == "conjugatepr") algo = kConjugatePR;
00083 if (algoname == "bfgs") algo = kVectorBFGS;
00084 if (algoname == "bfgs2") algo = kVectorBFGS2;
00085 if (algoname == "steepestdescent") algo = kSteepestDescent;
00086
00087
00088
00089
00090 fGSLMultiMin = new GSLMultiMinimizer(algo);
00091 fValues.reserve(10);
00092 fNames.reserve(10);
00093 fSteps.reserve(10);
00094
00095 fLSTolerance = 0.1;
00096 int niter = ROOT::Math::MinimizerOptions::DefaultMaxIterations();
00097 if (niter <=0 ) niter = 1000;
00098 SetMaxIterations(niter);
00099 SetPrintLevel(ROOT::Math::MinimizerOptions::DefaultPrintLevel());
00100 }
00101
00102
00103 GSLMinimizer::~GSLMinimizer () {
00104 assert(fGSLMultiMin != 0);
00105 delete fGSLMultiMin;
00106 if (fObjFunc) delete fObjFunc;
00107 }
00108
00109 bool GSLMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) {
00110
00111
00112 if (ivar > fValues.size() ) return false;
00113 if (ivar == fValues.size() ) {
00114 fValues.push_back(val);
00115 fNames.push_back(name);
00116 fSteps.push_back(step);
00117 fVarTypes.push_back(kDefault);
00118 }
00119 else {
00120 fValues[ivar] = val;
00121 fNames[ivar] = name;
00122 fSteps[ivar] = step;
00123 fVarTypes[ivar] = kDefault;
00124
00125
00126 std::map<unsigned int, std::pair<double, double> >::iterator iter = fBounds.find(ivar);
00127 if ( iter != fBounds.end() ) fBounds.erase (iter);
00128
00129 }
00130
00131 return true;
00132 }
00133
00134 bool GSLMinimizer::SetLowerLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower) {
00135
00136 bool ret = SetVariable(ivar, name, val, step);
00137 if (!ret) return false;
00138 fBounds[ivar] = std::make_pair( lower, lower);
00139 fVarTypes[ivar] = kLowBound;
00140 return true;
00141 }
00142 bool GSLMinimizer::SetUpperLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double upper ) {
00143
00144 bool ret = SetVariable(ivar, name, val, step);
00145 if (!ret) return false;
00146 fBounds[ivar] = std::make_pair( upper, upper);
00147 fVarTypes[ivar] = kUpBound;
00148 return true;
00149 }
00150
00151 bool GSLMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper) {
00152
00153 bool ret = SetVariable(ivar, name, val, step);
00154 if (!ret) return false;
00155 fBounds[ivar] = std::make_pair( lower, upper);
00156 fVarTypes[ivar] = kBounds;
00157 return true;
00158 }
00159
00160 bool GSLMinimizer::SetFixedVariable(unsigned int ivar , const std::string & name , double val ) {
00161
00162 bool ret = SetVariable(ivar, name, val, 0.);
00163 if (!ret) return false;
00164 fVarTypes[ivar] = kFix;
00165 return true;
00166 }
00167
00168
00169 bool GSLMinimizer::SetVariableValue(unsigned int ivar, double val) {
00170
00171
00172 if (ivar > fValues.size() ) return false;
00173 fValues[ivar] = val;
00174 return true;
00175 }
00176
00177 bool GSLMinimizer::SetVariableValues( const double * x) {
00178
00179 if (x == 0) return false;
00180 std::copy(x,x+fValues.size(), fValues.begin() );
00181 return true;
00182 }
00183
00184
00185 void GSLMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) {
00186
00187
00188 fObjFunc = new MultiNumGradFunction( func);
00189 fDim = fObjFunc->NDim();
00190 }
00191
00192 void GSLMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) {
00193
00194 fObjFunc = dynamic_cast<const ROOT::Math::IMultiGradFunction *>( func.Clone());
00195 assert(fObjFunc != 0);
00196 fDim = fObjFunc->NDim();
00197 }
00198
00199 unsigned int GSLMinimizer::NCalls() const {
00200
00201
00202 const ROOT::Math::MultiNumGradFunction * fnumgrad = dynamic_cast<const ROOT::Math::MultiNumGradFunction *>(fObjFunc);
00203 if (fnumgrad) return fnumgrad->NCalls();
00204 const ROOT::Math::FitMethodGradFunction * ffitmethod = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(fObjFunc);
00205 if (ffitmethod) return ffitmethod->NCalls();
00206
00207 return 0;
00208 }
00209
00210 bool GSLMinimizer::Minimize() {
00211
00212
00213 if (fGSLMultiMin == 0) return false;
00214 if (fObjFunc == 0) {
00215 MATH_ERROR_MSG("GSLMinimizer::Minimize","Function has not been set");
00216 return false;
00217 }
00218
00219 unsigned int npar = fValues.size();
00220 if (npar == 0 || npar < fObjFunc->NDim() ) {
00221 MATH_ERROR_MSGVAL("GSLMinimizer::Minimize","Wrong number of parameters",npar);
00222 return false;
00223 }
00224
00225
00226 double stepSize = 0;
00227 for (unsigned int i = 0; i < fSteps.size(); ++i)
00228 stepSize += fSteps[i]*fSteps[i];
00229 stepSize = std::sqrt(stepSize);
00230
00231 const double eps = std::numeric_limits<double>::epsilon();
00232 if (stepSize < eps) {
00233 MATH_ERROR_MSGVAL("GSLMinimizer::Minimize","Step size is too small",stepSize);
00234 return false;
00235 }
00236
00237
00238 bool doTransform = (fBounds.size() > 0);
00239 unsigned int ivar = 0;
00240 while (!doTransform && ivar < fVarTypes.size() ) {
00241 doTransform = (fVarTypes[ivar++] != kDefault );
00242 }
00243
00244
00245 std::vector<double> startValues(fValues.begin(), fValues.end() );
00246
00247 MinimTransformFunction * trFunc = 0;
00248
00249
00250
00251 if (doTransform) {
00252 trFunc = new MinimTransformFunction ( fObjFunc, fVarTypes, fValues, fBounds );
00253 trFunc->InvTransformation(&fValues.front(), &startValues[0]);
00254 startValues.resize( trFunc->NDim() );
00255 fObjFunc = trFunc;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 fGSLMultiMin->Set(*fObjFunc, &startValues.front(), stepSize, fLSTolerance );
00268
00269
00270 int debugLevel = PrintLevel();
00271
00272 if (debugLevel >=1 ) std::cout <<"Minimize using GSLMinimizer " << fGSLMultiMin->Name() << std::endl;
00273
00274
00275
00276
00277
00278
00279 unsigned int iter = 0;
00280 int status;
00281 bool minFound = false;
00282 bool iterFailed = false;
00283 do {
00284 status = fGSLMultiMin->Iterate();
00285 if (status) {
00286 iterFailed = true;
00287 break;
00288 }
00289
00290 status = fGSLMultiMin->TestGradient( Tolerance() );
00291 if (status == GSL_SUCCESS) {
00292 minFound = true;
00293 }
00294
00295 if (debugLevel >=3) {
00296 std::cout << "----------> Iteration " << iter << std::endl;
00297 int pr = std::cout.precision(18);
00298 std::cout << " FVAL = " << fGSLMultiMin->Minimum() << std::endl;
00299 std::cout.precision(pr);
00300 std::cout << " X Values : ";
00301 const double * xtmp = fGSLMultiMin->X();
00302 std::cout << std::endl;
00303 if (trFunc != 0 ) {
00304 xtmp = trFunc->Transformation(xtmp);
00305 }
00306 for (unsigned int i = 0; i < NDim(); ++i) {
00307 std::cout << " " << fNames[i] << " = " << xtmp[i];
00308
00309
00310 }
00311 std::cout << std::endl;
00312 }
00313
00314
00315 iter++;
00316
00317
00318 }
00319 while (status == GSL_CONTINUE && iter < MaxIterations() );
00320
00321
00322 double * x = fGSLMultiMin->X();
00323 if (x == 0) return false;
00324
00325
00326 if (trFunc != 0) {
00327 const double * xtrans = trFunc->Transformation(x);
00328 assert(fValues.size() == trFunc->NTot() );
00329 assert( trFunc->NTot() == NDim() );
00330 std::copy(xtrans, xtrans + trFunc->NTot(), fValues.begin() );
00331 }
00332 else {
00333
00334 assert( fValues.size() == NDim() );
00335 std::copy(x, x + NDim(), fValues.begin() );
00336 }
00337
00338 fMinVal = fGSLMultiMin->Minimum();
00339
00340 fStatus = status;
00341
00342
00343 if (minFound) {
00344 if (debugLevel >=1 ) {
00345 std::cout << "GSLMinimizer: Minimum Found" << std::endl;
00346 int pr = std::cout.precision(18);
00347 std::cout << "FVAL = " << fMinVal << std::endl;
00348 std::cout.precision(pr);
00349
00350 std::cout << "Niterations = " << iter << std::endl;
00351 unsigned int ncalls = NCalls();
00352 if (ncalls) std::cout << "NCalls = " << ncalls << std::endl;
00353 for (unsigned int i = 0; i < fDim; ++i)
00354 std::cout << fNames[i] << "\t = " << fValues[i] << std::endl;
00355 }
00356 return true;
00357 }
00358 else {
00359 if (debugLevel >= -1 ) {
00360 std::cout << "GSLMinimizer: Minimization did not converge" << std::endl;
00361 if (iterFailed) {
00362 if (status == GSL_ENOPROG)
00363 std::cout << "\t Iteration is not making progress towards solution" << std::endl;
00364 else
00365 std::cout << "\t Iteration failed with status " << status << std::endl;
00366
00367 if (debugLevel >= 1) {
00368 double * g = fGSLMultiMin->Gradient();
00369 double dg2 = 0;
00370 for (unsigned int i = 0; i < fDim; ++i) dg2 += g[i] * g[1];
00371 std::cout << "Grad module is " << std::sqrt(dg2) << std::endl;
00372 for (unsigned int i = 0; i < fDim; ++i)
00373 std::cout << fNames[i] << "\t = " << fValues[i] << std::endl;
00374 std::cout << "FVAL = " << fMinVal << std::endl;
00375
00376 std::cout << "Niterations = " << iter << std::endl;
00377 }
00378 }
00379 }
00380 return false;
00381 }
00382 return false;
00383 }
00384
00385 const double * GSLMinimizer::MinGradient() const {
00386
00387 return fGSLMultiMin->Gradient();
00388 }
00389
00390 const MinimTransformFunction * GSLMinimizer::TransformFunction() const {
00391 return dynamic_cast<const MinimTransformFunction *>(fObjFunc);
00392 }
00393
00394 }
00395
00396 }
00397