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 }