GSLNLSMinimizer.cxx

Go to the documentation of this file.
00001 // @(#)root/mathmore:$Id: GSLNLSMinimizer.cxx 37427 2010-12-09 08:57:45Z moneta $
00002 // Author: L. Moneta Wed Dec 20 17:16:32 2006
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 // Implementation file for class GSLNLSMinimizer
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 //#include "Math/Derivator.h"
00025 
00026 #include <iostream> 
00027 #include <iomanip>
00028 #include <cassert>
00029 #include <memory>
00030 
00031 namespace ROOT { 
00032 
00033    namespace Math { 
00034 
00035 
00036 // class to implement transformation of chi2 function
00037 // in general could make template on the fit method function type
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       // constructor
00051       // need to pass to MinimTransformFunction a new pointer which will be managed by the class itself
00052       // pass a gradient pointer although it will not be used byb the class 
00053    }
00054 
00055    ~FitTransformFunction() { 
00056       assert(fTransform); 
00057       delete fTransform; 
00058    }
00059 
00060    // re-implement data element
00061    virtual double DataElement(const double *  x, unsigned i, double * g = 0) const { 
00062       // transform from x internal to x external 
00063       const double * xExt = fTransform->Transformation(x); 
00064       if ( g == 0) return fFunc.DataElement( xExt, i );
00065       // use gradient 
00066       double val =  fFunc.DataElement( xExt, i, &fGrad[0]); 
00067       // transform gradient 
00068       fTransform->GradientTransformation( x, &fGrad.front(), g);  
00069       return val; 
00070    }
00071 
00072 
00073    IMultiGenFunction * Clone() const {
00074       // not supported
00075       return 0; 
00076    }
00077 
00078    // dimension (this is number of free dimensions)
00079    unsigned int NDim() const { 
00080       return fTransform->NDim(); 
00081    }
00082 
00083    unsigned int NTot() const { 
00084       return fTransform->NTot(); 
00085    }
00086 
00087    // forward of transformation functions
00088    const double * Transformation( const double * x) const { return fTransform->Transformation(x); }
00089 
00090 
00091    /// inverse transformation (external -> internal)
00092    void  InvTransformation(const double * xext,  double * xint) const { fTransform->InvTransformation(xext,xint); }
00093 
00094    /// inverse transformation for steps (external -> internal) at external point x
00095    void  InvStepTransformation(const double * x, const double * sext,  double * sint) const { fTransform->InvStepTransformation(x,sext,sint); }
00096 
00097    ///transform gradient vector (external -> internal) at internal point x
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;                  // pointer to original fit method function 
00109    MinimTransformFunction * fTransform;        // pointer to transformation function
00110    mutable std::vector<double> fGrad;          // cached vector of gradient values
00111    
00112 };
00113 
00114 
00115 
00116 
00117 // GSLNLSMinimizer implementation
00118 
00119 GSLNLSMinimizer::GSLNLSMinimizer( int /* ROOT::Math::EGSLNLSMinimizerType type */ ) : 
00120    fDim(0), 
00121    fNFree(0),
00122    fSize(0),
00123    fObjFunc(0), 
00124    fMinVal(0)
00125 {
00126    // Constructor implementation : create GSLMultiFit wrapper object
00127    fGSLMultiFit = new GSLMultiFit( /*type */ ); 
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 //   if (fObjFunc) delete fObjFunc; 
00142 }
00143 
00144 bool GSLNLSMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) { 
00145    // set variable in minimizer - support only free variables 
00146    // no transformation implemented - so far
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       // remove bounds if needed
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    //MATH_WARN_MSGVAL("GSLNLSMinimizer::SetLowerLimitedVariable","Ignore lower limit on variable ",ivar);
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    //MATH_WARN_MSGVAL("GSLNLSMinimizer::SetUpperLimitedVariable","Ignore upper limit on variable ",ivar);
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    //MATH_WARN_MSGVAL("GSLNLSMinimizer::SetLimitedVariable","Ignore bounds on variable ",ivar);
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    /// set fixed variable (override if minimizer supports them )
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    // set variable value in minimizer 
00203    // no transformation implemented - so far
00204    if (ivar > fValues.size() ) return false; 
00205    fValues[ivar] = val; 
00206    return true; 
00207 }
00208 
00209 bool GSLNLSMinimizer::SetVariableValues( const double * x) { 
00210    // set all variable values in minimizer 
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    // set the function to minimizer 
00220    // need to create vector of functions to be passed to GSL multifit
00221    // support now only CHi2 implementation
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    // use vector by value 
00233    fResiduals.reserve(fSize);   
00234    for (unsigned int i = 0; i < fSize; ++i) { 
00235       fResiduals.push_back( LSResidualFunc(*chi2Func, i) ); 
00236    }
00237    // keep pointers to the chi2 function
00238    fObjFunc = chi2Func; 
00239  }
00240 
00241 void GSLNLSMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func ) { 
00242    // set the function to minimizer using gradient interface
00243    // not supported yet, implemented using the other SetFunction
00244    return SetFunction(static_cast<const ROOT::Math::IMultiGenFunction &>(func) );
00245 }
00246 
00247 
00248 bool GSLNLSMinimizer::Minimize() { 
00249    // set initial parameters of the minimizer
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    // set residual functions and check if a transformation is needed
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    // in case of transformation wrap residual functions in new transformation functions
00277    // and transform from external variables  to internals one
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(); // actual dimension  
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 //    // use a global step size = min (step vectors) 
00293 //    double stepSize = 1; 
00294 //    for (unsigned int i = 0; i < fSteps.size(); ++i) 
00295 //       //stepSize += fSteps[i]; 
00296 //       if (fSteps[i] < stepSize) stepSize = fSteps[i]; 
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    // start iteration 
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       // check also the delta in X()
00329       status = fGSLMultiFit->TestDelta( Tolerance(), Tolerance() );
00330       if (status == GSL_SUCCESS) {
00331          minFound = true; 
00332       }
00333 
00334       // double-check with the gradient
00335       int status2 = fGSLMultiFit->TestGradient( Tolerance() );
00336       if ( minFound && status2 != GSL_SUCCESS) {
00337          // check now edm 
00338          fEdm = fGSLMultiFit->Edm(); 
00339          if (fEdm > Tolerance() ) { 
00340             // continue the iteration
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    // check edm 
00358    fEdm = fGSLMultiFit->Edm();
00359    if ( fEdm < Tolerance() ) { 
00360       minFound = true; 
00361    }
00362 
00363    // save state with values and function value
00364    const double * x = fGSLMultiFit->X(); 
00365    if (x == 0) return false; 
00366 
00367    // check to see if a transformation need to be applied 
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    // get errors from cov matrix 
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    // return gradient (internal values)
00425    return fGSLMultiFit->Gradient(); 
00426 }
00427 
00428 
00429 double GSLNLSMinimizer::CovMatrix(unsigned int i , unsigned int j ) const { 
00430    // return covariance matrix element
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    // return covariance  matrix status = 0 not computed,
00438    // 1 computed but is approximate because minimum is not valid, 3 is fine
00439    if ( fCovMatrix.size() == 0) return 0;  
00440    // case minimization did not finished correctly
00441    if (fStatus != GSL_SUCCESS) return 1;
00442    return 3;
00443 }
00444 
00445 
00446    } // end namespace Math
00447 
00448 } // end namespace ROOT
00449 

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