HessianGradientCalculator.cxx

Go to the documentation of this file.
00001 // @(#)root/minuit2:$Id: HessianGradientCalculator.cxx 28990 2009-06-15 08:46:25Z 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/HessianGradientCalculator.h"
00011 #include "Minuit2/InitialGradientCalculator.h"
00012 #include "Minuit2/MnFcn.h"
00013 #include "Minuit2/MnUserTransformation.h"
00014 #include "Minuit2/MnMachinePrecision.h"
00015 #include "Minuit2/MinimumParameters.h"
00016 #include "Minuit2/FunctionGradient.h"
00017 #include "Minuit2/MnStrategy.h"
00018 
00019 #include <math.h>
00020 
00021 //#define DEBUG
00022 
00023 #if defined(DEBUG) || defined(WARNINGMSG)
00024 #include "Minuit2/MnPrint.h"
00025 #endif
00026 
00027 #include "Minuit2/MPIProcess.h"
00028 
00029 namespace ROOT {
00030 
00031    namespace Minuit2 {
00032 
00033 
00034 FunctionGradient HessianGradientCalculator::operator()(const MinimumParameters& par) const {
00035    // use initial gradient as starting point
00036    InitialGradientCalculator gc(fFcn, fTransformation, fStrategy);
00037    FunctionGradient gra = gc(par);
00038    
00039    return (*this)(par, gra);  
00040 }
00041 
00042 FunctionGradient HessianGradientCalculator::operator()(const MinimumParameters& par, const FunctionGradient& Gradient) const {
00043    // interface of the base class. Use DeltaGradient for op.
00044    std::pair<FunctionGradient, MnAlgebraicVector> mypair = DeltaGradient(par, Gradient);
00045    
00046    return mypair.first;
00047 }
00048 
00049 const MnMachinePrecision& HessianGradientCalculator::Precision() const {
00050    // return the precision
00051    return fTransformation.Precision();
00052 }
00053 
00054 unsigned int HessianGradientCalculator::Ncycle() const {
00055    // return number of calculation cycles (defined in strategy)
00056    return Strategy().HessianGradientNCycles();
00057 }
00058 
00059 double HessianGradientCalculator::StepTolerance() const {
00060    // return tolerance on step size (defined in strategy)
00061    return Strategy().GradientStepTolerance();
00062 }
00063 
00064 double HessianGradientCalculator::GradTolerance() const {
00065    // return gradient tolerance (defines in strategy)
00066    return Strategy().GradientTolerance();
00067 }
00068 
00069 std::pair<FunctionGradient, MnAlgebraicVector> HessianGradientCalculator::DeltaGradient(const MinimumParameters& par, const FunctionGradient& Gradient) const {
00070    // calculate gradient for Hessian
00071    assert(par.IsValid());
00072    
00073    MnAlgebraicVector x = par.Vec();
00074    MnAlgebraicVector grd = Gradient.Grad();
00075    const MnAlgebraicVector& g2 = Gradient.G2();
00076    //const MnAlgebraicVector& gstep = Gradient.Gstep();
00077    // update also gradient step sizes
00078    MnAlgebraicVector gstep = Gradient.Gstep();
00079    
00080    double fcnmin = par.Fval();
00081    //   std::cout<<"fval: "<<fcnmin<<std::endl;
00082    
00083    double dfmin = 4.*Precision().Eps2()*(fabs(fcnmin)+Fcn().Up());
00084    
00085    unsigned int n = x.size();
00086    MnAlgebraicVector dgrd(n);
00087    
00088    MPIProcess mpiproc(n,0);
00089    // initial starting values
00090    unsigned int startElementIndex = mpiproc.StartElementIndex();
00091    unsigned int endElementIndex = mpiproc.EndElementIndex();
00092 
00093    for(unsigned int i = startElementIndex; i < endElementIndex; i++) {
00094       double xtf = x(i);
00095       double dmin = 4.*Precision().Eps2()*(xtf + Precision().Eps2());
00096       double epspri = Precision().Eps2() + fabs(grd(i)*Precision().Eps2());
00097       double optstp = sqrt(dfmin/(fabs(g2(i))+epspri));
00098       double d = 0.2*fabs(gstep(i));
00099       if(d > optstp) d = optstp;
00100       if(d < dmin) d = dmin;
00101       double chgold = 10000.;
00102       double dgmin = 0.;
00103       double grdold = 0.;
00104       double grdnew = 0.;
00105       for(unsigned int j = 0; j < Ncycle(); j++)  {
00106          x(i) = xtf + d;
00107          double fs1 = Fcn()(x);
00108          x(i) = xtf - d;
00109          double fs2 = Fcn()(x);
00110          x(i) = xtf;
00111          //       double sag = 0.5*(fs1+fs2-2.*fcnmin);
00112          //LM: should I calculate also here second derivatives ???
00113 
00114          grdold = grd(i);
00115          grdnew = (fs1-fs2)/(2.*d);
00116          dgmin = Precision().Eps()*(fabs(fs1) + fabs(fs2))/d;
00117          //if(fabs(grdnew) < Precision().Eps()) break;
00118          if (grdnew == 0) break; 
00119          double change = fabs((grdold-grdnew)/grdnew);
00120          if(change > chgold && j > 1) break;
00121          chgold = change;
00122          grd(i) = grdnew;
00123          //LM : update also the step sizes
00124          gstep(i) = d; 
00125 
00126          if(change < 0.05) break;
00127          if(fabs(grdold-grdnew) < dgmin) break;
00128          if(d < dmin) break;
00129          d *= 0.2;
00130       }  
00131 
00132       dgrd(i) = std::max(dgmin, fabs(grdold-grdnew));
00133 
00134 #ifdef DEBUG
00135       std::cout << "HGC Param : " << i << "\t new g1 = " << grd(i) << " gstep = " << d << " dgrd = " << dgrd(i) << std::endl;
00136 #endif
00137 
00138    }
00139    
00140    mpiproc.SyncVector(grd);
00141    mpiproc.SyncVector(gstep);
00142    mpiproc.SyncVector(dgrd);
00143    
00144    return std::pair<FunctionGradient, MnAlgebraicVector>(FunctionGradient(grd, g2, gstep), dgrd);
00145 }
00146 
00147    }  // namespace Minuit2
00148 
00149 }  // namespace ROOT

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