From 3ae4b525b39ca40d5bd22ca3318fa2297a844d28 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sun, 28 Jun 2026 14:29:40 +0200 Subject: [PATCH] [Minuit2] Document why covariance transform omits 2nd-derivative term Int2extCovariance/Ext2intCovariance transform the error matrix between internal and external coordinates using only the first-order Jacobian (dPext/dPint), even on the diagonal. This is intentional and contrasts with the Hessian/G2 transformation in AnalyticalGradientCalculator, which carries an extra diagonal term d^2Pext/dPint^2 * gradient. The Hessian needs that non-tensorial term because it is evaluated at arbitrary, non-stationary points where the external gradient is nonzero. The covariance matrix is the inverse Hessian evaluated at the minimum, where the gradient vanishes; the term is then identically zero and the covariance transforms as a genuine (2,0) tensor with the Jacobian alone. Adding it would also break the exact round-trip between Int2extCovariance and Ext2intCovariance. --- math/minuit2/src/MnUserTransformation.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/math/minuit2/src/MnUserTransformation.cxx b/math/minuit2/src/MnUserTransformation.cxx index e957395e429c9..0d3820a40b0a8 100644 --- a/math/minuit2/src/MnUserTransformation.cxx +++ b/math/minuit2/src/MnUserTransformation.cxx @@ -140,6 +140,15 @@ MnUserTransformation::Int2extCovariance(const MnAlgebraicVector &vec, const MnAl // return the external covariance matrix from the internal error matrix and the internal parameter value // the vector of internal parameter is needed for the derivatives (Jacobian of the transformation) // Vext(i,j) = Vint(i,j) * dPext(i)/dPint(i) * dPext(j)/dPint(j) + // + // Note: only the first derivative (Jacobian) of the int<->ext transformation enters here, even on the + // diagonal. Unlike the Hessian/G2 transformation (see AnalyticalGradientCalculator), there is no + // d^2Pext/dPint^2 * gradient term. The Hessian needs that extra non-tensorial term because it is + // evaluated at arbitrary, non-stationary points where the external gradient is nonzero. The covariance + // matrix, by contrast, is the inverse Hessian evaluated at the minimum, where the external gradient + // vanishes and that term is identically zero; the covariance then transforms as a genuine (2,0) tensor + // with the Jacobian alone. (Adding the term here would also break the exact round-trip between + // Int2extCovariance and Ext2intCovariance.) MnUserCovariance result(cov.Nrow()); for (unsigned int i = 0; i < vec.size(); i++) { @@ -171,6 +180,9 @@ MnUserTransformation::Ext2intCovariance(const MnAlgebraicVector &vec, const MnAl // return the internal covariance matrix from the external error matrix and the internal parameter value // the vector of internal parameter is needed for the derivatives (Jacobian of the transformation) // Vint(i,j) = Vext(i,j) * dPint(i)/dPext(i) * dPint(j)/dPext(j) + // + // As in Int2extCovariance, only the Jacobian enters: no second-derivative (d^2Pint/dPext^2 * gradient) + // term is needed, since the covariance is the inverse Hessian at the minimum where the gradient is zero. MnUserCovariance result(cov.Nrow()); for (unsigned int i = 0; i < vec.size(); i++) {