GSLMinimizer.cxx

Go to the documentation of this file.
00001 // @(#)root/mathmore:$Id: GSLMinimizer.cxx 37448 2010-12-09 20:20:56Z moneta $
00002 // Author: L. Moneta Tue Dec 19 15:41:39 2006
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  * This library is free software; you can redistribute it and/or      *
00009  * modify it under the terms of the GNU General Public License        *
00010  * as published by the Free Software Foundation; either version 2     *
00011  * of the License, or (at your option) any later version.             *
00012  *                                                                    *
00013  * This library is distributed in the hope that it will be useful,    *
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
00016  * General Public License for more details.                           *
00017  *                                                                    *
00018  * You should have received a copy of the GNU General Public License  *
00019  * along with this library (see file COPYING); if not, write          *
00020  * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
00021  * 330, Boston, MA 02111-1307 USA, or contact the author.             *
00022  *                                                                    *
00023  **********************************************************************/
00024 
00025 // Implementation file for class GSLMinimizer
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>   // need to use c version of tolower defined here
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    // Constructor implementation : create GSLMultiMin wrapper object
00056    //std::cout << "create GSL Minimizer of type " << type << std::endl;
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; // line search tolerance (use fixed)
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    // Constructor implementation from a string 
00076    std::string algoname(type);
00077    std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower ); 
00078 
00079    ROOT::Math::EGSLMinimizerType algo =   kVectorBFGS2; // default value
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    //std::cout << "create GSL Minimizer of type " << algo << std::endl;
00089 
00090    fGSLMultiMin = new GSLMultiMinimizer(algo); 
00091    fValues.reserve(10); 
00092    fNames.reserve(10); 
00093    fSteps.reserve(10); 
00094 
00095    fLSTolerance = 0.1; // use 10**-4 
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    // set variable in minimizer - support only free variables 
00111    // no transformation implemented - so far
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       // remove bounds if needed
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    //MATH_WARN_MSGVAL("GSLMinimizer::SetLowerLimitedVariable","Ignore lower limit on variable ",ivar);
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    //MATH_WARN_MSGVAL("GSLMinimizer::SetUpperLimitedVariable","Ignore upper limit on variable ",ivar);
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    //MATH_WARN_MSGVAL("GSLMinimizer::SetLimitedVariable","Ignore bounds on variable ",ivar);
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    /// set fixed variable (override if minimizer supports them )
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    // set variable value in minimizer 
00171    // no change to transformation or variable status
00172    if (ivar > fValues.size() ) return false; 
00173    fValues[ivar] = val; 
00174    return true; 
00175 }
00176 
00177 bool GSLMinimizer::SetVariableValues( const double * x) { 
00178    // set all variable values in minimizer 
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    // set the function to minimizer 
00187    // need to calculate numerically the derivatives: do via class MultiNumGradFunction
00188    fObjFunc = new MultiNumGradFunction( func); 
00189    fDim = fObjFunc->NDim(); 
00190 }
00191 
00192 void GSLMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) { 
00193    // set the function to minimizer 
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    // return numbr of function calls 
00201    // if method support 
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    // not supported in the other case
00207    return 0; 
00208 }
00209 
00210 bool GSLMinimizer::Minimize() { 
00211    // set initial parameters of the minimizer
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    // use a global step size = modules of  step vectors 
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    // check if a transformation is needed 
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    // in case of transformation wrap objective function in a new transformation function
00250    // and transform from external variables  to internals one
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 //    std::cout << " f has transform " << doTransform << "  " << fBounds.size() << "   " << startValues.size() <<  " ndim " << fObjFunc->NDim() << std::endl;   std::cout << "InitialValues external : "; 
00259 //    for (int i = 0; i < fValues.size(); ++i) std::cout << fValues[i] << "  "; 
00260 //    std::cout << "\n";
00261 //    std::cout << "InitialValues internal : "; 
00262 //    for (int i = 0; i < startValues.size(); ++i) std::cout << startValues[i] << "  "; 
00263 //    std::cout << "\n";
00264 
00265 
00266    // set parameters in internal GSL minimization class 
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    //std::cout <<"print Level " << debugLevel << std::endl; 
00276    //debugLevel = 3; 
00277 
00278    // start iteration 
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          // avoid nan
00309          // if (std::isnan(xtmp[i])) status = -11;
00310          }
00311          std::cout << std::endl; 
00312       }
00313 
00314 
00315       iter++;
00316 
00317 
00318    }
00319    while (status == GSL_CONTINUE && iter < MaxIterations() );
00320 
00321    // save state with values and function value
00322    double * x = fGSLMultiMin->X(); 
00323    if (x == 0) return false; 
00324 
00325    // check to see if a transformation need to be applied 
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       // case of no transformation applied 
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 //      std::cout << "Edm   = " << fState.Edm() << std::endl;
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) // case status 27
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 //      std::cout << "Edm   = " << fState.Edm() << std::endl;
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    // return gradient (internal values) 
00387    return fGSLMultiMin->Gradient(); 
00388 }
00389 
00390 const MinimTransformFunction * GSLMinimizer::TransformFunction() const { 
00391    return dynamic_cast<const MinimTransformFunction *>(fObjFunc);
00392 }
00393 
00394    } // end namespace Math
00395 
00396 } // end namespace ROOT
00397 

Generated on Tue Jul 5 14:34:56 2011 for ROOT_528-00b_version by  doxygen 1.5.1