From c31b379ea68aec0e2f5722ea309f3309a1f89ea2 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sun, 17 May 2026 06:41:46 +0200 Subject: [PATCH] [Minuit2] Allow setting the Hesse strategy flags individually HessianCentralFDMixedDerivatives and HessianForcePosDef could only be reached by asking for strategy 3, which also zeroes the Hessian step and G2 tolerances, forces all 7 refinement cycles and inherits strategy 2's Migrad behaviour: four unrelated changes behind a single integer. The central finite difference for the mixed second derivatives is the part that matters on ill-conditioned problems. With the default one-sided formula the O(h) truncation error is proportional to the third derivative times the step size of the *other* parameter, so on a likelihood whose curvatures span several orders of magnitude it can be large enough to make an otherwise positive-definite Hessian indefinite. MnPosDef then patches the covariance and the parameter errors that come out of it are wrong. Route both flags through customizedStrategy(), like the other strategy tunables, so they can be set by name through the "Minuit2" extra options of ROOT::Math::MinimizerOptions without paying for the rest of strategy 3. --- math/minuit2/inc/Minuit2/MnStrategy.h | 8 ++++++++ math/minuit2/src/Minuit2Minimizer.cxx | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/math/minuit2/inc/Minuit2/MnStrategy.h b/math/minuit2/inc/Minuit2/MnStrategy.h index 519bf832dfaef..dafa4d108e619 100644 --- a/math/minuit2/inc/Minuit2/MnStrategy.h +++ b/math/minuit2/inc/Minuit2/MnStrategy.h @@ -131,6 +131,14 @@ namespace Minuit2 { the case of high stats) and the forward finite difference (default) behaviour leads incorrectly to a non-positive-definite covariance matrix. + + The strategy level only sets the defaults: when Minuit2 is used through + ROOT::Minuit2::Minuit2Minimizer, the tunables listed below can also be overridden + individually, by name, through the "Minuit2" extra options of + ROOT::Math::MinimizerOptions. That is the way to pick up a single behaviour of a + higher strategy (most usefully **HessianCentralFDMixedDerivatives**) without + paying for all the others. + diff --git a/math/minuit2/src/Minuit2Minimizer.cxx b/math/minuit2/src/Minuit2Minimizer.cxx index 748869c8f53d8..9788394f02d09 100644 --- a/math/minuit2/src/Minuit2Minimizer.cxx +++ b/math/minuit2/src/Minuit2Minimizer.cxx @@ -443,6 +443,11 @@ ROOT::Minuit2::MnStrategy customizedStrategy(unsigned int strategyLevel, ROOT::M st.SetHessianStepTolerance(customize("HessianStepTolerance", st.HessianStepTolerance())); st.SetHessianG2Tolerance(customize("HessianG2Tolerance", st.HessianG2Tolerance())); + // These two are the parts of strategy 3 that matter most for ill-conditioned problems + st.SetHessianCentralFDMixedDerivatives( + customize("HessianCentralFDMixedDerivatives", int(st.HessianCentralFDMixedDerivatives()))); + st.SetHessianForcePosDef(customize("HessianForcePosDef", int(st.HessianForcePosDef()))); + return st; }