mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Fix flaky product and eigensolver_selfadjoint tests
libeigen/eigen!2326 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
@@ -26,7 +26,7 @@ void selfadjointeigensolver_essential_check(const MatrixType& m) {
|
|||||||
VERIFY_IS_EQUAL(eiSymm.info(), Success);
|
VERIFY_IS_EQUAL(eiSymm.info(), Success);
|
||||||
|
|
||||||
RealScalar scaling = m.cwiseAbs().maxCoeff();
|
RealScalar scaling = m.cwiseAbs().maxCoeff();
|
||||||
RealScalar unitary_error_factor = RealScalar(16);
|
RealScalar unitary_error_factor = RealScalar(32);
|
||||||
|
|
||||||
if (scaling < (std::numeric_limits<RealScalar>::min)()) {
|
if (scaling < (std::numeric_limits<RealScalar>::min)()) {
|
||||||
VERIFY(eiSymm.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
|
VERIFY(eiSymm.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
|
||||||
@@ -80,7 +80,7 @@ void selfadjointeigensolver(const MatrixType& m) {
|
|||||||
MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
|
MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
|
||||||
MatrixType symmC = symmA;
|
MatrixType symmC = symmA;
|
||||||
|
|
||||||
svd_fill_random(symmA, Symmetric);
|
svd_fill_random(symmA, SelfAdjoint);
|
||||||
|
|
||||||
symmA.template triangularView<StrictlyUpper>().setZero();
|
symmA.template triangularView<StrictlyUpper>().setZero();
|
||||||
symmC.template triangularView<StrictlyUpper>().setZero();
|
symmC.template triangularView<StrictlyUpper>().setZero();
|
||||||
|
|||||||
@@ -111,8 +111,12 @@ void product(const MatrixType& m) {
|
|||||||
VERIFY_IS_APPROX(m3, m1 * (m1.transpose() * m2));
|
VERIFY_IS_APPROX(m3, m1 * (m1.transpose() * m2));
|
||||||
|
|
||||||
// continue testing Product.h: distributivity
|
// continue testing Product.h: distributivity
|
||||||
VERIFY_IS_APPROX(square * (m1 + m2), square * m1 + square * m2);
|
{
|
||||||
VERIFY_IS_APPROX(square * (m1 - m2), square * m1 - square * m2);
|
// Increase tolerance, since coefficients here can get relatively large.
|
||||||
|
RealScalar tol = RealScalar(2) * get_test_precision(m1);
|
||||||
|
VERIFY(verifyIsApprox(square * (m1 + m2), square * m1 + square * m2, tol));
|
||||||
|
VERIFY(verifyIsApprox(square * (m1 - m2), square * m1 - square * m2, tol));
|
||||||
|
}
|
||||||
|
|
||||||
// continue testing Product.h: compatibility with ScalarMultiple.h
|
// continue testing Product.h: compatibility with ScalarMultiple.h
|
||||||
VERIFY_IS_APPROX(s1 * (square * m1), (s1 * square) * m1);
|
VERIFY_IS_APPROX(s1 * (square * m1), (s1 * square) * m1);
|
||||||
@@ -130,7 +134,10 @@ void product(const MatrixType& m) {
|
|||||||
|
|
||||||
// test the previous tests were not screwed up because operator* returns 0
|
// test the previous tests were not screwed up because operator* returns 0
|
||||||
// (we use the more accurate default epsilon)
|
// (we use the more accurate default epsilon)
|
||||||
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1) {
|
// Skip non-commutativity check for very low-precision types (e.g. bfloat16) where
|
||||||
|
// random small matrices can produce products that are approximately equal.
|
||||||
|
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1 &&
|
||||||
|
NumTraits<RealScalar>::dummy_precision() < RealScalar(0.04)) {
|
||||||
VERIFY(areNotApprox(m1.transpose() * m2, m2.transpose() * m1, not_approx_epsilon));
|
VERIFY(areNotApprox(m1.transpose() * m2, m2.transpose() * m1, not_approx_epsilon));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +145,8 @@ void product(const MatrixType& m) {
|
|||||||
res = square;
|
res = square;
|
||||||
res.noalias() += m1 * m2.transpose();
|
res.noalias() += m1 * m2.transpose();
|
||||||
VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
|
VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
|
||||||
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1) {
|
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1 &&
|
||||||
|
NumTraits<RealScalar>::dummy_precision() < RealScalar(0.04)) {
|
||||||
VERIFY(areNotApprox(res, square + m2 * m1.transpose(), not_approx_epsilon));
|
VERIFY(areNotApprox(res, square + m2 * m1.transpose(), not_approx_epsilon));
|
||||||
}
|
}
|
||||||
vcres = vc2;
|
vcres = vc2;
|
||||||
@@ -149,7 +157,8 @@ void product(const MatrixType& m) {
|
|||||||
res = square;
|
res = square;
|
||||||
res.noalias() -= m1 * m2.transpose();
|
res.noalias() -= m1 * m2.transpose();
|
||||||
VERIFY_IS_APPROX(res, square - (m1 * m2.transpose()));
|
VERIFY_IS_APPROX(res, square - (m1 * m2.transpose()));
|
||||||
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1) {
|
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1 &&
|
||||||
|
NumTraits<RealScalar>::dummy_precision() < RealScalar(0.04)) {
|
||||||
VERIFY(areNotApprox(res, square - m2 * m1.transpose(), not_approx_epsilon));
|
VERIFY(areNotApprox(res, square - m2 * m1.transpose(), not_approx_epsilon));
|
||||||
}
|
}
|
||||||
vcres = vc2;
|
vcres = vc2;
|
||||||
@@ -183,21 +192,35 @@ void product(const MatrixType& m) {
|
|||||||
res.noalias() -= square - m1 * m2.transpose();
|
res.noalias() -= square - m1 * m2.transpose();
|
||||||
VERIFY_IS_APPROX(res, square - m1 * m2.transpose());
|
VERIFY_IS_APPROX(res, square - m1 * m2.transpose());
|
||||||
|
|
||||||
tm1 = m1;
|
// Row-major vs col-major GEMV: different accumulation orders produce
|
||||||
VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
|
// rounding differences bounded by O(sqrt(n)) * epsilon per inner product.
|
||||||
VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
|
// tm1.transpose() * v1 has inner dimension rows; v1^T * tm1 has inner dim cols.
|
||||||
|
{
|
||||||
|
RealScalar gemv_tol = (std::max)(get_test_precision(m1),
|
||||||
|
numext::sqrt(RealScalar((std::max)(rows, cols))) * NumTraits<Scalar>::epsilon());
|
||||||
|
tm1 = m1;
|
||||||
|
VERIFY(verifyIsApprox(tm1.transpose() * v1, m1.transpose() * v1, gemv_tol));
|
||||||
|
VERIFY(verifyIsApprox(v1.transpose() * tm1, v1.transpose() * m1, gemv_tol));
|
||||||
|
}
|
||||||
|
|
||||||
// test submatrix and matrix/vector product
|
// test submatrix and matrix/vector product
|
||||||
for (int i = 0; i < rows; ++i) res.row(i) = m1.row(i) * m2.transpose();
|
// Row-by-row vs full GEMM: different evaluation strategies can differ
|
||||||
VERIFY_IS_APPROX(res, m1 * m2.transpose());
|
// by O(sqrt(n)) * epsilon for low-precision types.
|
||||||
// the other way round:
|
{
|
||||||
for (int i = 0; i < rows; ++i) res.col(i) = m1 * m2.transpose().col(i);
|
RealScalar prod_tol =
|
||||||
VERIFY_IS_APPROX(res, m1 * m2.transpose());
|
(std::max)(get_test_precision(m1), numext::sqrt(RealScalar(cols)) * NumTraits<Scalar>::epsilon());
|
||||||
|
for (int i = 0; i < rows; ++i) res.row(i) = m1.row(i) * m2.transpose();
|
||||||
|
VERIFY(verifyIsApprox(res, m1 * m2.transpose(), prod_tol));
|
||||||
|
// the other way round:
|
||||||
|
for (int i = 0; i < rows; ++i) res.col(i) = m1 * m2.transpose().col(i);
|
||||||
|
VERIFY(verifyIsApprox(res, m1 * m2.transpose(), prod_tol));
|
||||||
|
}
|
||||||
|
|
||||||
res2 = square2;
|
res2 = square2;
|
||||||
res2.noalias() += m1.transpose() * m2;
|
res2.noalias() += m1.transpose() * m2;
|
||||||
VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
|
VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
|
||||||
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1) {
|
if (!NumTraits<Scalar>::IsInteger && (std::min)(rows, cols) > 1 &&
|
||||||
|
NumTraits<RealScalar>::dummy_precision() < RealScalar(0.04)) {
|
||||||
VERIFY(areNotApprox(res2, square2 + m2.transpose() * m1, not_approx_epsilon));
|
VERIFY(areNotApprox(res2, square2 + m2.transpose() * m1, not_approx_epsilon));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user