37MinimumState ComputeNumerical(
const MnFcn &,
const MinimumState &,
const MnUserTransformation &,
unsigned int maxcalls,
38 MnStrategy
const &strat);
42MinimumState ComputeAnalytical(
const FCNBase &,
const MinimumState &,
const MnUserTransformation &);
60 state.
Edm(),
static_cast<int>(state.
NFcn())}, state.
Trafo());
69 static_cast<int>(state.
NFcn())},
79 MnFcn mfcn{fcn, min.UserState().Trafo(), min.NFcn()};
80 MinimumState st = (*this)(mfcn, min.State(), min.UserState().Trafo(), maxcalls);
85 unsigned int maxcalls)
const
91 return ComputeAnalytical(mfcn.
Fcn(), st, trafo);
95 return ComputeNumerical(mfcn, st, trafo, maxcalls,
fStrategy);
108 const MnMachinePrecision &prec = trafo.
Precision();
110 std::unique_ptr<AnalyticalGradientCalculator> hc;
112 hc = std::make_unique<ExternalInternalGradientCalculator>(fcn,trafo);
114 hc = std::make_unique<AnalyticalGradientCalculator>(fcn,trafo);
117 bool ret = hc->Hessian(st.
Parameters(), vhmat);
119 print.Error(
"Error computing analytical Hessian. MnHesse fails and will return a null matrix");
124 for (
unsigned int i = 0; i <
n; i++)
131 print.Debug(
"Original error matrix", vhmat);
133 MinimumError tmpErr = MnPosDef()(MinimumError(vhmat, 1.), prec);
134 vhmat = tmpErr.InvHessian();
136 print.Debug(
"PosDef error matrix", vhmat);
138 int ifail =
Invert(vhmat);
141 print.Warn(
"Matrix inversion fails; will return diagonal matrix");
144 for (
unsigned int j = 0; j <
n; j++) {
145 tmpsym(j,j) = 1. / g2(j);
151 VariableMetricEDMEstimator estim;
154 if (tmpErr.IsMadePosDef()) {
156 double edm = estim.Estimate(
gr, err);
161 MinimumError err(vhmat, 0.);
163 double edm = estim.Estimate(
gr, err);
165 print.Debug(
"Hessian is ACCURATE. New state:",
"\n First derivative:", st.
Gradient().
Grad(),
166 "\n Covariance matrix:", vhmat,
"\n Edm:", edm);
171MinimumState ComputeNumerical(
const MnFcn &mfcn,
const MinimumState &st,
const MnUserTransformation &trafo,
172 unsigned int maxcalls, MnStrategy
const &strat)
176 MnPrint print(
"MnHesse");
180 MnFcnCaller mfcnCaller{mfcn};
182 const MnMachinePrecision &prec = trafo.Precision();
184 double amin = mfcnCaller(st.Vec());
185 double aimsag = std::sqrt(prec.Eps2()) * (std::fabs(amin) + mfcn.Up());
189 unsigned int n = st.Parameters().Vec().size();
191 maxcalls = 200 + 100 *
n + 5 *
n *
n;
202 if (st.Gradient().IsAnalytical()) {
203 print.Info(
"Using analytical gradient but a numerical Hessian calculator - it could be not optimal");
204 Numerical2PGradientCalculator igc(mfcn, trafo, strat);
206 FunctionGradient tmp = igc(st.Parameters());
210 print.Warn(
"Analytical calculator ",grd,
" numerical ",tmp.Grad(),
" g2 ",g2);
215 print.Debug(
"Gradient is", st.Gradient().IsAnalytical() ?
"analytical" :
"numerical",
"\n point:",
x,
216 "\n fcn :", amin,
"\n grad :", grd,
"\n step :", gst,
"\n g2 :", g2);
218 for (
unsigned int i = 0; i <
n; i++) {
221 double dmin = 8. * prec.Eps2() * (std::fabs(xtf) + prec.Eps2());
222 double d = std::fabs(gst(i));
226 print.Debug(
"Derivative parameter", i,
"d =",
d,
"dmin =", dmin);
228 for (
unsigned int icyc = 0; icyc < strat.HessianNCycles(); icyc++) {
232 for (
unsigned int multpy = 0; multpy < 5; multpy++) {
238 sag = 0.5 * (fs1 + fs2 - 2. * amin);
240 print.Debug(
"cycle", icyc,
"mul", multpy,
"\tsag =", sag,
"d =",
d);
245 if (trafo.Parameter(i).HasLimits()) {
259 print.Warn(
"2nd derivative zero for parameter", trafo.Name(trafo.ExtOfInt(i)),
260 "; MnHesse fails and will return diagonal matrix");
262 for (
unsigned int j = 0; j <
n; j++) {
263 double tmp = g2(j) < prec.Eps2() ? 1. : 1. / g2(j);
264 vhmat(j, j) = tmp < prec.Eps2() ? 1. : tmp;
271 double g2bfor = g2(i);
272 g2(i) = 2. * sag / (
d *
d);
273 grd(i) = (fs1 - fs2) / (2. *
d);
278 d = std::sqrt(2. * aimsag / std::fabs(g2(i)));
279 if (trafo.Parameter(i).HasLimits())
280 d = std::min(0.5,
d);
284 print.Debug(
"g1 =", grd(i),
"g2 =", g2(i),
"step =", gst(i),
"d =",
d,
"diffd =", std::fabs(
d - dlast) /
d,
285 "diffg2 =", std::fabs(g2(i) - g2bfor) / g2(i));
288 if (std::fabs((
d - dlast) /
d) < strat.HessianStepTolerance())
290 if (std::fabs((g2(i) - g2bfor) / g2(i)) < strat.HessianG2Tolerance())
292 d = std::min(
d, 10. * dlast);
293 d = std::max(
d, 0.1 * dlast);
296 if (mfcn.NumOfCalls() > maxcalls) {
299 print.Warn(
"Maximum number of allowed function calls exhausted; will return diagonal matrix");
301 for (
unsigned int j = 0; j <
n; j++) {
302 double tmp = g2(j) < prec.Eps2() ? 1. : 1. / g2(j);
303 vhmat(j, j) = tmp < prec.Eps2() ? 1. : tmp;
307 st.Edm(), mfcn.NumOfCalls());
311 print.Debug(
"Second derivatives", g2);
313 if (strat.RefineGradientInHessian()) {
315 HessianGradientCalculator hgc(mfcn, trafo, strat);
316 FunctionGradient
gr = hgc(st.Parameters(), FunctionGradient(grd, g2, gst));
324 bool doCentralFD = strat.HessianCentralFDMixedDerivatives();
326 MPIProcess mpiprocOffDiagonal(
n * (
n - 1) / 2, 0);
327 unsigned int startParIndexOffDiagonal = mpiprocOffDiagonal.StartElementIndex();
328 unsigned int endParIndexOffDiagonal = mpiprocOffDiagonal.EndElementIndex();
330 unsigned int offsetVect = 0;
331 for (
unsigned int in = 0; in < startParIndexOffDiagonal; in++)
332 if ((in + offsetVect) % (
n - 1) == 0)
333 offsetVect += (in + offsetVect) / (
n - 1);
335 for (
unsigned int in = startParIndexOffDiagonal; in < endParIndexOffDiagonal; in++) {
337 int i = (in + offsetVect) / (
n - 1);
338 if ((in + offsetVect) % (
n - 1) == 0)
340 int j = (in + offsetVect) % (
n - 1) + 1;
342 if ((i + 1) == j || in == startParIndexOffDiagonal)
348 if(mfcn.Fcn().SecondDerivativeAlwaysVanishes(trafo.ExtOfInt(i), trafo.ExtOfInt(j))) {
350 }
else if(!doCentralFD) {
352 double fs1 = mfcnCaller(
x);
353 double elem = (fs1 + amin - yy(i) - yy(j)) / (dirin(i) * dirin(j));
358 double fs1 = mfcnCaller(
x);
362 double fs3 = mfcnCaller(
x);
365 double fs4 = mfcnCaller(
x);
368 double fs2 = mfcnCaller(
x);
370 double elem = (fs1 - fs2 - fs3 + fs4)/(4.*dirin(i)*dirin(j));
374 if (j % (
n - 1) == 0 || in == endParIndexOffDiagonal - 1)
378 mpiprocOffDiagonal.SyncSymMatrixOffDiagonal(vhmat);
386 print.Debug(
"Original error matrix", vhmat);
388 MinimumError tmpErr = MnPosDef()(MinimumError(vhmat, 1.), prec);
390 if (strat.HessianForcePosDef()) {
391 vhmat = tmpErr.InvHessian();
394 print.Debug(
"PosDef error matrix", vhmat);
396 int ifail =
Invert(vhmat);
399 print.Warn(
"Matrix inversion fails; will return diagonal matrix");
402 for (
unsigned int j = 0; j <
n; j++) {
403 double tmp = g2(j) < prec.Eps2() ? 1. : 1. / g2(j);
404 tmpsym(j, j) = tmp < prec.Eps2() ? 1. : tmp;
411 FunctionGradient
gr(grd, g2, gst);
412 VariableMetricEDMEstimator estim;
415 if (tmpErr.IsMadePosDef()) {
417 double edm = estim.Estimate(
gr, err);
418 return MinimumState(st.Parameters(), err,
gr, edm, mfcn.NumOfCalls());
422 MinimumError err(vhmat, 0.);
423 double edm = estim.Estimate(
gr, err);
425 print.Debug(
"Hessian is ACCURATE. New state:",
"\n First derivative:", grd,
"\n Second derivative:", g2,
426 "\n Gradient step:", gst,
"\n Covariance matrix:", vhmat,
"\n Edm:", edm);
428 return MinimumState(st.Parameters(), err,
gr, edm, mfcn.NumOfCalls());
Interface (abstract class) defining the function to be minimized, which has to be implemented by the ...
virtual double Up() const =0
Error definition of the function.
virtual bool HasHessian() const
virtual GradientParameterSpace gradParameterSpace() const
virtual bool HasGradient() const
bool IsAnalytical() const
const MnAlgebraicVector & Grad() const
class holding the full result of the minimization; both internal and external (MnUserParameterState) ...
Class describing a symmetric matrix of size n.
unsigned int size() const
const MnAlgebraicVector & Vec() const
MinimumState keeps the information (position, Gradient, 2nd deriv, etc) after one minimization step (...
const MinimumParameters & Parameters() const
const FunctionGradient & Gradient() const
Wrapper class to FCNBase interface used internally by Minuit.
const FCNBase & Fcn() const
MnUserParameterState operator()(const FCNBase &, const MnUserParameterState &, unsigned int maxcalls=0) const
FCN + MnUserParameterState.
class which holds the external user and/or internal Minuit representation of the parameters and error...
unsigned int NFcn() const
unsigned int VariableParameters() const
const std::vector< double > & IntParameters() const
const MnUserTransformation & Trafo() const
class performing the numerical gradient calculation
int Invert(LASymMatrix &)
LAVector MnAlgebraicVector
LASymMatrix MnAlgebraicSymMatrix