diff --git a/doc/userdoc.org b/doc/userdoc.org index 320a9c183270985d0d3ad17fbda9ebd562cad2c9..c338582d59ef05c6b2241c09b615a515e56b2fe0 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -2589,7 +2589,8 @@ The output is #+RESULTS: dot-examples A set of ~det~ functions is defined to get the determinant of matrices -$\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$. +of $\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and +$\mathbb{R}^{3\times3}$. #+NAME: det-examples #+BEGIN_SRC pugs :exports both :results output import math; @@ -2601,20 +2602,47 @@ $\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$. The output is #+RESULTS: det-examples +The ~trace~ functions compute the trace of matrices of +$\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$. +#+NAME: trace-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "trace([[1.2]]) = " << trace([[1.2]]) << "\n"; + cout << "trace([[1,2],[3,4]]) = " << trace([[1,2],[3,4]]) << "\n"; + cout << "trace([[1,2,3],[4,5,6],[7,8,9]]) = " + << trace([[1,2,3],[4,5,6],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: trace-examples + Also, one can compute inverses of $\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$ matrices using the ~inverse~ function set. #+NAME: inverse-examples #+BEGIN_SRC pugs :exports both :results output import math; - cout << "det([[1.2]]) = " << inverse([[1.2]]) << "\n"; - cout << "det([[1,2],[3,4]]) = " << inverse([[1,2],[3,4]]) << "\n"; - cout << "det([[3,2,1],[5,6,4],[7,8,9]]) = " - << det([[3,2,1],[5,6,4],[7,8,9]]) << "\n"; + cout << "inverse([[1.2]]) = " << inverse([[1.2]]) << "\n"; + cout << "inverse([[1,2],[3,4]]) = " << inverse([[1,2],[3,4]]) << "\n"; + cout << "inverse([[3,2,1],[5,6,4],[7,8,9]]) = " + << inverse([[3,2,1],[5,6,4],[7,8,9]]) << "\n"; #+END_SRC The output is #+RESULTS: inverse-examples +Transpose of matrices of $\mathbb{R}^{1\times1}$, +$\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$ are obtained using the +~transpose~ functions. +#+NAME: transpose-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "transpose([[1.2]]) = " << transpose([[1.2]]) << "\n"; + cout << "transpose([[1,2],[3,4]]) = " << transpose([[1,2],[3,4]]) << "\n"; + cout << "transpose([[3,2,1],[5,6,4],[7,8,9]]) = " + << transpose([[3,2,1],[5,6,4],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: transpose-examples + #+BEGIN_note Observe that the use of a proper rounding or truncation function is the right way to convert a real value to an integer one. Available @@ -3246,18 +3274,20 @@ Here is the list of these functions - ~tan: Vh -> Vh~ - ~tanh: Vh -> Vh~ -The ~det~ functions are defined for $\mathbb{P}_0(\mathbb{R^{}}^{1\times1})$, +A few functions are defined for $\mathbb{P}_0(\mathbb{R^{}}^{1\times1})$, $\mathbb{P}_0(\mathbb{R^{}}^{2\times2})$ and $\mathbb{P}_0(\mathbb{R^{}}^{3\times3})$ data and the return value is a $\mathbb{P}_0(\mathbb{R})$ function. The value is simply the application of the function to the cell values. - ~det: Vh -> Vh~ +- ~trace: Vh -> Vh~ -The ~inverse~ functions are defined for $\mathbb{P}_0(\mathbb{R}^{d\times d})$ +Also, functions are defined for $\mathbb{P}_0(\mathbb{R}^{d\times d})$ data and the return value is a $\mathbb{P}_0(\mathbb{R}^{d\times d})$ function, with $d\in\{1,2,3\}$. The value is simply the application of the function to the cell values. - ~inverse: Vh -> Vh~ +- ~transpose: Vh -> Vh~ ****** ~Vh*Vh -> Vh~ diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp index e34f98ed8c25df7a77ba90bbd7cd05305b5eb115..1717b48c78deaedc7cabd9f60feb215e29a80ebe 100644 --- a/src/algebra/TinyMatrix.hpp +++ b/src/algebra/TinyMatrix.hpp @@ -21,16 +21,21 @@ class [[nodiscard]] TinyMatrix using data_type = T; private: + static_assert((M > 0), "TinyMatrix number of rows must be strictly positive"); + static_assert((N > 0), "TinyMatrix number of columns must be strictly positive"); + T m_values[M * N]; PUGS_FORCEINLINE - constexpr size_t _index(size_t i, size_t j) const noexcept // LCOV_EXCL_LINE (due to forced inline) + constexpr size_t + _index(size_t i, size_t j) const noexcept // LCOV_EXCL_LINE (due to forced inline) { return i * N + j; } template <typename... Args> - PUGS_FORCEINLINE constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept + PUGS_FORCEINLINE constexpr void + _unpackVariadicInput(const T& t, Args&&... args) noexcept { m_values[M * N - 1 - sizeof...(args)] = t; if constexpr (sizeof...(args) > 0) { @@ -40,13 +45,15 @@ class [[nodiscard]] TinyMatrix public: PUGS_INLINE - constexpr bool isSquare() const noexcept + constexpr bool + isSquare() const noexcept { return M == N; } PUGS_INLINE - constexpr friend TinyMatrix<N, M, T> transpose(const TinyMatrix& A) + constexpr friend TinyMatrix<N, M, T> + transpose(const TinyMatrix& A) { TinyMatrix<N, M, T> tA; for (size_t i = 0; i < M; ++i) { @@ -58,31 +65,36 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr size_t dimension() const + constexpr size_t + dimension() const { return M * N; } PUGS_INLINE - constexpr size_t numberOfValues() const + constexpr size_t + numberOfValues() const { return this->dimension(); } PUGS_INLINE - constexpr size_t numberOfRows() const + constexpr size_t + numberOfRows() const { return M; } PUGS_INLINE - constexpr size_t numberOfColumns() const + constexpr size_t + numberOfColumns() const { return N; } PUGS_INLINE - constexpr TinyMatrix operator-() const + constexpr TinyMatrix + operator-() const { TinyMatrix opposite; for (size_t i = 0; i < M * N; ++i) { @@ -92,20 +104,23 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr friend TinyMatrix operator*(const T& t, const TinyMatrix& A) + constexpr friend TinyMatrix + operator*(const T& t, const TinyMatrix& A) { TinyMatrix B = A; return B *= t; } PUGS_INLINE - constexpr friend TinyMatrix operator*(const T& t, TinyMatrix&& A) + constexpr friend TinyMatrix + operator*(const T& t, TinyMatrix&& A) { return std::move(A *= t); } PUGS_INLINE - constexpr TinyMatrix& operator*=(const T& t) + constexpr TinyMatrix& + operator*=(const T& t) { for (size_t i = 0; i < M * N; ++i) { m_values[i] *= t; @@ -114,7 +129,8 @@ class [[nodiscard]] TinyMatrix } template <size_t P> - PUGS_INLINE constexpr TinyMatrix<M, P, T> operator*(const TinyMatrix<N, P, T>& B) const + PUGS_INLINE constexpr TinyMatrix<M, P, T> + operator*(const TinyMatrix<N, P, T>& B) const { const TinyMatrix& A = *this; TinyMatrix<M, P, T> AB; @@ -131,7 +147,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyVector<M, T> operator*(const TinyVector<N, T>& x) const + constexpr TinyVector<M, T> + operator*(const TinyVector<N, T>& x) const { const TinyMatrix& A = *this; TinyVector<M, T> Ax; @@ -146,7 +163,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A) + constexpr friend std::ostream& + operator<<(std::ostream& os, const TinyMatrix& A) { os << '['; for (size_t i = 0; i < M; ++i) { @@ -165,7 +183,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr bool operator==(const TinyMatrix& A) const + constexpr bool + operator==(const TinyMatrix& A) const { for (size_t i = 0; i < M * N; ++i) { if (m_values[i] != A.m_values[i]) @@ -175,13 +194,15 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr bool operator!=(const TinyMatrix& A) const + constexpr bool + operator!=(const TinyMatrix& A) const { return not this->operator==(A); } PUGS_INLINE - constexpr TinyMatrix operator+(const TinyMatrix& A) const + constexpr TinyMatrix + operator+(const TinyMatrix& A) const { TinyMatrix sum; for (size_t i = 0; i < M * N; ++i) { @@ -191,14 +212,16 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix operator+(TinyMatrix&& A) const + constexpr TinyMatrix + operator+(TinyMatrix&& A) const { A += *this; return std::move(A); } PUGS_INLINE - constexpr TinyMatrix operator-(const TinyMatrix& A) const + constexpr TinyMatrix + operator-(const TinyMatrix& A) const { TinyMatrix difference; for (size_t i = 0; i < M * N; ++i) { @@ -208,7 +231,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix operator-(TinyMatrix&& A) const + constexpr TinyMatrix + operator-(TinyMatrix&& A) const { for (size_t i = 0; i < M * N; ++i) { A.m_values[i] = m_values[i] - A.m_values[i]; @@ -217,7 +241,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator+=(const TinyMatrix& A) + constexpr TinyMatrix& + operator+=(const TinyMatrix& A) { for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; @@ -226,7 +251,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr void operator+=(const volatile TinyMatrix& A) volatile + constexpr void + operator+=(const volatile TinyMatrix& A) volatile { for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; @@ -234,7 +260,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator-=(const TinyMatrix& A) + constexpr TinyMatrix& + operator-=(const TinyMatrix& A) { for (size_t i = 0; i < M * N; ++i) { m_values[i] -= A.m_values[i]; @@ -243,21 +270,24 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr T& operator()(size_t i, size_t j) noexcept(NO_ASSERT) + constexpr T& + operator()(size_t i, size_t j) noexcept(NO_ASSERT) { Assert((i < M) and (j < N)); return m_values[_index(i, j)]; } PUGS_INLINE - constexpr const T& operator()(size_t i, size_t j) const noexcept(NO_ASSERT) + constexpr const T& + operator()(size_t i, size_t j) const noexcept(NO_ASSERT) { Assert((i < M) and (j < N)); return m_values[_index(i, j)]; } PUGS_INLINE - constexpr TinyMatrix& operator=(ZeroType) noexcept + constexpr TinyMatrix& + operator=(ZeroType) noexcept { static_assert(std::is_arithmetic<T>(), "Cannot assign 'zero' value for non-arithmetic types"); for (size_t i = 0; i < M * N; ++i) { @@ -267,7 +297,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator=(IdentityType) noexcept + constexpr TinyMatrix& + operator=(IdentityType) noexcept { static_assert(std::is_arithmetic<T>(), "Cannot assign 'identity' value for non-arithmetic types"); for (size_t i = 0; i < M; ++i) { @@ -329,7 +360,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix(const TinyMatrix&) noexcept = default; PUGS_INLINE - TinyMatrix(TinyMatrix && A) noexcept = default; + TinyMatrix(TinyMatrix&& A) noexcept = default; PUGS_INLINE ~TinyMatrix() = default; @@ -450,6 +481,19 @@ getMinor(const TinyMatrix<M, N, T>& A, size_t I, size_t J) return m; } +template <size_t N, typename T> +PUGS_INLINE T +trace(const TinyMatrix<N, N, T>& A) +{ + static_assert(std::is_arithmetic<T>::value, "trace is not defined for non-arithmetic types"); + + T t = A(0, 0); + for (size_t i = 1; i < N; ++i) { + t += A(i, i); + } + return t; +} + template <size_t N, typename T> PUGS_INLINE constexpr TinyMatrix<N, N, T> inverse(const TinyMatrix<N, N, T>& A); diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp index 5f2de33d8502fa84edd809f2dfbfa51c91c12ef4..4a1e7b35b76a4d9b8b05ebb1355f3cdca4f751d9 100644 --- a/src/language/modules/MathModule.cpp +++ b/src/language/modules/MathModule.cpp @@ -77,6 +77,12 @@ MathModule::MathModule() this->_addBuiltinFunction("det", std::function([](const TinyMatrix<3>& A) -> double { return det(A); })); + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<1> A) -> double { return trace(A); })); + + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<2>& A) -> double { return trace(A); })); + + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<3>& A) -> double { return trace(A); })); + this->_addBuiltinFunction("inverse", std::function([](const TinyMatrix<1> A) -> TinyMatrix<1> { return inverse(A); })); @@ -85,6 +91,15 @@ MathModule::MathModule() this->_addBuiltinFunction("inverse", std::function([](const TinyMatrix<3>& A) -> TinyMatrix<3> { return inverse(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<1> A) -> TinyMatrix<1> { return transpose(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<2>& A) -> TinyMatrix<2> { return transpose(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<3>& A) -> TinyMatrix<3> { return transpose(A); })); } void diff --git a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp index e4ac44a3328d40415a4cbdca52600e224f6885cc..67622f4a7c2ebbc7284f7305be98aeb3beb8768f 100644 --- a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp +++ b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp @@ -554,6 +554,57 @@ det(const std::shared_ptr<const IDiscreteFunction>& A) } } +template <typename MatrixType> +std::shared_ptr<const IDiscreteFunction> +trace(const std::shared_ptr<const IDiscreteFunction>& A) +{ + switch (A->mesh()->dimension()) { + case 1: { + using DiscreteFunctionType = DiscreteFunctionP0<1, MatrixType>; + return std::make_shared<const DiscreteFunctionP0<1, double>>(trace(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + case 2: { + using DiscreteFunctionType = DiscreteFunctionP0<2, MatrixType>; + return std::make_shared<const DiscreteFunctionP0<2, double>>(trace(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + case 3: { + using DiscreteFunctionType = DiscreteFunctionP0<3, MatrixType>; + return std::make_shared<const DiscreteFunctionP0<3, double>>(trace(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} + +std::shared_ptr<const IDiscreteFunction> +trace(const std::shared_ptr<const IDiscreteFunction>& A) +{ + if (A->dataType() == ASTNodeDataType::matrix_t and A->descriptor().type() == DiscreteFunctionType::P0) { + if (A->dataType().numberOfRows() != A->dataType().numberOfColumns()) { + throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(A)); + } + switch (A->dataType().numberOfRows()) { + case 1: { + return trace<TinyMatrix<1>>(A); + } + case 2: { + return trace<TinyMatrix<2>>(A); + } + case 3: { + return trace<TinyMatrix<3>>(A); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid matrix type"); + } + // LCOV_EXCL_STOP + } + } else { + throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(A)); + } +} + template <typename MatrixType> std::shared_ptr<const IDiscreteFunction> inverse(const std::shared_ptr<const IDiscreteFunction>& A) @@ -605,6 +656,57 @@ inverse(const std::shared_ptr<const IDiscreteFunction>& A) } } +template <typename MatrixType> +std::shared_ptr<const IDiscreteFunction> +transpose(const std::shared_ptr<const IDiscreteFunction>& A) +{ + switch (A->mesh()->dimension()) { + case 1: { + using DiscreteFunctionType = DiscreteFunctionP0<1, MatrixType>; + return std::make_shared<const DiscreteFunctionType>(transpose(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + case 2: { + using DiscreteFunctionType = DiscreteFunctionP0<2, MatrixType>; + return std::make_shared<const DiscreteFunctionType>(transpose(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + case 3: { + using DiscreteFunctionType = DiscreteFunctionP0<3, MatrixType>; + return std::make_shared<const DiscreteFunctionType>(transpose(dynamic_cast<const DiscreteFunctionType&>(*A))); + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} + +std::shared_ptr<const IDiscreteFunction> +transpose(const std::shared_ptr<const IDiscreteFunction>& A) +{ + if (A->dataType() == ASTNodeDataType::matrix_t and A->descriptor().type() == DiscreteFunctionType::P0) { + if (A->dataType().numberOfRows() != A->dataType().numberOfColumns()) { + throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(A)); + } + switch (A->dataType().numberOfRows()) { + case 1: { + return transpose<TinyMatrix<1>>(A); + } + case 2: { + return transpose<TinyMatrix<2>>(A); + } + case 3: { + return transpose<TinyMatrix<3>>(A); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid matrix type"); + } + // LCOV_EXCL_STOP + } + } else { + throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(A)); + } +} + double min(const std::shared_ptr<const IDiscreteFunction>& f) { diff --git a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp index 1908dd30cf16c6cc7fa3c3281d42429b0c661580..24994c743428d98befb8d34cc18c2cbbf12a2ba4 100644 --- a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp +++ b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp @@ -67,8 +67,12 @@ std::shared_ptr<const IDiscreteFunction> dot(const TinyVector<VectorDimension>&, std::shared_ptr<const IDiscreteFunction> det(const std::shared_ptr<const IDiscreteFunction>&); +std::shared_ptr<const IDiscreteFunction> trace(const std::shared_ptr<const IDiscreteFunction>&); + std::shared_ptr<const IDiscreteFunction> inverse(const std::shared_ptr<const IDiscreteFunction>&); +std::shared_ptr<const IDiscreteFunction> transpose(const std::shared_ptr<const IDiscreteFunction>&); + std::shared_ptr<const IDiscreteFunction> sum_of_Vh_components(const std::shared_ptr<const IDiscreteFunction>&); std::shared_ptr<const IDiscreteFunction> vectorize( diff --git a/src/scheme/DiscreteFunctionP0.hpp b/src/scheme/DiscreteFunctionP0.hpp index 6e1ef6a0d28a3436543fa090bee813586874bbee..d1bd72c3394346db10898cd83f1c609974f17697 100644 --- a/src/scheme/DiscreteFunctionP0.hpp +++ b/src/scheme/DiscreteFunctionP0.hpp @@ -536,6 +536,18 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> + trace(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<DataType>); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0<Dimension, double> result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = trace(A[cell_id]); }); + + return result; + } + PUGS_INLINE friend DiscreteFunctionP0 inverse(const DiscreteFunctionP0& A) { @@ -549,6 +561,19 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } + PUGS_INLINE friend DiscreteFunctionP0 + transpose(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<DataType>); + static_assert(DataType::NumberOfRows == DataType::NumberOfColumns, "cannot compute inverse of non square matrices"); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0 result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = transpose(A[cell_id]); }); + + return result; + } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> dot(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp index 7899ea66d6ca7bb0f1fcf79d38b524cc07fed1e5..0168633cea1d2d2e764b6b835093d1f17504024d 100644 --- a/tests/test_BuiltinFunctionProcessor.cpp +++ b/tests/test_BuiltinFunctionProcessor.cpp @@ -396,6 +396,44 @@ let d:R, d = det(A); -2.6, 5.2, -3.5})); } + { // trace + tested_function_set.insert("trace:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", trace(TinyMatrix<1>{-2})); + } + + { // trace + tested_function_set.insert("trace:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", + trace(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // trace + tested_function_set.insert("trace:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2.5, 2.9,-1.3], + [ 3.2, 2.3, 2.7], + [-2.6, 5.2,-3.5]]; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", + trace(TinyMatrix<3>{-2.5, 2.9, -1.3, // + +3.2, 2.3, +2.7, // + -2.6, 5.2, -3.5})); + } + { // inverse tested_function_set.insert("inverse:R^1x1"); std::string_view data = R"( @@ -434,6 +472,44 @@ let invA:R^3x3, invA = inverse(A); -2.6, 5.2, -3.5})); } + { // transpose + tested_function_set.insert("transpose:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let tA:R^1x1, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", transpose(TinyMatrix<1>{-2})); + } + + { // transpose + tested_function_set.insert("transpose:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let tA:R^2x2, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", + transpose(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // transpose + tested_function_set.insert("transpose:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2.5, 2.9,-1.3], + [ 3.2, 2.3, 2.7], + [-2.6, 5.2,-3.5]]; +let tA:R^3x3, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", + transpose(TinyMatrix<3>{-2.5, 2.9, -1.3, // + +3.2, 2.3, +2.7, // + -2.6, 5.2, -3.5})); + } + MathModule math_module; bool missing_test = false; diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index 6c420b8443b11b40d7931a7d628e6374d3a83c49..48c107e4ad2f07391a49270a04c9a3dc20d2db4a 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -3450,6 +3450,28 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") } } + SECTION("trace(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = trace(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != trace(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + SECTION("inverse(Ah)") { DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; @@ -3472,6 +3494,28 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") } } + SECTION("transpose(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = transpose(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != transpose(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + SECTION("scalar sum") { const CellValue<const double> cell_value = positive_function.cellValues(); diff --git a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp b/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp index 0fcc3c148a5da83d1f43663bb52c1eda05e02fd9..6d00782f96379548ebb66927044782def35612e8 100644 --- a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp +++ b/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp @@ -603,6 +603,71 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("trace Vh -> Vh") + { + { + std::shared_ptr p_fu = trace(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R2x2_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R3x3_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("inverse Vh -> Vh") { { @@ -686,6 +751,89 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("transpose Vh -> Vh") + { + { + std::shared_ptr p_fu = transpose(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id](0, 0) != transpose(values[cell_id])(0, 0)) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R2x2_u); + constexpr size_t nb_row = 2; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + const TinyMatrix invA = transpose(values[cell_id]); + const TinyMatrix<nb_row>& fu_i = fu[cell_id]; + for (size_t i = 0; i < nb_row; ++i) { + for (size_t j = 0; j < nb_row; ++j) { + if (fu_i(i, j) != invA(i, j)) { + is_same = false; + } + } + } + if (not is_same) { + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R3x3_u); + constexpr size_t nb_row = 3; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + const TinyMatrix invA = transpose(values[cell_id]); + const TinyMatrix<nb_row>& fu_i = fu[cell_id]; + for (size_t i = 0; i < nb_row; ++i) { + for (size_t j = 0; j < nb_row; ++j) { + if (fu_i(i, j) != invA(i, j)) { + is_same = false; + } + } + } + if (not is_same) { + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("sum_of_Vh Vh -> Vh") { { @@ -1323,6 +1471,71 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("trace Vh -> Vh") + { + { + std::shared_ptr p_fu = trace(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R2x2_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R3x3_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("inverse Vh -> Vh") { { @@ -1406,6 +1619,89 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("transpose Vh -> Vh") + { + { + std::shared_ptr p_fu = transpose(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id](0, 0) != transpose(values[cell_id])(0, 0)) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R2x2_u); + constexpr size_t nb_row = 2; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + const TinyMatrix invA = transpose(values[cell_id]); + const TinyMatrix<nb_row>& fu_i = fu[cell_id]; + for (size_t i = 0; i < nb_row; ++i) { + for (size_t j = 0; j < nb_row; ++j) { + if (fu_i(i, j) != invA(i, j)) { + is_same = false; + } + } + } + if (not is_same) { + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R3x3_u); + constexpr size_t nb_row = 3; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + const TinyMatrix invA = transpose(values[cell_id]); + const TinyMatrix<nb_row>& fu_i = fu[cell_id]; + for (size_t i = 0; i < nb_row; ++i) { + for (size_t j = 0; j < nb_row; ++j) { + if (fu_i(i, j) != invA(i, j)) { + is_same = false; + } + } + } + if (not is_same) { + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("sum_of_Vh Vh -> Vh") { { @@ -2041,6 +2337,71 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("trace Vh -> Vh") + { + { + std::shared_ptr p_fu = trace(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R2x2_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = trace(p_R3x3_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != trace(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("inverse Vh -> Vh") { { @@ -2108,6 +2469,73 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); } + SECTION("transpose Vh -> Vh") + { + { + std::shared_ptr p_fu = transpose(p_R1x1_u); + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*p_fu); + + auto values = p_R1x1_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != transpose(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R2x2_u); + constexpr size_t nb_row = 2; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R2x2_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != transpose(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + { + std::shared_ptr p_fu = transpose(p_R3x3_u); + constexpr size_t nb_row = 3; + + REQUIRE(p_fu.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu)); + + const auto& fu = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<nb_row>>&>(*p_fu); + + auto values = p_R3x3_u->cellValues(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + if (fu[cell_id] != transpose(values[cell_id])) { + is_same = false; + break; + } + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + SECTION("sum_of_Vh Vh -> Vh") { { diff --git a/tests/test_MathModule.cpp b/tests/test_MathModule.cpp index cea6c79519fe3530f64e3adc0cb1fd5fc6c57274..2cb3481b1e6cde7561733d8ea03decd46153db9d 100644 --- a/tests/test_MathModule.cpp +++ b/tests/test_MathModule.cpp @@ -13,7 +13,7 @@ TEST_CASE("MathModule", "[language]") MathModule math_module; const auto& name_builtin_function = math_module.getNameBuiltinFunctionMap(); - REQUIRE(name_builtin_function.size() == 36); + REQUIRE(name_builtin_function.size() == 42); SECTION("Z -> N") { @@ -509,6 +509,56 @@ TEST_CASE("MathModule", "[language]") const double result = det(arg); REQUIRE(std::get<double>(result_variant) == result); } + + SECTION("trace:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("trace:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("trace:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } } SECTION("R^dxd -> R^dxd") @@ -562,5 +612,55 @@ TEST_CASE("MathModule", "[language]") const TinyMatrix<3> result = inverse(arg); REQUIRE(std::get<TinyMatrix<3>>(result_variant) == result); } + + SECTION("transpose:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<1> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<1>>(result_variant) == result); + } + + SECTION("transpose:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<2> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<2>>(result_variant) == result); + } + + SECTION("transpose:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<3> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<3>>(result_variant) == result); + } } } diff --git a/tests/test_TinyMatrix.cpp b/tests/test_TinyMatrix.cpp index 2f4c09d4ad9ce1dbb5e3d856d8737d27344459f2..f6f09cf55dd2ad1ffef55c9275b989c203598f7e 100644 --- a/tests/test_TinyMatrix.cpp +++ b/tests/test_TinyMatrix.cpp @@ -194,6 +194,17 @@ TEST_CASE("TinyMatrix", "[algebra]") REQUIRE(det(TinyMatrix<4>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 0); } + SECTION("checking for trace calculations") + { + REQUIRE(trace(TinyMatrix<1, 1, int>(6)) == 6); + REQUIRE(trace(TinyMatrix<2, 2, int>(5, 1, -3, 6)) == 5 + 6); + REQUIRE(trace(TinyMatrix<3, 3, int>(1, 1, 1, 1, 2, 1, 2, 1, 3)) == 1 + 2 + 3); + REQUIRE(trace(TinyMatrix<3, 3, int>(6, 5, 3, 8, 34, 6, 35, 6, 7)) == 6 + 34 + 7); + REQUIRE(trace(TinyMatrix<4>(1, 2.3, 7, -6.2, 3, 4, 9, 1, 4.1, 5, 2, -3, 2, 27, 3, 17.5)) == + Catch::Approx(1 + 4 + 2 + 17.5).epsilon(1E-14)); + REQUIRE(trace(TinyMatrix<4>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 1 + 0 + 1 + 2); + } + SECTION("checking for inverse calculations") { {