From 64820553c7e77c833a76c3a6aab28c7c012cdc69 Mon Sep 17 00:00:00 2001 From: Cynopolis Date: Mon, 2 Jun 2025 16:19:23 -0400 Subject: [PATCH] New norms and division by scalar --- src/Matrix.cpp | 42 +++++++++++++++++++----------- src/Matrix.hpp | 6 ++++- src/Quaternion.cpp | 3 +-- unit-tests/matrix-tests.cpp | 10 ++++--- unit-tests/matrix-timing-tests.cpp | 2 +- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/Matrix.cpp b/src/Matrix.cpp index 570ee84..f253d89 100644 --- a/src/Matrix.cpp +++ b/src/Matrix.cpp @@ -337,6 +337,22 @@ Matrix Matrix::operator*(float scalar) const { return buffer; } +template +Matrix Matrix::operator/(float scalar) const { + Matrix buffer = *this; + if (scalar == 0) { + buffer.Fill(1e+10); + return buffer; + } + + for (uint8_t row = 0; row < rows; row++) { + for (uint8_t column = 0; column < columns; column++) { + buffer[row][column] /= scalar; + } + } + return buffer; +} + template template float Matrix::DotProduct(const Matrix<1, vector_size> &vec1, @@ -423,7 +439,7 @@ Matrix::adjugate(Matrix &result) const { } template -Matrix Matrix::EuclideanNorm() const { +float Matrix::EuclideanNorm() const { float sum{0}; for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { @@ -433,21 +449,17 @@ Matrix Matrix::EuclideanNorm() const { } } - Matrix result{}; - if (sum == 0) { - // this wouldn't do anything anyways - result.Fill(0); - return result; + return sqrt(sum); +} +template +float Matrix::L2Norm() const { + float sum{0}; + Matrix columnMatrix{}; + for (uint8_t column = 0; column < columns; column++) { + this.GetColumn(column, columnMatrix); + sum += columnMatrix.EuclideanNorm(); } - - sum = sqrt(sum); - for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { - for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { - result[row_idx][column_idx] = this->Get(row_idx, column_idx) / sum; - } - } - - return result; + return sqrt(sum); } template diff --git a/src/Matrix.hpp b/src/Matrix.hpp index b7ea1b9..0abd9b1 100644 --- a/src/Matrix.hpp +++ b/src/Matrix.hpp @@ -132,7 +132,9 @@ public: * @brief reduce the matrix so the sum of its elements equal 1 * @param result a buffer to store the result into */ - Matrix EuclideanNorm() const; + float EuclideanNorm() const; + + float L2Norm() const; /** * @brief Get a row from the matrix @@ -201,6 +203,8 @@ public: Matrix operator*(float scalar) const; + Matrix operator/(float scalar) const; + template Matrix SubMatrix() const; diff --git a/src/Quaternion.cpp b/src/Quaternion.cpp index 204896d..a946659 100644 --- a/src/Quaternion.cpp +++ b/src/Quaternion.cpp @@ -9,8 +9,7 @@ Quaternion Quaternion::FromAngleAndAxis(float angle, const Matrix<1, 3> &axis) { const float halfAngle = angle / 2; const float sinHalfAngle = sin(halfAngle); - Matrix<1, 3> normalizedAxis{}; - normalizedAxis = axis.EuclideanNorm(); + Matrix<1, 3> normalizedAxis = axis / axis.EuclideanNorm(); return Quaternion{static_cast(cos(halfAngle)), normalizedAxis.Get(0, 0) * sinHalfAngle, normalizedAxis.Get(0, 1) * sinHalfAngle, diff --git a/unit-tests/matrix-tests.cpp b/unit-tests/matrix-tests.cpp index fb0575e..f218b6b 100644 --- a/unit-tests/matrix-tests.cpp +++ b/unit-tests/matrix-tests.cpp @@ -373,13 +373,15 @@ float matrixSum(const Matrix &matrix) { return std::sqrt(sum); } +// TODO: Add test for scalar division + TEST_CASE("Normalization", "Matrix") { SECTION("2x2 Normalize") { Matrix<2, 2> mat1{1, 2, 3, 4}; Matrix<2, 2> mat2{}; - mat2 = mat1.EuclideanNorm(); + mat2 = mat1 / mat1.EuclideanNorm(); float sqrt_30{static_cast(sqrt(30.0f))}; @@ -394,7 +396,7 @@ TEST_CASE("Normalization", "Matrix") { SECTION("2x1 (Vector) Normalize") { Matrix<2, 1> mat1{-0.878877044, 2.92092276}; Matrix<2, 1> mat2{}; - mat2 = mat1.EuclideanNorm(); + mat2 = mat1 / mat1.EuclideanNorm(); REQUIRE_THAT(mat2.Get(0, 0), Catch::Matchers::WithinRel(-0.288129855179f, 1e-6f)); @@ -408,13 +410,13 @@ TEST_CASE("Normalization", "Matrix") { SECTION("Normalized vectors sum to 1") { Matrix<9, 1> mat1{1, 2, 3, 4, 5, 6, 7, 8, 9}; Matrix<9, 1> mat2; - mat2 = mat1.EuclideanNorm(); + mat2 = mat1 / mat1.EuclideanNorm(); float sum = matrixSum(mat2); REQUIRE_THAT(sum, Catch::Matchers::WithinRel(1.0f, 1e-6f)); Matrix<2, 3> mat3{1, 2, 3, 4, 5, 6}; Matrix<2, 3> mat4{}; - mat4 = mat3.EuclideanNorm(); + mat4 = mat3 / mat3.EuclideanNorm(); sum = matrixSum(mat4); REQUIRE_THAT(sum, Catch::Matchers::WithinRel(1.0f, 1e-6f)); } diff --git a/unit-tests/matrix-timing-tests.cpp b/unit-tests/matrix-timing-tests.cpp index c48802f..9c01347 100644 --- a/unit-tests/matrix-timing-tests.cpp +++ b/unit-tests/matrix-timing-tests.cpp @@ -99,7 +99,7 @@ TEST_CASE("Timing Tests", "Matrix") { SECTION("Normalize") { for (uint32_t i{0}; i < 10000; i++) { - mat3 = mat1.EuclideanNorm(); + mat3 = mat1 / mat1.EuclideanNorm(); } }