00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include "Minuit2/FumiliBuilder.h"
00011 #include "Minuit2/FumiliStandardMaximumLikelihoodFCN.h"
00012 #include "Minuit2/GradientCalculator.h"
00013 
00014 #include "Minuit2/MinimumState.h"
00015 #include "Minuit2/MinimumError.h"
00016 #include "Minuit2/FunctionGradient.h"
00017 #include "Minuit2/FunctionMinimum.h"
00018 #include "Minuit2/MnLineSearch.h"
00019 #include "Minuit2/MinimumSeed.h"
00020 #include "Minuit2/MnFcn.h"
00021 #include "Minuit2/MnMachinePrecision.h"
00022 #include "Minuit2/MnPosDef.h"
00023 #include "Minuit2/MnParabolaPoint.h"
00024 #include "Minuit2/LaSum.h"
00025 #include "Minuit2/LaProd.h"
00026 #include "Minuit2/MnStrategy.h"
00027 #include "Minuit2/MnHesse.h"
00028 
00029 
00030 
00031 
00032 #if defined(DEBUG) || defined(WARNINGMSG)
00033 #include "Minuit2/MnPrint.h" 
00034 #endif
00035 
00036 
00037 
00038 namespace ROOT {
00039 
00040    namespace Minuit2 {
00041 
00042 
00043 
00044 
00045 double inner_product(const LAVector&, const LAVector&);
00046 
00047 FunctionMinimum FumiliBuilder::Minimum(const MnFcn& fcn, const GradientCalculator& gc, const MinimumSeed& seed, const MnStrategy& strategy, unsigned int maxfcn, double edmval) const {
00048    
00049    
00050    
00051    edmval *= 0.0001;
00052    
00053    
00054    
00055 #ifdef DEBUG
00056    std::cout<<"FumiliBuilder convergence when edm < "<<edmval<<std::endl;
00057 #endif
00058    
00059    if(seed.Parameters().Vec().size() == 0) {
00060       return FunctionMinimum(seed, fcn.Up());
00061    }
00062    
00063    
00064    
00065    double edm = seed.State().Edm();
00066    
00067    FunctionMinimum min(seed, fcn.Up() );
00068    
00069    if(edm < 0.) {
00070 #ifdef WARNINGMSG
00071       MN_INFO_MSG("FumiliBuilder: initial matrix not pos.def.");
00072 #endif
00073       return min;
00074    }
00075    
00076    std::vector<MinimumState> result;
00077    
00078    result.reserve(8);
00079    
00080    result.push_back( seed.State() );
00081    
00082    
00083    
00084    
00085    
00086    
00087    int maxfcn_eff = int(0.5*maxfcn);
00088    int ipass = 0;
00089    double edmprev = 1;
00090    
00091    do { 
00092       
00093       
00094       min = Minimum(fcn, gc, seed, result, maxfcn_eff, edmval);
00095 
00096 
00097       
00098       if (ipass > 0) { 
00099          if(!min.IsValid()) {
00100 #ifdef WARNINGMSG
00101             MN_INFO_MSG("FumiliBuilder: FunctionMinimum is invalid.");
00102 #endif
00103             return min;
00104          }
00105       }
00106       
00107       
00108       edm = result.back().Edm();
00109 
00110 #ifdef DEBUG
00111       std::cout << "approximate edm is  " << edm << std::endl;
00112       std::cout << "npass is " << ipass << std::endl;
00113 #endif
00114       
00115       
00116          
00117 #ifdef DEBUG
00118       std::cout << "FumiliBuilder will verify convergence and Error matrix. " << std::endl;
00119       std::cout << "dcov is =  "<<  min.Error().Dcovar() << std::endl;
00120 #endif
00121 
00122 
00123 
00124 
00125 
00126          
00127       MinimumState st = MnHesse(strategy)(fcn, min.State(), min.Seed().Trafo(),maxfcn);
00128       result.push_back( st );
00129          
00130 
00131       
00132       edm = st.Edm();
00133 #ifdef DEBUG
00134       std::cout << "edm after Hesse calculation " << edm << std::endl;
00135       std::cout << "state after Hessian calculation  " << st << std::endl;
00136 #endif
00137          
00138       
00139       if (ipass > 0 && edm >= edmprev) { 
00140 #ifdef WARNINGMSG
00141          MN_INFO_MSG("FumiliBuilder: Exit iterations, no improvements after Hesse ");
00142          MN_INFO_VAL2("current edm is ", edm); 
00143          MN_INFO_VAL2("previous value ",edmprev);
00144 #endif
00145          break; 
00146       } 
00147       if (edm > edmval) { 
00148 #ifdef DEBUG
00149          std::cout << "FumiliBuilder: Tolerance is not sufficient - edm is " << edm << " requested " << edmval 
00150                    << " continue the minimization" << std::endl;
00151 #endif
00152       }
00153       else { 
00154          
00155          
00156          if (min.IsAboveMaxEdm() ) {
00157             min = FunctionMinimum( min.Seed(), min.States(), min.Up() );
00158             break;
00159          }
00160          
00161       } 
00162       
00163       
00164       
00165       
00166       
00167       
00168       
00169       if (ipass == 0) maxfcn_eff = maxfcn;
00170       ipass++;
00171       edmprev = edm; 
00172       
00173    }  while (edm > edmval );
00174    
00175    
00176    
00177    
00178    min.Add( result.back() );
00179    
00180    return min;
00181    
00182 }
00183 
00184 FunctionMinimum FumiliBuilder::Minimum(const MnFcn& fcn, const GradientCalculator& gc, const MinimumSeed& seed, std::vector<MinimumState>& result, unsigned int maxfcn, double edmval) const {
00185 
00186    
00187    
00188    
00189    
00190    
00191    
00192 
00193 
00194 
00195 
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 
00214 
00215    
00216    
00217    const MnMachinePrecision& prec = seed.Precision();
00218    
00219    const MinimumState & initialState = result.back();
00220    
00221    double edm = initialState.Edm();
00222    
00223    
00224 #ifdef DEBUG
00225    std::cout << "\n\nDEBUG FUMILI Builder  \nInitial State: "  
00226       << " Parameter " << initialState.Vec()       
00227       << " Gradient " << initialState.Gradient().Vec() 
00228       << " Inv Hessian " << initialState.Error().InvHessian()  
00229       << " edm = " << initialState.Edm() 
00230       << " maxfcn = " << maxfcn 
00231       << " tolerance = " << edmval 
00232       << std::endl; 
00233 #endif
00234    
00235    
00236    
00237    edm *= (1. + 3.*initialState.Error().Dcovar());
00238    MnAlgebraicVector step(initialState.Gradient().Vec().size());
00239    
00240    
00241    double lambda = 0.001; 
00242    
00243    
00244    do {   
00245       
00246       
00247       MinimumState s0 = result.back();
00248       
00249       step = -1.*s0.Error().InvHessian()*s0.Gradient().Vec();
00250       
00251       
00252 #ifdef DEBUG
00253       std::cout << "\n\n---> Iteration - " << result.size() 
00254       << "\nFval = " << s0.Fval() << " numOfCall = " << fcn.NumOfCalls() 
00255       << "\nInternal Parameter values " << s0.Vec() 
00256       << " Newton step " << step << std::endl; 
00257 #endif
00258       
00259       double gdel = inner_product(step, s0.Gradient().Grad());
00260       if(gdel > 0.) {
00261 #ifdef WARNINGMSG
00262          MN_INFO_MSG("FumiliBuilder: matrix not pos.def, gdel > 0");
00263          MN_INFO_VAL(gdel);
00264 #endif
00265          MnPosDef psdf;
00266          s0 = psdf(s0, prec);
00267          step = -1.*s0.Error().InvHessian()*s0.Gradient().Vec();
00268          gdel = inner_product(step, s0.Gradient().Grad());
00269 #ifdef WARNINGMSG
00270          MN_INFO_VAL2("After correction ",gdel);
00271 #endif
00272          if(gdel > 0.) {
00273             result.push_back(s0);
00274             return FunctionMinimum(seed, result, fcn.Up());
00275          }
00276       }
00277       
00278       
00279       
00280       
00281       
00282       
00283       
00284       
00285       
00286       
00287       
00288       
00289       
00290       
00291       
00292       
00293       MinimumParameters p(s0.Vec() + step,  fcn( s0.Vec() + step ) );
00294       
00295       
00296       
00297       if ( p.Fval() >= s0.Fval()  ) {
00298          MnLineSearch lsearch;   
00299          MnParabolaPoint pp = lsearch(fcn, s0.Parameters(), step, gdel, prec);
00300          
00301          if(fabs(pp.Y() - s0.Fval()) < prec.Eps()) {
00302             
00303             break; 
00304          }
00305          p =  MinimumParameters(s0.Vec() + pp.X()*step, pp.Y() );
00306       }
00307       
00308 #ifdef DEBUG
00309       std::cout << "Before Gradient " << fcn.NumOfCalls() << std::endl; 
00310 #endif
00311       
00312       FunctionGradient g = gc(p, s0.Gradient());
00313       
00314 #ifdef DEBUG   
00315       std::cout << "After Gradient " << fcn.NumOfCalls() << std::endl; 
00316 #endif
00317       
00318       
00319       
00320       
00321       
00322       
00323       MinimumError e = ErrorUpdator().Update(s0, p, gc, lambda);
00324       
00325       
00326       edm = Estimator().Estimate(g, s0.Error());
00327       
00328       
00329 #ifdef DEBUG
00330       std::cout << "Updated new point: \n " 
00331          << " FVAL      " << p.Fval()       
00332          << " Parameter " << p.Vec()       
00333          << " Gradient " << g.Vec() 
00334          << " InvHessian " << e.Matrix() 
00335          << " Hessian " << e.Hessian() 
00336          << " edm = " << edm << std::endl << std::endl;
00337 #endif
00338       
00339       if(edm < 0.) {
00340 #ifdef WARNINGMSG
00341          MN_INFO_MSG("FumiliBuilder: matrix not pos.def., edm < 0");
00342 #endif
00343          MnPosDef psdf;
00344          s0 = psdf(s0, prec);
00345          edm = Estimator().Estimate(g, s0.Error());
00346          if(edm < 0.) {
00347             result.push_back(s0);
00348             return FunctionMinimum(seed, result, fcn.Up());
00349          }
00350       } 
00351       
00352       
00353       if ( p.Fval() < s0.Fval()  ) 
00354          
00355          lambda *= 0.1;
00356       else { 
00357          lambda *= 10;
00358          
00359          if ( edm < 0.1 ) break;
00360       }
00361       
00362 #ifdef DEBUG
00363       std::cout <<  " finish iteration- " << result.size() << " lambda =  "  << lambda << " f1 = " << p.Fval() << " f0 = " << s0.Fval() << " num of calls = " << fcn.NumOfCalls() << " edm " << edm << std::endl; 
00364 #endif
00365             
00366       result.push_back(MinimumState(p, e, g, edm, fcn.NumOfCalls())); 
00367       
00368       
00369       edm *= (1. + 3.*e.Dcovar());
00370             
00371       
00372    } while(edm > edmval && fcn.NumOfCalls() < maxfcn);
00373    
00374    
00375    
00376    if(fcn.NumOfCalls() >= maxfcn) {
00377 #ifdef WARNINGMSG
00378       MN_INFO_MSG("FumiliBuilder: call limit exceeded.");
00379 #endif
00380       return FunctionMinimum(seed, result, fcn.Up(), FunctionMinimum::MnReachedCallLimit());
00381    }
00382    
00383    if(edm > edmval) {
00384       if(edm < fabs(prec.Eps2()*result.back().Fval())) {
00385 #ifdef WARNINGMSG
00386          MN_INFO_MSG("FumiliBuilder: machine accuracy limits further improvement.");
00387 #endif
00388          return FunctionMinimum(seed, result, fcn.Up());
00389       } else if(edm < 10.*edmval) {
00390          return FunctionMinimum(seed, result, fcn.Up());
00391       } else {
00392 #ifdef WARNINGMSG
00393          MN_INFO_MSG("FumiliBuilder: finishes without convergence.");
00394          MN_INFO_VAL2("FumiliBuilder: ",edm);
00395          MN_INFO_VAL2("    requested: ",edmval);
00396 #endif
00397          return FunctionMinimum(seed, result, fcn.Up(), FunctionMinimum::MnAboveMaxEdm());
00398       }
00399    }
00400    
00401    
00402 #ifdef DEBUG
00403    std::cout << "Exiting succesfully FumiliBuilder \n" 
00404       << "NFCalls = " << fcn.NumOfCalls() 
00405       << "\nFval = " <<  result.back().Fval() 
00406       << "\nedm = " << edm << " requested = " << edmval << std::endl; 
00407 #endif
00408    
00409    return FunctionMinimum(seed, result, fcn.Up());
00410 }
00411 
00412    }  
00413 
00414 }