Updated Matrix tests
All checks were successful
Build and Run C++ Unit Tests / build-and-test (push) Successful in 2m7s

This commit is contained in:
Pascal Serrarens 2025-12-19 14:52:11 +01:00
parent 39bed8db3e
commit 0def678cc5
3 changed files with 186 additions and 139 deletions

View File

@ -1377,6 +1377,10 @@ void Matrix2Of<T>::UpdateSlice(int rowStart,
// return r; // return r;
// } // }
template class Matrix2Of<int>;
template class Matrix2Of<float>;
template class Matrix2Of<double>;
#pragma endregion Matrix2Of #pragma endregion Matrix2Of
} // namespace LinearAlgebra } // namespace LinearAlgebra

View File

@ -127,7 +127,7 @@ using Matrix1Int = Matrix1Of<int>;
using Matrix1Float = Matrix1Of<float>; using Matrix1Float = Matrix1Of<float>;
using Matrix1Double = Matrix1Of<double>; using Matrix1Double = Matrix1Of<double>;
using Matrix1 = Matrix1Float; //using Matrix1 = Matrix1Float;
/* /*
class Matrix2; class Matrix2;
@ -406,10 +406,6 @@ Matrix2Of<U> operator/(U f, const Matrix2Of<U>& m) {
#pragma endregion friend functions #pragma endregion friend functions
template class Matrix2Of<int>;
template class Matrix2Of<float>;
template class Matrix2Of<double>;
using Matrix2Int = Matrix2Of<int>; using Matrix2Int = Matrix2Of<int>;
using Matrix2Float = Matrix2Of<float>; using Matrix2Float = Matrix2Of<float>;
using Matrix2Double = Matrix2Of<double>; using Matrix2Double = Matrix2Of<double>;

View File

@ -5,211 +5,258 @@
#include "Matrix.h" #include "Matrix.h"
TEST(Matrix2, Zero) { template <typename T>
bool isDefaultValue(const T& value) {
// Use std::is_floating_point to determine if T is a floating type
if constexpr (std::is_arithmetic<T>::value) {
return value == T(); // Default constructed value for T (0 or 0.0)
}
//return false; // Improve this if you handle non-arithmetic types
}
using MatrixTypes = ::testing::Types<Matrix2Of<float>, Matrix2Of<int>>;
template <typename T>
class Matrix2Test : public ::testing::Test {};
TYPED_TEST_SUITE(Matrix2Test, MatrixTypes);
TYPED_TEST(Matrix2Test, Zero) {
using Matrix2 = TypeParam;
// Test case 1: 2x2 zero matrix // Test case 1: 2x2 zero matrix
Matrix2 zeroMatrix = Matrix2::Zero(2, 2); Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
EXPECT_TRUE(zeroMatrix.nRows == 2); EXPECT_TRUE(zeroMatrix.RowCount() == 2);
EXPECT_TRUE(zeroMatrix.nCols == 2); EXPECT_TRUE(zeroMatrix.ColCount() == 2);
for (int i = 0; i < zeroMatrix.nValues; ++i) { for (unsigned int rowIx = 0; rowIx < zeroMatrix.RowCount(); ++rowIx) {
EXPECT_TRUE(zeroMatrix.data[i] == 0.0f); for (unsigned int colIx = 0; colIx < zeroMatrix.ColCount(); ++colIx)
EXPECT_TRUE(isDefaultValue(zeroMatrix(rowIx, colIx)));
} }
std::cout << "Test case 1 passed: 2x2 zero matrix\n"; std::cout << "Test case 1 passed: 2x2 zero matrix\n";
// Test case 2: 3x3 zero matrix // Test case 2: 3x3 zero matrix
zeroMatrix = Matrix2::Zero(3, 3); zeroMatrix = Matrix2::Zero(3, 3);
EXPECT_TRUE(zeroMatrix.nRows == 3); EXPECT_TRUE(zeroMatrix.RowCount() == 3);
EXPECT_TRUE(zeroMatrix.nCols == 3); EXPECT_TRUE(zeroMatrix.ColCount() == 3);
for (int i = 0; i < zeroMatrix.nValues; ++i) { for (unsigned int rowIx = 0; rowIx < zeroMatrix.RowCount(); ++rowIx) {
EXPECT_TRUE(zeroMatrix.data[i] == 0.0f); for (unsigned int colIx = 0; colIx < zeroMatrix.ColCount(); ++colIx)
EXPECT_TRUE(isDefaultValue(zeroMatrix(rowIx, colIx)));
} }
std::cout << "Test case 2 passed: 3x3 zero matrix\n"; std::cout << "Test case 2 passed: 3x3 zero matrix\n";
// Test case 3: 1x1 zero matrix // Test case 3: 1x1 zero matrix
zeroMatrix = Matrix2::Zero(1, 1); zeroMatrix = Matrix2::Zero(1, 1);
EXPECT_TRUE(zeroMatrix.nRows == 1); EXPECT_TRUE(zeroMatrix.RowCount() == 1);
EXPECT_TRUE(zeroMatrix.nCols == 1); EXPECT_TRUE(zeroMatrix.ColCount() == 1);
EXPECT_TRUE(zeroMatrix.data[0] == 0.0f); EXPECT_TRUE(isDefaultValue(zeroMatrix(0, 0)));
std::cout << "Test case 3 passed: 1x1 zero matrix\n"; std::cout << "Test case 3 passed: 1x1 zero matrix\n";
// Test case 4: 0x0 matrix (edge case) // Test case 4: 0x0 matrix (edge case)
zeroMatrix = Matrix2::Zero(0, 0); zeroMatrix = Matrix2::Zero(0, 0);
EXPECT_TRUE(zeroMatrix.nRows == 0); EXPECT_TRUE(zeroMatrix.RowCount() == 0);
EXPECT_TRUE(zeroMatrix.nCols == 0); EXPECT_TRUE(zeroMatrix.ColCount() == 0);
EXPECT_TRUE(zeroMatrix.data == nullptr);
std::cout << "Test case 4 passed: 0x0 matrix\n"; std::cout << "Test case 4 passed: 0x0 matrix\n";
} }
TEST(Matrix2, Multiplication) { // TYPED_TEST(Matrix2Test, Multiplication) {
// Test 1: Multiplying two 2x2 matrices // using T = typename TestFixture::TypeParam;
float dataA[] = {1, 2, 3, 4}; // using Matrix2 = TypeParam;
float dataB[] = {5, 6, 7, 8}; // // Test 1: Multiplying two 2x2 matrices
Matrix2 A(dataA, 2, 2); // T dataA[] = {1, 2, 3, 4};
Matrix2 B(dataB, 2, 2); // T dataB[] = {5, 6, 7, 8};
// Matrix2 A(dataA, 2, 2);
// Matrix2 B(dataB, 2, 2);
Matrix2 result = A * B; // Matrix2 result = A * B;
float expectedData[] = {19, 22, 43, 50}; // float expectedData[] = {19, 22, 43, 50};
for (int i = 0; i < 4; ++i) // for (int i = 0; i < 4; ++i)
EXPECT_TRUE(result.data[i] == expectedData[i]); // EXPECT_TRUE(result.data[i] == expectedData[i]);
std::cout << "Test 1 passed: 2x2 matrix multiplication.\n"; // std::cout << "Test 1 passed: 2x2 matrix multiplication.\n";
// // Test 2: Multiplying a 3x2 matrix with a 2x3 matrix
// float dataC[] = {1, 2, 3, 4, 5, 6};
// float dataD[] = {7, 8, 9, 10, 11, 12};
// Matrix2 C(dataC, 3, 2);
// Matrix2 D(dataD, 2, 3);
// Test 2: Multiplying a 3x2 matrix with a 2x3 matrix // Matrix2 result2 = C * D;
float dataC[] = {1, 2, 3, 4, 5, 6};
float dataD[] = {7, 8, 9, 10, 11, 12};
Matrix2 C(dataC, 3, 2);
Matrix2 D(dataD, 2, 3);
Matrix2 result2 = C * D; // float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117};
// for (int i = 0; i < 9; ++i)
// EXPECT_TRUE(result2.data[i] == expectedData2[i]);
// std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n";
float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117}; // // Test 3: Multiplying with a zero matrix
for (int i = 0; i < 9; ++i) // Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
EXPECT_TRUE(result2.data[i] == expectedData2[i]); // Matrix2 result3 = A * zeroMatrix;
std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n";
// Test 3: Multiplying with a zero matrix // for (int i = 0; i < 4; ++i)
Matrix2 zeroMatrix = Matrix2::Zero(2, 2); // EXPECT_TRUE(result3.data[i] == 0);
Matrix2 result3 = A * zeroMatrix; // std::cout << "Test 3 passed: Multiplication with zero matrix.\n";
for (int i = 0; i < 4; ++i) // // Test 4: Multiplying with an identity matrix
EXPECT_TRUE(result3.data[i] == 0); // Matrix2 identityMatrix = Matrix2::Identity(2);
std::cout << "Test 3 passed: Multiplication with zero matrix.\n"; // Matrix2 result4 = A * identityMatrix;
// Test 4: Multiplying with an identity matrix // for (int i = 0; i < 4; ++i)
Matrix2 identityMatrix = Matrix2::Identity(2); // EXPECT_TRUE(result4.data[i] == A.data[i]);
Matrix2 result4 = A * identityMatrix; // std::cout << "Test 4 passed: Multiplication with identity matrix.\n";
// }
for (int i = 0; i < 4; ++i) template <typename T>
EXPECT_TRUE(result4.data[i] == A.data[i]); class Matrix1Test : public ::testing::Test {
std::cout << "Test 4 passed: Multiplication with identity matrix.\n"; protected:
};
TYPED_TEST_SUITE(Matrix1Test, MatrixTypes);
} TYPED_TEST(Matrix2Test, Init) {
using Matrix2 = TypeParam;
TEST(MatrixSingle, Init) {
// zero // zero
MatrixOf<float> m0 = MatrixOf<float>(0, 0); Matrix2 m0 = Matrix2(0, 0);
// one // one
float data1[] = {1.0F}; Matrix2 m1 = Matrix2(1, 1);
MatrixOf<float> m1 = MatrixOf<float>(1, 1, data1); m1(0, 0) = 1;
// two // two
float data2[] = {1.0F, 2.0F, 3.0F, 4.0F}; Matrix2 m2 = Matrix2(2, 2);
MatrixOf<float> m2 = MatrixOf<float>(2, 2, data2); m2(0, 0) = 1;
m2(0, 1) = 2;
m2(1, 0) = 3;
m2(1, 1) = 4;
// negative // negative
// MatrixOf<float> m_1 = MatrixOf<float>(-1, -1); // Matrix1 m_1 = Matrix1(-1, -1);
// parameters are unsigned // parameters are unsigned
} }
TEST(MatrixSingle, Transpose) { TYPED_TEST(Matrix2Test, Transpose) {
float data1[] = {1.0F}; using Matrix2 = TypeParam;
MatrixOf<float> m = MatrixOf<float>(1, 1, data1); Matrix2 m = Matrix2(1, 1);
m(0, 0) = 1;
MatrixOf<float> r = MatrixOf<float>(1, 1); Matrix2 r = Matrix2(1, 1);
m.Transpose(&r); m = r.Transposed();
// 2 x 2 // 2 x 2
float data3[] = {1.0F, 2.0F, 3.0F, 4.0F}; Matrix2 m22 = Matrix2(2, 2);
MatrixOf<float> m22 = MatrixOf<float>(2, 2, data3); m22(0, 0) = 1;
m22(0, 1) = 2;
m22(1, 0) = 3;
m22(1, 1) = 4;
EXPECT_EQ(m22.RowCount(), 2); EXPECT_EQ(m22.RowCount(), 2);
EXPECT_EQ(m22.ColCount(), 2); EXPECT_EQ(m22.ColCount(), 2);
float data4[] = {0.0F, 0.0F, 0.0F, 0.0F}; Matrix2 r22 = Matrix2(2, 2);
MatrixOf<float> r22 = MatrixOf<float>(2, 2, data4); r22(0, 0) = 1;
r22(0, 1) = 2;
r22(1, 0) = 3;
r22(1, 1) = 4;
EXPECT_EQ(r22.RowCount(), 2); EXPECT_EQ(r22.RowCount(), 2);
EXPECT_EQ(r22.ColCount(), 2); EXPECT_EQ(r22.ColCount(), 2);
m22.Transpose(&r22); r22 = m22.Transposed();
EXPECT_EQ(r22.RowCount(), 2); EXPECT_EQ(r22.RowCount(), 2);
EXPECT_EQ(r22.ColCount(), 2); EXPECT_EQ(r22.ColCount(), 2);
EXPECT_FLOAT_EQ(r22.Get(0, 0), 1.0F); EXPECT_EQ(r22(0, 0), 1);
EXPECT_FLOAT_EQ(r22.Get(0, 1), 3.0F); EXPECT_EQ(r22(0, 1), 3);
EXPECT_FLOAT_EQ(r22.Get(1, 0), 2.0F); EXPECT_EQ(r22(1, 0), 2);
EXPECT_FLOAT_EQ(r22.Get(1, 1), 4.0F); EXPECT_EQ(r22(1, 1), 4);
// 1 x 2 // 1 x 2
float data12[] = {1.0F, 2.0F}; Matrix2 m12 = Matrix2(1, 2);
MatrixOf<float> m12 = MatrixOf<float>(1, 2, data12); m12(0, 0) = 1;
m12(0, 1) = 2;
EXPECT_EQ(m12.RowCount(), 1); EXPECT_EQ(m12.RowCount(), 1);
EXPECT_EQ(m12.ColCount(), 2); EXPECT_EQ(m12.ColCount(), 2);
float data21[] = {0.0F, 0.0F}; //float data21[] = {0.0F, 0.0F};
MatrixOf<float> r21 = MatrixOf<float>(2, 1, data21); Matrix2 r21 = Matrix2(2, 1);
r21(0,0) = 0;
r21(1,0) = 0;
EXPECT_EQ(r21.RowCount(), 2); EXPECT_EQ(r21.RowCount(), 2);
EXPECT_EQ(r21.ColCount(), 1); EXPECT_EQ(r21.ColCount(), 1);
m12.Transpose(&r21); //m12.Transpose(&r21);
r21 = m12.Transposed();
EXPECT_EQ(r21.RowCount(), 2); EXPECT_EQ(r21.RowCount(), 2);
EXPECT_EQ(r21.ColCount(), 1); EXPECT_EQ(r21.ColCount(), 1);
EXPECT_FLOAT_EQ(r21.Get(0, 0), 1.0F); EXPECT_EQ(r21(0, 0), 1);
EXPECT_FLOAT_EQ(r21.Get(1, 0), 2.0F); EXPECT_EQ(r21(1, 0), 2);
// changing dimensions, same size is okay // changing dimensions, same size is okay
MatrixOf<float> r12 = MatrixOf<float>(1, 2, data21); Matrix2 r12 = Matrix2::Zero(1, 2);
EXPECT_EQ(r12.RowCount(), 1); EXPECT_EQ(r12.RowCount(), 1);
EXPECT_EQ(r12.ColCount(), 2); EXPECT_EQ(r12.ColCount(), 2);
m12.Transpose(&r12); //m12.Transpose(&r12);
r12 = m12.Transposed();
EXPECT_EQ(r12.RowCount(), 2); EXPECT_EQ(r12.RowCount(), 2);
EXPECT_EQ(r12.ColCount(), 1); EXPECT_EQ(r12.ColCount(), 1);
EXPECT_FLOAT_EQ(r12.Get(0, 0), 1.0F); EXPECT_EQ(r12(0, 0), 1);
EXPECT_FLOAT_EQ(r12.Get(0, 1), 2.0F); EXPECT_EQ(r12(0, 1), 2);
} }
TEST(MatrixSingle, Multiply) { TYPED_TEST(Matrix2Test, Multiply) {
float m12data[] = {1.0F, 2.0F}; using Matrix1 = TypeParam;
MatrixOf<float> m12 = MatrixOf<float>(1, 2, m12data); Matrix1 m12 = Matrix1(1, 2);
m12(0,0) = 1;
m12(0,1) = 2;
EXPECT_EQ(m12.RowCount(), 1); EXPECT_EQ(m12.RowCount(), 1);
EXPECT_EQ(m12.ColCount(), 2); EXPECT_EQ(m12.ColCount(), 2);
EXPECT_FLOAT_EQ(m12.Get(0, 0), 1.0F); EXPECT_EQ(m12(0, 0), 1);
EXPECT_FLOAT_EQ(m12.Get(0, 1), 2.0F); EXPECT_EQ(m12(0, 1), 2);
float m21data[] = {3.0F, 4.0F}; //float m21data[] = {3.0F, 4.0F};
MatrixOf<float> m21 = MatrixOf<float>(2, 1, m21data); Matrix1 m21 = Matrix1(2, 1); //, m21data);
m21(0,0) = 3;
m21(1,0) = 4;
EXPECT_EQ(m21.RowCount(), 2); EXPECT_EQ(m21.RowCount(), 2);
EXPECT_EQ(m21.ColCount(), 1); EXPECT_EQ(m21.ColCount(), 1);
EXPECT_FLOAT_EQ(m21.Get(0, 0), 3.0F); EXPECT_EQ(m21(0, 0), 3);
EXPECT_FLOAT_EQ(m21.Get(1, 0), 4.0F); EXPECT_EQ(m21(1, 0), 4);
float r11data[] = {0.0F}; //float r11data[] = {0.0F};
MatrixOf<float> r11 = MatrixOf<float>(1, 1, r11data); Matrix1 r11 = Matrix1::Zero(1, 1); //, r11data);
EXPECT_EQ(r11.RowCount(), 1); EXPECT_EQ(r11.RowCount(), 1);
EXPECT_EQ(r11.ColCount(), 1); EXPECT_EQ(r11.ColCount(), 1);
MatrixOf<float>::Multiply(&m12, &m21, &r11); r11 = m12 * m21; //Matrix1::Multiply(&m12, &m21, &r11);
EXPECT_EQ(r11.RowCount(), 1); EXPECT_EQ(r11.RowCount(), 1);
EXPECT_EQ(r11.ColCount(), 1); EXPECT_EQ(r11.ColCount(), 1);
EXPECT_FLOAT_EQ(r11.Get(0, 0), 11.0F); EXPECT_EQ(r11(0, 0), 11);
float r22data[] = {0.0F, 0.0F, 0.0F, 0.0F}; //float r22data[] = {0.0F, 0.0F, 0.0F, 0.0F};
MatrixOf<float> r22 = MatrixOf<float>(2, 2, r22data); Matrix1 r22 = Matrix1::Zero(2, 2); //, r22data);
MatrixOf<float>::Multiply(&m21, &m12, &r22); //Matrix1::Multiply(&m21, &m12, &r22);
r22 = m21 * m12;
EXPECT_EQ(r22.RowCount(), 2); EXPECT_EQ(r22.RowCount(), 2);
EXPECT_EQ(r22.ColCount(), 2); EXPECT_EQ(r22.ColCount(), 2);
EXPECT_FLOAT_EQ(r22.Get(0, 0), 3.0F); EXPECT_EQ(r22(0, 0), 3);
EXPECT_FLOAT_EQ(r22.Get(0, 1), 4.0F); EXPECT_EQ(r22(0, 1), 6);
EXPECT_FLOAT_EQ(r22.Get(1, 0), 6.0F); EXPECT_EQ(r22(1, 0), 4);
EXPECT_FLOAT_EQ(r22.Get(1, 1), 8.0F); EXPECT_EQ(r22(1, 1), 8);
} }
TEST(MatrixSingle, Multiply_Vector3) { // TYPED_TEST(Matrix2Test, Multiply_Vector3) {
Vector3 v = Vector3(1.0, 2.0, 3.0); // using Matrix2 = TypeParam;
Vector3 r = Vector3::zero; // auto v = Vector3(1.0, 2.0, 3.0);
// Matrix1Of r = Matrix1Of<int>::zero;
// float m13data[] = {3.0, 4.0, 5.0}; // // float m13data[] = {3.0, 4.0, 5.0};
// MatrixOf<float> m13 = MatrixOf<float>(1, 3, m13data); // // Matrix1 m13 = Matrix1(1, 3, m13data);
// Vector3 r = MatrixOf<float>::Multiply(&m13, v); // // Vector3 r = Matrix1::Multiply(&m13, v);
float m33data[] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // //float m33data[] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
MatrixOf<float> m33 = MatrixOf<float>(3, 3, m33data); // Matrix2 m33 = Matrix2::Identity(3, 3); //, m33data);
r = MatrixOf<float>::Multiply(&m33, v);
EXPECT_FLOAT_EQ(Vector3::Distance(r, Vector3(1.0f, 2.0f, 3.0f)), 0); // //r = Matrix1::Multiply(&m33, v);
} // r = m33 * v;
// EXPECT_FLOAT_EQ(Vector3::Distance(r, Vector3(1.0f, 2.0f, 3.0f)), 0);
// }
#endif #endif