00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "Minuit2/MnHesse.h"
00011 #include "Minuit2/MnUserParameterState.h"
00012 #include "Minuit2/MnUserFcn.h"
00013 #include "Minuit2/FCNBase.h"
00014 #include "Minuit2/MnPosDef.h"
00015 #include "Minuit2/HessianGradientCalculator.h"
00016 #include "Minuit2/Numerical2PGradientCalculator.h"
00017 #include "Minuit2/InitialGradientCalculator.h"
00018 #include "Minuit2/MinimumState.h"
00019 #include "Minuit2/VariableMetricEDMEstimator.h"
00020 #include "Minuit2/FunctionMinimum.h"
00021
00022
00023
00024 #if defined(DEBUG) || defined(WARNINGMSG)
00025 #include "Minuit2/MnPrint.h"
00026 #endif
00027
00028 #include "Minuit2/MPIProcess.h"
00029
00030 namespace ROOT {
00031
00032 namespace Minuit2 {
00033
00034
00035 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const std::vector<double>& par, const std::vector<double>& err, unsigned int maxcalls) const {
00036
00037 return (*this)(fcn, MnUserParameterState(par, err), maxcalls);
00038 }
00039
00040 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const std::vector<double>& par, unsigned int nrow, const std::vector<double>& cov, unsigned int maxcalls) const {
00041
00042 return (*this)(fcn, MnUserParameterState(par, cov, nrow), maxcalls);
00043 }
00044
00045 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const std::vector<double>& par, const MnUserCovariance& cov, unsigned int maxcalls) const {
00046
00047 return (*this)(fcn, MnUserParameterState(par, cov), maxcalls);
00048 }
00049
00050 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const MnUserParameters& par, unsigned int maxcalls) const {
00051
00052 return (*this)(fcn, MnUserParameterState(par), maxcalls);
00053 }
00054
00055 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const MnUserParameters& par, const MnUserCovariance& cov, unsigned int maxcalls) const {
00056
00057 return (*this)(fcn, MnUserParameterState(par, cov), maxcalls);
00058 }
00059
00060 MnUserParameterState MnHesse::operator()(const FCNBase& fcn, const MnUserParameterState& state, unsigned int maxcalls) const {
00061
00062
00063 unsigned int n = state.VariableParameters();
00064 MnUserFcn mfcn(fcn, state.Trafo(),state.NFcn());
00065 MnAlgebraicVector x(n);
00066 for(unsigned int i = 0; i < n; i++) x(i) = state.IntParameters()[i];
00067 double amin = mfcn(x);
00068 Numerical2PGradientCalculator gc(mfcn, state.Trafo(), fStrategy);
00069 MinimumParameters par(x, amin);
00070 FunctionGradient gra = gc(par);
00071 MinimumState tmp = (*this)(mfcn, MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.), gra, state.Edm(), state.NFcn()), state.Trafo(), maxcalls);
00072
00073 return MnUserParameterState(tmp, fcn.Up(), state.Trafo());
00074 }
00075
00076 void MnHesse::operator()(const FCNBase& fcn, FunctionMinimum& min, unsigned int maxcalls) const {
00077
00078
00079
00080 MnUserFcn mfcn(fcn, min.UserState().Trafo(),min.NFcn());
00081 MinimumState st = (*this)( mfcn, min.State(), min.UserState().Trafo(), maxcalls);
00082 min.Add(st);
00083 }
00084
00085 MinimumState MnHesse::operator()(const MnFcn& mfcn, const MinimumState& st, const MnUserTransformation& trafo, unsigned int maxcalls) const {
00086
00087
00088
00089 const MnMachinePrecision& prec = trafo.Precision();
00090
00091 double amin = mfcn(st.Vec());
00092 double aimsag = sqrt(prec.Eps2())*(fabs(amin)+mfcn.Up());
00093
00094
00095
00096 unsigned int n = st.Parameters().Vec().size();
00097 if(maxcalls == 0) maxcalls = 200 + 100*n + 5*n*n;
00098
00099 MnAlgebraicSymMatrix vhmat(n);
00100 MnAlgebraicVector g2 = st.Gradient().G2();
00101 MnAlgebraicVector gst = st.Gradient().Gstep();
00102 MnAlgebraicVector grd = st.Gradient().Grad();
00103 MnAlgebraicVector dirin = st.Gradient().Gstep();
00104 MnAlgebraicVector yy(n);
00105
00106
00107
00108
00109 if(st.Gradient().IsAnalytical() ) {
00110 Numerical2PGradientCalculator igc(mfcn, trafo, fStrategy);
00111 FunctionGradient tmp = igc(st.Parameters());
00112 gst = tmp.Gstep();
00113 dirin = tmp.Gstep();
00114 g2 = tmp.G2();
00115 }
00116
00117 MnAlgebraicVector x = st.Parameters().Vec();
00118
00119 #ifdef DEBUG
00120 std::cout << "\nMnHesse " << std::endl;
00121 std::cout << " x " << x << std::endl;
00122 std::cout << " amin " << amin << " " << st.Fval() << std::endl;
00123 std::cout << " grd " << grd << std::endl;
00124 std::cout << " gst " << gst << std::endl;
00125 std::cout << " g2 " << g2 << std::endl;
00126 std::cout << " Gradient is analytical " << st.Gradient().IsAnalytical() << std::endl;
00127 #endif
00128
00129
00130 for(unsigned int i = 0; i < n; i++) {
00131
00132 double xtf = x(i);
00133 double dmin = 8.*prec.Eps2()*(fabs(xtf) + prec.Eps2());
00134 double d = fabs(gst(i));
00135 if(d < dmin) d = dmin;
00136
00137 #ifdef DEBUG
00138 std::cout << "\nDerivative parameter " << i << " d = " << d << " dmin = " << dmin << std::endl;
00139 #endif
00140
00141
00142 for(unsigned int icyc = 0; icyc < Ncycles(); icyc++) {
00143 double sag = 0.;
00144 double fs1 = 0.;
00145 double fs2 = 0.;
00146 for(unsigned int multpy = 0; multpy < 5; multpy++) {
00147 x(i) = xtf + d;
00148 fs1 = mfcn(x);
00149 x(i) = xtf - d;
00150 fs2 = mfcn(x);
00151 x(i) = xtf;
00152 sag = 0.5*(fs1+fs2-2.*amin);
00153
00154 #ifdef DEBUG
00155 std::cout << "cycle " << icyc << " mul " << multpy << "\t sag = " << sag << " d = " << d << std::endl;
00156 #endif
00157
00158 if (sag != 0) goto L30;
00159 if(trafo.Parameter(i).HasLimits()) {
00160 if(d > 0.5) goto L26;
00161 d *= 10.;
00162 if(d > 0.5) d = 0.51;
00163 continue;
00164 }
00165 d *= 10.;
00166 }
00167
00168 L26:
00169 #ifdef WARNINGMSG
00170 MN_INFO_VAL2("MnHesse: 2nd derivative zero for Parameter ",i);
00171 MN_INFO_MSG("MnHesse fails and will return diagonal matrix ");
00172 #endif
00173
00174 for(unsigned int j = 0; j < n; j++) {
00175 double tmp = g2(j) < prec.Eps2() ? 1. : 1./g2(j);
00176 vhmat(j,j) = tmp < prec.Eps2() ? 1. : tmp;
00177 }
00178
00179 return MinimumState(st.Parameters(), MinimumError(vhmat, MinimumError::MnHesseFailed()), st.Gradient(), st.Edm(), mfcn.NumOfCalls());
00180
00181 L30:
00182 double g2bfor = g2(i);
00183 g2(i) = 2.*sag/(d*d);
00184 grd(i) = (fs1-fs2)/(2.*d);
00185 gst(i) = d;
00186 dirin(i) = d;
00187 yy(i) = fs1;
00188 double dlast = d;
00189 d = sqrt(2.*aimsag/fabs(g2(i)));
00190 if(trafo.Parameter(i).HasLimits()) d = std::min(0.5, d);
00191 if(d < dmin) d = dmin;
00192
00193 #ifdef DEBUG
00194 std::cout << "\t g1 = " << grd(i) << " g2 = " << g2(i) << " step = " << gst(i) << " d = " << d
00195 << " diffd = " << fabs(d-dlast)/d << " diffg2 = " << fabs(g2(i)-g2bfor)/g2(i) << std::endl;
00196 #endif
00197
00198
00199
00200 if(fabs((d-dlast)/d) < Tolerstp()) break;
00201 if(fabs((g2(i)-g2bfor)/g2(i)) < TolerG2()) break;
00202 d = std::min(d, 10.*dlast);
00203 d = std::max(d, 0.1*dlast);
00204 }
00205 vhmat(i,i) = g2(i);
00206 if(mfcn.NumOfCalls() > maxcalls) {
00207
00208 #ifdef WARNINGMSG
00209
00210 MN_INFO_MSG("MnHesse: maximum number of allowed function calls exhausted.");
00211 MN_INFO_MSG("MnHesse fails and will return diagonal matrix ");
00212 #endif
00213
00214 for(unsigned int j = 0; j < n; j++) {
00215 double tmp = g2(j) < prec.Eps2() ? 1. : 1./g2(j);
00216 vhmat(j,j) = tmp < prec.Eps2() ? 1. : tmp;
00217 }
00218
00219 return MinimumState(st.Parameters(), MinimumError(vhmat, MinimumError::MnHesseFailed()), st.Gradient(), st.Edm(), mfcn.NumOfCalls());
00220 }
00221
00222 }
00223
00224 #ifdef DEBUG
00225 std::cout << "\n Second derivatives " << g2 << std::endl;
00226 #endif
00227
00228 if(fStrategy.Strategy() > 0) {
00229
00230 HessianGradientCalculator hgc(mfcn, trafo, fStrategy);
00231 FunctionGradient gr = hgc(st.Parameters(), FunctionGradient(grd, g2, gst));
00232
00233 grd = gr.Grad();
00234 gst = gr.Gstep();
00235 }
00236
00237
00238
00239 MPIProcess mpiprocOffDiagonal(n*(n-1)/2,0);
00240 unsigned int startParIndexOffDiagonal = mpiprocOffDiagonal.StartElementIndex();
00241 unsigned int endParIndexOffDiagonal = mpiprocOffDiagonal.EndElementIndex();
00242
00243 unsigned int offsetVect = 0;
00244 for (unsigned int in = 0; in<startParIndexOffDiagonal; in++)
00245 if ((in+offsetVect)%(n-1)==0) offsetVect += (in+offsetVect)/(n-1);
00246
00247 for (unsigned int in = startParIndexOffDiagonal;
00248 in<endParIndexOffDiagonal; in++) {
00249
00250 int i = (in+offsetVect)/(n-1);
00251 if ((in+offsetVect)%(n-1)==0) offsetVect += i;
00252 int j = (in+offsetVect)%(n-1)+1;
00253
00254 if ((i+1)==j || in==startParIndexOffDiagonal)
00255 x(i) += dirin(i);
00256
00257 x(j) += dirin(j);
00258
00259 double fs1 = mfcn(x);
00260 double elem = (fs1 + amin - yy(i) - yy(j))/(dirin(i)*dirin(j));
00261 vhmat(i,j) = elem;
00262
00263 x(j) -= dirin(j);
00264
00265 if (j%(n-1)==0 || in==endParIndexOffDiagonal-1)
00266 x(i) -= dirin(i);
00267
00268 }
00269
00270 mpiprocOffDiagonal.SyncSymMatrixOffDiagonal(vhmat);
00271
00272
00273
00274 #ifdef DEBUG
00275 std::cout << "Original error matrix " << vhmat << std::endl;
00276 #endif
00277
00278 MinimumError tmpErr = MnPosDef()(MinimumError(vhmat,1.), prec);
00279
00280 #ifdef DEBUG
00281 std::cout << "Original error matrix " << vhmat << std::endl;
00282 #endif
00283
00284 vhmat = tmpErr.InvHessian();
00285
00286 #ifdef DEBUG
00287 std::cout << "PosDef error matrix " << vhmat << std::endl;
00288 #endif
00289
00290
00291 int ifail = Invert(vhmat);
00292 if(ifail != 0) {
00293
00294 #ifdef WARNINGMSG
00295 MN_INFO_MSG("MnHesse: matrix inversion fails!");
00296 MN_INFO_MSG("MnHesse fails and will return diagonal matrix.");
00297 #endif
00298
00299 MnAlgebraicSymMatrix tmpsym(vhmat.Nrow());
00300 for(unsigned int j = 0; j < n; j++) {
00301 double tmp = g2(j) < prec.Eps2() ? 1. : 1./g2(j);
00302 tmpsym(j,j) = tmp < prec.Eps2() ? 1. : tmp;
00303 }
00304
00305 return MinimumState(st.Parameters(), MinimumError(tmpsym, MinimumError::MnInvertFailed()), st.Gradient(), st.Edm(), mfcn.NumOfCalls());
00306 }
00307
00308 FunctionGradient gr(grd, g2, gst);
00309 VariableMetricEDMEstimator estim;
00310
00311
00312 if(tmpErr.IsMadePosDef()) {
00313 MinimumError err(vhmat, MinimumError::MnMadePosDef() );
00314 double edm = estim.Estimate(gr, err);
00315 #ifdef WARNINGMSG
00316 MN_INFO_MSG("MnHesse: matrix was forced pos. def. ");
00317 #endif
00318 return MinimumState(st.Parameters(), err, gr, edm, mfcn.NumOfCalls());
00319 }
00320
00321
00322 MinimumError err(vhmat, 0.);
00323 double edm = estim.Estimate(gr, err);
00324
00325 #ifdef DEBUG
00326 std::cout << "\nNew state from MnHesse " << std::endl;
00327 std::cout << "Gradient " << grd << std::endl;
00328 std::cout << "Second Deriv " << g2 << std::endl;
00329 std::cout << "Gradient step " << gst << std::endl;
00330 std::cout << "Error " << vhmat << std::endl;
00331 std::cout << "edm " << edm << std::endl;
00332 #endif
00333
00334
00335 return MinimumState(st.Parameters(), err, gr, edm, mfcn.NumOfCalls());
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 }
00436
00437 }