Updated merge checker and seperated the matrix tests fro mthe timing tests
All checks were successful
Merge-Checker / build_and_test (pull_request) Successful in 21s

This commit is contained in:
2025-05-21 17:58:18 -04:00
parent c03e26ef38
commit e179fcc701
6 changed files with 180 additions and 219 deletions

View File

@@ -5,22 +5,44 @@ on:
branches: ["**"] branches: ["**"]
jobs: jobs:
build: build_and_test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install dependencies (CMake + Ninja + Compiler) - name: Install dependencies (CMake + Ninja + build tools)
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y cmake ninja-build build-essential sudo apt-get install -y cmake ninja-build build-essential time
- name: Configure project with CMake - name: Configure project with CMake
run: | run: cmake -G Ninja -S . -B build/
cmake -G Ninja -S . -B build/
- name: Build with Ninja - name: Build with Ninja
run: ninja -C build/
- name: Run all unit tests except matrix-timing-tests
run: | run: |
ninja -C build/ for test_exec in build/unit-tests/matrix-tests build/unit-tests/quaternion-tests build/unit-tests/vector-3d-tests; do
if [ -x "$test_exec" ]; then
echo "Running $test_exec"
"$test_exec"
else
echo "Warning: $test_exec not found or not executable"
fi
done
- name: Run matrix-timing-tests with per-test timing output
run: |
if [ -x build/unit-tests/matrix-timing-tests ]; then
echo "Running matrix-timing-tests with timing"
# Run the test executable and capture timing info
# Assuming the executable prints timings per test internally
# If not, you might want to wrap each subtest with 'time' or
# run the entire executable with time:
/usr/bin/time -v build/unit-tests/matrix-timing-tests
else
echo "matrix-timing-tests executable not found or not executable"
fi

View File

@@ -16,6 +16,15 @@ target_link_libraries(matrix-tests
Catch2::Catch2WithMain Catch2::Catch2WithMain
) )
# matrix timing tests
add_executable(matrix-timing-tests matrix-timing-tests.cpp)
target_link_libraries(matrix-timing-tests
PRIVATE
matrix
Catch2::Catch2WithMain
)
# Vector 3D Tests # Vector 3D Tests
add_executable(vector-3d-tests vector-tests.cpp) add_executable(vector-3d-tests vector-tests.cpp)

View File

@@ -1,14 +0,0 @@
Addition: 0.419 s
Subtraction: 0.421 s
Multiplication: 3.297 s
Scalar Multiplication: 0.329 s
Element Multiply: 0.306 s
Element Divide: 0.302 s
Minor Matrix: 0.331 s
Determinant: 0.177 s
Matrix of Minors: 0.766 s
Invert: 0.183 s
Transpose: 0.215 s
Normalize: 0.315 s
GET ROW: 0.008 s
GET COLUMN: 0.43 s

View File

@@ -10,15 +10,13 @@
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
TEST_CASE("Elementary Matrix Operations", "Matrix") TEST_CASE("Elementary Matrix Operations", "Matrix") {
{
std::array<float, 4> arr2{5, 6, 7, 8}; std::array<float, 4> arr2{5, 6, 7, 8};
Matrix<2, 2> mat1{1, 2, 3, 4}; Matrix<2, 2> mat1{1, 2, 3, 4};
Matrix<2, 2> mat2{arr2}; Matrix<2, 2> mat2{arr2};
Matrix<2, 2> mat3{}; Matrix<2, 2> mat3{};
SECTION("Initialization") SECTION("Initialization") {
{
// array initialization // array initialization
REQUIRE(mat1.Get(0, 0) == 1); REQUIRE(mat1.Get(0, 0) == 1);
REQUIRE(mat1.Get(0, 1) == 2); REQUIRE(mat1.Get(0, 1) == 2);
@@ -40,17 +38,14 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
// large matrix // large matrix
Matrix<255, 255> mat6{}; Matrix<255, 255> mat6{};
mat6.Fill(4); mat6.Fill(4);
for (uint8_t row{0}; row < 255; row++) for (uint8_t row{0}; row < 255; row++) {
{ for (uint8_t column{0}; column < 255; column++) {
for (uint8_t column{0}; column < 255; column++)
{
REQUIRE(mat6.Get(row, column) == 4); REQUIRE(mat6.Get(row, column) == 4);
} }
} }
} }
SECTION("Fill") SECTION("Fill") {
{
mat1.Fill(0); mat1.Fill(0);
REQUIRE(mat1.Get(0, 0) == 0); REQUIRE(mat1.Get(0, 0) == 0);
REQUIRE(mat1.Get(0, 1) == 0); REQUIRE(mat1.Get(0, 1) == 0);
@@ -70,12 +65,10 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat3.Get(1, 1) == -20); REQUIRE(mat3.Get(1, 1) == -20);
} }
SECTION("Addition") SECTION("Addition") {
{
std::string strBuf1 = ""; std::string strBuf1 = "";
mat1.ToString(strBuf1); mat1.ToString(strBuf1);
std::cout << "Matrix 1:\n" std::cout << "Matrix 1:\n" << strBuf1 << std::endl;
<< strBuf1 << std::endl;
mat1.Add(mat2, mat3); mat1.Add(mat2, mat3);
@@ -93,8 +86,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat3.Get(1, 1) == 12); REQUIRE(mat3.Get(1, 1) == 12);
} }
SECTION("Subtraction") SECTION("Subtraction") {
{
mat1.Sub(mat2, mat3); mat1.Sub(mat2, mat3);
REQUIRE(mat3.Get(0, 0) == -4); REQUIRE(mat3.Get(0, 0) == -4);
@@ -111,8 +103,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat3.Get(1, 1) == -4); REQUIRE(mat3.Get(1, 1) == -4);
} }
SECTION("Multiplication") SECTION("Multiplication") {
{
mat1.Mult(mat2, mat3); mat1.Mult(mat2, mat3);
REQUIRE(mat3.Get(0, 0) == 19); REQUIRE(mat3.Get(0, 0) == 19);
@@ -131,8 +122,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
// TODO: You need to add non-square multiplications to this. // TODO: You need to add non-square multiplications to this.
} }
SECTION("Scalar Multiplication") SECTION("Scalar Multiplication") {
{
mat1.Mult(2, mat3); mat1.Mult(2, mat3);
REQUIRE(mat3.Get(0, 0) == 2); REQUIRE(mat3.Get(0, 0) == 2);
@@ -141,8 +131,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat3.Get(1, 1) == 8); REQUIRE(mat3.Get(1, 1) == 8);
} }
SECTION("Element Multiply") SECTION("Element Multiply") {
{
mat1.ElementMultiply(mat2, mat3); mat1.ElementMultiply(mat2, mat3);
REQUIRE(mat3.Get(0, 0) == 5); REQUIRE(mat3.Get(0, 0) == 5);
@@ -151,8 +140,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat3.Get(1, 1) == 32); REQUIRE(mat3.Get(1, 1) == 32);
} }
SECTION("Element Divide") SECTION("Element Divide") {
{
mat1.ElementDivide(mat2, mat3); mat1.ElementDivide(mat2, mat3);
REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(0.2f, 1e-6f)); REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(0.2f, 1e-6f));
@@ -161,8 +149,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE_THAT(mat3.Get(1, 1), Catch::Matchers::WithinRel(0.5f, 1e-6f)); REQUIRE_THAT(mat3.Get(1, 1), Catch::Matchers::WithinRel(0.5f, 1e-6f));
} }
SECTION("Minor Matrix") SECTION("Minor Matrix") {
{
// what about matrices of 0,0 or 1,1? // what about matrices of 0,0 or 1,1?
// minor matrix for 2x2 matrix // minor matrix for 2x2 matrix
Matrix<1, 1> minorMat1{}; Matrix<1, 1> minorMat1{};
@@ -198,8 +185,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(minorMat4.Get(1, 1) == 5); REQUIRE(minorMat4.Get(1, 1) == 5);
} }
SECTION("Determinant") SECTION("Determinant") {
{
float det1 = mat1.Det(); float det1 = mat1.Det();
REQUIRE_THAT(det1, Catch::Matchers::WithinRel(-2.0F, 1e-6f)); REQUIRE_THAT(det1, Catch::Matchers::WithinRel(-2.0F, 1e-6f));
@@ -216,8 +202,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE_THAT(det5, Catch::Matchers::WithinRel(6.0F, 1e-6f)); REQUIRE_THAT(det5, Catch::Matchers::WithinRel(6.0F, 1e-6f));
} }
SECTION("Matrix of Minors") SECTION("Matrix of Minors") {
{
mat1.MatrixOfMinors(mat3); mat1.MatrixOfMinors(mat3);
REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(4.0F, 1e-6f)); REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(4.0F, 1e-6f));
REQUIRE_THAT(mat3.Get(0, 1), Catch::Matchers::WithinRel(3.0F, 1e-6f)); REQUIRE_THAT(mat3.Get(0, 1), Catch::Matchers::WithinRel(3.0F, 1e-6f));
@@ -238,8 +223,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE_THAT(mat5.Get(2, 2), Catch::Matchers::WithinRel(-3.0F, 1e-6f)); REQUIRE_THAT(mat5.Get(2, 2), Catch::Matchers::WithinRel(-3.0F, 1e-6f));
} }
SECTION("Invert") SECTION("Invert") {
{
mat3 = mat1.Invert(); mat3 = mat1.Invert();
REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(-2.0F, 1e-6f)); REQUIRE_THAT(mat3.Get(0, 0), Catch::Matchers::WithinRel(-2.0F, 1e-6f));
REQUIRE_THAT(mat3.Get(0, 1), Catch::Matchers::WithinRel(1.0F, 1e-6f)); REQUIRE_THAT(mat3.Get(0, 1), Catch::Matchers::WithinRel(1.0F, 1e-6f));
@@ -247,8 +231,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE_THAT(mat3.Get(1, 1), Catch::Matchers::WithinRel(-0.5F, 1e-6f)); REQUIRE_THAT(mat3.Get(1, 1), Catch::Matchers::WithinRel(-0.5F, 1e-6f));
}; };
SECTION("Transpose") SECTION("Transpose") {
{
// transpose a square matrix // transpose a square matrix
mat3 = mat1.Transpose(); mat3 = mat1.Transpose();
@@ -271,8 +254,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat5.Get(2, 1) == 6); REQUIRE(mat5.Get(2, 1) == 6);
} }
SECTION("Normalize") SECTION("Normalize") {
{
mat1.Normalize(mat3); mat1.Normalize(mat3);
float sqrt_30{sqrt(30)}; float sqrt_30{sqrt(30)};
@@ -292,8 +274,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
Catch::Matchers::WithinRel(0.957591346325f, 1e-6f)); Catch::Matchers::WithinRel(0.957591346325f, 1e-6f));
} }
SECTION("GET ROW") SECTION("GET ROW") {
{
Matrix<1, 2> mat1Rows{}; Matrix<1, 2> mat1Rows{};
mat1.GetRow(0, mat1Rows); mat1.GetRow(0, mat1Rows);
REQUIRE(mat1Rows.Get(0, 0) == 1); REQUIRE(mat1Rows.Get(0, 0) == 1);
@@ -304,8 +285,7 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat1Rows.Get(0, 1) == 4); REQUIRE(mat1Rows.Get(0, 1) == 4);
} }
SECTION("GET COLUMN") SECTION("GET COLUMN") {
{
Matrix<2, 1> mat1Columns{}; Matrix<2, 1> mat1Columns{};
mat1.GetColumn(0, mat1Columns); mat1.GetColumn(0, mat1Columns);
REQUIRE(mat1Columns.Get(0, 0) == 1); REQUIRE(mat1Columns.Get(0, 0) == 1);
@@ -316,12 +296,8 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat1Columns.Get(1, 0) == 4); REQUIRE(mat1Columns.Get(1, 0) == 4);
} }
SECTION("Get Sub-Matrices") SECTION("Get Sub-Matrices") {
{ Matrix<3, 3> mat4{1, 2, 3, 4, 5, 6, 7, 8, 9};
Matrix<3, 3> mat4{
1, 2, 3,
4, 5, 6,
7, 8, 9};
Matrix<2, 2> mat5 = mat4.SubMatrix<2, 2, 0, 0>(); Matrix<2, 2> mat5 = mat4.SubMatrix<2, 2, 0, 0>();
@@ -347,12 +323,8 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat7.Get(0, 2) == 3); REQUIRE(mat7.Get(0, 2) == 3);
} }
SECTION("Set Sub-Matrices") SECTION("Set Sub-Matrices") {
{ Matrix<3, 3> startMatrix{1, 2, 3, 4, 5, 6, 7, 8, 9};
Matrix<3, 3> startMatrix{
1, 2, 3,
4, 5, 6,
7, 8, 9};
Matrix<3, 3> mat4 = startMatrix; Matrix<3, 3> mat4 = startMatrix;
Matrix<2, 2> mat5{10, 11, 12, 13}; Matrix<2, 2> mat5{10, 11, 12, 13};
@@ -381,144 +353,4 @@ TEST_CASE("Elementary Matrix Operations", "Matrix")
REQUIRE(mat4.Get(0, 1) == 11); REQUIRE(mat4.Get(0, 1) == 11);
REQUIRE(mat4.Get(0, 2) == 12); REQUIRE(mat4.Get(0, 2) == 12);
} }
}
// basically re-run all of the previous tests with huge matrices and time the
// results.
TEST_CASE("Timing Tests", "Matrix")
{
std::array<float, 50 * 50> arr1{};
for (uint16_t i{0}; i < 50 * 50; i++)
{
arr1[i] = i;
}
std::array<float, 50 * 50> arr2{5, 6, 7, 8};
for (uint16_t i{50 * 50}; i < 2 * 50 * 50; i++)
{
arr2[i] = i;
}
Matrix<50, 50> mat1{arr1};
Matrix<50, 50> mat2{arr2};
Matrix<50, 50> mat3{};
// A smaller matrix to use for really badly optimized operations
Matrix<4, 4> mat4{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
Matrix<4, 4> mat5{};
SECTION("Addition")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat3 = mat1 + mat2;
}
}
SECTION("Subtraction")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat3 = mat1 - mat2;
}
}
SECTION("Multiplication")
{
for (uint32_t i{0}; i < 1000; i++)
{
mat3 = mat1 * mat2;
}
}
SECTION("Scalar Multiplication")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat3 = mat1 * 3;
}
}
SECTION("Element Multiply")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat1.ElementMultiply(mat2, mat3);
}
}
SECTION("Element Divide")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat1.ElementDivide(mat2, mat3);
}
}
SECTION("Minor Matrix")
{
// what about matrices of 0,0 or 1,1?
// minor matrix for 2x2 matrix
Matrix<49, 49> minorMat1{};
for (uint32_t i{0}; i < 10000; i++)
{
mat1.MinorMatrix(minorMat1, 0, 0);
}
}
SECTION("Determinant")
{
for (uint32_t i{0}; i < 100000; i++)
{
float det1 = mat4.Det();
}
}
SECTION("Matrix of Minors")
{
for (uint32_t i{0}; i < 100000; i++)
{
mat4.MatrixOfMinors(mat5);
}
}
SECTION("Invert")
{
for (uint32_t i{0}; i < 100000; i++)
{
mat5 = mat4.Invert();
}
};
SECTION("Transpose")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat3 = mat1.Transpose();
}
}
SECTION("Normalize")
{
for (uint32_t i{0}; i < 10000; i++)
{
mat1.Normalize(mat3);
}
}
SECTION("GET ROW")
{
Matrix<1, 50> mat1Rows{};
for (uint32_t i{0}; i < 1000000; i++)
{
mat1.GetRow(0, mat1Rows);
}
}
SECTION("GET COLUMN")
{
Matrix<50, 1> mat1Columns{};
for (uint32_t i{0}; i < 1000000; i++)
{
mat1.GetColumn(0, mat1Columns);
}
}
} }

View File

@@ -0,0 +1,119 @@
// include the unit test framework first
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
// include the module you're going to test next
#include "Matrix.hpp"
// any other libraries
#include <array>
#include <cmath>
// basically re-run all of the matrix tests with huge matrices and time the
// results.
TEST_CASE("Timing Tests", "Matrix") {
std::array<float, 50 * 50> arr1{};
for (uint16_t i{0}; i < 50 * 50; i++) {
arr1[i] = i;
}
std::array<float, 50 * 50> arr2{5, 6, 7, 8};
for (uint16_t i{50 * 50}; i < 2 * 50 * 50; i++) {
arr2[i] = i;
}
Matrix<50, 50> mat1{arr1};
Matrix<50, 50> mat2{arr2};
Matrix<50, 50> mat3{};
// A smaller matrix to use for really badly optimized operations
Matrix<4, 4> mat4{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
Matrix<4, 4> mat5{};
SECTION("Addition") {
for (uint32_t i{0}; i < 10000; i++) {
mat3 = mat1 + mat2;
}
}
SECTION("Subtraction") {
for (uint32_t i{0}; i < 10000; i++) {
mat3 = mat1 - mat2;
}
}
SECTION("Multiplication") {
for (uint32_t i{0}; i < 1000; i++) {
mat3 = mat1 * mat2;
}
}
SECTION("Scalar Multiplication") {
for (uint32_t i{0}; i < 10000; i++) {
mat3 = mat1 * 3;
}
}
SECTION("Element Multiply") {
for (uint32_t i{0}; i < 10000; i++) {
mat1.ElementMultiply(mat2, mat3);
}
}
SECTION("Element Divide") {
for (uint32_t i{0}; i < 10000; i++) {
mat1.ElementDivide(mat2, mat3);
}
}
SECTION("Minor Matrix") {
// what about matrices of 0,0 or 1,1?
// minor matrix for 2x2 matrix
Matrix<49, 49> minorMat1{};
for (uint32_t i{0}; i < 10000; i++) {
mat1.MinorMatrix(minorMat1, 0, 0);
}
}
SECTION("Determinant") {
for (uint32_t i{0}; i < 100000; i++) {
float det1 = mat4.Det();
}
}
SECTION("Matrix of Minors") {
for (uint32_t i{0}; i < 100000; i++) {
mat4.MatrixOfMinors(mat5);
}
}
SECTION("Invert") {
for (uint32_t i{0}; i < 100000; i++) {
mat5 = mat4.Invert();
}
};
SECTION("Transpose") {
for (uint32_t i{0}; i < 10000; i++) {
mat3 = mat1.Transpose();
}
}
SECTION("Normalize") {
for (uint32_t i{0}; i < 10000; i++) {
mat1.Normalize(mat3);
}
}
SECTION("GET ROW") {
Matrix<1, 50> mat1Rows{};
for (uint32_t i{0}; i < 1000000; i++) {
mat1.GetRow(0, mat1Rows);
}
}
SECTION("GET COLUMN") {
Matrix<50, 1> mat1Columns{};
for (uint32_t i{0}; i < 1000000; i++) {
mat1.GetColumn(0, mat1Columns);
}
}
}

View File

@@ -1,7 +0,0 @@
# be in the root folder of this project when you run this
cd build/
ninja matrix-tests
echo "Running tests. This will take a while."
./unit-tests/matrix-tests -n "Timing Tests" -d yes > ../unit-tests/matrix-test-timings-temp.txt
cd ../unit-tests/
python3 test-timing-post-process.py