#include "math/dense_blas_internal.h" #include #include #include #include #include #include namespace fesa::dense_blas_internal { namespace { TEST(DenseBlasInternal, CDup003ConvertsZeroNormalAndOverflowLengths) { const auto zero = ToMklSize(0U); ASSERT_TRUE(zero.HasValue()); EXPECT_EQ(zero.Value(), 0); const auto normal = ToMklSize(3U); ASSERT_TRUE(normal.HasValue()); EXPECT_EQ(normal.Value(), 3); const std::size_t overflow = static_cast((std::numeric_limits::max)()) + 1U; const auto rejected = ToMklSize(overflow); EXPECT_FALSE(rejected.HasValue()); EXPECT_FALSE(rejected.GetStatus().IsOk()); } TEST(DenseBlasInternal, CDup003CopiesZeroAndNonzeroContiguousValues) { EXPECT_NO_THROW(CopyValues(nullptr, 0U, nullptr)); const std::array source{1.25, -2.5, 4.0}; std::array destination{}; CopyValues(source.data(), source.size(), destination.data()); EXPECT_EQ(destination, source); } TEST(DenseBlasInternal, TransposeProductChecksShapeAndKnownRectangularAction) { Matrix left{3U, 2U}; Matrix right{3U, 1U}; for (std::size_t row = 0; row < 3U; ++row) { left(row, 0U) = static_cast(row + 1U); left(row, 1U) = 2.0; right(row, 0U) = static_cast(row); } const auto product = MultiplyTransposeLeft(left, right); ASSERT_EQ(product.Rows(), 2U); ASSERT_EQ(product.Columns(), 1U); EXPECT_DOUBLE_EQ(product(0U, 0U), 8.0); EXPECT_DOUBLE_EQ(product(1U, 0U), 6.0); EXPECT_THROW(static_cast(MultiplyTransposeLeft(left, Matrix{2U, 1U})), std::invalid_argument); const auto empty = MultiplyTransposeLeft(Matrix{0U, 2U}, Matrix{0U, 3U}); EXPECT_EQ(empty.Rows(), 2U); EXPECT_EQ(empty.Columns(), 3U); 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(MultiplyDiagonal(diagonal, Vector{2U})), std::invalid_argument); input[0U] = std::numeric_limits::infinity(); EXPECT_THROW(static_cast(MultiplyDiagonal(diagonal, input)), std::invalid_argument); input[0U] = 1; diagonal[0U] = std::numeric_limits::quiet_NaN(); EXPECT_THROW(static_cast(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(CholeskyLowerAndInverse( Matrix{2U, 1U}, lower, inverse)), std::invalid_argument); matrix(0U, 0U) = std::numeric_limits::quiet_NaN(); EXPECT_THROW(static_cast(CholeskyLowerAndInverse(matrix, lower, inverse)), std::invalid_argument); } } // namespace } // namespace fesa::dense_blas_internal