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