Fix flaky matrix_power test

libeigen/eigen!2325

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
Rasmus Munk Larsen
2026-03-22 09:54:32 -07:00
parent 6490b17e6f
commit ac6aedc60a
3 changed files with 69 additions and 24 deletions

View File

@@ -178,14 +178,17 @@ void MatrixPowerAtomic<MatrixType>::compute2x2(ResultType& res, RealScalar p) co
for (Index i = 1; i < m_A.cols(); ++i) {
res.coeffRef(i, i) = pow(m_A.coeff(i, i), p);
if (m_A.coeff(i - 1, i - 1) == m_A.coeff(i, i))
res.coeffRef(i - 1, i) = p * pow(m_A.coeff(i, i), p - 1);
else if (2 * abs(m_A.coeff(i - 1, i - 1)) < abs(m_A.coeff(i, i)) ||
2 * abs(m_A.coeff(i, i)) < abs(m_A.coeff(i - 1, i - 1)))
res.coeffRef(i - 1, i) =
(res.coeff(i, i) - res.coeff(i - 1, i - 1)) / (m_A.coeff(i, i) - m_A.coeff(i - 1, i - 1));
Scalar a = m_A.coeff(i - 1, i - 1);
Scalar b = m_A.coeff(i, i);
Scalar diff = b - a;
// Use the derivative formula when eigenvalues are nearly equal to avoid
// catastrophic cancellation in the difference quotient.
if (abs(diff) <= RealScalar(2) * (std::numeric_limits<RealScalar>::epsilon)() * (std::max)(abs(a), abs(b)))
res.coeffRef(i - 1, i) = p * pow(b, p - 1);
else if (2 * abs(a) < abs(b) || 2 * abs(b) < abs(a))
res.coeffRef(i - 1, i) = (res.coeff(i, i) - res.coeff(i - 1, i - 1)) / diff;
else
res.coeffRef(i - 1, i) = computeSuperDiag(m_A.coeff(i, i), m_A.coeff(i - 1, i - 1), p);
res.coeffRef(i - 1, i) = computeSuperDiag(b, a, p);
res.coeffRef(i - 1, i) *= m_A.coeff(i - 1, i);
}
}