// @(#)root/minuit2:$Id$ // Authors: M. Winkler, F. James, L. Moneta, A. Zsenei 2003-2005 /********************************************************************** * * * Copyright (c) 2005 LCG ROOT Math team, CERN/PH-SFT * * * **********************************************************************/ #include "Minuit2/HessianGradientCalculator.h" #include "Minuit2/InitialGradientCalculator.h" #include "Minuit2/MnFcn.h" #include "Minuit2/MnUserTransformation.h" #include "Minuit2/MnMachinePrecision.h" #include "Minuit2/MinimumParameters.h" #include "Minuit2/FunctionGradient.h" #include "Minuit2/MnStrategy.h" #include //#define DEBUG #if defined(DEBUG) || defined(WARNINGMSG) #include "Minuit2/MnPrint.h" #endif #include "Minuit2/MPIProcess.h" namespace ROOT { namespace Minuit2 { FunctionGradient HessianGradientCalculator::operator()(const MinimumParameters& par) const { // use initial gradient as starting point InitialGradientCalculator gc(fFcn, fTransformation, fStrategy); FunctionGradient gra = gc(par); return (*this)(par, gra); } FunctionGradient HessianGradientCalculator::operator()(const MinimumParameters& par, const FunctionGradient& Gradient) const { // interface of the base class. Use DeltaGradient for op. std::pair mypair = DeltaGradient(par, Gradient); return mypair.first; } const MnMachinePrecision& HessianGradientCalculator::Precision() const { // return the precision return fTransformation.Precision(); } unsigned int HessianGradientCalculator::Ncycle() const { // return number of calculation cycles (defined in strategy) return Strategy().HessianGradientNCycles(); } double HessianGradientCalculator::StepTolerance() const { // return tolerance on step size (defined in strategy) return Strategy().GradientStepTolerance(); } double HessianGradientCalculator::GradTolerance() const { // return gradient tolerance (defines in strategy) return Strategy().GradientTolerance(); } std::pair HessianGradientCalculator::DeltaGradient(const MinimumParameters& par, const FunctionGradient& Gradient) const { // calculate gradient for Hessian assert(par.IsValid()); MnAlgebraicVector x = par.Vec(); MnAlgebraicVector grd = Gradient.Grad(); const MnAlgebraicVector& g2 = Gradient.G2(); //const MnAlgebraicVector& gstep = Gradient.Gstep(); // update also gradient step sizes MnAlgebraicVector gstep = Gradient.Gstep(); double fcnmin = par.Fval(); // std::cout<<"fval: "< optstp) d = optstp; if(d < dmin) d = dmin; double chgold = 10000.; double dgmin = 0.; double grdold = 0.; double grdnew = 0.; for(unsigned int j = 0; j < Ncycle(); j++) { x(i) = xtf + d; double fs1 = Fcn()(x); x(i) = xtf - d; double fs2 = Fcn()(x); x(i) = xtf; // double sag = 0.5*(fs1+fs2-2.*fcnmin); //LM: should I calculate also here second derivatives ??? grdold = grd(i); grdnew = (fs1-fs2)/(2.*d); dgmin = Precision().Eps()*(fabs(fs1) + fabs(fs2))/d; //if(fabs(grdnew) < Precision().Eps()) break; if (grdnew == 0) break; double change = fabs((grdold-grdnew)/grdnew); if(change > chgold && j > 1) break; chgold = change; grd(i) = grdnew; //LM : update also the step sizes gstep(i) = d; if(change < 0.05) break; if(fabs(grdold-grdnew) < dgmin) break; if(d < dmin) break; d *= 0.2; } dgrd(i) = std::max(dgmin, fabs(grdold-grdnew)); #ifdef DEBUG std::cout << "HGC Param : " << i << "\t new g1 = " << grd(i) << " gstep = " << d << " dgrd = " << dgrd(i) << std::endl; #endif } mpiproc.SyncVector(grd); mpiproc.SyncVector(gstep); mpiproc.SyncVector(dgrd); return std::pair(FunctionGradient(grd, g2, gstep), dgrd); } } // namespace Minuit2 } // namespace ROOT