/*
* Copyright (C) 2026 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see .
*/
#include
#include "math/SquareMatrix.hpp"
namespace lms::math::squareMatrixTests
{
constexpr float epsilon{ 1e-4F };
TEST(SquareMatrix, choleskyDecomposePositiveDefinite)
{
SquareMatrix matrix;
matrix.fill(0.F);
matrix[0][0] = 4.F;
matrix[0][1] = 12.F;
matrix[0][2] = -16.F;
matrix[1][0] = 12.F;
matrix[1][1] = 37.F;
matrix[1][2] = -43.F;
matrix[2][0] = -16.F;
matrix[2][1] = -43.F;
matrix[2][2] = 98.F;
SquareMatrix lower;
EXPECT_TRUE(choleskyDecompose(matrix, lower));
EXPECT_FLOAT_EQ(lower[0][0], 2.F);
EXPECT_FLOAT_EQ(lower[1][0], 6.F);
EXPECT_FLOAT_EQ(lower[1][1], 1.F);
EXPECT_FLOAT_EQ(lower[2][0], -8.F);
EXPECT_FLOAT_EQ(lower[2][1], 5.F);
EXPECT_FLOAT_EQ(lower[2][2], 3.F);
}
TEST(SquareMatrix, choleskyDecomposeIdentity)
{
SquareMatrix matrix;
matrix.fill(0.F);
matrix[0][0] = 1.F;
matrix[1][1] = 1.F;
matrix[2][2] = 1.F;
SquareMatrix lower;
EXPECT_TRUE(choleskyDecompose(matrix, lower));
for (std::size_t i{}; i < 3; ++i)
{
for (std::size_t j{}; j < 3; ++j)
{
if (i == j)
EXPECT_FLOAT_EQ(lower[i][j], 1.F);
else
EXPECT_FLOAT_EQ(lower[i][j], 0.F);
}
}
}
TEST(SquareMatrix, choleskyDecomposeSize1)
{
SquareMatrix matrix;
matrix[0][0] = 9.F;
SquareMatrix lower;
EXPECT_TRUE(choleskyDecompose(matrix, lower));
EXPECT_FLOAT_EQ(lower[0][0], 3.F);
}
TEST(SquareMatrix, choleskyDecomposeNonPositiveDefinite)
{
SquareMatrix matrix;
matrix.fill(0.F);
SquareMatrix lower;
EXPECT_FALSE(choleskyDecompose(matrix, lower));
}
TEST(SquareMatrix, invertLowerTriangular)
{
SquareMatrix lower;
lower.fill(0.F);
lower[0][0] = 2.F;
lower[1][0] = 6.F;
lower[1][1] = 1.F;
lower[2][0] = -8.F;
lower[2][1] = 5.F;
lower[2][2] = 3.F;
SquareMatrix inverse;
invertLowerTriangular(lower, inverse);
SquareMatrix identity;
identity.fill(0.F);
for (std::size_t i{}; i < 3; ++i)
{
for (std::size_t j{}; j < 3; ++j)
{
float sum = 0.F;
for (std::size_t k{}; k < 3; ++k)
{
sum += lower[i][k] * inverse[k][j];
}
identity[i][j] = sum;
}
}
for (std::size_t i{}; i < 3; ++i)
{
for (std::size_t j{}; j < 3; ++j)
{
if (i == j)
EXPECT_NEAR(identity[i][j], 1.F, epsilon);
else
EXPECT_NEAR(identity[i][j], 0.F, epsilon);
}
}
}
TEST(SquareMatrix, invertLowerTriangularSize1)
{
SquareMatrix lower;
lower[0][0] = 5.F;
SquareMatrix inverse;
invertLowerTriangular(lower, inverse);
EXPECT_FLOAT_EQ(inverse[0][0], 0.2F);
}
TEST(SquareMatrix, computeSymmetryMaxDiff)
{
SquareMatrix matrix;
matrix.fill(0.F);
matrix[0][1] = 1.F;
matrix[1][0] = 1.2F;
EXPECT_NEAR(computeSymmetryMaxDiff(matrix), 0.2F, epsilon);
}
} // namespace lms::math::squareMatrixTests