fix(math): preserve certified sums and complete MKL algebra

This commit is contained in:
KOKO\Mimi
2026-10-14 15:40:52 +09:00
parent 59c8e93b07
commit 590a93793f
9 changed files with 236 additions and 95 deletions
@@ -3,6 +3,7 @@
#include <gtest/gtest.h>
#include <array>
#include <cmath>
#include <cstddef>
#include <limits>
#include <stdexcept>
@@ -57,5 +58,55 @@ TEST(DenseBlasInternal, TransposeProductChecksShapeAndKnownRectangularAction) {
EXPECT_DOUBLE_EQ(empty(1U, 2U), 0.0);
}
TEST(DenseBlasInternal, DiagonalProductKeepsEntrywiseCancellationAndChecks) {
Vector diagonal{3U};
diagonal[0U] = 4;
diagonal[1U] = 2;
diagonal[2U] = -1;
Vector input{3U};
const double large = std::ldexp(1.0, 56);
input[0U] = 1;
input[1U] = -large;
input[2U] = 2 * large;
const auto product = MultiplyDiagonal(diagonal, input);
EXPECT_DOUBLE_EQ(product[0U] + (product[1U] - product[2U]), 4);
EXPECT_EQ(MultiplyDiagonal(Vector{0U}, Vector{0U}).Size(), 0U);
EXPECT_THROW(static_cast<void>(MultiplyDiagonal(diagonal, Vector{2U})),
std::invalid_argument);
input[0U] = std::numeric_limits<double>::infinity();
EXPECT_THROW(static_cast<void>(MultiplyDiagonal(diagonal, input)),
std::invalid_argument);
input[0U] = 1;
diagonal[0U] = std::numeric_limits<double>::quiet_NaN();
EXPECT_THROW(static_cast<void>(MultiplyDiagonal(diagonal, input)),
std::invalid_argument);
}
TEST(DenseBlasInternal, CholeskyAndInverseMatchKnownFactorsAndKeepFailedOutput) {
Matrix matrix{2U, 2U};
matrix(0U, 0U) = 4;
matrix(0U, 1U) = 2;
matrix(1U, 0U) = 2;
matrix(1U, 1U) = 5;
Matrix lower{0U, 0U}, inverse{0U, 0U};
ASSERT_TRUE(CholeskyLowerAndInverse(matrix, lower, inverse));
EXPECT_DOUBLE_EQ(lower(0U, 0U), 2);
EXPECT_DOUBLE_EQ(lower(1U, 0U), 1);
EXPECT_DOUBLE_EQ(lower(1U, 1U), 2);
EXPECT_DOUBLE_EQ(lower(0U, 1U), 0);
EXPECT_DOUBLE_EQ(inverse(0U, 0U), .5);
EXPECT_DOUBLE_EQ(inverse(1U, 0U), -.25);
EXPECT_DOUBLE_EQ(inverse(1U, 1U), .5);
matrix(1U, 1U) = 0;
EXPECT_FALSE(CholeskyLowerAndInverse(matrix, lower, inverse));
EXPECT_DOUBLE_EQ(lower(1U, 1U), 2);
EXPECT_DOUBLE_EQ(inverse(1U, 1U), .5);
EXPECT_THROW(static_cast<void>(CholeskyLowerAndInverse(
Matrix{2U, 1U}, lower, inverse)), std::invalid_argument);
matrix(0U, 0U) = std::numeric_limits<double>::quiet_NaN();
EXPECT_THROW(static_cast<void>(CholeskyLowerAndInverse(matrix, lower, inverse)),
std::invalid_argument);
}
} // namespace
} // namespace fesa::dense_blas_internal