SimplexBuilder.cxx

Go to the documentation of this file.
00001 // @(#)root/minuit2:$Id: SimplexBuilder.cxx 23654 2008-05-06 07:30:34Z moneta $
00002 // Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005  
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
00007  *                                                                    *
00008  **********************************************************************/
00009 
00010 #include "Minuit2/SimplexBuilder.h"
00011 #include "Minuit2/FunctionMinimum.h"
00012 #include "Minuit2/MnFcn.h"
00013 #include "Minuit2/MinimumSeed.h"
00014 #include "Minuit2/SimplexParameters.h"
00015 #include "Minuit2/MinimumState.h"
00016 
00017 #if defined(DEBUG) || defined(WARNINGMSG)
00018 #include "Minuit2/MnPrint.h" 
00019 #endif
00020 
00021 
00022 namespace ROOT {
00023 
00024    namespace Minuit2 {
00025 
00026 
00027 //#define DEBUG 1
00028 
00029 FunctionMinimum SimplexBuilder::Minimum(const MnFcn& mfcn, const GradientCalculator&, const MinimumSeed& seed, const MnStrategy&, unsigned int maxfcn, double minedm) const {
00030    // find the minimum using the Simplex method of Nelder and Mead (does not use function gradient)
00031    // method to find initial simplex is slightly different than in the orginal Fortran 
00032    // Minuit since has not been proofed that one to be better
00033    
00034 #ifdef DEBUG
00035    std::cout << "Running Simplex with maxfcn = " << maxfcn << " minedm = " << minedm << std::endl;
00036 #endif  
00037    
00038    const MnMachinePrecision& prec = seed.Precision();
00039    MnAlgebraicVector x = seed.Parameters().Vec();
00040    MnAlgebraicVector step = 10.*seed.Gradient().Gstep();
00041    
00042    unsigned int n = x.size();
00043    double wg = 1./double(n);
00044    double alpha = 1., beta = 0.5, gamma = 2., rhomin = 4., rhomax = 8.;
00045    double rho1 = 1. + alpha;
00046    //double rho2 = rho1 + alpha*gamma;
00047    //change proposed by david sachs (fnal)
00048    double rho2 = 1. + alpha*gamma;
00049    
00050    
00051    std::vector<std::pair<double, MnAlgebraicVector> > simpl; simpl.reserve(n+1);
00052    simpl.push_back(std::pair<double, MnAlgebraicVector>(seed.Fval(), x));
00053    
00054    unsigned int jl = 0, jh = 0;
00055    double amin = seed.Fval(), aming = seed.Fval();
00056    
00057    for(unsigned int i = 0; i < n; i++) {
00058       double dmin = 8.*prec.Eps2()*(fabs(x(i)) + prec.Eps2());
00059       if(step(i) < dmin) step(i) = dmin;
00060       x(i) += step(i);
00061       double tmp = mfcn(x);
00062       if(tmp < amin) {
00063          amin = tmp;
00064          jl = i+1;
00065       }
00066       if(tmp > aming) {
00067          aming = tmp;
00068          jh = i+1;
00069       }
00070       simpl.push_back(std::pair<double, MnAlgebraicVector>(tmp, x));
00071       x(i) -= step(i);
00072    }
00073    SimplexParameters simplex(simpl, jh, jl);
00074    
00075 #ifdef DEBUG
00076    std::cout << "simplex initial parameters - min  " << jl << "  " << amin << " max " << jh << "  " << aming << std::endl;
00077    for (unsigned int i = 0; i < simplex.Simplex().size(); ++i)  
00078       std::cout << " i = " << i << " x = " << simplex(i).second << " fval(x) = " << simplex(i).first << std::endl; 
00079 #endif
00080    
00081    double edmPrev = simplex.Edm();
00082    do {
00083       jl = simplex.Jl();
00084       jh = simplex.Jh();
00085       amin = simplex(jl).first;
00086       edmPrev = simplex.Edm();
00087       
00088 #ifdef DEBUG
00089       std::cout << "\n\nsimplex iteration: edm =  " << simplex.Edm()  
00090                 << "\n--> Min Param is  " << jl << " pmin " << simplex(jl).second << " f(pmin) " << amin 
00091                 << "\n--> Max param is " << jh << "  " << simplex(jh).first << std::endl;
00092       
00093       //     std::cout << "ALL SIMPLEX PARAMETERS: "<< std::endl; 
00094       //     for (unsigned int i = 0; i < simplex.Simplex().size(); ++i)  
00095       //       std::cout << " i = " << i << " x = " << simplex(i).second << " fval(x) = " << simplex(i).first << std::endl; 
00096 #endif
00097       MnAlgebraicVector pbar(n);
00098       for(unsigned int i = 0; i < n+1; i++) {
00099          if(i == jh) continue;
00100          pbar += (wg*simplex(i).second);
00101       }
00102       
00103       MnAlgebraicVector pstar = (1. + alpha)*pbar - alpha*simplex(jh).second;
00104       double ystar = mfcn(pstar);
00105       
00106 #ifdef DEBUG
00107       std::cout << " pbar = " << pbar << std::endl;
00108       std::cout << " pstar = " << pstar << " f(pstar) =  " << ystar << std::endl;
00109 #endif
00110       
00111       if(ystar > amin) {
00112          if(ystar < simplex(jh).first) {
00113             simplex.Update(ystar, pstar);
00114             if(jh != simplex.Jh()) continue;
00115          } 
00116          MnAlgebraicVector pstst = beta*simplex(jh).second + (1. - beta)*pbar;
00117          double ystst = mfcn(pstst);
00118 #ifdef DEBUG
00119          std::cout << "Reduced simplex pstst = " << pstst << " f(pstst) =  " << ystst << std::endl;
00120 #endif      
00121          if(ystst > simplex(jh).first) break; 
00122          simplex.Update(ystst, pstst);
00123          continue;
00124       }
00125       
00126       MnAlgebraicVector pstst = gamma*pstar + (1. - gamma)*pbar;
00127       double ystst = mfcn(pstst);
00128 #ifdef DEBUG
00129       std::cout << " pstst = " << pstst << " f(pstst) =  " << ystst << std::endl;
00130 #endif
00131       
00132       double y1 = (ystar - simplex(jh).first)*rho2;
00133       double y2 = (ystst - simplex(jh).first)*rho1;
00134       double rho = 0.5*(rho2*y1 - rho1*y2)/(y1 - y2);
00135       if(rho < rhomin) {
00136          if(ystst < simplex(jl).first) simplex.Update(ystst, pstst);
00137          else simplex.Update(ystar, pstar);
00138          continue;
00139       }
00140       if(rho > rhomax) rho = rhomax;
00141       MnAlgebraicVector prho = rho*pbar + (1. - rho)*simplex(jh).second;
00142       double yrho = mfcn(prho);
00143 #ifdef DEBUG
00144       std::cout << " prho = " << prho << " f(prho) =  " << yrho << std::endl;
00145 #endif
00146       if(yrho < simplex(jl).first && yrho < ystst) {
00147          simplex.Update(yrho, prho);
00148          continue;
00149       }
00150       if(ystst < simplex(jl).first) {
00151          simplex.Update(ystst, pstst);
00152          continue;
00153       }
00154       if(yrho > simplex(jl).first) {
00155          if(ystst < simplex(jl).first) simplex.Update(ystst, pstst);
00156          else simplex.Update(ystar, pstar);
00157          continue;
00158       }
00159       if(ystar > simplex(jh).first) {
00160          pstst = beta*simplex(jh).second + (1. - beta)*pbar;
00161          ystst = mfcn(pstst);
00162          if(ystst > simplex(jh).first) break; 
00163          simplex.Update(ystst, pstst);
00164       }
00165 #ifdef DEBUG
00166       std::cout << "End loop : edm = " << simplex.Edm() << "  pstst = " << pstst << " f(pstst) =  " << ystst << std::endl;
00167 #endif
00168    } while( (simplex.Edm() > minedm || edmPrev > minedm )  && mfcn.NumOfCalls() < maxfcn);
00169    
00170    jl = simplex.Jl();
00171    jh = simplex.Jh();
00172    amin = simplex(jl).first;
00173    
00174    MnAlgebraicVector pbar(n);
00175    for(unsigned int i = 0; i < n+1; i++) {
00176       if(i == jh) continue;
00177       pbar += (wg*simplex(i).second);
00178    }
00179    double ybar = mfcn(pbar);
00180    if(ybar < amin) simplex.Update(ybar, pbar);
00181    else {
00182       pbar = simplex(jl).second;
00183       ybar = simplex(jl).first;
00184    }
00185    
00186    MnAlgebraicVector dirin = simplex.Dirin();
00187    //   Scale to sigmas on parameters werr^2 = dirin^2 * (up/edm) 
00188    dirin *= sqrt(mfcn.Up()/simplex.Edm());
00189    
00190 #ifdef DEBUG
00191    std::cout << "End simplex " << simplex.Edm() << "  pbar = " << pbar << " f(p) =  " << ybar << std::endl;
00192 #endif
00193    
00194    
00195    MinimumState st(MinimumParameters(pbar, dirin, ybar), simplex.Edm(), mfcn.NumOfCalls());
00196    
00197    if(mfcn.NumOfCalls() > maxfcn) {
00198 #ifdef WARNINGMSG
00199       MN_INFO_MSG("Simplex did not converge, #fcn calls exhausted.");
00200 #endif
00201       return FunctionMinimum(seed, std::vector<MinimumState>(1, st), mfcn.Up(), FunctionMinimum::MnReachedCallLimit());
00202    }
00203    if(simplex.Edm() > minedm) {
00204 #ifdef WARNINGMSG
00205       MN_INFO_MSG("Simplex did not converge, edm > minedm.");
00206 #endif
00207       return FunctionMinimum(seed, std::vector<MinimumState>(1, st), mfcn.Up(), FunctionMinimum::MnAboveMaxEdm());
00208    }
00209    
00210    return FunctionMinimum(seed, std::vector<MinimumState>(1, st), mfcn.Up());
00211 }
00212 
00213    }  // namespace Minuit2
00214 
00215 }  // namespace ROOT

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