MnLineSearch.cxx

Go to the documentation of this file.
00001 // @(#)root/minuit2:$Id: MnLineSearch.cxx 23522 2008-04-24 15:09:19Z 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/MnLineSearch.h"
00011 #include "Minuit2/MnFcn.h"
00012 #include "Minuit2/MinimumParameters.h"
00013 #include "Minuit2/MnMachinePrecision.h"
00014 #include "Minuit2/MnParabola.h"
00015 #include "Minuit2/MnParabolaPoint.h"
00016 #include "Minuit2/MnParabolaFactory.h"
00017 #include "Minuit2/LaSum.h"
00018 
00019 #include <iostream>
00020 #include "Minuit2/MnPrint.h"
00021 
00022 #ifdef USE_OTHER_LS
00023 
00024 #include "Math/SMatrix.h"
00025 #include "Math/SVector.h"
00026 
00027 #include "Math/IFunction.h"
00028 #include "Math/Minimizer1D.h"
00029 
00030 #endif
00031 
00032 //#define DEBUG
00033 
00034 namespace ROOT {
00035 
00036    namespace Minuit2 {
00037 
00038 
00039 /**  Perform a line search from position defined by the vector st
00040        along the direction step, where the length of vector step
00041        gives the expected position of Minimum.
00042        fcn is Value of function at the starting position ,  
00043        gdel (if non-zero) is df/dx along step at st. 
00044        Return a parabola point containing Minimum x position and y (function Value)
00045     - add a falg to control the debug 
00046 */
00047 
00048 MnParabolaPoint MnLineSearch::operator()(const MnFcn& fcn, const MinimumParameters& st, const MnAlgebraicVector& step, double gdel, const MnMachinePrecision& prec, bool debug) const {
00049    
00050    //*-*-*-*-*-*-*-*-*-*Perform a line search from position st along step   *-*-*-*-*-*-*-*
00051    //*-*                =========================================
00052    //*-* SLAMBG and ALPHA control the maximum individual steps allowed.
00053    //*-* The first step is always =1. The max length of second step is SLAMBG.
00054    //*-* The max size of subsequent steps is the maximum previous successful
00055    //*-*   step multiplied by ALPHA + the size of most recent successful step,
00056    //*-*   but cannot be smaller than SLAMBG.
00057    //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
00058 
00059 #ifdef DEBUG
00060    debug = true; 
00061 #endif
00062 
00063    if (debug) {
00064       std::cout<<"gdel= "<<gdel<<std::endl;
00065       std::cout<<"step= "<<step<<std::endl;
00066    }
00067    
00068    double overal = 1000.;
00069    double undral = -100.;
00070    double toler = 0.05;
00071    double slamin = 0.;
00072    double slambg = 5.;
00073    double alpha = 2.;
00074    int maxiter = 12;
00075    // start as in Fortran from 1 and count all the time we evaluate the function
00076    int niter = 1; 
00077    
00078    for(unsigned int i = 0; i < step.size(); i++) {
00079       if(step(i) == 0 )  continue;
00080       double ratio = fabs(st.Vec()(i)/step(i));
00081       if( slamin == 0) slamin = ratio;
00082       if(ratio < slamin) slamin = ratio;
00083    }
00084    if(fabs(slamin) < prec.Eps()) slamin = prec.Eps();
00085    slamin *= prec.Eps2();
00086    
00087    double f0 = st.Fval();
00088    double f1 = fcn(st.Vec()+step);
00089    niter++;
00090    double fvmin = st.Fval();
00091    double xvmin = 0.;
00092    
00093    if(f1 < f0) {
00094       fvmin = f1;
00095       xvmin = 1.;
00096    }
00097    double toler8 = toler;
00098    double slamax = slambg;
00099    double flast = f1;
00100    double slam = 1.;
00101    
00102    bool iterate = false;
00103    MnParabolaPoint p0(0., f0);
00104    MnParabolaPoint p1(slam, flast);
00105    double f2 = 0.;
00106    // quadratic interpolation using the two points p0,p1 and the slope at p0
00107    do {  
00108       // cut toler8 as function goes up 
00109       iterate = false;
00110       //MnParabola pb = MnParabolaFactory()(p0, gdel, p1);
00111 
00112       if (debug) { 
00113          //         std::cout<<"pb.Min() = "<<pb.Min()<<std::endl;
00114          std::cout<<"flast, f0= "<<flast<<", "<<f0<<std::endl;
00115          std::cout<<"flast-f0= "<<flast-f0<<std::endl;
00116          std::cout<<"slam= "<<slam<<std::endl;
00117       }
00118       //     double df = flast-f0;
00119       //     if(fabs(df) < prec.Eps2()) {
00120       //       if(flast-f0 < 0.) df = -prec.Eps2();
00121       //       else df = prec.Eps2();
00122       //     }
00123       //     std::cout<<"df= "<<df<<std::endl;
00124       //     double denom = 2.*(df-gdel*slam)/(slam*slam);
00125       double denom = 2.*(flast-f0-gdel*slam)/(slam*slam);
00126       if (debug)     std::cout<<"denom= "<<denom<<std::endl;
00127       if(denom != 0) {
00128          slam =  - gdel/denom;
00129       } else {
00130          denom = -0.1*gdel;
00131          slam = 1.;
00132       } 
00133       if (debug)     std::cout<<"new slam= "<<slam<<std::endl;
00134 
00135 
00136 #ifdef TRY_OPPOSIT_DIR  
00137       // if is less than zero indicates maximum position. Use then slamax or x = x0 - 2slam + 1
00138       bool slamIsNeg = false; 
00139       double slamNeg = 0;
00140 #endif
00141 
00142       if(slam < 0.) { 
00143          if (debug)     std::cout<<"slam is negative- set to   " << slamax << std::endl;
00144 #ifdef TRY_OPPOSITE_DIR
00145          slamNeg = 2*slam -1; 
00146          slamIsNeg = true;
00147          if (debug)     std::cout<<"slam is negative- compare values between  "<< slamNeg << " and  " << slamax << std::endl;
00148 #endif
00149          slam = slamax;
00150       }
00151       //     std::cout<<"slam= "<<slam<<std::endl;
00152       if(slam > slamax) { 
00153          slam = slamax;
00154          if (debug) std::cout << "slam larger than mac value - set to " << slamax << std::endl;
00155       }
00156 
00157       if(slam < toler8) { 
00158          if (debug) std::cout << "slam too small  - set to " << toler8 << std::endl;
00159          slam = toler8;
00160       }
00161       //     std::cout<<"slam= "<<slam<<std::endl;
00162       if(slam < slamin) {
00163          if (debug) std::cout << "slam smaller than " << slamin << " return " << std::endl; 
00164          //       std::cout<<"f1, f2= "<<p0.Y()<<", "<<p1.Y()<<std::endl;
00165          //       std::cout<<"x1, x2= "<<p0.X()<<", "<<p1.X()<<std::endl;
00166          //       std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
00167          return MnParabolaPoint(xvmin, fvmin);
00168       }
00169       if(fabs(slam - 1.) < toler8 && p1.Y() < p0.Y()) {
00170          //       std::cout<<"f1, f2= "<<p0.Y()<<", "<<p1.Y()<<std::endl;
00171          //       std::cout<<"x1, x2= "<<p0.X()<<", "<<p1.X()<<std::endl;
00172          //       std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
00173          return MnParabolaPoint(xvmin, fvmin);
00174       }
00175       if(fabs(slam - 1.) < toler8) slam = 1. + toler8;
00176       
00177       //     if(fabs(gdel) < prec.Eps2() && fabs(denom) < prec.Eps2())
00178       //       slam = 1000.;
00179       //     MnAlgebraicVector tmp = step;
00180       //     tmp *= slam;
00181       //     f2 = fcn(st.Vec()+tmp);
00182       f2 = fcn(st.Vec() + slam*step);
00183 
00184       niter++; // do as in Minuit (count all func evalu)  
00185 
00186 #ifdef TRY_OPPOSITE_DIR
00187       if (slamIsNeg) { 
00188          // try alternative in the opposite direction
00189          double f2alt = fcn(st.Vec() + slamNeg*step);
00190          if (f2alt < f2) { 
00191             slam = slamNeg; 
00192             f2 = f2alt; 
00193             undral += slam;
00194          }
00195       }
00196 #endif
00197       if(f2 < fvmin) {
00198          fvmin = f2;
00199          xvmin = slam;
00200       }
00201       // LM : correct a bug using precision
00202       if (fabs( p0.Y() - fvmin) < fabs(fvmin)*prec.Eps() ) { 
00203          //   if(p0.Y()-prec.Eps() < fvmin && fvmin < p0.Y()+prec.Eps()) {
00204          iterate = true;
00205          flast = f2;
00206          toler8 = toler*slam;
00207          overal = slam - toler8;
00208          slamax = overal;
00209          p1 = MnParabolaPoint(slam, flast);
00210          //niter++;
00211          }
00212       } while(iterate && niter < maxiter);
00213    if(niter >= maxiter) {
00214       // exhausted max number of iterations
00215       return MnParabolaPoint(xvmin, fvmin);  
00216    }
00217    
00218    if (debug){
00219       std::cout<<"after initial 2-point iter: "<<std::endl;
00220       std::cout<<"x0, x1, x2= "<<p0.X()<<", "<<p1.X()<<", "<<slam<<std::endl;
00221       std::cout<<"f0, f1, f2= "<<p0.Y()<<", "<<p1.Y()<<", "<<f2<<std::endl;
00222    }
00223    
00224    MnParabolaPoint p2(slam, f2);
00225    
00226    // do now the quadratic interpolation with 3 points
00227    do {
00228       slamax = std::max(slamax, alpha*fabs(xvmin));
00229       MnParabola pb = MnParabolaFactory()(p0, p1, p2);
00230       if (debug) { 
00231          std::cout << "\nLS Iteration " << niter << std::endl;  
00232          std::cout<<"x0, x1, x2= "<<p0.X()<<", "<<p1.X()<<", "<<p2.X() <<std::endl;
00233          std::cout<<"f0, f1, f2= "<<p0.Y()<<", "<<p1.Y()<<", "<<p2.Y() <<std::endl;
00234          std::cout << "slamax = " << slamax << std::endl;
00235          std::cout<<"p2-p0,p1: "<<p2.Y() - p0.Y()<<", "<<p2.Y() - p1.Y()<<std::endl;
00236          std::cout<<"a, b, c= "<<pb.A()<<" "<<pb.B()<<" "<<pb.C()<<std::endl;
00237       }
00238       if(pb.A() < prec.Eps2()) {
00239          double slopem = 2.*pb.A()*xvmin + pb.B();
00240          if(slopem < 0.) slam = xvmin + slamax;
00241          else slam = xvmin - slamax;
00242          if (debug) std::cout << "xvmin = " << xvmin << " slopem " << slopem << " slam " << slam << std::endl;
00243       } else {
00244          slam = pb.Min();
00245          //      std::cout<<"pb.Min() slam= "<<slam<<std::endl;
00246          if(slam > xvmin + slamax) slam = xvmin + slamax;
00247          if(slam < xvmin - slamax) slam = xvmin - slamax;
00248       }
00249       if(slam > 0.) {
00250          if(slam > overal) slam = overal;
00251       } else {
00252          if(slam < undral) slam = undral;
00253       }
00254 
00255       if (debug) { 
00256          std::cout<<" slam= "<<slam<< " undral " << undral << " overal " << overal << std::endl;
00257       }
00258       
00259       double f3 = 0.;
00260       do {
00261 
00262          if (debug) std::cout << " iterate on f3- slam  " << niter << " slam = " << slam << " xvmin " << xvmin << std::endl; 
00263 
00264          iterate = false;
00265          double toler9 = std::max(toler8, fabs(toler8*slam));
00266          // min. of parabola at one point    
00267          if(fabs(p0.X() - slam) < toler9 || 
00268             fabs(p1.X() - slam) < toler9 || 
00269             fabs(p2.X() - slam) < toler9) {
00270             //          std::cout<<"f1, f2, f3= "<<p0.Y()<<", "<<p1.Y()<<", "<<p2.Y()<<std::endl;
00271             //          std::cout<<"x1, x2, x3= "<<p0.X()<<", "<<p1.X()<<", "<<p2.X()<<std::endl;
00272             //          std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
00273             return MnParabolaPoint(xvmin, fvmin);
00274          }
00275          
00276          // take the step
00277          //       MnAlgebraicVector tmp = step;
00278          //       tmp *= slam;
00279          f3 = fcn(st.Vec() + slam*step);
00280          if (debug) { 
00281                std::cout<<"f3= "<<f3<<std::endl;
00282                std::cout<<"f3-p(2-0).Y()= "<<f3-p2.Y()<<" "<<f3-p1.Y()<<" "<<f3-p0.Y()<<std::endl;
00283          }
00284          // if latest point worse than all three previous, cut step
00285          if(f3 > p0.Y() && f3 > p1.Y() && f3 > p2.Y()) {
00286             if (debug) { 
00287                 std::cout<<"f3 worse than all three previous"<<std::endl;
00288             }
00289             if(slam > xvmin) overal = std::min(overal, slam-toler8);
00290             if(slam < xvmin) undral = std::max(undral, slam+toler8);    
00291             slam = 0.5*(slam + xvmin);
00292             if (debug) { 
00293                 std::cout<<"new slam= "<<slam<<std::endl;
00294             }
00295             iterate = true;
00296             niter++;
00297          }
00298       } while(iterate && niter < maxiter);
00299       if(niter >= maxiter) {
00300          // exhausted max number of iterations
00301          return MnParabolaPoint(xvmin, fvmin);  
00302       }
00303       
00304       // find worst previous point out of three and replace
00305       MnParabolaPoint p3(slam, f3);
00306       if(p0.Y() > p1.Y() && p0.Y() > p2.Y()) p0 = p3;
00307       else if(p1.Y() > p0.Y() && p1.Y() > p2.Y()) p1 = p3;
00308       else p2 = p3;
00309       if (debug) std::cout << " f3 " << f3 << " fvmin " << fvmin << " xvmin " << xvmin << std::endl;
00310       if(f3 < fvmin) {
00311          fvmin = f3;
00312          xvmin = slam;
00313       } else {
00314          if(slam > xvmin) overal = std::min(overal, slam-toler8);
00315          if(slam < xvmin) undral = std::max(undral, slam+toler8);       
00316       }
00317       
00318       niter++;
00319    } while(niter < maxiter);
00320    
00321    if (debug) { 
00322       std::cout<<"f1, f2= "<<p0.Y()<<", "<<p1.Y()<<std::endl;
00323       std::cout<<"x1, x2= "<<p0.X()<<", "<<p1.X()<<std::endl;
00324       std::cout<<"x, f= "<<xvmin<<", "<<fvmin<<std::endl;
00325    }
00326    return MnParabolaPoint(xvmin, fvmin);
00327 
00328 }
00329 
00330 #ifdef USE_OTHER_LS
00331 
00332 /**  Perform a line search using a cubic interpolation using x0, x1 , df/dx(x0) and d2/dx(x0) (second derivative)
00333      This is used at the beginning when the second derivative is known to be negative
00334 */
00335 
00336 MnParabolaPoint MnLineSearch::CubicSearch(const MnFcn& fcn, const MinimumParameters& st, const MnAlgebraicVector& step, double gdel, double g2del,  const MnMachinePrecision& prec, bool debug) const {
00337 
00338 
00339 
00340    if (debug) {
00341       std::cout<<"gdel= "<<gdel<<std::endl;
00342       std::cout<<"g2del= "<<g2del<<std::endl;
00343       std::cout<<"step= "<<step<<std::endl;
00344    }
00345    
00346    // change ot large values
00347    double overal = 100.;
00348    double undral = -100.;
00349    double toler = 0.05;
00350    double slamin = 0.;
00351    double slambg = 5.;
00352    double alpha = 2.;
00353    
00354    for(unsigned int i = 0; i < step.size(); i++) {
00355       if(step(i) == 0 )  continue;
00356       double ratio = fabs(st.Vec()(i)/step(i));
00357       if( slamin == 0) slamin = ratio;
00358       if(ratio < slamin) slamin = ratio;
00359    }
00360    if(fabs(slamin) < prec.Eps()) slamin = prec.Eps();
00361    slamin *= prec.Eps2();
00362    
00363    double f0 = st.Fval();
00364    double f1 = fcn(st.Vec()+step);
00365    double fvmin = st.Fval();
00366    double xvmin = 0.;
00367    if (debug) std::cout << "f0 " << f0 << "  f1 " << f1 << std::endl;
00368    
00369    if(f1 < f0) {
00370       fvmin = f1;
00371       xvmin = 1.;
00372    }
00373    double toler8 = toler;
00374    double slamax = slambg;
00375    double flast = f1;
00376    double slam = 1.;
00377    
00378 //    MnParabolaPoint p0(0., f0);
00379 //    MnParabolaPoint p1(slam, flast);
00380 
00381    ROOT::Math::SMatrix<double, 3> cubicMatrix;
00382    ROOT::Math::SVector<double, 3> cubicCoeff;   // cubic coefficients to be found
00383    ROOT::Math::SVector<double, 3> bVec;   // cubic coefficients to be found
00384    double x0 = 0; 
00385 
00386    // cubic interpolation using the two points p0,p1 and the slope at p0 and the second derivative at p0
00387 
00388    // cut toler8 as function goes up 
00389    double x1 = slam; 
00390    cubicMatrix(0,0) = (x0*x0*x0 - x1*x1*x1)/3.;
00391    cubicMatrix(0,1) = (x0*x0 - x1*x1)/2.;
00392    cubicMatrix(0,2) = (x0 - x1);
00393    cubicMatrix(1,0) = x0*x0;
00394    cubicMatrix(1,1) = x0;
00395    cubicMatrix(1,2) = 1;
00396    cubicMatrix(2,0) = 2.*x0;
00397    cubicMatrix(2,1) = 1;
00398    cubicMatrix(2,2) = 0;
00399 
00400    bVec(0) = f0-f1; 
00401    bVec(1) = gdel; 
00402    bVec(2) = g2del; 
00403    
00404    //if (debug) std::cout << "Matrix:\n " << cubicMatrix << std::endl; 
00405    if (debug) std::cout << "Vec:\n   " << bVec << std::endl; 
00406    
00407    // find the minimum need to invert the matrix
00408    if (!cubicMatrix.Invert() ) { 
00409       std::cout << "Inversion failed - return " << std::endl;
00410       return MnParabolaPoint(xvmin, fvmin);
00411    }
00412    
00413    cubicCoeff = cubicMatrix * bVec; 
00414    if (debug) std::cout << "Cubic:\n   " << cubicCoeff << std::endl; 
00415    
00416    
00417    double ddd = cubicCoeff(1)*cubicCoeff(1)-4*cubicCoeff(0)*cubicCoeff(2);  // b**2 - 4ac 
00418    double slam1, slam2 = 0;
00419    // slam1 should be minimum and slam2 the maximum
00420    if (cubicCoeff(0) > 0) { 
00421       slam1 = (- cubicCoeff(1) - std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00422       slam2 = (- cubicCoeff(1) + std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00423    }
00424    else if (cubicCoeff(0) < 0) { 
00425       slam1 = (- cubicCoeff(1) + std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00426       slam2 = (- cubicCoeff(1) - std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00427    }
00428    else { // case == 0 (-b/c)
00429       slam1 = - gdel/g2del; 
00430       slam2 = slam1; 
00431    }
00432    
00433    std::cout << "slam1 &  slam 2 " << slam1 << "  " << slam2 << std::endl; 
00434       
00435    // this should be the minimum otherwise inversion failed and I should do something else
00436 
00437    if (slam2 < undral) slam2 = undral;
00438    if (slam2 > overal) slam2 = overal;
00439 
00440    
00441    // I am stack somewhere - take a large step 
00442    if (std::fabs(slam2) < toler) slam2 = ( slam2 >=0 ) ? slamax : -slamax;  
00443 
00444 
00445    std::cout << "try with slam 2 " << slam2 << std::endl; 
00446    
00447    double f2 = fcn(st.Vec()+slam2*step); 
00448 
00449    std::cout << "try with slam 2 " << slam2 << " f2 " << f2 << std::endl; 
00450 
00451    double fp; 
00452    // use this as new minimum 
00453    //bool noImpr = false;
00454    if (f2 < fvmin) { 
00455       slam = slam2; 
00456       xvmin = slam; 
00457       fvmin = f2; 
00458       fp = fvmin;
00459    } else { 
00460       // try with slam2 if it is better
00461       
00462       if (slam1 < undral) slam1 = undral;
00463       if (slam1 > overal) slam1 = overal;
00464 
00465       
00466       if (std::fabs(slam1) < toler) slam1 = ( slam1 >=0 ) ? -slamax : slamax;  
00467       
00468       double f3 = fcn(st.Vec()+slam1*step); 
00469 
00470       std::cout << "try with slam 1 " << slam1 << " f3 " << f3 << std::endl; 
00471       
00472       if (f3 < fvmin) { 
00473          slam = slam1; 
00474          fp = fvmin;
00475          xvmin = slam; 
00476          fvmin = f3; 
00477       }  else { 
00478          // case both f2 and f3 did not produce a better result
00479          if (f2 < f3) { 
00480             slam = slam1;
00481             fp = f2; 
00482          } else { 
00483             slam = slam2; 
00484             fp = f3; 
00485          }
00486       }
00487    }
00488 
00489    bool iterate2 = false; 
00490    int niter = 0; 
00491 
00492    int maxiter = 10;
00493    
00494    do { 
00495       iterate2 = false;
00496 
00497       std::cout << "\n iter" << niter << " test approx deriv ad second deriv at " << slam << " fp " << fp << std::endl; 
00498       
00499       // estimate grad and second derivative at new point taking a step of 10-3  
00500       double h = 0.001*slam; 
00501       double fh = fcn(st.Vec()+(slam+h)*step);
00502       double fl = fcn(st.Vec()+(slam-h)*step);
00503       double df = (fh-fl)/(2.*h);
00504       double df2 = (fh+fl-2.*fp )/(h*h);
00505 
00506       std::cout << "deriv: " << df << " , " << df2 << std::endl; 
00507 
00508       // if I am in a point of still negative derivative 
00509       if ( std::fabs(df ) < prec.Eps() && std::fabs( df2 ) < prec.Eps() ) { 
00510          // try in opposite direction with an opposite value
00511          slam = ( slam >=0 ) ? -slamax : slamax;  
00512          slamax *= 10; 
00513          fp = fcn(st.Vec()+slam*step);
00514       }
00515       else if (  std::fabs(df2 ) <= 0) { // gradient is significative different than zero then redo a cubic interpolation 
00516                                     // from new point
00517 
00518          return MnParabolaPoint(slam, fp); // should redo a cubic interpol.  ??
00519 //          niter ++; 
00520 //          if (niter > maxiter) break;
00521          
00522 //          MinimumParameters pa = MinimumParameters(st.Vec() + stepNew, fp); 
00523 //          gdel = stepNew(i)
00524 //          MnParabolaPoint pp = CubicSearch(fcn, st, stepNew, df, df2 
00525 
00526 
00527       }
00528 
00529       else 
00530          return MnParabolaPoint(slam, fp);
00531       
00532       niter++;
00533    } while (niter < maxiter); 
00534 
00535    return MnParabolaPoint(xvmin, fvmin); 
00536 
00537 
00538 }
00539 
00540 
00541 // class describing Fcn function in one dimension
00542       class ProjectedFcn : public ROOT::Math::IGenFunction { 
00543 
00544       public: 
00545 
00546          ProjectedFcn(const MnFcn & fcn, const MinimumParameters & pa, const MnAlgebraicVector & step) :  
00547             fFcn(fcn), 
00548             fPar(pa), 
00549             fStep(step)
00550          {}
00551 
00552 
00553          ROOT::Math::IGenFunction * Clone() const { return new ProjectedFcn(*this); } 
00554 
00555       private: 
00556          
00557          double DoEval(double x) const { 
00558             return fFcn(fPar.Vec() + x*fStep); 
00559          }
00560 
00561          const MnFcn & fFcn; 
00562          const MinimumParameters & fPar;
00563          const MnAlgebraicVector & fStep;
00564       };
00565 
00566 
00567 MnParabolaPoint MnLineSearch::BrentSearch(const MnFcn& fcn, const MinimumParameters& st, const MnAlgebraicVector& step, double gdel, double g2del,  const MnMachinePrecision& prec, bool debug) const {
00568 
00569    if (debug) {
00570       std::cout<<"gdel= "<<gdel<<std::endl;
00571       std::cout<<"g2del= "<<g2del<<std::endl;
00572       for (unsigned int i = 0; i < step.size(); ++i) { 
00573          if (step(i) != 0) { 
00574             std::cout<<"step(i)= "<<step(i)<<std::endl;
00575             std::cout<<"par(i) "  <<st.Vec()(i) <<std::endl;
00576             break;
00577          }
00578       }
00579    }
00580 
00581    ProjectedFcn func(fcn, st, step); 
00582 
00583 
00584 // do first a cubic interpolation
00585 
00586    double f0 = st.Fval();
00587    double f1 = fcn(st.Vec()+step);
00588    f0 = func(0.0);
00589    f1 = func(1.);
00590    double fvmin = st.Fval();
00591    double xvmin = 0.;
00592    if (debug) std::cout << "f0 " << f0 << "  f1 " << f1 << std::endl;
00593    
00594    if(f1 < f0) {
00595       fvmin = f1;
00596       xvmin = 1.;
00597    }
00598 //    double toler8 = toler;
00599 //    double slamax = slambg;
00600 //    double flast = f1;
00601    double slam = 1.;
00602 
00603    double undral = -1000;
00604    double overal = 1000;
00605 
00606    double x0 = 0; 
00607    
00608 //    MnParabolaPoint p0(0., f0);
00609 //    MnParabolaPoint p1(slam, flast);
00610 #ifdef USE_CUBIC
00611 
00612    ROOT::Math::SMatrix<double, 3> cubicMatrix;
00613    ROOT::Math::SVector<double, 3> cubicCoeff;   // cubic coefficients to be found
00614    ROOT::Math::SVector<double, 3> bVec;   // cubic coefficients to be found
00615 
00616    // cubic interpolation using the two points p0,p1 and the slope at p0 and the second derivative at p0
00617 
00618    // cut toler8 as function goes up 
00619    double x1 = slam; 
00620    cubicMatrix(0,0) = (x0*x0*x0 - x1*x1*x1)/3.;
00621    cubicMatrix(0,1) = (x0*x0 - x1*x1)/2.;
00622    cubicMatrix(0,2) = (x0 - x1);
00623    cubicMatrix(1,0) = x0*x0;
00624    cubicMatrix(1,1) = x0;
00625    cubicMatrix(1,2) = 1;
00626    cubicMatrix(2,0) = 2.*x0;
00627    cubicMatrix(2,1) = 1;
00628    cubicMatrix(2,2) = 0;
00629 
00630    bVec(0) = f0-f1; 
00631    bVec(1) = gdel; 
00632    bVec(2) = g2del; 
00633    
00634    //if (debug) std::cout << "Matrix:\n " << cubicMatrix << std::endl; 
00635    if (debug) std::cout << "Vec:\n   " << bVec << std::endl; 
00636    
00637    // find the minimum need to invert the matrix
00638    if (!cubicMatrix.Invert() ) { 
00639       std::cout << "Inversion failed - return " << std::endl;
00640       return MnParabolaPoint(xvmin, fvmin);
00641    }
00642    
00643    cubicCoeff = cubicMatrix * bVec; 
00644    if (debug) std::cout << "Cubic:\n   " << cubicCoeff << std::endl; 
00645    
00646    
00647    double ddd = cubicCoeff(1)*cubicCoeff(1)-4*cubicCoeff(0)*cubicCoeff(2);  // b**2 - 4ac 
00648    double slam1, slam2 = 0;
00649    // slam1 should be minimum and slam2 the maximum
00650    if (cubicCoeff(0) > 0) { 
00651       slam1 = (- cubicCoeff(1) - std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00652       slam2 = (- cubicCoeff(1) + std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00653    }
00654    else if (cubicCoeff(0) < 0) { 
00655       slam1 = (- cubicCoeff(1) + std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00656       slam2 = (- cubicCoeff(1) - std::sqrt(ddd) ) / ( 2. * cubicCoeff(0) ); 
00657    }
00658    else { // case == 0 (-b/c)
00659       slam1 = - gdel/g2del; 
00660       slam2 = slam1; 
00661    }
00662 
00663    if (slam1 < undral) slam1 = undral;
00664    if (slam1 > overal) slam1 = overal;
00665 
00666    if (slam2 < undral) slam2 = undral;
00667    if (slam2 > overal) slam2 = overal;
00668 
00669    
00670    double fs1 = func(slam1);
00671    double fs2 = func(slam2);
00672    std::cout << "slam1 &  slam 2 " << slam1 << "  " << slam2 << std::endl; 
00673    std::cout << "f(slam1) &  f(slam 2) " << fs1 << "  " << fs2 << std::endl; 
00674    
00675    if (fs1 < fs2) { 
00676       x0 = slam1; 
00677       f0 = fs1; 
00678    }
00679    else { 
00680       x0 = slam2; 
00681       f0 = fs2;
00682    }
00683 
00684 #else 
00685    x0 = xvmin;
00686    f0 = fvmin;
00687 #endif
00688 
00689 
00690    double astart = 100;
00691    
00692 
00693   // do a Brent search in a large interval
00694    double a = x0 -astart;
00695    double b = x0 + astart;
00696    //double x0 = 1; 
00697    int maxiter = 20;
00698    double absTol = 0.5;
00699    double relTol = 0.05;
00700 
00701    ROOT::Math::Minim1D::Type minType = ROOT::Math::Minim1D::BRENT;
00702 
00703    bool iterate = false; 
00704    int iter = 0; 
00705 
00706    std::cout << "f(0)" << func(0.) << std::endl;
00707    std::cout << "f(1)" << func(1.0) << std::endl;
00708    std::cout << "f(3)" << func(3.0) << std::endl;
00709    std::cout << "f(5)" << func(5.0) << std::endl;
00710 
00711    double fa = func(a);
00712    double fb = func(b);
00713    //double f0 = func(x0); 
00714    double toler = 0.01; 
00715    double delta0 = 5; 
00716    double delta = delta0; 
00717    bool enlarge = true; 
00718    bool scanmin = false;
00719    double x2, f2 = 0; 
00720    double dir = 1;
00721    int nreset = 0; 
00722    
00723    do { 
00724       
00725       std::cout << " iter " << iter << " a , b , x0 " << a << "  " << b << "  x0 " << x0 << std::endl;
00726       std::cout << " fa , fb , f0 " << fa << "  " << fb << "  f0 " << f0 << std::endl;
00727       if (fa <= f0 || fb  <= f0) { 
00728          scanmin = false; 
00729          if (fa < fb) { 
00730             if (fa < fvmin) { 
00731                fvmin = fa; 
00732                xvmin = a; 
00733             }
00734 //             double f2 = fa; 
00735 //             double x2 = a; 
00736             if (enlarge) { 
00737                x2 = a - 1000;  // move lower
00738                f2 = func(x2); 
00739             }
00740             if ( std::fabs ( (fa -f2 )/(a-x2) ) >  toler ) {  //  significant change in f continue to enlarge interval
00741                x0 = a;
00742                f0 = fa;
00743                a = x2; 
00744                fa = f2;
00745                enlarge = true;
00746             } else { 
00747                // move direction of [a
00748                // values change a little, start from central point try with x0 = x0 - delta
00749                if (nreset == 0) dir = -1;
00750                enlarge = false; 
00751                x0 = x0 + dir * delta; 
00752                f0 = func(x0); 
00753                // if reached limit try opposite direction , direction b]
00754                if ( std::fabs (( f0 -fa )/(x0 -a) ) <  toler ) { 
00755                   delta = 10 * delta0/(10.*(nreset+1));  // decrease the delta if still not change observed
00756                   a = x0; 
00757                   fa = f0; 
00758                   x0 = delta;
00759                   f0 = func(x0); 
00760                   dir *= -1; 
00761                   nreset++; 
00762                   std::cout << " A: Done a reset - scan in opposite direction ! " << std::endl;
00763                } 
00764                delta *= 2; // double delta at next iteration
00765                if (x0 <  b && x0 > a ) 
00766                   scanmin = true;  
00767                else { 
00768                   x0 = 0; 
00769                   f0 = st.Fval();
00770                }
00771             }
00772          }
00773          else {  // fb < fa
00774             if (fb < fvmin) { 
00775                fvmin = fb; 
00776                xvmin = b; 
00777             }
00778             if (enlarge) { 
00779                x2 = b + 1000;  // move upper
00780                f2 = func(x2); 
00781             }
00782             if ( std::fabs ( (fb -f2 )/(x2-b) ) >  toler ) {  //  significant change in f continue to enlarge interval
00783                f0 = fb; 
00784                x0 = b; 
00785                b = x2; //
00786                fb = f2;
00787                enlarge = true;
00788             } else { 
00789                // here move direction b 
00790                // values change a little, try with x0 = fa + delta
00791                if (nreset == 0) dir = 1;
00792                enlarge = false;
00793                x0 = x0 + dir * delta; 
00794                f0 = func(x0); 
00795                // if reached limit try other side
00796                if ( std::fabs ( ( f0 -fb )/(x0-b) ) <  toler ) { 
00797                   delta = 10 * delta0/(10.*(nreset+1));  // decrease the delta if still not change observed
00798                   b = x0; 
00799                   fb = f0; 
00800                   x0 = -delta;
00801                   f0 = func(x0); 
00802                   dir *= -1; 
00803                   nreset++; 
00804                   std::cout << " B: Done a reset - scan in opposite direction ! " << std::endl;
00805                } 
00806                delta *= 2; // double delta at next iteration
00807                if (x0 >  a && x0 < b) 
00808                   scanmin = true;  
00809                else { 
00810                   x0 = 0; 
00811                   f0 = st.Fval();
00812                }
00813 
00814             }
00815 
00816          }
00817 
00818          if ( f0 < fvmin) { 
00819             x0 = xvmin;
00820             fvmin = f0;
00821          }
00822 
00823          std::cout <<  " new x0 " << x0 << "  " << f0 << std::endl; 
00824 
00825          // use golden section
00826          iterate = scanmin || enlarge; 
00827 
00828       } else {  // x0 is a min of [a,b]  
00829          iterate = false; 
00830       }
00831 
00832       iter++;
00833    } while (iterate && iter < maxiter ); 
00834 
00835    if ( f0 > fa || f0 > fb) 
00836       // skip minim 1d try Minuit LS
00837       // return (*this) (fcn, st, step, gdel, prec, debug);
00838       return MnParabolaPoint(xvmin, fvmin);
00839 
00840 
00841    
00842 
00843    std::cout << "1D minimization using " << minType << std::endl;
00844    
00845    ROOT::Math::Minimizer1D min(minType); 
00846    
00847    min.SetFunction(func,x0, a, b); 
00848    int ret = min.Minimize(maxiter, absTol, relTol); 
00849 
00850    std::cout << "result of GSL 1D minimization: "  << ret << " niter " << min.Iterations() << std::endl;
00851    std::cout << " xmin = " << min.XMinimum() << " fmin " << min.FValMinimum() << std::endl; 
00852 
00853    return MnParabolaPoint(min.XMinimum(), min.FValMinimum());
00854 
00855 }
00856 
00857 #endif
00858 
00859 
00860       
00861 }  // namespace Minuit2
00862 
00863 }  // namespace ROOT

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