113 lines
3.8 KiB
C++
113 lines
3.8 KiB
C++
#include "math/dense_blas_internal.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <limits>
|
|
#include <stdexcept>
|
|
|
|
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::size_t>((std::numeric_limits<MKL_INT>::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<double, 3U> source{1.25, -2.5, 4.0};
|
|
std::array<double, 3U> 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<double>(row + 1U);
|
|
left(row, 1U) = 2.0;
|
|
right(row, 0U) = static_cast<double>(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<void>(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<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
|