diff --git a/src/algebra/CRSMatrix.hpp b/src/algebra/CRSMatrix.hpp index 1f7fe37e571447b104b81ff61cf38dcf2144d897..c2df50e454fa883bf402c56ac81f8617cf9b7742 100644 --- a/src/algebra/CRSMatrix.hpp +++ b/src/algebra/CRSMatrix.hpp @@ -27,6 +27,117 @@ class CRSMatrix Array<const DataType> m_values; Array<const IndexType> m_column_indices; + template <typename DataType2, typename BinOp> + CRSMatrix + _binOp(const CRSMatrix& A, const CRSMatrix<DataType2, IndexType>& B) const + { + static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), + "Cannot add matrices of different types"); + Assert(A.numberOfRows() == B.numberOfRows() and A.numberOfColumns() == B.numberOfColumns(), + "cannot apply inner binary operator on matrices of different sizes"); + + Array<int> non_zeros(A.m_nb_rows); + for (IndexType i_row = 0; i_row < A.m_nb_rows; ++i_row) { + const auto A_row_begin = A.m_row_map[i_row]; + const auto A_row_end = A.m_row_map[i_row + 1]; + const auto B_row_begin = B.m_row_map[i_row]; + const auto B_row_end = B.m_row_map[i_row + 1]; + IndexType i_row_A = A_row_begin; + IndexType i_row_B = B_row_begin; + + int row_nb_columns = 0; + + while (i_row_A < A_row_end or i_row_B < B_row_end) { + const IndexType A_column_idx = [&] { + if (i_row_A < A_row_end) { + return A.m_column_indices[i_row_A]; + } else { + return std::numeric_limits<IndexType>::max(); + } + }(); + + const IndexType B_column_idx = [&] { + if (i_row_B < B_row_end) { + return B.m_column_indices[i_row_B]; + } else { + return std::numeric_limits<IndexType>::max(); + } + }(); + + if (A_column_idx == B_column_idx) { + ++row_nb_columns; + ++i_row_A; + ++i_row_B; + } else if (A_column_idx < B_column_idx) { + ++row_nb_columns; + ++i_row_A; + } else { + Assert(B_column_idx < A_column_idx); + ++row_nb_columns; + ++i_row_B; + } + } + non_zeros[i_row] = row_nb_columns; + } + + Array<IndexType> row_map(A.m_nb_rows + 1); + row_map[0] = 0; + for (IndexType i = 0; i < A.m_nb_rows; ++i) { + row_map[i + 1] = row_map[i] + non_zeros[i]; + } + + const IndexType nb_values = row_map[row_map.size() - 1]; + Array<DataType> values(nb_values); + Array<IndexType> column_indices(nb_values); + + IndexType i_value = 0; + for (IndexType i_row = 0; i_row < A.m_nb_rows; ++i_row) { + const auto A_row_begin = A.m_row_map[i_row]; + const auto A_row_end = A.m_row_map[i_row + 1]; + const auto B_row_begin = B.m_row_map[i_row]; + const auto B_row_end = B.m_row_map[i_row + 1]; + IndexType i_row_A = A_row_begin; + IndexType i_row_B = B_row_begin; + + while (i_row_A < A_row_end or i_row_B < B_row_end) { + const IndexType A_column_idx = [&] { + if (i_row_A < A_row_end) { + return A.m_column_indices[i_row_A]; + } else { + return std::numeric_limits<IndexType>::max(); + } + }(); + + const IndexType B_column_idx = [&] { + if (i_row_B < B_row_end) { + return B.m_column_indices[i_row_B]; + } else { + return std::numeric_limits<IndexType>::max(); + } + }(); + + if (A_column_idx == B_column_idx) { + column_indices[i_value] = A_column_idx; + values[i_value] = BinOp()(A.m_values[i_row_A], B.m_values[i_row_B]); + ++i_row_A; + ++i_row_B; + } else if (A_column_idx < B_column_idx) { + column_indices[i_value] = A_column_idx; + values[i_value] = BinOp()(A.m_values[i_row_A], 0); + ++i_row_A; + } else { + Assert(B_column_idx < A_column_idx); + column_indices[i_value] = B_column_idx; + values[i_value] = BinOp()(0, B.m_values[i_row_B]); + ++i_row_B; + } + ++i_value; + } + } + + return CRSMatrix(A.m_nb_rows, A.m_nb_columns, row_map, values, column_indices); + } + public: PUGS_INLINE bool @@ -72,9 +183,9 @@ class CRSMatrix operator*(const Vector<DataType2>& x) const { static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), - "Cannot multiply matrix and vector of different type"); + "Cannot multiply matrix and vector of different types"); - Assert(x.size() - m_nb_columns == 0); + Assert(x.size() - m_nb_columns == 0, "cannot compute product: incompatible matrix and vector sizes"); Vector<MutableDataType> Ax(m_nb_rows); @@ -92,6 +203,20 @@ class CRSMatrix return Ax; } + template <typename DataType2> + CRSMatrix<DataType> + operator+(const CRSMatrix<DataType2>& B) const + { + return this->_binOp<DataType2, std::plus<DataType>>(*this, B); + } + + template <typename DataType2> + CRSMatrix<DataType> + operator-(const CRSMatrix<DataType2>& B) const + { + return this->_binOp<DataType2, std::minus<DataType>>(*this, B); + } + friend PUGS_INLINE std::ostream& operator<<(std::ostream& os, const CRSMatrix& A) { diff --git a/src/algebra/CRSMatrixDescriptor.hpp b/src/algebra/CRSMatrixDescriptor.hpp index 4be6a323630a9845ecb142b32f73ceca5d6dc7f6..9c2e0894152ead3e01d4e38396f581a05c283fa2 100644 --- a/src/algebra/CRSMatrixDescriptor.hpp +++ b/src/algebra/CRSMatrixDescriptor.hpp @@ -248,9 +248,9 @@ class CRSMatrixDescriptor } } - CRSMatrixDescriptor(const IndexType nb_rows, const IndexType nb_columns, const Array<IndexType>& non_zeros) - : m_nb_rows{nb_rows}, - m_nb_columns{nb_columns}, + CRSMatrixDescriptor(const size_t nb_rows, const size_t nb_columns, const Array<IndexType>& non_zeros) + : m_nb_rows(nb_rows), + m_nb_columns(nb_columns), m_row_map{this->_computeRowMap(non_zeros)}, m_values(m_row_map[m_row_map.size() - 1]), m_column_indices(m_row_map[m_row_map.size() - 1]), @@ -268,6 +268,10 @@ class CRSMatrixDescriptor } } + CRSMatrixDescriptor(const size_t nb_rows, const Array<IndexType>& non_zeros) + : CRSMatrixDescriptor(nb_rows, nb_rows, non_zeros) + {} + ~CRSMatrixDescriptor() = default; }; diff --git a/src/algebra/EigenvalueSolver.cpp b/src/algebra/EigenvalueSolver.cpp index 1d96d01f992d22a8346417dce85750d9b186749b..6125e67e6c5fad94a122028ce78bd78ef7b12e6c 100644 --- a/src/algebra/EigenvalueSolver.cpp +++ b/src/algebra/EigenvalueSolver.cpp @@ -63,7 +63,7 @@ struct EigenvalueSolver::Internals }; void -EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, Array<double>& eigenvalues) +EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, SmallArray<double>& eigenvalues) { EPS eps; @@ -76,7 +76,7 @@ EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, Arr PetscInt nb_eigenvalues; EPSGetDimensions(eps, &nb_eigenvalues, nullptr, nullptr); - eigenvalues = Array<double>(nb_eigenvalues); + eigenvalues = SmallArray<double>(nb_eigenvalues); for (PetscInt i = 0; i < nb_eigenvalues; ++i) { EPSGetEigenpair(eps, i, &(eigenvalues[i]), nullptr, nullptr, nullptr); } @@ -86,8 +86,8 @@ EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, Arr void EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, - Array<double>& eigenvalues, - std::vector<Vector<double>>& eigenvector_list) + SmallArray<double>& eigenvalues, + std::vector<SmallVector<double>>& eigenvector_list) { EPS eps; @@ -100,11 +100,11 @@ EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, PetscInt nb_eigenvalues; EPSGetDimensions(eps, &nb_eigenvalues, nullptr, nullptr); - eigenvalues = Array<double>(nb_eigenvalues); + eigenvalues = SmallArray<double>(nb_eigenvalues); eigenvector_list.reserve(nb_eigenvalues); for (PetscInt i = 0; i < nb_eigenvalues; ++i) { Vec Vr; - Vector<double> eigenvector{A.numberOfRows()}; + SmallVector<double> eigenvector{A.numberOfRows()}; VecCreateSeqWithArray(PETSC_COMM_SELF, 1, A.numberOfRows(), &(eigenvector[0]), &Vr); EPSGetEigenpair(eps, i, &(eigenvalues[i]), nullptr, Vr, nullptr); VecDestroy(&Vr); @@ -116,8 +116,8 @@ EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, void EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, - Array<double>& eigenvalues, - DenseMatrix<double>& P) + SmallArray<double>& eigenvalues, + SmallMatrix<double>& P) { EPS eps; @@ -130,8 +130,8 @@ EigenvalueSolver::computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, PetscInt nb_eigenvalues; EPSGetDimensions(eps, &nb_eigenvalues, nullptr, nullptr); - eigenvalues = Array<double>(nb_eigenvalues); - P = DenseMatrix<double>(nb_eigenvalues, nb_eigenvalues); + eigenvalues = SmallArray<double>(nb_eigenvalues); + P = SmallMatrix<double>(nb_eigenvalues, nb_eigenvalues); Array<double> eigenvector(nb_eigenvalues); for (PetscInt i = 0; i < nb_eigenvalues; ++i) { diff --git a/src/algebra/EigenvalueSolver.hpp b/src/algebra/EigenvalueSolver.hpp index a9dd941b9bd87d3f0a79be5f36e5683ae8a1afb6..a9b462509514ace4b736424c65f7c9abe4572f26 100644 --- a/src/algebra/EigenvalueSolver.hpp +++ b/src/algebra/EigenvalueSolver.hpp @@ -3,10 +3,10 @@ #include <algebra/PETScUtils.hpp> -#include <algebra/DenseMatrix.hpp> -#include <algebra/Vector.hpp> -#include <utils/Array.hpp> +#include <algebra/SmallMatrix.hpp> +#include <algebra/SmallVector.hpp> #include <utils/Exceptions.hpp> +#include <utils/SmallArray.hpp> class EigenvalueSolver { @@ -14,19 +14,21 @@ class EigenvalueSolver struct Internals; #ifdef PUGS_HAS_SLEPC - void computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, Array<double>& eigenvalues); + void computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, SmallArray<double>& eigenvalues); void computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, - Array<double>& eigenvalues, - std::vector<Vector<double>>& eigenvectors); + SmallArray<double>& eigenvalues, + std::vector<SmallVector<double>>& eigenvectors); - void computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, Array<double>& eigenvalues, DenseMatrix<double>& P); + void computeForSymmetricMatrix(const PETScAijMatrixEmbedder& A, + SmallArray<double>& eigenvalues, + SmallMatrix<double>& P); #endif // PUGS_HAS_SLEPC public: template <typename MatrixType> void - computeForSymmetricMatrix([[maybe_unused]] const MatrixType& A, [[maybe_unused]] Array<double>& eigenvalues) + computeForSymmetricMatrix([[maybe_unused]] const MatrixType& A, [[maybe_unused]] SmallArray<double>& eigenvalues) { #ifdef PUGS_HAS_SLEPC this->computeForSymmetricMatrix(PETScAijMatrixEmbedder{A}, eigenvalues); @@ -38,8 +40,8 @@ class EigenvalueSolver template <typename MatrixType> void computeForSymmetricMatrix([[maybe_unused]] const MatrixType& A, - [[maybe_unused]] Array<double>& eigenvalues, - [[maybe_unused]] std::vector<Vector<double>>& eigenvectors) + [[maybe_unused]] SmallArray<double>& eigenvalues, + [[maybe_unused]] std::vector<SmallVector<double>>& eigenvectors) { #ifdef PUGS_HAS_SLEPC this->computeForSymmetricMatrix(PETScAijMatrixEmbedder{A}, eigenvalues, eigenvectors); @@ -51,8 +53,8 @@ class EigenvalueSolver template <typename MatrixType> void computeForSymmetricMatrix([[maybe_unused]] const MatrixType& A, - [[maybe_unused]] Array<double>& eigenvalues, - [[maybe_unused]] DenseMatrix<double>& P) + [[maybe_unused]] SmallArray<double>& eigenvalues, + [[maybe_unused]] SmallMatrix<double>& P) { #ifdef PUGS_HAS_SLEPC this->computeForSymmetricMatrix(PETScAijMatrixEmbedder{A}, eigenvalues, P); diff --git a/src/algebra/LinearSolver.cpp b/src/algebra/LinearSolver.cpp index 3cffca7298b0a7377996c130195ac9e43a66ca44..99bff927c744c9ba216e575dcc914a2bdba1d4da 100644 --- a/src/algebra/LinearSolver.cpp +++ b/src/algebra/LinearSolver.cpp @@ -66,7 +66,7 @@ struct LinearSolver::Internals case LSMethod::bicgstab2: case LSMethod::gmres: case LSMethod::lu: - case LSMethod::choleski: { + case LSMethod::cholesky: { break; } // LCOV_EXCL_START @@ -97,7 +97,7 @@ struct LinearSolver::Internals case LSPrecond::none: case LSPrecond::amg: case LSPrecond::diagonal: - case LSPrecond::incomplete_choleski: + case LSPrecond::incomplete_cholesky: case LSPrecond::incomplete_LU: { break; } @@ -221,9 +221,10 @@ struct LinearSolver::Internals direct_solver = true; break; } - case LSMethod::choleski: { + case LSMethod::cholesky: { KSPSetType(ksp, KSPPREONLY); PCSetType(pc, PCCHOLESKY); + PCFactorSetShiftType(pc, MAT_SHIFT_NONZERO); direct_solver = true; break; } @@ -248,7 +249,7 @@ struct LinearSolver::Internals PCSetType(pc, PCILU); break; } - case LSPrecond::incomplete_choleski: { + case LSPrecond::incomplete_cholesky: { PCSetType(pc, PCICC); break; } @@ -335,7 +336,7 @@ LinearSolver::solveLocalSystem(const CRSMatrix<double, int>& A, Vector<double>& } void -LinearSolver::solveLocalSystem(const DenseMatrix<double>& A, Vector<double>& x, const Vector<const double>& b) +LinearSolver::solveLocalSystem(const SmallMatrix<double>& A, SmallVector<double>& x, const SmallVector<const double>& b) { Internals::solveLocalSystem(A, x, b, m_options); } diff --git a/src/algebra/LinearSolver.hpp b/src/algebra/LinearSolver.hpp index 1ab43a1405ee312fdb9255c6b1f4508ade4e168e..e90402c8ddc78c9426f97300ab6b10730b4c503b 100644 --- a/src/algebra/LinearSolver.hpp +++ b/src/algebra/LinearSolver.hpp @@ -2,8 +2,8 @@ #define LINEAR_SOLVER_HPP #include <algebra/CRSMatrix.hpp> -#include <algebra/DenseMatrix.hpp> #include <algebra/LinearSolverOptions.hpp> +#include <algebra/SmallMatrix.hpp> #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> #include <algebra/Vector.hpp> @@ -24,13 +24,10 @@ class LinearSolver void solveLocalSystem(const TinyMatrix<N>& A, TinyVector<N>& x, const TinyVector<N>& b) { - DenseMatrix A_dense{A}; - Vector<double> x_vector{N}; - Vector<double> b_vector{N}; - for (size_t i = 0; i < N; ++i) { - x_vector[i] = x[i]; - b_vector[i] = b[i]; - } + SmallMatrix A_dense{A}; + + SmallVector x_vector{x}; + SmallVector b_vector{b}; this->solveLocalSystem(A_dense, x_vector, b_vector); @@ -40,7 +37,7 @@ class LinearSolver } void solveLocalSystem(const CRSMatrix<double, int>& A, Vector<double>& x, const Vector<const double>& b); - void solveLocalSystem(const DenseMatrix<double>& A, Vector<double>& x, const Vector<const double>& b); + void solveLocalSystem(const SmallMatrix<double>& A, SmallVector<double>& x, const SmallVector<const double>& b); LinearSolver(); LinearSolver(const LinearSolverOptions& options); diff --git a/src/algebra/LinearSolverOptions.hpp b/src/algebra/LinearSolverOptions.hpp index 014ee86d64bee4d2a128e820ab8876450a195369..940ce1ed63a2dbbf046022aee838c3f9438c1906 100644 --- a/src/algebra/LinearSolverOptions.hpp +++ b/src/algebra/LinearSolverOptions.hpp @@ -24,7 +24,7 @@ enum class LSMethod : int8_t bicgstab2, gmres, lu, - choleski, + cholesky, // LS__end }; @@ -35,7 +35,7 @@ enum class LSPrecond : int8_t // none = LS__begin, diagonal, - incomplete_choleski, + incomplete_cholesky, incomplete_LU, amg, // @@ -77,8 +77,8 @@ name(const LSMethod method) case LSMethod::lu: { return "LU"; } - case LSMethod::choleski: { - return "Choleski"; + case LSMethod::cholesky: { + return "Cholesky"; } case LSMethod::LS__end: { } @@ -96,8 +96,8 @@ name(const LSPrecond precond) case LSPrecond::diagonal: { return "diagonal"; } - case LSPrecond::incomplete_choleski: { - return "ICholeski"; + case LSPrecond::incomplete_cholesky: { + return "ICholesky"; } case LSPrecond::incomplete_LU: { return "ILU"; diff --git a/src/algebra/PETScUtils.cpp b/src/algebra/PETScUtils.cpp index 63c5a68ac5f3a248ba7e5bc51bf381f5418dbe4a..29904103577a02f454b6c1fbb91f90fb637b8bec 100644 --- a/src/algebra/PETScUtils.cpp +++ b/src/algebra/PETScUtils.cpp @@ -12,24 +12,25 @@ PETScAijMatrixEmbedder::PETScAijMatrixEmbedder(const size_t nb_rows, const size_ MatSetUp(m_petscMat); { - Array<PetscInt> row_indices(nb_rows); + SmallArray<PetscInt> row_indices(nb_rows); for (size_t i = 0; i < nb_rows; ++i) { row_indices[i] = i; } - m_row_indices = row_indices; + m_small_row_indices = row_indices; } if (nb_rows == nb_columns) { - m_column_indices = m_row_indices; + m_small_column_indices = m_small_row_indices; } else { - Array<PetscInt> column_indices(nb_columns); + SmallArray<PetscInt> column_indices(nb_columns); for (size_t i = 0; i < nb_columns; ++i) { column_indices[i] = i; } - m_column_indices = column_indices; + m_small_column_indices = column_indices; } - MatSetValuesBlocked(m_petscMat, nb_rows, &(m_row_indices[0]), nb_columns, &(m_column_indices[0]), A, INSERT_VALUES); + MatSetValuesBlocked(m_petscMat, nb_rows, &(m_small_row_indices[0]), nb_columns, &(m_small_column_indices[0]), A, + INSERT_VALUES); MatAssemblyBegin(m_petscMat, MAT_FINAL_ASSEMBLY); MatAssemblyEnd(m_petscMat, MAT_FINAL_ASSEMBLY); @@ -42,9 +43,10 @@ PETScAijMatrixEmbedder::PETScAijMatrixEmbedder(const CRSMatrix<double, int>& A) "index type conversion is not implemented yet"); static_assert(std::is_same_v<PetscScalar, typename std::decay_t<decltype(A)>::data_type>, "value type conversion is not implemented yet"); - m_values = copy(A.values()); - m_row_indices = copy(A.rowMap()); - m_column_indices = copy(A.columnIndices()); + + m_values = A.values(); + m_row_indices = A.rowMap(); + m_column_indices = A.columnIndices(); MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, A.numberOfRows(), A.numberOfColumns(), const_cast<PetscInt*>(&m_row_indices[0]), // These ugly const_cast diff --git a/src/algebra/PETScUtils.hpp b/src/algebra/PETScUtils.hpp index 3e7cff5b87b843f84575ed9b2af4a425e6ed4f5a..c4db9ee5910ef8e58333dbfb6dc20c8a1987bb46 100644 --- a/src/algebra/PETScUtils.hpp +++ b/src/algebra/PETScUtils.hpp @@ -6,7 +6,7 @@ #ifdef PUGS_HAS_PETSC #include <algebra/CRSMatrix.hpp> -#include <algebra/DenseMatrix.hpp> +#include <algebra/SmallMatrix.hpp> #include <algebra/TinyMatrix.hpp> #include <petsc.h> @@ -18,6 +18,8 @@ class PETScAijMatrixEmbedder Array<const PetscScalar> m_values; Array<const PetscInt> m_row_indices; Array<const PetscInt> m_column_indices; + SmallArray<const PetscInt> m_small_row_indices; + SmallArray<const PetscInt> m_small_column_indices; const size_t m_nb_rows; const size_t m_nb_columns; @@ -54,7 +56,7 @@ class PETScAijMatrixEmbedder PETScAijMatrixEmbedder(const TinyMatrix<N>& A) : PETScAijMatrixEmbedder{N, N, &A(0, 0)} {} - PETScAijMatrixEmbedder(const DenseMatrix<double>& A) + PETScAijMatrixEmbedder(const SmallMatrix<double>& A) : PETScAijMatrixEmbedder{A.numberOfRows(), A.numberOfColumns(), &A(0, 0)} {} diff --git a/src/algebra/DenseMatrix.hpp b/src/algebra/SmallMatrix.hpp similarity index 62% rename from src/algebra/DenseMatrix.hpp rename to src/algebra/SmallMatrix.hpp index 952342fedbd04246879356d67425275d471af2c9..d0d6ee329f02c41626900384c794d1cfa490089c 100644 --- a/src/algebra/DenseMatrix.hpp +++ b/src/algebra/SmallMatrix.hpp @@ -1,18 +1,18 @@ -#ifndef DENSE_MATRIX_HPP -#define DENSE_MATRIX_HPP +#ifndef SMALL_MATRIX_HPP +#define SMALL_MATRIX_HPP +#include <algebra/SmallVector.hpp> #include <algebra/TinyMatrix.hpp> -#include <algebra/Vector.hpp> -#include <utils/Array.hpp> #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> #include <utils/PugsUtils.hpp> +#include <utils/SmallArray.hpp> #include <utils/Types.hpp> #include <iostream> template <typename DataType> -class DenseMatrix // LCOV_EXCL_LINE +class [[nodiscard]] SmallMatrix // LCOV_EXCL_LINE { public: using data_type = DataType; @@ -21,32 +21,29 @@ class DenseMatrix // LCOV_EXCL_LINE private: size_t m_nb_rows; size_t m_nb_columns; - Array<DataType> m_values; + SmallArray<DataType> m_values; static_assert(std::is_same_v<typename decltype(m_values)::index_type, index_type>); - static_assert(std::is_arithmetic_v<DataType>, "Dense matrices expect arithmetic data"); + static_assert(std::is_arithmetic_v<DataType>, "Small matrices expect arithmetic data"); // Allows const version to access our data - friend DenseMatrix<std::add_const_t<DataType>>; + friend SmallMatrix<std::add_const_t<DataType>>; public: PUGS_INLINE - bool - isSquare() const noexcept + bool isSquare() const noexcept { return m_nb_rows == m_nb_columns; } - friend PUGS_INLINE DenseMatrix<std::remove_const_t<DataType>> - copy(const DenseMatrix& A) noexcept + friend PUGS_INLINE SmallMatrix<std::remove_const_t<DataType>> copy(const SmallMatrix& A) noexcept { return {A.m_nb_rows, A.m_nb_columns, copy(A.m_values)}; } - friend PUGS_INLINE DenseMatrix<std::remove_const_t<DataType>> - transpose(const DenseMatrix& A) + friend PUGS_INLINE SmallMatrix<std::remove_const_t<DataType>> transpose(const SmallMatrix& A) { - DenseMatrix<std::remove_const_t<DataType>> A_transpose{A.m_nb_columns, A.m_nb_rows}; + SmallMatrix<std::remove_const_t<DataType>> A_transpose{A.m_nb_columns, A.m_nb_rows}; for (size_t i = 0; i < A.m_nb_rows; ++i) { for (size_t j = 0; j < A.m_nb_columns; ++j) { A_transpose(j, i) = A(i, j); @@ -55,22 +52,20 @@ class DenseMatrix // LCOV_EXCL_LINE return A_transpose; } - friend PUGS_INLINE DenseMatrix - operator*(const DataType& a, const DenseMatrix& A) + friend PUGS_INLINE SmallMatrix operator*(const DataType& a, const SmallMatrix& A) { - DenseMatrix<std::remove_const_t<DataType>> aA = copy(A); + SmallMatrix<std::remove_const_t<DataType>> aA = copy(A); return aA *= a; } template <typename DataType2> - PUGS_INLINE Vector<std::remove_const_t<DataType>> - operator*(const Vector<DataType2>& x) const + PUGS_INLINE SmallVector<std::remove_const_t<DataType>> operator*(const SmallVector<DataType2>& x) const { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); Assert(m_nb_columns == x.size(), "cannot compute matrix-vector product: incompatible sizes"); - const DenseMatrix& A = *this; - Vector<std::remove_const_t<DataType>> Ax{m_nb_rows}; + const SmallMatrix& A = *this; + SmallVector<std::remove_const_t<DataType>> Ax{m_nb_rows}; for (size_t i = 0; i < m_nb_rows; ++i) { std::remove_const_t<DataType> Axi = A(i, 0) * x[0]; for (size_t j = 1; j < m_nb_columns; ++j) { @@ -82,14 +77,13 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix<std::remove_const_t<DataType>> - operator*(const DenseMatrix<DataType2>& B) const + PUGS_INLINE SmallMatrix<std::remove_const_t<DataType>> operator*(const SmallMatrix<DataType2>& B) const { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); Assert(m_nb_columns == B.numberOfRows(), "cannot compute matrix product: incompatible sizes"); - const DenseMatrix& A = *this; - DenseMatrix<std::remove_const_t<DataType>> AB{m_nb_rows, B.numberOfColumns()}; + const SmallMatrix& A = *this; + SmallMatrix<std::remove_const_t<DataType>> AB{m_nb_rows, B.numberOfColumns()}; for (size_t i = 0; i < m_nb_rows; ++i) { for (size_t j = 0; j < B.numberOfColumns(); ++j) { @@ -104,16 +98,14 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix& - operator/=(const DataType2& a) + PUGS_INLINE SmallMatrix& operator/=(const DataType2& a) { const auto inv_a = 1. / a; return (*this) *= inv_a; } template <typename DataType2> - PUGS_INLINE DenseMatrix& - operator*=(const DataType2& a) + PUGS_INLINE SmallMatrix& operator*=(const DataType2& a) { parallel_for( m_values.size(), PUGS_LAMBDA(index_type i) { m_values[i] *= a; }); @@ -121,8 +113,7 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix& - operator-=(const DenseMatrix<DataType2>& B) + PUGS_INLINE SmallMatrix& operator-=(const SmallMatrix<DataType2>& B) { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); @@ -135,8 +126,7 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix& - operator+=(const DenseMatrix<DataType2>& B) + PUGS_INLINE SmallMatrix& operator+=(const SmallMatrix<DataType2>& B) { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); @@ -148,15 +138,14 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix<std::remove_const_t<DataType>> - operator+(const DenseMatrix<DataType2>& B) const + PUGS_INLINE SmallMatrix<std::remove_const_t<DataType>> operator+(const SmallMatrix<DataType2>& B) const { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); Assert((m_nb_rows == B.numberOfRows()) and (m_nb_columns == B.numberOfColumns()), "cannot compute matrix sum: incompatible sizes"); - DenseMatrix<std::remove_const_t<DataType>> sum{B.numberOfRows(), B.numberOfColumns()}; + SmallMatrix<std::remove_const_t<DataType>> sum{B.numberOfRows(), B.numberOfColumns()}; parallel_for( m_values.size(), PUGS_LAMBDA(index_type i) { sum.m_values[i] = m_values[i] + B.m_values[i]; }); @@ -165,15 +154,14 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix<std::remove_const_t<DataType>> - operator-(const DenseMatrix<DataType2>& B) const + PUGS_INLINE SmallMatrix<std::remove_const_t<DataType>> operator-(const SmallMatrix<DataType2>& B) const { static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "incompatible data types"); Assert((m_nb_rows == B.numberOfRows()) and (m_nb_columns == B.numberOfColumns()), "cannot compute matrix difference: incompatible sizes"); - DenseMatrix<std::remove_const_t<DataType>> difference{B.numberOfRows(), B.numberOfColumns()}; + SmallMatrix<std::remove_const_t<DataType>> difference{B.numberOfRows(), B.numberOfColumns()}; parallel_for( m_values.size(), PUGS_LAMBDA(index_type i) { difference.m_values[i] = m_values[i] - B.m_values[i]; }); @@ -182,40 +170,36 @@ class DenseMatrix // LCOV_EXCL_LINE } PUGS_INLINE - DataType& - operator()(index_type i, index_type j) const noexcept(NO_ASSERT) + DataType& operator()(index_type i, index_type j) const noexcept(NO_ASSERT) { Assert(i < m_nb_rows and j < m_nb_columns, "cannot access element: invalid indices"); return m_values[i * m_nb_columns + j]; } PUGS_INLINE - size_t - numberOfRows() const noexcept + size_t numberOfRows() const noexcept { return m_nb_rows; } PUGS_INLINE - size_t - numberOfColumns() const noexcept + size_t numberOfColumns() const noexcept { return m_nb_columns; } - PUGS_INLINE void - fill(const DataType& value) noexcept + PUGS_INLINE void fill(const DataType& value) noexcept { m_values.fill(value); } - PUGS_INLINE DenseMatrix& operator=(ZeroType) noexcept + PUGS_INLINE SmallMatrix& operator=(ZeroType) noexcept { m_values.fill(0); return *this; } - PUGS_INLINE DenseMatrix& operator=(IdentityType) noexcept(NO_ASSERT) + PUGS_INLINE SmallMatrix& operator=(IdentityType) noexcept(NO_ASSERT) { Assert(m_nb_rows == m_nb_columns, "identity must be a square matrix"); @@ -226,15 +210,14 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - PUGS_INLINE DenseMatrix& - operator=(const DenseMatrix<DataType2>& A) noexcept + PUGS_INLINE SmallMatrix& operator=(const SmallMatrix<DataType2>& A) noexcept { // ensures that DataType is the same as source DataType2 static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), - "Cannot assign DenseMatrix of different type"); + "Cannot assign SmallMatrix of different type"); // ensures that const is not lost through copy static_assert(((std::is_const<DataType2>() and std::is_const<DataType>()) or not std::is_const<DataType2>()), - "Cannot assign DenseMatrix of const to DenseMatrix of non-const"); + "Cannot assign SmallMatrix of const to SmallMatrix of non-const"); m_nb_rows = A.m_nb_rows; m_nb_columns = A.m_nb_columns; @@ -243,13 +226,12 @@ class DenseMatrix // LCOV_EXCL_LINE } PUGS_INLINE - DenseMatrix& operator=(const DenseMatrix&) = default; + SmallMatrix& operator=(const SmallMatrix&) = default; PUGS_INLINE - DenseMatrix& operator=(DenseMatrix&&) = default; + SmallMatrix& operator=(SmallMatrix&&) = default; - friend std::ostream& - operator<<(std::ostream& os, const DenseMatrix& A) + friend std::ostream& operator<<(std::ostream& os, const SmallMatrix& A) { for (size_t i = 0; i < A.numberOfRows(); ++i) { os << i << '|'; @@ -262,51 +244,42 @@ class DenseMatrix // LCOV_EXCL_LINE } template <typename DataType2> - DenseMatrix(const DenseMatrix<DataType2>& A) + SmallMatrix(const SmallMatrix<DataType2>& A) { // ensures that DataType is the same as source DataType2 static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), - "Cannot assign DenseMatrix of different type"); + "Cannot assign SmallMatrix of different type"); // ensures that const is not lost through copy static_assert(((std::is_const<DataType2>() and std::is_const<DataType>()) or not std::is_const<DataType2>()), - "Cannot assign DenseMatrix of const to DenseMatrix of non-const"); + "Cannot assign SmallMatrix of const to SmallMatrix of non-const"); this->operator=(A); } - DenseMatrix(const DenseMatrix&) = default; + SmallMatrix(const SmallMatrix&) = default; - DenseMatrix(DenseMatrix&&) = default; + SmallMatrix(SmallMatrix &&) = default; - explicit DenseMatrix(size_t nb_rows, size_t nb_columns) noexcept + explicit SmallMatrix(size_t nb_rows, size_t nb_columns) noexcept : m_nb_rows{nb_rows}, m_nb_columns{nb_columns}, m_values{nb_rows * nb_columns} {} - explicit DenseMatrix(size_t nb_rows) noexcept : m_nb_rows{nb_rows}, m_nb_columns{nb_rows}, m_values{nb_rows * nb_rows} + explicit SmallMatrix(size_t nb_rows) noexcept : m_nb_rows{nb_rows}, m_nb_columns{nb_rows}, m_values{nb_rows * nb_rows} {} - template <size_t N> - explicit DenseMatrix(const TinyMatrix<N, DataType>& M) noexcept : m_nb_rows{N}, m_nb_columns{N}, m_values{N * N} + template <size_t M, size_t N> + explicit SmallMatrix(const TinyMatrix<M, N, DataType>& A) noexcept : m_nb_rows{M}, m_nb_columns{N}, m_values{M * N} { - parallel_for( - N, PUGS_LAMBDA(const index_type i) { - for (size_t j = 0; j < N; ++j) { - m_values[i * N + j] = M(i, j); - } - }); + for (size_t i = 0; i < M; ++i) { + for (size_t j = 0; j < N; ++j) { + m_values[i * N + j] = A(i, j); + } + } } - DenseMatrix() noexcept : m_nb_rows{0}, m_nb_columns{0} {} + SmallMatrix() noexcept : m_nb_rows{0}, m_nb_columns{0} {} - private: - DenseMatrix(size_t nb_rows, size_t nb_columns, const Array<DataType> values) noexcept(NO_ASSERT) - : m_nb_rows{nb_rows}, m_nb_columns{nb_columns}, m_values{values} - { - Assert(m_values.size() == m_nb_rows * m_nb_columns, "cannot create matrix: incorrect number of values"); - } - - public: - ~DenseMatrix() = default; + ~SmallMatrix() = default; }; -#endif // DENSE_MATRIX_HPP +#endif // SMALL_MATRIX_HPP diff --git a/src/algebra/SmallVector.hpp b/src/algebra/SmallVector.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d20bb48f4cdb700f61a0881898fb5273217693aa --- /dev/null +++ b/src/algebra/SmallVector.hpp @@ -0,0 +1,216 @@ +#ifndef SMALL_VECTOR_HPP +#define SMALL_VECTOR_HPP + +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> +#include <utils/PugsUtils.hpp> +#include <utils/SmallArray.hpp> +#include <utils/Types.hpp> + +template <typename DataType> +class SmallVector // LCOV_EXCL_LINE +{ + public: + using data_type = DataType; + using index_type = size_t; + + private: + SmallArray<DataType> m_values; + + static_assert(std::is_same_v<typename decltype(m_values)::index_type, index_type>); + static_assert(std::is_arithmetic_v<DataType>, "SmallVector is only defined for arithmetic values"); + + // Allows const version to access our data + friend SmallVector<std::add_const_t<DataType>>; + + public: + friend std::ostream& + operator<<(std::ostream& os, const SmallVector& x) + { + return os << x.m_values; + } + + friend SmallVector<std::remove_const_t<DataType>> + copy(const SmallVector& x) + { + auto values = copy(x.m_values); + + SmallVector<std::remove_const_t<DataType>> x_copy{0}; + x_copy.m_values = values; + return x_copy; + } + + friend SmallVector operator*(const DataType& a, const SmallVector& x) + { + SmallVector<std::remove_const_t<DataType>> y = copy(x); + return y *= a; + } + + template <typename DataType2> + PUGS_INLINE friend auto + dot(const SmallVector& x, const SmallVector<DataType2>& y) + { + Assert(x.size() == y.size(), "cannot compute dot product: incompatible vector sizes"); + // Quite ugly, TODO: fix me in C++20 + auto promoted = [] { + DataType a{0}; + DataType2 b{0}; + return a * b; + }(); + + decltype(promoted) sum = 0; + + // Does not use parallel_for to preserve sum order + for (index_type i = 0; i < x.size(); ++i) { + sum += x[i] * y[i]; + } + + return sum; + } + + template <typename DataType2> + PUGS_INLINE SmallVector& + operator/=(const DataType2& a) + { + const auto inv_a = 1. / a; + return (*this) *= inv_a; + } + + template <typename DataType2> + PUGS_INLINE SmallVector& + operator*=(const DataType2& a) + { + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { m_values[i] *= a; }); + return *this; + } + + template <typename DataType2> + PUGS_INLINE SmallVector& + operator-=(const SmallVector<DataType2>& y) + { + Assert(this->size() == y.size(), "cannot substract vector: incompatible sizes"); + + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { m_values[i] -= y[i]; }); + + return *this; + } + + template <typename DataType2> + PUGS_INLINE SmallVector& + operator+=(const SmallVector<DataType2>& y) + { + Assert(this->size() == y.size(), "cannot add vector: incompatible sizes"); + + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { m_values[i] += y[i]; }); + + return *this; + } + + template <typename DataType2> + PUGS_INLINE SmallVector<std::remove_const_t<DataType>> + operator+(const SmallVector<DataType2>& y) const + { + Assert(this->size() == y.size(), "cannot compute vector sum: incompatible sizes"); + SmallVector<std::remove_const_t<DataType>> sum{y.size()}; + + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { sum.m_values[i] = m_values[i] + y[i]; }); + + return sum; + } + + template <typename DataType2> + PUGS_INLINE SmallVector<std::remove_const_t<DataType>> + operator-(const SmallVector<DataType2>& y) const + { + Assert(this->size() == y.size(), "cannot compute vector difference: incompatible sizes"); + SmallVector<std::remove_const_t<DataType>> sum{y.size()}; + + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { sum.m_values[i] = m_values[i] - y[i]; }); + + return sum; + } + + PUGS_INLINE + DataType& operator[](index_type i) const noexcept(NO_ASSERT) + { + return m_values[i]; + } + + PUGS_INLINE + size_t + size() const noexcept + { + return m_values.size(); + } + + PUGS_INLINE SmallVector& + fill(const DataType& value) noexcept + { + m_values.fill(value); + return *this; + } + + PUGS_INLINE SmallVector& operator=(const DataType&) = delete; + + PUGS_INLINE SmallVector& + operator=(const ZeroType&) noexcept + { + m_values.fill(0); + return *this; + } + + template <typename DataType2> + PUGS_INLINE SmallVector& + operator=(const SmallVector<DataType2>& x) + { + // ensures that DataType is the same as source DataType2 + static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), + "Cannot assign SmallVector of different type"); + // ensures that const is not lost through copy. If this point is + // reached data types only differ through their constness + static_assert((not std::is_const_v<DataType2>), "Cannot assign SmallVector of const to SmallVector of non-const"); + + m_values = x.m_values; + return *this; + } + + PUGS_INLINE + SmallVector& operator=(const SmallVector&) = default; + + PUGS_INLINE + SmallVector& operator=(SmallVector&& x) = default; + + template <typename DataType2> + SmallVector(const SmallVector<DataType2>& x) + { + // ensures that DataType is the same as source DataType2 + static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), + "Cannot assign SmallVector of different type"); + // ensures that const is not lost through copy + static_assert(((std::is_const_v<DataType2> and std::is_const_v<DataType>) or not std::is_const_v<DataType2>), + "Cannot assign SmallVector of const to SmallVector of non-const"); + + m_values = x.m_values; + } + + template <size_t N> + explicit SmallVector(const TinyVector<N, DataType>& x) : m_values{N} + { + std::copy(&x[0], &x[0] + N, &m_values[0]); + } + + SmallVector(const SmallVector&) = default; + SmallVector(SmallVector&&) = default; + + SmallVector(size_t size) : m_values{size} {} + + SmallVector() = default; + ~SmallVector() = default; +}; + +#endif // SMALL_VECTOR_HPP diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp index 98030dd447ee6cac14b6de0f3c45d55b68cdf7ba..0d3b9c0e5fef46f85fa576b68f940708c8ed529d 100644 --- a/src/algebra/TinyMatrix.hpp +++ b/src/algebra/TinyMatrix.hpp @@ -10,15 +10,14 @@ #include <iostream> -template <size_t N, typename T = double> +template <size_t M, size_t N = M, typename T = double> class [[nodiscard]] TinyMatrix { public: using data_type = T; private: - T m_values[N * N]; - static_assert((N > 0), "TinyMatrix size 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) @@ -29,7 +28,7 @@ class [[nodiscard]] TinyMatrix template <typename... Args> PUGS_FORCEINLINE constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept { - m_values[N * N - 1 - sizeof...(args)] = t; + m_values[M * N - 1 - sizeof...(args)] = t; if constexpr (sizeof...(args) > 0) { this->_unpackVariadicInput(std::forward<Args>(args)...); } @@ -39,13 +38,25 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr bool isSquare() const noexcept { - return true; + return M == N; + } + + PUGS_INLINE + constexpr friend TinyMatrix<N, M, T> transpose(const TinyMatrix& A) + { + TinyMatrix<N, M, T> tA; + for (size_t i = 0; i < M; ++i) { + for (size_t j = 0; j < N; ++j) { + tA(j, i) = A(i, j); + } + } + return tA; } PUGS_INLINE constexpr size_t dimension() const { - return N * N; + return M * N; } PUGS_INLINE @@ -57,7 +68,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr size_t numberOfRows() const { - return N; + return M; } PUGS_INLINE @@ -70,7 +81,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix operator-() const { TinyMatrix opposite; - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { opposite.m_values[i] = -m_values[i]; } return opposite; @@ -92,19 +103,19 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr TinyMatrix& operator*=(const T& t) { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] *= t; } return *this; } - PUGS_INLINE - constexpr TinyMatrix operator*(const TinyMatrix& B) const + template <size_t P> + PUGS_INLINE constexpr TinyMatrix<M, P, T> operator*(const TinyMatrix<N, P, T>& B) const { const TinyMatrix& A = *this; - TinyMatrix AB; - for (size_t i = 0; i < N; ++i) { - for (size_t j = 0; j < N; ++j) { + TinyMatrix<M, P, T> AB; + for (size_t i = 0; i < M; ++i) { + for (size_t j = 0; j < P; ++j) { T sum = A(i, 0) * B(0, j); for (size_t k = 1; k < N; ++k) { sum += A(i, k) * B(k, j); @@ -116,11 +127,11 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyVector<N, T> operator*(const TinyVector<N, T>& x) const + constexpr TinyVector<M, T> operator*(const TinyVector<N, T>& x) const { const TinyMatrix& A = *this; - TinyVector<N, T> Ax; - for (size_t i = 0; i < N; ++i) { + TinyVector<M, T> Ax; + for (size_t i = 0; i < M; ++i) { T sum = A(i, 0) * x[0]; for (size_t j = 1; j < N; ++j) { sum += A(i, j) * x[j]; @@ -134,7 +145,7 @@ class [[nodiscard]] TinyMatrix constexpr friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A) { os << '['; - for (size_t i = 0; i < N; ++i) { + for (size_t i = 0; i < M; ++i) { os << '(' << NaNHelper(A(i, 0)); for (size_t j = 1; j < N; ++j) { os << ',' << NaNHelper(A(i, j)); @@ -149,7 +160,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr bool operator==(const TinyMatrix& A) const { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { if (m_values[i] != A.m_values[i]) return false; } @@ -166,7 +177,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix operator+(const TinyMatrix& A) const { TinyMatrix sum; - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { sum.m_values[i] = m_values[i] + A.m_values[i]; } return sum; @@ -175,9 +186,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr TinyMatrix operator+(TinyMatrix&& A) const { - for (size_t i = 0; i < N * N; ++i) { - A.m_values[i] += m_values[i]; - } + A += *this; return std::move(A); } @@ -185,7 +194,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix operator-(const TinyMatrix& A) const { TinyMatrix difference; - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { difference.m_values[i] = m_values[i] - A.m_values[i]; } return difference; @@ -194,7 +203,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr TinyMatrix operator-(TinyMatrix&& A) const { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { A.m_values[i] = m_values[i] - A.m_values[i]; } return std::move(A); @@ -203,7 +212,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr TinyMatrix& operator+=(const TinyMatrix& A) { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; } return *this; @@ -212,7 +221,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr void operator+=(const volatile TinyMatrix& A) volatile { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; } } @@ -220,7 +229,7 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr TinyMatrix& operator-=(const TinyMatrix& A) { - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] -= A.m_values[i]; } return *this; @@ -229,14 +238,14 @@ class [[nodiscard]] TinyMatrix PUGS_INLINE constexpr T& operator()(size_t i, size_t j) noexcept(NO_ASSERT) { - Assert((i < N) and (j < N)); + 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) { - Assert((i < N) and (j < N)); + Assert((i < M) and (j < N)); return m_values[_index(i, j)]; } @@ -244,7 +253,7 @@ class [[nodiscard]] TinyMatrix 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 < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] = 0; } return *this; @@ -254,7 +263,7 @@ class [[nodiscard]] TinyMatrix 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 < N; ++i) { + for (size_t i = 0; i < M; ++i) { for (size_t j = 0; j < N; ++j) { m_values[_index(i, j)] = (i == j) ? 1 : 0; } @@ -271,7 +280,7 @@ class [[nodiscard]] TinyMatrix template <typename... Args> PUGS_INLINE constexpr TinyMatrix(const T& t, Args&&... args) noexcept { - static_assert(sizeof...(args) == N * N - 1, "wrong number of parameters"); + static_assert(sizeof...(args) == M * N - 1, "wrong number of parameters"); this->_unpackVariadicInput(t, std::forward<Args>(args)...); } @@ -281,7 +290,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix() noexcept { #ifndef NDEBUG - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] = invalid_data_v<T>; } #endif // NDEBUG @@ -292,7 +301,7 @@ class [[nodiscard]] TinyMatrix { static_assert(std::is_arithmetic<T>(), "Cannot construct from 'zero' value " "for non-arithmetic types"); - for (size_t i = 0; i < N * N; ++i) { + for (size_t i = 0; i < M * N; ++i) { m_values[i] = 0; } } @@ -302,7 +311,7 @@ class [[nodiscard]] TinyMatrix { static_assert(std::is_arithmetic<T>(), "Cannot construct from 'identity' " "value for non-arithmetic types"); - for (size_t i = 0; i < N; ++i) { + for (size_t i = 0; i < M; ++i) { for (size_t j = 0; j < N; ++j) { m_values[_index(i, j)] = (i == j) ? 1 : 0; } @@ -319,12 +328,12 @@ class [[nodiscard]] TinyMatrix ~TinyMatrix() = default; }; -template <size_t N, typename T> -PUGS_INLINE constexpr TinyMatrix<N, T> -tensorProduct(const TinyVector<N, T>& x, const TinyVector<N, T>& y) +template <size_t M, size_t N, typename T> +PUGS_INLINE constexpr TinyMatrix<M, N, T> +tensorProduct(const TinyVector<M, T>& x, const TinyVector<N, T>& y) { - TinyMatrix<N, T> A; - for (size_t i = 0; i < N; ++i) { + TinyMatrix<M, N, T> A; + for (size_t i = 0; i < M; ++i) { for (size_t j = 0; j < N; ++j) { A(i, j) = x[i] * y[j]; } @@ -334,16 +343,17 @@ tensorProduct(const TinyVector<N, T>& x, const TinyVector<N, T>& y) template <size_t N, typename T> PUGS_INLINE constexpr T -det(const TinyMatrix<N, T>& A) +det(const TinyMatrix<N, N, T>& A) { - static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non-arithmetic types"); - static_assert(std::is_floating_point<T>::value, "determinent for arbitrary dimension N is defined for floating " + static_assert(std::is_arithmetic<T>::value, "determinant is not defined for non-arithmetic types"); + static_assert(std::is_floating_point<T>::value, "determinant for arbitrary dimension N is defined for floating " "point types only"); - TinyMatrix<N, T> M = A; + TinyMatrix B = A; TinyVector<N, size_t> index; - for (size_t i = 0; i < N; ++i) + for (size_t i = 0; i < N; ++i) { index[i] = i; + } T determinent = 1; for (size_t i = 0; i < N; ++i) { @@ -351,7 +361,7 @@ det(const TinyMatrix<N, T>& A) size_t l = j; const size_t J = index[j]; for (size_t k = j + 1; k < N; ++k) { - if (std::abs(M(index[k], i)) > std::abs(M(J, i))) { + if (std::abs(B(index[k], i)) > std::abs(B(J, i))) { l = k; } } @@ -361,14 +371,14 @@ det(const TinyMatrix<N, T>& A) } } const size_t I = index[i]; - const T Mii = M(I, i); - if (Mii != 0) { - const T inv_Mii = 1. / M(I, i); + const T Bii = B(I, i); + if (Bii != 0) { + const T inv_Bii = 1. / B(I, i); for (size_t k = i + 1; k < N; ++k) { const size_t K = index[k]; - const T factor = M(K, i) * inv_Mii; + const T factor = B(K, i) * inv_Bii; for (size_t l = i + 1; l < N; ++l) { - M(K, l) -= factor * M(I, l); + B(K, l) -= factor * B(I, l); } } } else { @@ -377,14 +387,14 @@ det(const TinyMatrix<N, T>& A) } for (size_t i = 0; i < N; ++i) { - determinent *= M(index[i], i); + determinent *= B(index[i], i); } return determinent; } template <typename T> PUGS_INLINE constexpr T -det(const TinyMatrix<1, T>& A) +det(const TinyMatrix<1, 1, T>& A) { static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non-arithmetic types"); return A(0, 0); @@ -392,7 +402,7 @@ det(const TinyMatrix<1, T>& A) template <typename T> PUGS_INLINE constexpr T -det(const TinyMatrix<2, T>& A) +det(const TinyMatrix<2, 2, T>& A) { static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non-arithmetic types"); return A(0, 0) * A(1, 1) - A(1, 0) * A(0, 1); @@ -400,56 +410,56 @@ det(const TinyMatrix<2, T>& A) template <typename T> PUGS_INLINE constexpr T -det(const TinyMatrix<3, T>& A) +det(const TinyMatrix<3, 3, T>& A) { static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non-arithmetic types"); return A(0, 0) * (A(1, 1) * A(2, 2) - A(2, 1) * A(1, 2)) - A(1, 0) * (A(0, 1) * A(2, 2) - A(2, 1) * A(0, 2)) + A(2, 0) * (A(0, 1) * A(1, 2) - A(1, 1) * A(0, 2)); } -template <size_t N, typename T> -PUGS_INLINE constexpr TinyMatrix<N - 1, T> -getMinor(const TinyMatrix<N, T>& A, size_t I, size_t J) +template <size_t M, size_t N, typename T> +PUGS_INLINE constexpr TinyMatrix<M - 1, N - 1, T> +getMinor(const TinyMatrix<M, N, T>& A, size_t I, size_t J) { - static_assert(N >= 2, "minor calculation requires at least 2x2 matrices"); - Assert((I < N) and (J < N)); - TinyMatrix<N - 1, T> M; + static_assert(M >= 2 and N >= 2, "minor calculation requires at least 2x2 matrices"); + Assert((I < M) and (J < N)); + TinyMatrix<M - 1, N - 1, T> minor; for (size_t i = 0; i < I; ++i) { for (size_t j = 0; j < J; ++j) { - M(i, j) = A(i, j); + minor(i, j) = A(i, j); } for (size_t j = J + 1; j < N; ++j) { - M(i, j - 1) = A(i, j); + minor(i, j - 1) = A(i, j); } } - for (size_t i = I + 1; i < N; ++i) { + for (size_t i = I + 1; i < M; ++i) { for (size_t j = 0; j < J; ++j) { - M(i - 1, j) = A(i, j); + minor(i - 1, j) = A(i, j); } for (size_t j = J + 1; j < N; ++j) { - M(i - 1, j - 1) = A(i, j); + minor(i - 1, j - 1) = A(i, j); } } - return M; + return minor; } template <size_t N, typename T> -PUGS_INLINE constexpr TinyMatrix<N, T> inverse(const TinyMatrix<N, T>& A); +PUGS_INLINE constexpr TinyMatrix<N, N, T> inverse(const TinyMatrix<N, N, T>& A); template <typename T> -PUGS_INLINE constexpr TinyMatrix<1, T> -inverse(const TinyMatrix<1, T>& A) +PUGS_INLINE constexpr TinyMatrix<1, 1, T> +inverse(const TinyMatrix<1, 1, T>& A) { static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non-arithmetic types"); static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only"); - TinyMatrix<1, T> A_1(1. / A(0, 0)); + TinyMatrix<1, 1, T> A_1(1. / A(0, 0)); return A_1; } template <size_t N, typename T> PUGS_INLINE constexpr T -cofactor(const TinyMatrix<N, T>& A, size_t i, size_t j) +cofactor(const TinyMatrix<N, N, T>& A, size_t i, size_t j) { static_assert(std::is_arithmetic<T>::value, "cofactor is not defined for non-arithmetic types"); const T sign = ((i + j) % 2) ? -1 : 1; @@ -458,8 +468,8 @@ cofactor(const TinyMatrix<N, T>& A, size_t i, size_t j) } template <typename T> -PUGS_INLINE constexpr TinyMatrix<2, T> -inverse(const TinyMatrix<2, T>& A) +PUGS_INLINE constexpr TinyMatrix<2, 2, T> +inverse(const TinyMatrix<2, 2, T>& A) { static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non-arithmetic types"); static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only"); @@ -467,22 +477,22 @@ inverse(const TinyMatrix<2, T>& A) const T determinent = det(A); const T inv_determinent = 1. / determinent; - TinyMatrix<2, T> A_cofactors_T(A(1, 1), -A(0, 1), -A(1, 0), A(0, 0)); + TinyMatrix<2, 2, T> A_cofactors_T(A(1, 1), -A(0, 1), -A(1, 0), A(0, 0)); return A_cofactors_T *= inv_determinent; } template <typename T> -PUGS_INLINE constexpr TinyMatrix<3, T> -inverse(const TinyMatrix<3, T>& A) +PUGS_INLINE constexpr TinyMatrix<3, 3, T> +inverse(const TinyMatrix<3, 3, T>& A) { static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non-arithmetic types"); static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only"); const T determinent = det(A); - TinyMatrix<3, T> A_cofactors_T(cofactor(A, 0, 0), cofactor(A, 1, 0), cofactor(A, 2, 0), cofactor(A, 0, 1), - cofactor(A, 1, 1), cofactor(A, 2, 1), cofactor(A, 0, 2), cofactor(A, 1, 2), - cofactor(A, 2, 2)); + TinyMatrix<3, 3, T> A_cofactors_T(cofactor(A, 0, 0), cofactor(A, 1, 0), cofactor(A, 2, 0), cofactor(A, 0, 1), + cofactor(A, 1, 1), cofactor(A, 2, 1), cofactor(A, 0, 2), cofactor(A, 1, 2), + cofactor(A, 2, 2)); return A_cofactors_T *= 1. / determinent; } diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp index a3ad0342839eb5cc5ee6693e4a49e22d99cf41d2..723d9a710f277aff551508ef849632c24e727575 100644 --- a/src/language/PEGGrammar.hpp +++ b/src/language/PEGGrammar.hpp @@ -126,11 +126,7 @@ struct BREAK : seq < break_kw, ignored > {}; struct continue_kw : TAO_PEGTL_KEYWORD("continue") {}; struct CONTINUE : seq < continue_kw, ignored > {}; -struct cout_kw : TAO_PEGTL_KEYWORD("cout") {}; -struct cerr_kw : TAO_PEGTL_KEYWORD("cerr") {}; -struct clog_kw : TAO_PEGTL_KEYWORD("clog") {}; - -struct keyword : sor < basic_type, import_kw, true_kw, false_kw, let_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, not_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {}; +struct keyword : sor < basic_type, import_kw, true_kw, false_kw, let_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, not_kw, break_kw, continue_kw> {}; struct identifier_minus_keyword : minus< identifier, keyword > {}; @@ -218,7 +214,9 @@ struct product : list_must< unary_expression, sor< multiply_op, divide_op > > {} struct sum : list_must< product, sor< plus_op, minus_op > > {}; -struct compare : list_must<sum, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{}; +struct shift : list_must<sum, sor< shift_left_op, shift_right_op > >{}; + +struct compare : list_must<shift, sor< lesser_or_eq_op, greater_or_eq_op, lesser_op, greater_op > >{}; struct equality : list_must< compare, sor< eqeq_op, not_eq_op > >{}; @@ -289,15 +287,11 @@ struct for_statement_block; struct for_statement : if_must< FOR, open_parent, for_init, SEMICOL, for_test, SEMICOL, for_post, close_parent, for_statement_block >{}; -struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{}; -struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{}; - struct instruction : sor<if_statement, if_must<do_while_statement, semicol>, while_statement, for_statement, - if_must< ostream_statement, semicol >, if_must< BREAK, semicol >, if_must< CONTINUE, semicol >, block, diff --git a/src/language/ast/ASTBuilder.cpp b/src/language/ast/ASTBuilder.cpp index 0c433bbfd21704702ed87012d5956519a0f93bde..a4dc8c822bab53a67be975b6444eb9dffa9bb6be 100644 --- a/src/language/ast/ASTBuilder.cpp +++ b/src/language/ast/ASTBuilder.cpp @@ -214,20 +214,6 @@ struct ASTBuilder::simplify_for_post : TAO_PEGTL_NAMESPACE::parse_tree::apply<AS } }; -struct ASTBuilder::simplify_stream_statement - : TAO_PEGTL_NAMESPACE::parse_tree::apply<ASTBuilder::simplify_stream_statement> -{ - template <typename... States> - static void - transform(std::unique_ptr<ASTNode>& n, States&&...) - { - for (size_t i = 1; i < n->children.size(); ++i) { - n->children[0]->children.emplace_back(std::move(n->children[i])); - } - n = std::move(n->children[0]); - } -}; - template <typename Rule> using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector< Rule, @@ -248,9 +234,6 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector< language::vector_type, language::matrix_type, language::string_type, - language::cout_kw, - language::cerr_kw, - language::clog_kw, language::var_declaration, language::fct_declaration, language::type_mapping, @@ -269,6 +252,7 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector< language::equality, language::compare, language::sum, + language::shift, language::product, language::affectation, language::expression>, @@ -282,6 +266,8 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector< language::name_subscript_expression>, TAO_PEGTL_NAMESPACE::parse_tree::remove_content::on<language::plus_op, language::minus_op, + language::shift_left_op, + language::shift_right_op, language::multiply_op, language::divide_op, language::lesser_op, @@ -308,8 +294,7 @@ using selector = TAO_PEGTL_NAMESPACE::parse_tree::selector< ASTBuilder::simplify_statement_block::on<language::statement_block>, ASTBuilder::simplify_for_init::on<language::for_init>, ASTBuilder::simplify_for_test::on<language::for_test>, - ASTBuilder::simplify_for_post::on<language::for_post>, - ASTBuilder::simplify_stream_statement::on<language::ostream_statement>>; + ASTBuilder::simplify_for_post::on<language::for_post>>; template <typename InputT> std::unique_ptr<ASTNode> diff --git a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp index b6904220a9c42f2fcbfd49e8ce5881fbd9b7cf3a..c96b8799e3edbd037f70f8e68453bf700ced0fa2 100644 --- a/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp +++ b/src/language/ast/ASTNodeBinaryOperatorExpressionBuilder.cpp @@ -22,6 +22,11 @@ ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(A } else if (n.is_type<language::minus_op>()) { return binaryOperatorMangler<language::minus_op>(lhs_data_type, rhs_data_type); + } else if (n.is_type<language::shift_left_op>()) { + return binaryOperatorMangler<language::shift_left_op>(lhs_data_type, rhs_data_type); + } else if (n.is_type<language::shift_right_op>()) { + return binaryOperatorMangler<language::shift_right_op>(lhs_data_type, rhs_data_type); + } else if (n.is_type<language::or_op>()) { return binaryOperatorMangler<language::or_op>(lhs_data_type, rhs_data_type); } else if (n.is_type<language::and_op>()) { diff --git a/src/language/ast/ASTNodeDataTypeBuilder.cpp b/src/language/ast/ASTNodeDataTypeBuilder.cpp index eb307e2c16893be52128166c973f4992e86f3cb4..cb9e479df5f2e1f64edb4d5cb732acebcb505af6 100644 --- a/src/language/ast/ASTNodeDataTypeBuilder.cpp +++ b/src/language/ast/ASTNodeDataTypeBuilder.cpp @@ -161,8 +161,6 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const } else if (n.is_type<language::literal>()) { n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::string_t>(); - } else if (n.is_type<language::cout_kw>() or n.is_type<language::cerr_kw>() or n.is_type<language::clog_kw>()) { - n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::void_t>(); } else if (n.is_type<language::var_declaration>()) { auto& name_node = *(n.children[0]); auto& type_node = *(n.children[1]); @@ -460,6 +458,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const } } else if (n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or + n.is_type<language::shift_left_op>() or n.is_type<language::shift_right_op>() or n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>() or n.is_type<language::and_op>() or @@ -482,6 +481,12 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const return operator_repository.getBinaryOperatorValueType( binaryOperatorMangler<language::divide_op>(type_0, type_1)); + } else if (n.is_type<language::shift_left_op>()) { + return operator_repository.getBinaryOperatorValueType( + binaryOperatorMangler<language::shift_left_op>(type_0, type_1)); + } else if (n.is_type<language::shift_right_op>()) { + return operator_repository.getBinaryOperatorValueType( + binaryOperatorMangler<language::shift_right_op>(type_0, type_1)); } else if (n.is_type<language::lesser_op>()) { return operator_repository.getBinaryOperatorValueType( binaryOperatorMangler<language::lesser_op>(type_0, type_1)); diff --git a/src/language/ast/ASTNodeExpressionBuilder.cpp b/src/language/ast/ASTNodeExpressionBuilder.cpp index d9b3b4e439183e1f3a205a7c94e47252ac7a42f2..bbbcda43e788356d6bf4ec338643a79049069fc0 100644 --- a/src/language/ast/ASTNodeExpressionBuilder.cpp +++ b/src/language/ast/ASTNodeExpressionBuilder.cpp @@ -18,7 +18,6 @@ #include <language/node_processor/IfProcessor.hpp> #include <language/node_processor/LocalNameProcessor.hpp> #include <language/node_processor/NameProcessor.hpp> -#include <language/node_processor/OStreamProcessor.hpp> #include <language/node_processor/TupleToTinyVectorProcessor.hpp> #include <language/node_processor/TupleToVectorProcessor.hpp> #include <language/node_processor/ValueProcessor.hpp> @@ -105,17 +104,12 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n) } else if (n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or n.is_type<language::or_op>() or n.is_type<language::and_op>() or n.is_type<language::xor_op>() or n.is_type<language::greater_op>() or + n.is_type<language::shift_left_op>() or n.is_type<language::shift_right_op>() or n.is_type<language::greater_or_eq_op>() or n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>()) { ASTNodeBinaryOperatorExpressionBuilder{n}; - } else if (n.is_type<language::cout_kw>()) { - n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cout); - } else if (n.is_type<language::cerr_kw>()) { - n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::cerr); - } else if (n.is_type<language::clog_kw>()) { - n.m_node_processor = std::make_unique<OStreamProcessor>(n, std::clog); } else if (n.is_type<language::if_statement>()) { n.m_node_processor = std::make_unique<IfProcessor>(n); } else if (n.is_type<language::statement_block>()) { diff --git a/src/language/modules/BuiltinModule.cpp b/src/language/modules/BuiltinModule.cpp index 98d8f71c6c91bd83ac53ff8d45b98f419c283fe9..cc76f78f7369f057c476a1ae15b953798d88903b 100644 --- a/src/language/modules/BuiltinModule.cpp +++ b/src/language/modules/BuiltinModule.cpp @@ -2,6 +2,7 @@ #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/TypeDescriptor.hpp> +#include <language/utils/ValueDescriptor.hpp> #include <utils/Exceptions.hpp> #include <memory> @@ -44,6 +45,17 @@ BuiltinModule::_addBuiltinFunction(const std::string& name, } } +void +BuiltinModule::_addNameValue(const std::string& name, const ASTNodeDataType& type, const DataVariant& data) +{ + std::shared_ptr value_descriptor = std::make_shared<ValueDescriptor>(type, data); + + auto [i_type, success] = m_name_value_map.insert(std::make_pair(name, value_descriptor)); + if (not success) { + throw NormalError("variable '" + name + "' cannot be added!\n"); + } +} + void BuiltinModule::_addTypeDescriptor(const ASTNodeDataType& ast_node_data_type) { diff --git a/src/language/modules/BuiltinModule.hpp b/src/language/modules/BuiltinModule.hpp index 2be1d162578fb0d111e6eac7ae93e10dae981bce..3dd9ad1dbb9895f3f79ba04ec2702cc7ee0bd15f 100644 --- a/src/language/modules/BuiltinModule.hpp +++ b/src/language/modules/BuiltinModule.hpp @@ -6,18 +6,22 @@ class IBuiltinFunctionEmbedder; class TypeDescriptor; +class ValueDescriptor; class BuiltinModule : public IModule { protected: NameBuiltinFunctionMap m_name_builtin_function_map; NameTypeMap m_name_type_map; + NameValueMap m_name_value_map; void _addBuiltinFunction(const std::string& name, std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder); void _addTypeDescriptor(const ASTNodeDataType& type); + void _addNameValue(const std::string& name, const ASTNodeDataType& type, const DataVariant& data); + const bool m_is_mandatory; public: @@ -39,6 +43,12 @@ class BuiltinModule : public IModule return m_name_type_map; } + const NameValueMap& + getNameValueMap() const final + { + return m_name_value_map; + } + BuiltinModule(bool is_mandatory = false); ~BuiltinModule() = default; diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp index 1cc699455e23c123fbd1fee059f5296917a46b9b..9b70144e8559ccf97515bed9b71b174afb1a9311 100644 --- a/src/language/modules/CoreModule.cpp +++ b/src/language/modules/CoreModule.cpp @@ -22,6 +22,8 @@ #include <language/utils/IncDecOperatorRegisterForN.hpp> #include <language/utils/IncDecOperatorRegisterForR.hpp> #include <language/utils/IncDecOperatorRegisterForZ.hpp> +#include <language/utils/OFStream.hpp> +#include <language/utils/OStream.hpp> #include <language/utils/UnaryOperatorRegisterForB.hpp> #include <language/utils/UnaryOperatorRegisterForN.hpp> #include <language/utils/UnaryOperatorRegisterForR.hpp> @@ -83,6 +85,25 @@ CoreModule::CoreModule() : BuiltinModule(true) []() { RandomEngine::instance().resetRandomSeed(); } )); + + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const OStream>>); + + this + ->_addBuiltinFunction("ofstream", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const OStream>(const std::string&)>>( + + [](const std::string& filename) { return std::make_shared<const OFStream>(filename); } + + )); + + this->_addNameValue("cout", ast_node_data_type_from<std::shared_ptr<const OStream>>, + EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cout))}); + + this->_addNameValue("cerr", ast_node_data_type_from<std::shared_ptr<const OStream>>, + EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cerr))}); + + this->_addNameValue("clog", ast_node_data_type_from<std::shared_ptr<const OStream>>, + EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::clog))}); } void diff --git a/src/language/modules/IModule.hpp b/src/language/modules/IModule.hpp index ceb3fd3dffc7d0af7f6423e3a21e7e8aa9686ffc..04aefbe91b57ab1925f55bae62ad233c1ea135cf 100644 --- a/src/language/modules/IModule.hpp +++ b/src/language/modules/IModule.hpp @@ -1,6 +1,8 @@ #ifndef IMODULE_HPP #define IMODULE_HPP +#include <language/utils/DataVariant.hpp> + #include <memory> #include <string> #include <string_view> @@ -8,12 +10,14 @@ class IBuiltinFunctionEmbedder; class TypeDescriptor; +class ValueDescriptor; class IModule { public: using NameBuiltinFunctionMap = std::unordered_map<std::string, std::shared_ptr<IBuiltinFunctionEmbedder>>; using NameTypeMap = std::unordered_map<std::string, std::shared_ptr<TypeDescriptor>>; + using NameValueMap = std::unordered_map<std::string, std::shared_ptr<ValueDescriptor>>; IModule() = default; IModule(IModule&&) = default; @@ -25,6 +29,8 @@ class IModule virtual const NameTypeMap& getNameTypeMap() const = 0; + virtual const NameValueMap& getNameValueMap() const = 0; + virtual void registerOperators() const = 0; virtual std::string_view name() const = 0; diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp index e516ab800833f5503de27bcfdd73e8b8381e06e6..71a1368b9dc374b19562bae27cc14a5d2b54c233 100644 --- a/src/language/modules/ModuleRepository.cpp +++ b/src/language/modules/ModuleRepository.cpp @@ -13,6 +13,8 @@ #include <language/utils/ParseError.hpp> #include <language/utils/SymbolTable.hpp> #include <language/utils/TypeDescriptor.hpp> +#include <language/utils/ValueDescriptor.hpp> + #include <utils/PugsAssert.hpp> #include <algorithm> @@ -85,6 +87,28 @@ ModuleRepository::_populateEmbedderTableT(const ASTNode& module_node, } } +void +ModuleRepository::_populateSymbolTable(const ASTNode& module_node, + const std::string& module_name, + const IModule::NameValueMap& name_value_descriptor_map, + SymbolTable& symbol_table) +{ + for (auto [symbol_name, value_descriptor] : name_value_descriptor_map) { + auto [i_symbol, success] = symbol_table.add(symbol_name, module_node.begin()); + + if (not success) { + std::ostringstream error_message; + error_message << "importing module '" << module_name << "', cannot add symbol '" << symbol_name + << "', it is already defined!"; + throw ParseError(error_message.str(), module_node.begin()); + } + + i_symbol->attributes().setDataType(value_descriptor->type()); + i_symbol->attributes().setIsInitialized(); + i_symbol->attributes().value() = value_descriptor->value(); + } +} + void ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table) { @@ -110,6 +134,8 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table, symbol_table.typeEmbedderTable()); + this->_populateSymbolTable(module_name_node, module_name, populating_module.getNameValueMap(), symbol_table); + for (auto [symbol_name, embedded] : populating_module.getNameTypeMap()) { BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name)); } @@ -132,6 +158,12 @@ ModuleRepository::populateMandatorySymbolTable(const ASTNode& root_node, SymbolT ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table, symbol_table.typeEmbedderTable()); + this->_populateSymbolTable(root_node, module_name, i_module->getNameValueMap(), symbol_table); + + for (auto [symbol_name, embedded] : i_module->getNameTypeMap()) { + BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name)); + } + i_module->registerOperators(); } } diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp index c4c9870fcedf550c82f94374f759f94d4c9cc878..c7289c8d1c4b9c7f795925bfdbf65e3f526082e7 100644 --- a/src/language/modules/ModuleRepository.hpp +++ b/src/language/modules/ModuleRepository.hpp @@ -26,6 +26,11 @@ class ModuleRepository SymbolTable& symbol_table, EmbedderTableT& embedder_table); + void _populateSymbolTable(const ASTNode& module_node, + const std::string& module_name, + const IModule::NameValueMap& name_value_map, + SymbolTable& symbol_table); + public: void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table); void populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table); diff --git a/src/language/node_processor/BinaryExpressionProcessor.hpp b/src/language/node_processor/BinaryExpressionProcessor.hpp index 2c5d7460f26577633abed7281425d234b4d95432..7f278d4c7d4a007ad5db4c9f5d444665ccca56d6 100644 --- a/src/language/node_processor/BinaryExpressionProcessor.hpp +++ b/src/language/node_processor/BinaryExpressionProcessor.hpp @@ -82,6 +82,34 @@ struct BinOp<language::lesser_op> } }; +class OStream; + +template <> +struct BinOp<language::shift_left_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a << b) + { + if constexpr (std::is_same_v<A, std::shared_ptr<const OStream>> and std::is_same_v<B, bool>) { + return a << std::boolalpha << b; + } else { + return a << b; + } + } +}; + +template <> +struct BinOp<language::shift_right_op> +{ + template <typename A, typename B> + PUGS_INLINE auto + eval(const A& a, const B& b) -> decltype(a >> b) + { + return a >> b; + } +}; + template <> struct BinOp<language::lesser_or_eq_op> { @@ -286,7 +314,8 @@ struct BinaryExpressionProcessor<BinaryOpT, std::shared_ptr<ValueT>, std::shared PUGS_INLINE DataVariant _eval(const DataVariant& a, const DataVariant& b) { - if constexpr ((std::is_arithmetic_v<B_DataT>) or (is_tiny_matrix_v<B_DataT>) or (is_tiny_vector_v<B_DataT>)) { + if constexpr ((std::is_arithmetic_v<B_DataT>) or (is_tiny_matrix_v<B_DataT>) or (is_tiny_vector_v<B_DataT>) or + (std::is_same_v<std::string, B_DataT>)) { const auto& embedded_a = std::get<EmbeddedData>(a); const auto& b_value = std::get<B_DataT>(b); diff --git a/src/language/node_processor/OStreamProcessor.hpp b/src/language/node_processor/OStreamProcessor.hpp deleted file mode 100644 index e67dd7b6d9fcfa2440a59367efecd42ffd35a8ca..0000000000000000000000000000000000000000 --- a/src/language/node_processor/OStreamProcessor.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef OSTREAM_PROCESSOR_HPP -#define OSTREAM_PROCESSOR_HPP - -#include <language/ast/ASTNode.hpp> -#include <language/node_processor/INodeProcessor.hpp> -#include <language/utils/ParseError.hpp> - -class OStreamProcessor final : public INodeProcessor -{ - private: - ASTNode& m_node; - std::ostream& m_os; - - public: - DataVariant - execute(ExecutionPolicy& exec_policy) - { - for (size_t i = 0; i < m_node.children.size(); ++i) { - m_os << m_node.children[i]->execute(exec_policy); - } - - return {}; - } - - OStreamProcessor(ASTNode& node, std::ostream& os) : m_node{node}, m_os(os) - { - for (auto& child : m_node.children) { - if ((child->m_data_type == ASTNodeDataType::type_name_id_t) or - (child->m_data_type == ASTNodeDataType::function_t) or - (child->m_data_type == ASTNodeDataType::builtin_function_t)) { - throw ParseError("invalid argument, cannot print a '" + dataTypeName(child->m_data_type) + "'", - std::vector{child->begin()}); - } - } - } -}; - -#endif // OSTREAM_PROCESSOR_HPP diff --git a/src/language/utils/BinaryOperatorMangler.hpp b/src/language/utils/BinaryOperatorMangler.hpp index f3648f3fb860a6207b70ad712aee9935b669e493..d7f0c6c79358ffb555f20b1f55036cde2ce47504 100644 --- a/src/language/utils/BinaryOperatorMangler.hpp +++ b/src/language/utils/BinaryOperatorMangler.hpp @@ -13,6 +13,9 @@ struct divide_op; struct plus_op; struct minus_op; +struct shift_left_op; +struct shift_right_op; + struct or_op; struct and_op; struct xor_op; @@ -56,6 +59,10 @@ binaryOperatorMangler(const ASTNodeDataType& lhs_data_type, const ASTNodeDataTyp return "=="; } else if constexpr (std::is_same_v<BinaryOperatorT, language::not_eq_op>) { return "!="; + } else if constexpr (std::is_same_v<BinaryOperatorT, language::shift_left_op>) { + return "<<"; + } else if constexpr (std::is_same_v<BinaryOperatorT, language::shift_right_op>) { + return ">>"; } else { static_assert(std::is_same_v<language::multiply_op, BinaryOperatorT>, "undefined binary operator"); } diff --git a/src/language/utils/BinaryOperatorRegisterForB.cpp b/src/language/utils/BinaryOperatorRegisterForB.cpp index cba803aaf3e3d7d4c72be7b69ca1a835203a49b2..dc228471d52330e486887e523c83dfa2d1917cef 100644 --- a/src/language/utils/BinaryOperatorRegisterForB.cpp +++ b/src/language/utils/BinaryOperatorRegisterForB.cpp @@ -1,6 +1,18 @@ #include <language/utils/BinaryOperatorRegisterForB.hpp> #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> + +void +BinaryOperatorRegisterForB::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, bool>>()); +} void BinaryOperatorRegisterForB::_register_comparisons() @@ -61,6 +73,7 @@ BinaryOperatorRegisterForB::_register_divide() BinaryOperatorRegisterForB::BinaryOperatorRegisterForB() { + this->_register_ostream(); this->_register_comparisons(); this->_register_logical_operators(); this->_register_plus(); diff --git a/src/language/utils/BinaryOperatorRegisterForB.hpp b/src/language/utils/BinaryOperatorRegisterForB.hpp index 651411bf7f2cd8e8386d26c071220d36cb79a691..545b49c5010e063654fea2b8570e4fd6e490f0e6 100644 --- a/src/language/utils/BinaryOperatorRegisterForB.hpp +++ b/src/language/utils/BinaryOperatorRegisterForB.hpp @@ -4,6 +4,7 @@ class BinaryOperatorRegisterForB { private: + void _register_ostream(); void _register_comparisons(); void _register_logical_operators(); void _register_plus(); diff --git a/src/language/utils/BinaryOperatorRegisterForN.cpp b/src/language/utils/BinaryOperatorRegisterForN.cpp index 66d589405545924af9e2de137f7738c9b40b8430..e32e2b53a5fb70af8b84069790dd8435a362e051 100644 --- a/src/language/utils/BinaryOperatorRegisterForN.cpp +++ b/src/language/utils/BinaryOperatorRegisterForN.cpp @@ -1,6 +1,18 @@ #include <language/utils/BinaryOperatorRegisterForN.hpp> #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> + +void +BinaryOperatorRegisterForN::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, uint64_t>>()); +} void BinaryOperatorRegisterForN::_register_comparisons() @@ -42,6 +54,7 @@ BinaryOperatorRegisterForN::_register_minus() BinaryOperatorRegisterForN::BinaryOperatorRegisterForN() { + this->_register_ostream(); this->_register_comparisons(); this->_register_arithmetic<language::plus_op>(); this->_register_minus(); diff --git a/src/language/utils/BinaryOperatorRegisterForN.hpp b/src/language/utils/BinaryOperatorRegisterForN.hpp index 80dc52b013f36e05e08f7bf561f2ac3b41ccbfbf..997b6be7ab35284723ee64b6630ecb514f773bcd 100644 --- a/src/language/utils/BinaryOperatorRegisterForN.hpp +++ b/src/language/utils/BinaryOperatorRegisterForN.hpp @@ -4,6 +4,7 @@ class BinaryOperatorRegisterForN { private: + void _register_ostream(); template <typename OperatorT> void _register_arithmetic(); void _register_comparisons(); diff --git a/src/language/utils/BinaryOperatorRegisterForR.cpp b/src/language/utils/BinaryOperatorRegisterForR.cpp index 4f69988925e373fbd7369bff3d0bb87860b1aa3d..cc8ba8a79dc59c447317200a308103b8d7dfc1d8 100644 --- a/src/language/utils/BinaryOperatorRegisterForR.cpp +++ b/src/language/utils/BinaryOperatorRegisterForR.cpp @@ -1,6 +1,18 @@ #include <language/utils/BinaryOperatorRegisterForR.hpp> #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> + +void +BinaryOperatorRegisterForR::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, double>>()); +} void BinaryOperatorRegisterForR::_register_comparisons() @@ -44,6 +56,7 @@ BinaryOperatorRegisterForR::_register_arithmetic() BinaryOperatorRegisterForR::BinaryOperatorRegisterForR() { + this->_register_ostream(); this->_register_comparisons(); this->_register_arithmetic<language::plus_op>(); this->_register_arithmetic<language::minus_op>(); diff --git a/src/language/utils/BinaryOperatorRegisterForR.hpp b/src/language/utils/BinaryOperatorRegisterForR.hpp index cbde82fb3d36e565ef84d99b95b58c6c0556eb01..c14fa410f9a4dac520ae4482d3a62114f4840029 100644 --- a/src/language/utils/BinaryOperatorRegisterForR.hpp +++ b/src/language/utils/BinaryOperatorRegisterForR.hpp @@ -4,6 +4,7 @@ class BinaryOperatorRegisterForR { private: + void _register_ostream(); template <typename OperatorT> void _register_arithmetic(); void _register_comparisons(); diff --git a/src/language/utils/BinaryOperatorRegisterForRn.cpp b/src/language/utils/BinaryOperatorRegisterForRn.cpp index 41e5b031f7e3db02d8e59a9962e028c046f813a8..6e900d036871ed79eb13dfa737445becd50a1a9a 100644 --- a/src/language/utils/BinaryOperatorRegisterForRn.cpp +++ b/src/language/utils/BinaryOperatorRegisterForRn.cpp @@ -1,8 +1,23 @@ #include <language/utils/BinaryOperatorRegisterForRn.hpp> #include <language/utils/BinaryOperatorProcessorBuilder.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> #include <language/utils/OperatorRepository.hpp> +template <size_t Dimension> +void +BinaryOperatorRegisterForRn<Dimension>::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + using Rn = TinyVector<Dimension>; + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, Rn>>()); +} + template <size_t Dimension> void BinaryOperatorRegisterForRn<Dimension>::_register_comparisons() @@ -54,6 +69,8 @@ BinaryOperatorRegisterForRn<Dimension>::_register_arithmetic() template <size_t Dimension> BinaryOperatorRegisterForRn<Dimension>::BinaryOperatorRegisterForRn() { + this->_register_ostream(); + this->_register_comparisons(); this->_register_product_by_a_scalar(); diff --git a/src/language/utils/BinaryOperatorRegisterForRn.hpp b/src/language/utils/BinaryOperatorRegisterForRn.hpp index b9f27d4165d236b913e3393e342a144019fe6015..fc83d3a670a18b49824d7f59360c41dac9d39b6d 100644 --- a/src/language/utils/BinaryOperatorRegisterForRn.hpp +++ b/src/language/utils/BinaryOperatorRegisterForRn.hpp @@ -7,10 +7,9 @@ template <size_t Dimension> class BinaryOperatorRegisterForRn { private: + void _register_ostream(); void _register_comparisons(); - void _register_product_by_a_scalar(); - template <typename OperatorT> void _register_arithmetic(); diff --git a/src/language/utils/BinaryOperatorRegisterForRnxn.cpp b/src/language/utils/BinaryOperatorRegisterForRnxn.cpp index 3d8850e79a4129c9a2098baa14b869f48bb8d1ce..f164203ddaca12e83f5ae5770dcb4848d366d3a4 100644 --- a/src/language/utils/BinaryOperatorRegisterForRnxn.cpp +++ b/src/language/utils/BinaryOperatorRegisterForRnxn.cpp @@ -1,8 +1,23 @@ #include <language/utils/BinaryOperatorRegisterForRnxn.hpp> #include <language/utils/BinaryOperatorProcessorBuilder.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> #include <language/utils/OperatorRepository.hpp> +template <size_t Dimension> +void +BinaryOperatorRegisterForRnxn<Dimension>::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + using Rnxn = TinyMatrix<Dimension>; + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, Rnxn>>()); +} + template <size_t Dimension> void BinaryOperatorRegisterForRnxn<Dimension>::_register_comparisons() @@ -68,6 +83,8 @@ BinaryOperatorRegisterForRnxn<Dimension>::_register_arithmetic() template <size_t Dimension> BinaryOperatorRegisterForRnxn<Dimension>::BinaryOperatorRegisterForRnxn() { + this->_register_ostream(); + this->_register_comparisons(); this->_register_product_by_a_scalar(); diff --git a/src/language/utils/BinaryOperatorRegisterForRnxn.hpp b/src/language/utils/BinaryOperatorRegisterForRnxn.hpp index 594740b629b0a7201d64139fd8e2ce4a12b38cd2..9edad436b51a5606fafc6aa980fd1578084f7e85 100644 --- a/src/language/utils/BinaryOperatorRegisterForRnxn.hpp +++ b/src/language/utils/BinaryOperatorRegisterForRnxn.hpp @@ -7,11 +7,10 @@ template <size_t Dimension> class BinaryOperatorRegisterForRnxn { private: + void _register_ostream(); void _register_comparisons(); - void _register_product_by_a_scalar(); void _register_product_by_a_vector(); - template <typename OperatorT> void _register_arithmetic(); diff --git a/src/language/utils/BinaryOperatorRegisterForString.cpp b/src/language/utils/BinaryOperatorRegisterForString.cpp index 0e89cbe00502938d817405c3f3f3d6d991f0433e..999950cf1b1310bbe52614cc6823f37be53f82a4 100644 --- a/src/language/utils/BinaryOperatorRegisterForString.cpp +++ b/src/language/utils/BinaryOperatorRegisterForString.cpp @@ -2,8 +2,20 @@ #include <language/utils/BinaryOperatorProcessorBuilder.hpp> #include <language/utils/ConcatExpressionProcessorBuilder.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> #include <language/utils/OperatorRepository.hpp> +void +BinaryOperatorRegisterForString::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, std::string>>()); +} + void BinaryOperatorRegisterForString::_register_comparisons() { @@ -27,6 +39,8 @@ BinaryOperatorRegisterForString::_register_concat() BinaryOperatorRegisterForString::BinaryOperatorRegisterForString() { + this->_register_ostream(); + this->_register_comparisons(); this->_register_concat<bool>(); diff --git a/src/language/utils/BinaryOperatorRegisterForString.hpp b/src/language/utils/BinaryOperatorRegisterForString.hpp index 36af13ee6442086244ee5234ad496f3580f79c22..b7d4a74402092b60ae958c1beb20e61b4151592d 100644 --- a/src/language/utils/BinaryOperatorRegisterForString.hpp +++ b/src/language/utils/BinaryOperatorRegisterForString.hpp @@ -4,6 +4,8 @@ class BinaryOperatorRegisterForString { private: + void _register_ostream(); + void _register_comparisons(); template <typename RHS_T> diff --git a/src/language/utils/BinaryOperatorRegisterForZ.cpp b/src/language/utils/BinaryOperatorRegisterForZ.cpp index cc8b22d117a8bebc557efff84083b8e45dcf8602..1d318850226beac44d27fe5f4fdba6c8e36a4e61 100644 --- a/src/language/utils/BinaryOperatorRegisterForZ.cpp +++ b/src/language/utils/BinaryOperatorRegisterForZ.cpp @@ -1,6 +1,18 @@ #include <language/utils/BinaryOperatorRegisterForZ.hpp> #include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp> +#include <language/utils/DataHandler.hpp> +#include <language/utils/OStream.hpp> + +void +BinaryOperatorRegisterForZ::_register_ostream() +{ + OperatorRepository& repository = OperatorRepository::instance(); + + repository.addBinaryOperator<language::shift_left_op>( + std::make_shared<BinaryOperatorProcessorBuilder<language::shift_left_op, std::shared_ptr<const OStream>, + std::shared_ptr<const OStream>, int64_t>>()); +} void BinaryOperatorRegisterForZ::_register_comparisons() @@ -36,6 +48,7 @@ BinaryOperatorRegisterForZ::_register_arithmetic() BinaryOperatorRegisterForZ::BinaryOperatorRegisterForZ() { + this->_register_ostream(); this->_register_comparisons(); this->_register_arithmetic<language::plus_op>(); this->_register_arithmetic<language::minus_op>(); diff --git a/src/language/utils/BinaryOperatorRegisterForZ.hpp b/src/language/utils/BinaryOperatorRegisterForZ.hpp index 3f9a7c30c2f8e3674e6ebda7e9069153a6162f13..cb734843dc5013637ec597a8357a50d05a3b5373 100644 --- a/src/language/utils/BinaryOperatorRegisterForZ.hpp +++ b/src/language/utils/BinaryOperatorRegisterForZ.hpp @@ -4,6 +4,7 @@ class BinaryOperatorRegisterForZ { private: + void _register_ostream(); template <typename OperatorT> void _register_arithmetic(); void _register_comparisons(); diff --git a/src/language/utils/CMakeLists.txt b/src/language/utils/CMakeLists.txt index a86bd52d4a89b6102f262e6de7caae4355b99911..cd3f8af2314e96e87bacec25ac1dfc08d015192b 100644 --- a/src/language/utils/CMakeLists.txt +++ b/src/language/utils/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(PugsLanguageUtils IncDecOperatorRegisterForN.cpp IncDecOperatorRegisterForR.cpp IncDecOperatorRegisterForZ.cpp + OFStream.cpp OperatorRepository.cpp UnaryOperatorRegisterForB.cpp UnaryOperatorRegisterForN.cpp diff --git a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp index 52e69c29af17a994d1a51d8d87de48c02249645c..fa746269722229bff7fbd15f47edf926f14784cc 100644 --- a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp +++ b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp @@ -3,6 +3,7 @@ #include <language/utils/EmbeddedIDiscreteFunctionUtils.hpp> #include <mesh/IMesh.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> #include <scheme/DiscreteFunctionUtils.hpp> #include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> @@ -318,45 +319,65 @@ template <size_t Dimension> std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) { - Assert((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == g->dataType().dimension())); + Assert(((f->descriptor().type() == DiscreteFunctionType::P0Vector) and + (g->descriptor().type() == DiscreteFunctionType::P0Vector)) or + ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and + (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and + (f->dataType().dimension() == g->dataType().dimension()))); - using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; + if ((f->descriptor().type() == DiscreteFunctionType::P0Vector) and + (g->descriptor().type() == DiscreteFunctionType::P0Vector)) { + using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; + using DiscreteFunctionType = DiscreteFunctionP0Vector<Dimension, double>; - switch (f->dataType().dimension()) { - case 1: { - using Rd = TinyVector<1>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using Rd = TinyVector<2>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using Rd = TinyVector<3>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP + const DiscreteFunctionType& f_vector = dynamic_cast<const DiscreteFunctionType&>(*f); + const DiscreteFunctionType& g_vector = dynamic_cast<const DiscreteFunctionType&>(*g); + + if (f_vector.size() != g_vector.size()) { + throw NormalError("operands have different dimension"); + } else { + return std::make_shared<const DiscreteFunctionResultType>(dot(f_vector, g_vector)); + } + + } else { + using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; + + switch (f->dataType().dimension()) { + case 1: { + using Rd = TinyVector<1>; + using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; + return std::make_shared<const DiscreteFunctionResultType>( + dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); + } + case 2: { + using Rd = TinyVector<2>; + using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; + return std::make_shared<const DiscreteFunctionResultType>( + dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); + } + case 3: { + using Rd = TinyVector<3>; + using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; + return std::make_shared<const DiscreteFunctionResultType>( + dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); + } + // LCOV_EXCL_STOP + } } } std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) { - if ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == g->dataType().dimension())) { + if (((f->descriptor().type() == DiscreteFunctionType::P0Vector) and + (g->descriptor().type() == DiscreteFunctionType::P0Vector)) or + ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and + (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and + (f->dataType().dimension() == g->dataType().dimension()))) { std::shared_ptr mesh = getCommonMesh({f, g}); if (mesh.use_count() == 0) { diff --git a/src/language/utils/OFStream.cpp b/src/language/utils/OFStream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39b7cc8ecedee3ff76e3d6d54790d25f90d01569 --- /dev/null +++ b/src/language/utils/OFStream.cpp @@ -0,0 +1,17 @@ +#include <language/utils/OFStream.hpp> + +#include <utils/Messenger.hpp> + +OFStream::OFStream(const std::string& filename) +{ + if (parallel::rank() == 0) { + m_fstream.open(filename); + if (m_fstream.is_open()) { + m_ostream = &m_fstream; + } else { + std::stringstream error_msg; + error_msg << "cannot create file " << rang::fgB::yellow << filename << rang::style::reset; + throw NormalError(error_msg.str()); + } + } +} diff --git a/src/language/utils/OFStream.hpp b/src/language/utils/OFStream.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8421906fca8746192b0d24730f7a731fe2640894 --- /dev/null +++ b/src/language/utils/OFStream.hpp @@ -0,0 +1,20 @@ +#ifndef OFSTREAM_HPP +#define OFSTREAM_HPP + +#include <language/utils/OStream.hpp> + +#include <fstream> + +class OFStream final : public OStream +{ + private: + std::ofstream m_fstream; + + public: + OFStream(const std::string& filename); + + OFStream() = delete; + ~OFStream() = default; +}; + +#endif // OFSTREAM_HPP diff --git a/src/language/utils/OStream.hpp b/src/language/utils/OStream.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d9410e25e35d2a3e9d5ac147911f6464d3b71eb7 --- /dev/null +++ b/src/language/utils/OStream.hpp @@ -0,0 +1,36 @@ +#ifndef OSTREAM_HPP +#define OSTREAM_HPP + +#include <language/utils/ASTNodeDataTypeTraits.hpp> +#include <utils/PugsAssert.hpp> + +#include <memory> + +class OStream +{ + protected: + mutable std::ostream* m_ostream = nullptr; + + public: + template <typename DataT> + friend std::shared_ptr<const OStream> + operator<<(const std::shared_ptr<const OStream>& os, const DataT& t) + { + Assert(os.use_count() > 0, "non allocated stream"); + if (os->m_ostream != nullptr) { + *os->m_ostream << t; + } + return os; + } + + OStream(std::ostream& os) : m_ostream(&os) {} + OStream() = default; + + virtual ~OStream() = default; +}; + +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const OStream>> = + ASTNodeDataType::build<ASTNodeDataType::type_id_t>("ostream"); + +#endif // OSTREAM_HPP diff --git a/src/language/utils/ValueDescriptor.hpp b/src/language/utils/ValueDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..36bca35356b0b4a9759aee028b1b1ac02d9f7120 --- /dev/null +++ b/src/language/utils/ValueDescriptor.hpp @@ -0,0 +1,36 @@ +#ifndef VALUE_DESCRIPTOR_HPP +#define VALUE_DESCRIPTOR_HPP + +#include <language/utils/ASTNodeDataType.hpp> +#include <language/utils/DataVariant.hpp> + +#include <string> + +class ValueDescriptor +{ + private: + const ASTNodeDataType m_type; + const DataVariant m_value; + + public: + const ASTNodeDataType + type() const + { + return m_type; + } + + const DataVariant + value() const + { + return m_value; + } + + ValueDescriptor(const ASTNodeDataType& type, const DataVariant& value) : m_type{type}, m_value{value} {} + + ValueDescriptor(const ValueDescriptor&) = delete; + ValueDescriptor(ValueDescriptor&&) = delete; + + ~ValueDescriptor() = default; +}; + +#endif // VALUE_DESCRIPTOR_HPP diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp index b312e4a8e3296fceb7ca0b747bdf5841200b8274..4a3ab6939b02dffef76dbdda5e99273c6653bce9 100644 --- a/src/mesh/MeshData.hpp +++ b/src/mesh/MeshData.hpp @@ -85,7 +85,7 @@ class MeshData : public IMeshData FaceValue<double> ll{m_mesh.connectivity()}; parallel_for( - m_mesh.numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { ll[face_id] = L2Norm(Nl[face_id]); }); + m_mesh.numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { ll[face_id] = l2Norm(Nl[face_id]); }); m_ll = ll; } @@ -103,11 +103,10 @@ class MeshData : public IMeshData FaceValue<Rd> nl{m_mesh.connectivity()}; - const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); parallel_for( m_mesh.numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { nl[face_id] = (1. / ll[face_id]) * Nl[face_id]; }); - m_Nl = Nl; + m_nl = nl; } } diff --git a/src/output/OutputNamedItemValueSet.hpp b/src/output/OutputNamedItemValueSet.hpp index bf90ddc3bad9636f2339695e87a446b11d81ae1a..69d6424d5bf3d4e9be9bbfb4ed3cee3281b3a786 100644 --- a/src/output/OutputNamedItemValueSet.hpp +++ b/src/output/OutputNamedItemValueSet.hpp @@ -67,9 +67,9 @@ class OutputNamedItemDataSet NodeValue<const TinyVector<1, double>>, NodeValue<const TinyVector<2, double>>, NodeValue<const TinyVector<3, double>>, - NodeValue<const TinyMatrix<1, double>>, - NodeValue<const TinyMatrix<2, double>>, - NodeValue<const TinyMatrix<3, double>>, + NodeValue<const TinyMatrix<1, 1, double>>, + NodeValue<const TinyMatrix<2, 2, double>>, + NodeValue<const TinyMatrix<3, 3, double>>, CellValue<const bool>, CellValue<const int>, @@ -79,9 +79,9 @@ class OutputNamedItemDataSet CellValue<const TinyVector<1, double>>, CellValue<const TinyVector<2, double>>, CellValue<const TinyVector<3, double>>, - CellValue<const TinyMatrix<1, double>>, - CellValue<const TinyMatrix<2, double>>, - CellValue<const TinyMatrix<3, double>>, + CellValue<const TinyMatrix<1, 1, double>>, + CellValue<const TinyMatrix<2, 2, double>>, + CellValue<const TinyMatrix<3, 3, double>>, NodeArray<const bool>, NodeArray<const int>, diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp index 0bbdde090daab2cb49a086d359dbbe3b4e53739a..d01476cac3da67c1400efef7e3603e9bb91e096d 100644 --- a/src/output/VTKWriter.cpp +++ b/src/output/VTKWriter.cpp @@ -273,7 +273,7 @@ template <size_t N, typename DataType> void VTKWriter::_write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyMatrix<N, DataType>>& item_value, + const NodeValue<const TinyMatrix<N, N, DataType>>& item_value, SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N * N diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp index 7baede4556fb37e2b3b29f449dfbdaf5dfa8b143..913a05ef1de358cfe32f9b6faf1a9e6720585238 100644 --- a/src/output/VTKWriter.hpp +++ b/src/output/VTKWriter.hpp @@ -61,7 +61,7 @@ class VTKWriter : public WriterBase template <size_t N, typename DataType> void _write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyMatrix<N, DataType>>& item_value, + const NodeValue<const TinyMatrix<N, N, DataType>>& item_value, SerializedDataList& serialized_data_list) const; template <typename DataType> diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp index 21589e732ecde0a85491438ae7dba259b8ed3060..adf3f4a7f38216558602b5e5634c89364ef3cf6e 100644 --- a/src/output/WriterBase.cpp +++ b/src/output/WriterBase.cpp @@ -89,19 +89,19 @@ WriterBase::_register(const std::string& name, switch (data_type.numberOfRows()) { case 1: { _register(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<1, double>>&>(i_discrete_function), + dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<1, 1, double>>&>(i_discrete_function), named_item_data_set); break; } case 2: { _register(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<2, double>>&>(i_discrete_function), + dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<2, 2, double>>&>(i_discrete_function), named_item_data_set); break; } case 3: { _register(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<3, double>>&>(i_discrete_function), + dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<3, 3, double>>&>(i_discrete_function), named_item_data_set); break; } diff --git a/src/scheme/DiscreteFunctionP0Vector.hpp b/src/scheme/DiscreteFunctionP0Vector.hpp index 103718b125e123692241715e697ab89869d078eb..5f00d5964d3b0e060549a6337b62e40fe2b97f21 100644 --- a/src/scheme/DiscreteFunctionP0Vector.hpp +++ b/src/scheme/DiscreteFunctionP0Vector.hpp @@ -3,6 +3,7 @@ #include <scheme/IDiscreteFunction.hpp> +#include <algebra/Vector.hpp> #include <mesh/Connectivity.hpp> #include <mesh/ItemArray.hpp> #include <mesh/Mesh.hpp> @@ -194,6 +195,19 @@ class DiscreteFunctionP0Vector : public IDiscreteFunction return product; } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> + dot(const DiscreteFunctionP0Vector& f, const DiscreteFunctionP0Vector& g) + { + Assert(f.mesh() == g.mesh(), "functions are nor defined on the same mesh"); + Assert(f.size() == g.size()); + DiscreteFunctionP0<Dimension, double> result{f.m_mesh}; + parallel_for( + f.m_mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { result[cell_id] = dot(Vector{f[cell_id]}, Vector{g[cell_id]}); }); + + return result; + } + DiscreteFunctionP0Vector(const std::shared_ptr<const MeshType>& mesh, size_t size) : m_mesh{mesh}, m_cell_arrays{mesh->connectivity(), size} {} diff --git a/src/utils/BacktraceManager.cpp b/src/utils/BacktraceManager.cpp index 26219cbd7b0eb3eb6a451e3ba0587af14445676a..0ba95d6a6edd0e52b059e0b28638384eec13b602 100644 --- a/src/utils/BacktraceManager.cpp +++ b/src/utils/BacktraceManager.cpp @@ -8,6 +8,14 @@ #include <rang.hpp> #include <regex> +bool BacktraceManager::s_show = false; + +void +BacktraceManager::setShow(bool show_backtrace) +{ + s_show = show_backtrace; +} + BacktraceManager::BacktraceManager() { const int size = 100; @@ -26,28 +34,33 @@ BacktraceManager::BacktraceManager() std::ostream& operator<<(std::ostream& os, const BacktraceManager& btm) { - const std::vector<std::string>& lines = btm.m_lines; - - const std::regex mangled_function(R"%(\(.*\+)%"); - const int width = std::log10(lines.size()) + 1; - - for (size_t i_line = 0; i_line < lines.size(); ++i_line) { - const auto& line = lines[i_line]; - os << rang::fg::green << "[" << std::setw(width) << i_line + 1 << '/' << lines.size() << "] " << rang::fg::reset; - std::smatch matchex; - if (std::regex_search(line, matchex, mangled_function)) { - std::string prefix = matchex.prefix().str(); - std::string function = line.substr(matchex.position() + 1, matchex.length() - 2); - std::string suffix = matchex.suffix().str(); - - os << prefix << '('; - if (function.size() > 0) { - os << rang::style::bold << demangle(function) << rang::style::reset; + if (BacktraceManager::s_show) { + const std::vector<std::string>& lines = btm.m_lines; + + const std::regex mangled_function(R"%(\(.*\+)%"); + const int width = std::log10(lines.size()) + 1; + + for (size_t i_line = 0; i_line < lines.size(); ++i_line) { + const auto& line = lines[i_line]; + os << rang::fg::green << "[" << std::setw(width) << i_line + 1 << '/' << lines.size() << "] " << rang::fg::reset; + std::smatch matchex; + if (std::regex_search(line, matchex, mangled_function)) { + std::string prefix = matchex.prefix().str(); + std::string function = line.substr(matchex.position() + 1, matchex.length() - 2); + std::string suffix = matchex.suffix().str(); + + os << prefix << '('; + if (function.size() > 0) { + os << rang::style::bold << demangle(function) << rang::style::reset; + } + os << '+' << suffix << '\n'; + } else { + os << line << '\n'; } - os << '+' << suffix << '\n'; - } else { - os << line << '\n'; } + } else { + os << rang::fg::yellow << "\n[To display backtrace launch pugs with the --backtrace option]" << rang::style::reset + << '\n'; } return os; diff --git a/src/utils/BacktraceManager.hpp b/src/utils/BacktraceManager.hpp index 0ff2d2d42575ee42498a33fa2fd1c235a3e20b22..e990ffd3b4060f71370a0f8b7386cdfcd6c03ea8 100644 --- a/src/utils/BacktraceManager.hpp +++ b/src/utils/BacktraceManager.hpp @@ -7,9 +7,12 @@ class BacktraceManager { private: + static bool s_show; std::vector<std::string> m_lines; public: + static void setShow(bool show_backtrace); + BacktraceManager(); friend std::ostream& operator<<(std::ostream& os, const BacktraceManager& btm); diff --git a/src/utils/PETScWrapper.cpp b/src/utils/PETScWrapper.cpp index f88bbfd8a6bfd9de92d153e54c68e111f0b692b6..18b16aa1435c2f27dc4d850c0727ddb4e259acb0 100644 --- a/src/utils/PETScWrapper.cpp +++ b/src/utils/PETScWrapper.cpp @@ -13,6 +13,7 @@ initialize([[maybe_unused]] int& argc, [[maybe_unused]] char* argv[]) { #ifdef PUGS_HAS_PETSC PetscOptionsSetValue(NULL, "-no_signal_handler", "true"); + PetscOptionsSetValue(NULL, "-fp_trap", "false"); PetscInitialize(&argc, &argv, 0, 0); #endif // PUGS_HAS_PETSC } diff --git a/src/utils/PugsTraits.hpp b/src/utils/PugsTraits.hpp index 504d694ad86a08811a4a87e2c8098dab77cd607d..46a2b1d6dc5923d8ee12668d88484875f404944c 100644 --- a/src/utils/PugsTraits.hpp +++ b/src/utils/PugsTraits.hpp @@ -12,7 +12,7 @@ template <size_t N, typename T> class TinyVector; -template <size_t N, typename T> +template <size_t M, size_t N, typename T> class TinyMatrix; template <typename DataType, ItemType item_type, typename ConnectivityPtr> @@ -30,10 +30,10 @@ inline constexpr bool is_trivially_castable<TinyVector<N, T>> = is_trivially_cas template <size_t N, typename T> inline constexpr bool is_trivially_castable<const TinyVector<N, T>> = is_trivially_castable<T>; -template <size_t N, typename T> -inline constexpr bool is_trivially_castable<TinyMatrix<N, T>> = is_trivially_castable<T>; -template <size_t N, typename T> -inline constexpr bool is_trivially_castable<const TinyMatrix<N, T>> = is_trivially_castable<T>; +template <size_t M, size_t N, typename T> +inline constexpr bool is_trivially_castable<TinyMatrix<M, N, T>> = is_trivially_castable<T>; +template <size_t M, size_t N, typename T> +inline constexpr bool is_trivially_castable<const TinyMatrix<M, N, T>> = is_trivially_castable<T>; // Traits is_false @@ -105,8 +105,8 @@ inline constexpr bool is_tiny_vector_v<TinyVector<N, T>> = true; template <typename T> inline constexpr bool is_tiny_matrix_v = false; -template <size_t N, typename T> -inline constexpr bool is_tiny_matrix_v<TinyMatrix<N, T>> = true; +template <size_t M, size_t N, typename T> +inline constexpr bool is_tiny_matrix_v<TinyMatrix<M, N, T>> = true; // Trais is ItemValue diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp index d35fa95f43cb03810814ec6b62ed039842de1289..c4372c47dd3b826fdff2be76704070a04b2f9fcf 100644 --- a/src/utils/PugsUtils.cpp +++ b/src/utils/PugsUtils.cpp @@ -1,5 +1,6 @@ #include <utils/PugsUtils.hpp> +#include <utils/BacktraceManager.hpp> #include <utils/BuildInfo.hpp> #include <utils/ConsoleManager.hpp> #include <utils/FPEManager.hpp> @@ -79,6 +80,8 @@ std::string initialize(int& argc, char* argv[]) { parallel::Messenger::create(argc, argv); + bool enable_fpe = true; + bool enable_signals = true; std::string filename; { @@ -100,10 +103,11 @@ initialize(int& argc, char* argv[]) bool enable_color = true; app.add_flag("--color,!--no-color", enable_color, "Colorize console output [default: true]"); - bool enable_fpe = true; app.add_flag("--fpe,!--no-fpe", enable_fpe, "Trap floating point exceptions [default: true]"); - bool enable_signals = true; + bool show_backtrace = false; + app.add_flag("-b,--backtrace,!--no-backtrace", show_backtrace, "Show backtrace on failure [default: false]"); + app.add_flag("--signal,!--no-signal", enable_signals, "Catches signals [default: true]"); bool pause_on_error = false; @@ -118,15 +122,17 @@ initialize(int& argc, char* argv[]) std::exit(app.exit(e, std::cout, std::cerr)); } + BacktraceManager::setShow(show_backtrace); ConsoleManager::init(enable_color); - FPEManager::init(enable_fpe); SignalManager::setPauseForDebug(pause_on_error); - SignalManager::init(enable_signals); } PETScWrapper::initialize(argc, argv); SLEPcWrapper::initialize(argc, argv); + FPEManager::init(enable_fpe); + SignalManager::init(enable_signals); + setDefaultOMPEnvironment(); Kokkos::initialize(argc, argv); std::cout << "----------------- " << rang::fg::green << "pugs exec info" << rang::fg::reset diff --git a/src/utils/SmallArray.hpp b/src/utils/SmallArray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b5186a7f6341606a92084fd7ee5521b5d252b4ee --- /dev/null +++ b/src/utils/SmallArray.hpp @@ -0,0 +1,144 @@ +#ifndef SMALL_ARRAY_HPP +#define SMALL_ARRAY_HPP + +#include <utils/InvalidData.hpp> +#include <utils/NaNHelper.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> +#include <utils/PugsUtils.hpp> + +#include <algorithm> + +template <typename DataType> +class [[nodiscard]] SmallArray +{ + public: + using data_type = DataType; + using index_type = size_t; + + private: + index_type m_size; + std::shared_ptr<DataType[]> m_values; + + // Allows const version to access our data + friend SmallArray<std::add_const_t<DataType>>; + + public: + PUGS_INLINE size_t size() const noexcept + { + return m_size; + } + + friend PUGS_INLINE SmallArray<std::remove_const_t<DataType>> copy(const SmallArray<DataType>& source) + { + SmallArray<std::remove_const_t<DataType>> image(source.m_size); + std::copy(source.m_values.get(), source.m_values.get() + source.m_size, image.m_values.get()); + + return image; + } + + friend PUGS_INLINE void copy_to(const SmallArray<DataType>& source, + const SmallArray<std::remove_const_t<DataType>>& destination) + { + Assert(source.size() == destination.size()); + std::copy(source.m_values.get(), source.m_values.get() + source.m_size, destination.m_values.get()); + } + + PUGS_INLINE DataType& operator[](index_type i) const noexcept(NO_ASSERT) + { + Assert(i < m_size); + return m_values[i]; + } + + PUGS_INLINE + void fill(const DataType& data) const + { + static_assert(not std::is_const_v<DataType>, "Cannot modify SmallArray of const"); + std::fill(m_values.get(), m_values.get() + m_size, data); + } + + template <typename DataType2> + PUGS_INLINE SmallArray& operator=(const SmallArray<DataType2>& array) noexcept + { + // ensures that DataType is the same as source DataType2 + static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), + "Cannot assign SmallArray of different type"); + // ensures that const is not lost through copy + static_assert(((std::is_const_v<DataType2> and std::is_const_v<DataType>) or not std::is_const_v<DataType2>), + "Cannot assign SmallArray of const to SmallArray of non-const"); + + m_size = array.size(); + m_values = array.m_values; + return *this; + } + + PUGS_INLINE + SmallArray& operator=(const SmallArray&) = default; + + PUGS_INLINE + SmallArray& operator=(SmallArray&&) = default; + + PUGS_INLINE + explicit SmallArray(size_t size) : m_size{size}, m_values{std::shared_ptr<DataType[]>(new DataType[size])} + { + static_assert(not std::is_const<DataType>(), "Cannot allocate SmallArray of const data: only view is " + "supported"); + +#ifndef NDEBUG + if constexpr (not std::is_const_v<DataType>) { + using T = std::decay_t<DataType>; + if constexpr (std::is_arithmetic_v<T>) { + this->fill(invalid_data_v<T>); + } else if constexpr (is_tiny_vector_v<T>) { + this->fill(T{}); + } else if constexpr (is_tiny_matrix_v<T>) { + this->fill(T{}); + } + } +#endif // NDEBUG + } + + friend std::ostream& operator<<(std::ostream& os, const SmallArray& x) + { + if (x.size() > 0) { + os << 0 << ':' << NaNHelper(x[0]); + } + for (size_t i = 1; i < x.size(); ++i) { + os << ' ' << i << ':' << NaNHelper(x[i]); + } + return os; + } + + PUGS_INLINE + SmallArray() = default; + + PUGS_INLINE + SmallArray(const SmallArray&) = default; + + template <typename DataType2> + PUGS_INLINE SmallArray(const SmallArray<DataType2>& array) noexcept + { + this->operator=(array); + } + + PUGS_INLINE + SmallArray(SmallArray &&) = default; + + PUGS_INLINE + ~SmallArray() = default; +}; + +// map, multimap, unordered_map and stack cannot be copied this way +template <typename Container> +PUGS_INLINE SmallArray<std::remove_const_t<typename Container::value_type>> +convert_to_small_array(const Container& given_container) +{ + using DataType = typename Container::value_type; + SmallArray<std::remove_const_t<DataType>> array(given_container.size()); + if (given_container.size() > 0) { + std::copy(begin(given_container), end(given_container), &(array[0])); + } + return array; +} + +#endif // SMALL_ARRAY_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 63a95ae67d58d3028c9af1996955588f96992346..5902fa80c022ef4efea13be21c6865ad32204df1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -59,7 +59,6 @@ add_executable (unit_tests test_CRSMatrix.cpp test_CRSMatrixDescriptor.cpp test_DataVariant.cpp - test_DenseMatrix.cpp test_Demangle.cpp test_DiscreteFunctionDescriptorP0.cpp test_DiscreteFunctionDescriptorP0Vector.cpp @@ -88,13 +87,14 @@ add_executable (unit_tests test_MathModule.cpp test_NameProcessor.cpp test_NaNHelper.cpp - test_OStreamProcessor.cpp + test_OStream.cpp test_ParseError.cpp test_PETScUtils.cpp test_PugsAssert.cpp test_PugsFunctionAdapter.cpp test_PugsUtils.cpp test_RevisionInfo.cpp + test_SmallArray.cpp test_SymbolTable.cpp test_Table.cpp test_Timer.cpp @@ -120,6 +120,7 @@ add_executable (mpi_unit_tests test_ItemValue.cpp test_ItemValueUtils.cpp test_Messenger.cpp + test_OFStream.cpp test_Partitioner.cpp test_RandomEngine.cpp test_SubItemValuePerItem.cpp diff --git a/tests/test_ASTBuilder.cpp b/tests/test_ASTBuilder.cpp index 387e84b75b359b1cd4f95dd594f798e56b02208c..3ce2855eff1b059c0ac0e4215b8b1410e45af165 100644 --- a/tests/test_ASTBuilder.cpp +++ b/tests/test_ASTBuilder.cpp @@ -600,7 +600,7 @@ for(let i:N, i=0; i<10; ++i) { CHECK_AST(data, result); } - SECTION("ostream simplifications") + SECTION("ostream") { std::string_view data = R"( cout << 1+2 << "\n"; @@ -610,16 +610,22 @@ clog << "log " << l << "\n"; std::string_view result = R"( (root) - +-(language::cout_kw) - | +-(language::plus_op) - | | +-(language::integer:1) - | | `-(language::integer:2) + +-(language::shift_left_op) + | +-(language::shift_left_op) + | | +-(language::name:cout) + | | `-(language::plus_op) + | | +-(language::integer:1) + | | `-(language::integer:2) | `-(language::literal:"\n") - +-(language::cerr_kw) + +-(language::shift_left_op) + | +-(language::name:cerr) | `-(language::literal:"error?\n") - `-(language::clog_kw) - +-(language::literal:"log ") - +-(language::name:l) + `-(language::shift_left_op) + +-(language::shift_left_op) + | +-(language::shift_left_op) + | | +-(language::name:clog) + | | `-(language::literal:"log ") + | `-(language::name:l) `-(language::literal:"\n") )"; CHECK_AST(data, result); diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp index 96af38a0b905014ea518653795ba95850e486055..2e3835024a270781d0dccb37edd914abfdd63a51 100644 --- a/tests/test_ASTNodeDataTypeBuilder.cpp +++ b/tests/test_ASTNodeDataTypeBuilder.cpp @@ -1413,11 +1413,14 @@ clog << "clog\n"; std::string_view result = R"( (root:void) - +-(language::cout_kw:void) + +-(language::shift_left_op:ostream) + | +-(language::name:cout:ostream) | `-(language::literal:"cout\n":string) - +-(language::cerr_kw:void) + +-(language::shift_left_op:ostream) + | +-(language::name:cerr:ostream) | `-(language::literal:"cerr\n":string) - `-(language::clog_kw:void) + `-(language::shift_left_op:ostream) + +-(language::name:clog:ostream) `-(language::literal:"clog\n":string) )"; @@ -1445,8 +1448,10 @@ for (let i : N, i=0; i<3; ++i){ | `-(language::integer:3:Z) +-(language::unary_plusplus:N) | `-(language::name:i:N) - `-(language::cout_kw:void) - +-(language::name:i:N) + `-(language::shift_left_op:ostream) + +-(language::shift_left_op:ostream) + | +-(language::name:cout:ostream) + | `-(language::name:i:N) `-(language::literal:"\n":string) )"; diff --git a/tests/test_ASTNodeExpressionBuilder.cpp b/tests/test_ASTNodeExpressionBuilder.cpp index cb6fdbfef85884a013e112a978207729ba965835..25a3d3a93f21294bbd04ae238ccbfcca5f4738fb 100644 --- a/tests/test_ASTNodeExpressionBuilder.cpp +++ b/tests/test_ASTNodeExpressionBuilder.cpp @@ -684,7 +684,7 @@ cout; std::string result = R"( (root:ASTNodeListProcessor) - `-(language::cout_kw:OStreamProcessor) + `-(language::name:cout:NameProcessor) )"; CHECK_AST(data, result); @@ -698,7 +698,7 @@ cerr; std::string result = R"( (root:ASTNodeListProcessor) - `-(language::cerr_kw:OStreamProcessor) + `-(language::name:cerr:NameProcessor) )"; CHECK_AST(data, result); @@ -712,7 +712,7 @@ clog; std::string result = R"( (root:ASTNodeListProcessor) - `-(language::clog_kw:OStreamProcessor) + `-(language::name:clog:NameProcessor) )"; CHECK_AST(data, result); diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp index b37dd10869bb5665c9292b22e363af09be4b9ead..4bf775a679490306efecc2617547cb424c6a256b 100644 --- a/tests/test_ASTNodeFunctionExpressionBuilder.cpp +++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp @@ -655,7 +655,7 @@ f(1); std::string_view result = R"( (root:ASTNodeListProcessor) - `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<1ul, double>, ZeroType>) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<1ul, 1ul, double>, ZeroType>) +-(language::name:f:NameProcessor) `-(language::integer:1:ValueProcessor) )"; @@ -672,7 +672,7 @@ f(1); std::string_view result = R"( (root:ASTNodeListProcessor) - `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<2ul, double>, ZeroType>) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<2ul, 2ul, double>, ZeroType>) +-(language::name:f:NameProcessor) `-(language::integer:1:ValueProcessor) )"; @@ -689,7 +689,7 @@ f(1); std::string_view result = R"( (root:ASTNodeListProcessor) - `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<3ul, double>, ZeroType>) + `-(language::function_evaluation:FunctionExpressionProcessor<TinyMatrix<3ul, 3ul, double>, ZeroType>) +-(language::name:f:NameProcessor) `-(language::integer:1:ValueProcessor) )"; diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp index 6eab14fe5162b64a1d883cd54d8b9a70e20a5d66..8d495053e0d0e09b67c103a4f387ecf6afc018bf 100644 --- a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp +++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp @@ -239,17 +239,17 @@ let (x1,x2,x3,x) : R^1x1*R^2x2*R^3x3*R, std::string_view result = R"( (root:ASTNodeListProcessor) - +-(language::eq_op:AffectationProcessor<language::eq_op, TinyMatrix<1ul, double>, long>) + +-(language::eq_op:AffectationProcessor<language::eq_op, TinyMatrix<1ul, 1ul, double>, long>) | +-(language::name:a:NameProcessor) | `-(language::integer:0:ValueProcessor) - +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<2ul, double> >) + +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<2ul, 2ul, double> >) | +-(language::name:b:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:1:ValueProcessor) | +-(language::integer:2:ValueProcessor) | +-(language::integer:3:ValueProcessor) | `-(language::integer:4:ValueProcessor) - +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<3ul, double> >) + +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<3ul, 3ul, double> >) | +-(language::name:c:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:9:ValueProcessor) diff --git a/tests/test_ASTNodeTypeCleaner.cpp b/tests/test_ASTNodeTypeCleaner.cpp index e1abf88d600d45ba9ae77d3c25b4904adf6992d4..d78d4ce17fba3046d75e3ea1108d3874a3636dec 100644 --- a/tests/test_ASTNodeTypeCleaner.cpp +++ b/tests/test_ASTNodeTypeCleaner.cpp @@ -42,9 +42,12 @@ cout << "two=" << 2 << "\n"; std::string_view result = R"( (root) - `-(language::cout_kw) - +-(language::literal:"two=") - +-(language::integer:2) + `-(language::shift_left_op) + +-(language::shift_left_op) + | +-(language::shift_left_op) + | | +-(language::name:cout) + | | `-(language::literal:"two=") + | `-(language::integer:2) `-(language::literal:"\n") )"; diff --git a/tests/test_AffectationToTupleProcessor.cpp b/tests/test_AffectationToTupleProcessor.cpp index 650e60ca61bb6bc1d8b2e239c9e4c67713c3212a..d832ac2739cb6b8417e6dfd3818e11252639b7b4 100644 --- a/tests/test_AffectationToTupleProcessor.cpp +++ b/tests/test_AffectationToTupleProcessor.cpp @@ -87,7 +87,7 @@ let s :(R^1); s = 1.3; const std::string A_string = []() -> std::string { std::ostringstream os; - os << TinyMatrix<2, double>{1, 2, 3, 4}; + os << TinyMatrix<2>{1, 2, 3, 4}; return os.str(); }(); @@ -162,7 +162,7 @@ let t :(R^1); t = (x,2); const std::string A_string = []() -> std::string { std::ostringstream os; - os << TinyMatrix<2, double>{1, 2, 3, 4}; + os << TinyMatrix<2>{1, 2, 3, 4}; return os.str(); }(); @@ -216,7 +216,7 @@ let s :(string); s = x; const std::string A_string = []() -> std::string { std::ostringstream os; - os << TinyMatrix<3, double>{1, 2, 3, 4, 5, 6, 7, 8, 9}; + os << TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}; return os.str(); }(); diff --git a/tests/test_ArrayUtils.cpp b/tests/test_ArrayUtils.cpp index 79df610d909873a84328b59403ec861269b4f8b3..eb976b40df67c640bbe1a376671706835ca4c2e0 100644 --- a/tests/test_ArrayUtils.cpp +++ b/tests/test_ArrayUtils.cpp @@ -64,7 +64,7 @@ TEST_CASE("ArrayUtils", "[utils]") SECTION("TinyMatrix Sum") { - using N22 = TinyMatrix<2, int>; + using N22 = TinyMatrix<2, 2, int>; Array<N22> b(10); b[0] = {13, 2, 0, 1}; b[1] = {1, 3, 6, 3}; diff --git a/tests/test_CRSMatrix.cpp b/tests/test_CRSMatrix.cpp index d0d9476ab0e47ff90874391c63f39a6321adbc3b..cf6d65b87b10c362e89935ce89dc7ac79f490cd4 100644 --- a/tests/test_CRSMatrix.cpp +++ b/tests/test_CRSMatrix.cpp @@ -165,6 +165,177 @@ TEST_CASE("CRSMatrix", "[algebra]") REQUIRE(y[3] == 150); } + SECTION("square matrices sum") + { + Array<int> non_zeros_DA{4}; + non_zeros_DA.fill(2); + CRSMatrixDescriptor<int> DA{4, 4, non_zeros_DA}; + DA(0, 0) = 1; + DA(0, 1) = 2; + DA(1, 0) = 5; + DA(1, 1) = 6; + DA(2, 0) = 9; + DA(2, 3) = 12; + DA(3, 0) = 13; + DA(3, 3) = 16; + + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> non_zeros_DB{4}; + non_zeros_DB.fill(2); + CRSMatrixDescriptor<int> DB{4, 4, non_zeros_DB}; + DB(0, 0) = 1; + DB(0, 2) = 2; + DB(1, 0) = 5; + DB(1, 2) = 6; + DB(2, 0) = 9; + DB(2, 2) = 12; + DB(3, 0) = 13; + DB(3, 3) = 16; + + CRSMatrix<int> B{DB.getCRSMatrix()}; + + std::ostringstream ost; + ost << A + B; + + std::string ref = R"(0| 0:2 1:2 2:2 +1| 0:10 1:6 2:6 +2| 0:18 2:12 3:12 +3| 0:26 3:32 +)"; + + REQUIRE(ost.str() == ref); + } + + SECTION("square matrices difference") + { + Array<int> non_zeros_DA{4}; + non_zeros_DA.fill(2); + CRSMatrixDescriptor<int> DA{4, 4, non_zeros_DA}; + DA(0, 0) = 1; + DA(0, 1) = 2; + DA(1, 0) = 5; + DA(1, 1) = 6; + DA(2, 0) = 9; + DA(2, 3) = 12; + DA(3, 0) = 13; + DA(3, 3) = 16; + + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> non_zeros_DB{4}; + non_zeros_DB.fill(2); + CRSMatrixDescriptor<int> DB{4, 4, non_zeros_DB}; + DB(0, 0) = -1; + DB(0, 2) = 3; + DB(1, 0) = 7; + DB(1, 2) = 3; + DB(2, 0) = 7; + DB(2, 2) = 11; + DB(3, 0) = 3; + DB(3, 3) = 8; + + CRSMatrix<int> B{DB.getCRSMatrix()}; + + std::ostringstream ost; + ost << A - B; + + std::string ref = R"(0| 0:2 1:2 2:-3 +1| 0:-2 1:6 2:-3 +2| 0:2 2:-11 3:12 +3| 0:10 3:8 +)"; + + REQUIRE(ost.str() == ref); + } + + SECTION("rectangle matrices sum") + { + Array<int> non_zeros_DA{4}; + non_zeros_DA.fill(2); + CRSMatrixDescriptor<int> DA{4, 5, non_zeros_DA}; + DA(0, 0) = 1; + DA(0, 1) = 2; + DA(0, 4) = 2; + DA(1, 0) = 5; + DA(1, 1) = 6; + DA(2, 0) = 9; + DA(2, 3) = 12; + DA(3, 0) = 13; + DA(3, 3) = 16; + DA(3, 4) = 16; + + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> non_zeros_DB{4}; + non_zeros_DB.fill(2); + CRSMatrixDescriptor<int> DB{4, 5, non_zeros_DB}; + DB(0, 0) = 1; + DB(0, 2) = 2; + DB(1, 0) = 5; + DB(1, 2) = 6; + DB(1, 4) = 3; + DB(2, 0) = 9; + DB(2, 2) = 12; + DB(3, 0) = 13; + DB(3, 3) = 16; + + CRSMatrix<int> B{DB.getCRSMatrix()}; + + std::ostringstream ost; + ost << A + B; + + std::string ref = R"(0| 0:2 1:2 2:2 4:2 +1| 0:10 1:6 2:6 4:3 +2| 0:18 2:12 3:12 +3| 0:26 3:32 4:16 +)"; + + REQUIRE(ost.str() == ref); + } + + SECTION("rectangle matrices difference") + { + Array<int> non_zeros_DA{4}; + non_zeros_DA.fill(2); + CRSMatrixDescriptor<int> DA{4, 3, non_zeros_DA}; + DA(0, 0) = 1; + DA(0, 1) = 2; + DA(1, 0) = 5; + DA(1, 1) = 6; + DA(2, 0) = 9; + DA(2, 2) = 12; + DA(3, 0) = 13; + DA(3, 2) = 16; + + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> non_zeros_DB{4}; + non_zeros_DB.fill(2); + CRSMatrixDescriptor<int> DB{4, 3, non_zeros_DB}; + DB(0, 0) = -1; + DB(0, 2) = 3; + DB(1, 0) = 7; + DB(1, 2) = 3; + DB(2, 0) = 7; + DB(2, 2) = 11; + DB(3, 0) = 3; + DB(3, 1) = 8; + + CRSMatrix<int> B{DB.getCRSMatrix()}; + + std::ostringstream ost; + ost << A - B; + + std::string ref = R"(0| 0:2 1:2 2:-3 +1| 0:-2 1:6 2:-3 +2| 0:2 2:1 +3| 0:10 1:-8 2:16 +)"; + + REQUIRE(ost.str() == ref); + } + SECTION("check values") { Array<int> non_zeros{4}; @@ -237,14 +408,45 @@ TEST_CASE("CRSMatrix", "[algebra]") } #ifndef NDEBUG - SECTION("incompatible runtime matrix/vector product") + SECTION("runtime incompatible matrix/vector product") { Array<int> non_zeros(2); non_zeros.fill(0); CRSMatrixDescriptor<int> S{2, 4, non_zeros}; CRSMatrix<int> A{S.getCRSMatrix()}; Vector<int> x{2}; - REQUIRE_THROWS_AS(A * x, AssertError); + REQUIRE_THROWS_WITH(A * x, "cannot compute product: incompatible matrix and vector sizes"); } + + SECTION("runtime incompatible matrices sum") + { + Array<int> A_non_zeros(2); + A_non_zeros.fill(0); + CRSMatrixDescriptor<int> DA{2, 4, A_non_zeros}; + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> B_non_zeros(3); + B_non_zeros.fill(0); + CRSMatrixDescriptor<int> DB{3, 4, B_non_zeros}; + CRSMatrix<int> B{DB.getCRSMatrix()}; + + REQUIRE_THROWS_WITH(A + B, "cannot apply inner binary operator on matrices of different sizes"); + } + + SECTION("runtime incompatible matrices difference") + { + Array<int> A_non_zeros(2); + A_non_zeros.fill(0); + CRSMatrixDescriptor<int> DA{2, 4, A_non_zeros}; + CRSMatrix<int> A{DA.getCRSMatrix()}; + + Array<int> B_non_zeros(2); + B_non_zeros.fill(0); + CRSMatrixDescriptor<int> DB{2, 3, B_non_zeros}; + CRSMatrix<int> B{DB.getCRSMatrix()}; + + REQUIRE_THROWS_WITH(A - B, "cannot apply inner binary operator on matrices of different sizes"); + } + #endif // NDEBUG } diff --git a/tests/test_DenseMatrix.cpp b/tests/test_DenseMatrix.cpp deleted file mode 100644 index b794689a09793f0bd844144c9b7ccdb39338f648..0000000000000000000000000000000000000000 --- a/tests/test_DenseMatrix.cpp +++ /dev/null @@ -1,470 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <utils/PugsAssert.hpp> - -#include <algebra/DenseMatrix.hpp> -#include <algebra/Vector.hpp> - -// Instantiate to ensure full coverage is performed -template class DenseMatrix<int>; - -// clazy:excludeall=non-pod-global-static - -TEST_CASE("DenseMatrix", "[algebra]") -{ - SECTION("size") - { - DenseMatrix<int> A{2, 3}; - REQUIRE(A.numberOfRows() == 2); - REQUIRE(A.numberOfColumns() == 3); - } - - SECTION("is square") - { - REQUIRE(not DenseMatrix<int>{2, 3}.isSquare()); - REQUIRE(not DenseMatrix<int>{4, 3}.isSquare()); - REQUIRE(DenseMatrix<int>{1, 1}.isSquare()); - REQUIRE(DenseMatrix<int>{2, 2}.isSquare()); - REQUIRE(DenseMatrix<int>{3, 3}.isSquare()); - } - - SECTION("write access") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - REQUIRE(A(0, 0) == 0); - REQUIRE(A(0, 1) == 1); - REQUIRE(A(0, 2) == 2); - REQUIRE(A(1, 0) == 3); - REQUIRE(A(1, 1) == 4); - REQUIRE(A(1, 2) == 5); - DenseMatrix<const int> const_A = A; - REQUIRE(const_A(0, 0) == 0); - REQUIRE(const_A(0, 1) == 1); - REQUIRE(const_A(0, 2) == 2); - REQUIRE(const_A(1, 0) == 3); - REQUIRE(const_A(1, 1) == 4); - REQUIRE(const_A(1, 2) == 5); - } - - SECTION("fill") - { - DenseMatrix<int> A{2, 3}; - A.fill(2); - REQUIRE(A(0, 0) == 2); - REQUIRE(A(0, 1) == 2); - REQUIRE(A(0, 2) == 2); - REQUIRE(A(1, 0) == 2); - REQUIRE(A(1, 1) == 2); - REQUIRE(A(1, 2) == 2); - } - - SECTION("zero matrix") - { - DenseMatrix<int> A{2, 3}; - A = zero; - for (size_t i = 0; i < A.numberOfRows(); ++i) { - for (size_t j = 0; j < A.numberOfColumns(); ++j) { - REQUIRE(A(i, j) == 0); - } - } - } - - SECTION("identity matrix") - { - DenseMatrix<int> A{3, 3}; - A = identity; - for (size_t i = 0; i < A.numberOfRows(); ++i) { - for (size_t j = 0; j < A.numberOfColumns(); ++j) { - REQUIRE(A(i, j) == (i == j)); - } - } - } - - SECTION("copy constructor (shallow)") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - const DenseMatrix<int> B = A; - REQUIRE(B(0, 0) == 0); - REQUIRE(B(0, 1) == 1); - REQUIRE(B(0, 2) == 2); - REQUIRE(B(1, 0) == 3); - REQUIRE(B(1, 1) == 4); - REQUIRE(B(1, 2) == 5); - } - - SECTION("copy (deep)") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - const DenseMatrix<int> B = copy(A); - - A(0, 0) = 10; - A(0, 1) = 11; - A(0, 2) = 12; - A(1, 0) = 13; - A(1, 1) = 14; - A(1, 2) = 15; - - REQUIRE(B(0, 0) == 0); - REQUIRE(B(0, 1) == 1); - REQUIRE(B(0, 2) == 2); - REQUIRE(B(1, 0) == 3); - REQUIRE(B(1, 1) == 4); - REQUIRE(B(1, 2) == 5); - - REQUIRE(A(0, 0) == 10); - REQUIRE(A(0, 1) == 11); - REQUIRE(A(0, 2) == 12); - REQUIRE(A(1, 0) == 13); - REQUIRE(A(1, 1) == 14); - REQUIRE(A(1, 2) == 15); - } - - SECTION("self scalar multiplication") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - A *= 2; - REQUIRE(A(0, 0) == 0); - REQUIRE(A(0, 1) == 2); - REQUIRE(A(0, 2) == 4); - REQUIRE(A(1, 0) == 6); - REQUIRE(A(1, 1) == 8); - REQUIRE(A(1, 2) == 10); - } - - SECTION("left scalar multiplication") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - const DenseMatrix<int> B = 2 * A; - - REQUIRE(B(0, 0) == 0); - REQUIRE(B(0, 1) == 2); - REQUIRE(B(0, 2) == 4); - REQUIRE(B(1, 0) == 6); - REQUIRE(B(1, 1) == 8); - REQUIRE(B(1, 2) == 10); - } - - SECTION("product matrix vector") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 6; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - Vector<int> x{3}; - x[0] = 7; - x[1] = 3; - x[2] = 4; - - Vector y = A * x; - REQUIRE(y[0] == 53); - REQUIRE(y[1] == 53); - } - - SECTION("self scalar division") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 2; - A(0, 2) = 4; - A(1, 0) = 6; - A(1, 1) = 8; - A(1, 2) = 10; - - A /= 2; - - REQUIRE(A(0, 0) == 0); - REQUIRE(A(0, 1) == 1); - REQUIRE(A(0, 2) == 2); - REQUIRE(A(1, 0) == 3); - REQUIRE(A(1, 1) == 4); - REQUIRE(A(1, 2) == 5); - } - - SECTION("self minus") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - DenseMatrix<int> B{2, 3}; - B(0, 0) = 5; - B(0, 1) = 6; - B(0, 2) = 4; - B(1, 0) = 2; - B(1, 1) = 1; - B(1, 2) = 3; - - A -= B; - - REQUIRE(A(0, 0) == -5); - REQUIRE(A(0, 1) == -5); - REQUIRE(A(0, 2) == -2); - REQUIRE(A(1, 0) == 1); - REQUIRE(A(1, 1) == 3); - REQUIRE(A(1, 2) == 2); - } - - SECTION("self sum") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - DenseMatrix<int> B{2, 3}; - B(0, 0) = 5; - B(0, 1) = 6; - B(0, 2) = 4; - B(1, 0) = 2; - B(1, 1) = 1; - B(1, 2) = 3; - - A += B; - - REQUIRE(A(0, 0) == 5); - REQUIRE(A(0, 1) == 7); - REQUIRE(A(0, 2) == 6); - REQUIRE(A(1, 0) == 5); - REQUIRE(A(1, 1) == 5); - REQUIRE(A(1, 2) == 8); - } - - SECTION("sum") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 6; - A(0, 1) = 5; - A(0, 2) = 4; - A(1, 0) = 3; - A(1, 1) = 2; - A(1, 2) = 1; - - DenseMatrix<int> B{2, 3}; - B(0, 0) = 0; - B(0, 1) = 1; - B(0, 2) = 2; - B(1, 0) = 3; - B(1, 1) = 4; - B(1, 2) = 5; - - DenseMatrix C = A + B; - REQUIRE(C(0, 0) == 6); - REQUIRE(C(0, 1) == 6); - REQUIRE(C(0, 2) == 6); - REQUIRE(C(1, 0) == 6); - REQUIRE(C(1, 1) == 6); - REQUIRE(C(1, 2) == 6); - } - - SECTION("difference") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 6; - A(0, 1) = 5; - A(0, 2) = 4; - A(1, 0) = 3; - A(1, 1) = 2; - A(1, 2) = 1; - - DenseMatrix<int> B{2, 3}; - B(0, 0) = 0; - B(0, 1) = 1; - B(0, 2) = 2; - B(1, 0) = 3; - B(1, 1) = 4; - B(1, 2) = 5; - - DenseMatrix C = A - B; - REQUIRE(C(0, 0) == 6); - REQUIRE(C(0, 1) == 4); - REQUIRE(C(0, 2) == 2); - REQUIRE(C(1, 0) == 0); - REQUIRE(C(1, 1) == -2); - REQUIRE(C(1, 2) == -4); - } - - SECTION("transpose") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 0; - A(0, 1) = 1; - A(0, 2) = 2; - A(1, 0) = 3; - A(1, 1) = 4; - A(1, 2) = 5; - - DenseMatrix B = transpose(A); - REQUIRE(B(0, 0) == 0); - REQUIRE(B(0, 1) == 3); - REQUIRE(B(1, 0) == 1); - REQUIRE(B(1, 1) == 4); - REQUIRE(B(2, 0) == 2); - REQUIRE(B(2, 1) == 5); - } - - SECTION("product matrix vector") - { - DenseMatrix<int> A{2, 3}; - A(0, 0) = 1; - A(0, 1) = 2; - A(0, 2) = 3; - A(1, 0) = 4; - A(1, 1) = 5; - A(1, 2) = 6; - - DenseMatrix<int> B{3, 2}; - B(0, 0) = 2; - B(0, 1) = 8; - B(1, 0) = 4; - B(1, 1) = 9; - B(2, 0) = 6; - B(2, 1) = 10; - - DenseMatrix C = A * B; - REQUIRE(C(0, 0) == 28); - REQUIRE(C(0, 1) == 56); - REQUIRE(C(1, 0) == 64); - REQUIRE(C(1, 1) == 137); - } - - SECTION("output") - { - DenseMatrix<double> A(3, 2); - A(0, 0) = 1; - A(0, 1) = 3; - A(1, 0) = -8; - A(1, 1) = -2; - A(2, 0) = 4; - A(2, 1) = -5; - std::ostringstream A_ost; - A_ost << A; - - std::ostringstream ref_ost; - ref_ost << "0| " << 0 << ':' << 1. << ' ' << 1 << ':' << 3. << '\n'; - ref_ost << "1| " << 0 << ':' << -8. << ' ' << 1 << ':' << -2. << '\n'; - ref_ost << "2| " << 0 << ':' << 4. << ' ' << 1 << ':' << -5. << '\n'; - - REQUIRE(A_ost.str() == ref_ost.str()); - } - -#ifndef NDEBUG - SECTION("output with signaling NaN") - { - DenseMatrix<double> A(3, 2); - A(0, 0) = 1; - A(1, 1) = -2; - A(2, 1) = -5; - std::ostringstream A_ost; - A_ost << A; - - std::ostringstream ref_ost; - ref_ost << "0| " << 0 << ':' << 1. << ' ' << 1 << ":nan\n"; - ref_ost << "1| " << 0 << ":nan " << 1 << ':' << -2. << '\n'; - ref_ost << "2| " << 0 << ":nan " << 1 << ':' << -5. << '\n'; - - REQUIRE(A_ost.str() == ref_ost.str()); - } - - SECTION("non square identity matrix") - { - DenseMatrix<int> A(2, 3); - - REQUIRE_THROWS_WITH(A = identity, "identity must be a square matrix"); - } - - SECTION("invalid matrix vector product") - { - DenseMatrix<int> A(2, 3); - Vector<int> u(2); - - REQUIRE_THROWS_WITH(A * u, "cannot compute matrix-vector product: incompatible sizes"); - } - - SECTION("invalid matrix product") - { - DenseMatrix<int> A(2, 3); - DenseMatrix<int> B(2, 3); - - REQUIRE_THROWS_WITH(A * B, "cannot compute matrix product: incompatible sizes"); - } - - SECTION("invalid matrix substract") - { - DenseMatrix<int> A(2, 3); - DenseMatrix<int> B(3, 2); - - REQUIRE_THROWS_WITH(A -= B, "cannot substract matrix: incompatible sizes"); - } - - SECTION("invalid matrix sum") - { - DenseMatrix<int> A(2, 3); - DenseMatrix<int> B(3, 2); - - REQUIRE_THROWS_WITH(A + B, "cannot compute matrix sum: incompatible sizes"); - } - - SECTION("invalid matrix difference") - { - DenseMatrix<int> A(2, 3); - DenseMatrix<int> B(3, 2); - - REQUIRE_THROWS_WITH(A - B, "cannot compute matrix difference: incompatible sizes"); - } - - SECTION("invalid indices") - { - DenseMatrix<int> A(2, 3); - - REQUIRE_THROWS_WITH(A(2, 0), "cannot access element: invalid indices"); - REQUIRE_THROWS_WITH(A(0, 3), "cannot access element: invalid indices"); - } - -#endif // NDEBUG -} diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index acfa7a0064d5368c251af31ff3cb8b9a6a9a749a..f8d7bb6ef78d027287cf7d721299f051ba7c7a98 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -302,9 +302,9 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") SECTION("matrix") { - const TinyMatrix<3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, size_t>> f{mesh}; + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; f.fill(value); REQUIRE(all_values_equal(f, value)); @@ -318,7 +318,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") copy_to(g, f); g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); REQUIRE(all_values_equal(f, value)); REQUIRE(all_values_equal(g, zero)); @@ -397,9 +397,9 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") SECTION("matrix") { - const TinyMatrix<3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, size_t>> f{mesh}; + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; f.fill(value); REQUIRE(all_values_equal(f, value)); @@ -413,7 +413,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") copy_to(g, f); g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); REQUIRE(all_values_equal(f, value)); REQUIRE(all_values_equal(g, zero)); @@ -492,9 +492,9 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") SECTION("matrix") { - const TinyMatrix<3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, size_t>> f{mesh}; + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; f.fill(value); REQUIRE(all_values_equal(f, value)); @@ -508,7 +508,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") copy_to(g, f); g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); REQUIRE(all_values_equal(f, value)); REQUIRE(all_values_equal(g, zero)); diff --git a/tests/test_EigenvalueSolver.cpp b/tests/test_EigenvalueSolver.cpp index 3ca8f7f5136d72f7003357113b7b597d1b84ef54..fb7bf07907bf6c9e1db9333c9713365350918b06 100644 --- a/tests/test_EigenvalueSolver.cpp +++ b/tests/test_EigenvalueSolver.cpp @@ -3,8 +3,8 @@ #include <algebra/CRSMatrix.hpp> #include <algebra/CRSMatrixDescriptor.hpp> -#include <algebra/DenseMatrix.hpp> #include <algebra/EigenvalueSolver.hpp> +#include <algebra/SmallMatrix.hpp> #include <utils/pugs_config.hpp> @@ -36,7 +36,7 @@ TEST_CASE("EigenvalueSolver", "[algebra]") SECTION("eigenvalues") { - Array<double> eigenvalues; + SmallArray<double> eigenvalues; #ifdef PUGS_HAS_SLEPC EigenvalueSolver{}.computeForSymmetricMatrix(A, eigenvalues); @@ -51,8 +51,8 @@ TEST_CASE("EigenvalueSolver", "[algebra]") SECTION("eigenvalues and eigenvectors") { - Array<double> eigenvalue_list; - std::vector<Vector<double>> eigenvector_list; + SmallArray<double> eigenvalue_list; + std::vector<SmallVector<double>> eigenvector_list; #ifdef PUGS_HAS_SLEPC EigenvalueSolver{}.computeForSymmetricMatrix(A, eigenvalue_list, eigenvector_list); @@ -61,9 +61,9 @@ TEST_CASE("EigenvalueSolver", "[algebra]") REQUIRE(eigenvalue_list[1] == Catch::Approx(-1)); REQUIRE(eigenvalue_list[2] == Catch::Approx(8)); - DenseMatrix<double> P{3}; - DenseMatrix<double> PT{3}; - DenseMatrix<double> D{3}; + SmallMatrix<double> P{3}; + SmallMatrix<double> PT{3}; + SmallMatrix<double> D{3}; D = zero; for (size_t i = 0; i < 3; ++i) { @@ -74,7 +74,7 @@ TEST_CASE("EigenvalueSolver", "[algebra]") D(i, i) = eigenvalue_list[i]; } - DenseMatrix PDPT = P * D * PT; + SmallMatrix PDPT = P * D * PT; for (size_t i = 0; i < 3; ++i) { for (size_t j = 0; j < 3; ++j) { REQUIRE(PDPT(i, j) - S(i, j) == Catch::Approx(0).margin(1E-13)); @@ -88,8 +88,8 @@ TEST_CASE("EigenvalueSolver", "[algebra]") SECTION("eigenvalues and passage matrix") { - Array<double> eigenvalue_list; - DenseMatrix<double> P{}; + SmallArray<double> eigenvalue_list; + SmallMatrix<double> P{}; #ifdef PUGS_HAS_SLEPC EigenvalueSolver{}.computeForSymmetricMatrix(A, eigenvalue_list, P); @@ -98,14 +98,14 @@ TEST_CASE("EigenvalueSolver", "[algebra]") REQUIRE(eigenvalue_list[1] == Catch::Approx(-1)); REQUIRE(eigenvalue_list[2] == Catch::Approx(8)); - DenseMatrix<double> D{3}; + SmallMatrix<double> D{3}; D = zero; for (size_t i = 0; i < 3; ++i) { D(i, i) = eigenvalue_list[i]; } - DenseMatrix PT = transpose(P); + SmallMatrix PT = transpose(P); - DenseMatrix PDPT = P * D * PT; + SmallMatrix PDPT = P * D * PT; for (size_t i = 0; i < 3; ++i) { for (size_t j = 0; j < 3; ++j) { REQUIRE(PDPT(i, j) - S(i, j) == Catch::Approx(0).margin(1E-13)); diff --git a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp b/tests/test_EmbeddedIDiscreteFunctionUtils.cpp index 72ce3374369ace3e93551c94094000d117cb336e..0ded74fd6b5764bfb67917a48a1a24ab8b1db873 100644 --- a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp +++ b/tests/test_EmbeddedIDiscreteFunctionUtils.cpp @@ -15,9 +15,9 @@ TEST_CASE("EmbeddedIDiscreteFunctionUtils", "[language]") using R2 = TinyVector<2, double>; using R3 = TinyVector<3, double>; - using R1x1 = TinyMatrix<1, double>; - using R2x2 = TinyMatrix<2, double>; - using R3x3 = TinyMatrix<3, double>; + using R1x1 = TinyMatrix<1, 1, double>; + using R2x2 = TinyMatrix<2, 2, double>; + using R3x3 = TinyMatrix<3, 3, double>; SECTION("operand type name") { diff --git a/tests/test_LinearSolver.cpp b/tests/test_LinearSolver.cpp index f8bcd9972ca5b52a6ea5fe48d70eb1b8c2064107..11195faab3dad2f94e82dba78b9afc368d0edcd0 100644 --- a/tests/test_LinearSolver.cpp +++ b/tests/test_LinearSolver.cpp @@ -46,8 +46,8 @@ TEST_CASE("LinearSolver", "[algebra]") options.method() = LSMethod::lu; REQUIRE_THROWS_WITH(LinearSolver{options}, "error: LU is not a builtin linear solver!"); - options.method() = LSMethod::choleski; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Choleski is not a builtin linear solver!"); + options.method() = LSMethod::cholesky; + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: Cholesky is not a builtin linear solver!"); options.method() = LSMethod::gmres; REQUIRE_THROWS_WITH(LinearSolver{options}, "error: GMRES is not a builtin linear solver!"); @@ -67,8 +67,8 @@ TEST_CASE("LinearSolver", "[algebra]") options.precond() = LSPrecond::incomplete_LU; REQUIRE_THROWS_WITH(LinearSolver{options}, "error: ILU is not a builtin preconditioner!"); - options.precond() = LSPrecond::incomplete_choleski; - REQUIRE_THROWS_WITH(LinearSolver{options}, "error: ICholeski is not a builtin preconditioner!"); + options.precond() = LSPrecond::incomplete_cholesky; + REQUIRE_THROWS_WITH(LinearSolver{options}, "error: ICholesky is not a builtin preconditioner!"); options.precond() = LSPrecond::amg; REQUIRE_THROWS_WITH(LinearSolver{options}, "error: AMG is not a builtin preconditioner!"); @@ -101,7 +101,7 @@ TEST_CASE("LinearSolver", "[algebra]") options.method() = LSMethod::lu; REQUIRE_NOTHROW(linear_solver.checkOptions(options)); - options.method() = LSMethod::choleski; + options.method() = LSMethod::cholesky; REQUIRE_NOTHROW(linear_solver.checkOptions(options)); options.method() = LSMethod::gmres; @@ -122,7 +122,7 @@ TEST_CASE("LinearSolver", "[algebra]") options.precond() = LSPrecond::incomplete_LU; REQUIRE_NOTHROW(linear_solver.checkOptions(options)); - options.precond() = LSPrecond::incomplete_choleski; + options.precond() = LSPrecond::incomplete_cholesky; REQUIRE_NOTHROW(linear_solver.checkOptions(options)); options.precond() = LSPrecond::amg; @@ -245,9 +245,9 @@ TEST_CASE("LinearSolver", "[algebra]") REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("CG ICholeski") + SECTION("CG ICholesky") { - options.precond() = LSPrecond::incomplete_choleski; + options.precond() = LSPrecond::incomplete_cholesky; Vector<double> x{5}; x = zero; @@ -274,11 +274,11 @@ TEST_CASE("LinearSolver", "[algebra]") } } - SECTION("Choleski") + SECTION("Cholesky") { LinearSolverOptions options; options.library() = LSLibrary::petsc; - options.method() = LSMethod::choleski; + options.method() = LSMethod::cholesky; options.precond() = LSPrecond::none; Vector<double> x{5}; @@ -545,7 +545,7 @@ TEST_CASE("LinearSolver", "[algebra]") { SECTION("symmetric system") { - DenseMatrix<double> A{5}; + SmallMatrix<double> A{5}; A = zero; A(0, 0) = 2; @@ -566,8 +566,8 @@ TEST_CASE("LinearSolver", "[algebra]") A(4, 3) = -1; A(4, 4) = 2; - Vector<const double> x_exact = [] { - Vector<double> y{5}; + SmallVector<const double> x_exact = [] { + SmallVector<double> y{5}; y[0] = 1; y[1] = 3; y[2] = 2; @@ -576,7 +576,7 @@ TEST_CASE("LinearSolver", "[algebra]") return y; }(); - Vector<double> b = A * x_exact; + SmallVector<double> b = A * x_exact; SECTION("builtin") { @@ -587,13 +587,13 @@ TEST_CASE("LinearSolver", "[algebra]") options.method() = LSMethod::cg; options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -614,13 +614,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -628,27 +628,27 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::diagonal; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } - SECTION("CG ICholeski") + SECTION("CG ICholesky") { - options.precond() = LSPrecond::incomplete_choleski; + options.precond() = LSPrecond::incomplete_cholesky; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -656,31 +656,31 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::amg; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } - SECTION("Choleski") + SECTION("Cholesky") { LinearSolverOptions options; options.library() = LSLibrary::petsc; - options.method() = LSMethod::choleski; + options.method() = LSMethod::cholesky; options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -700,7 +700,7 @@ TEST_CASE("LinearSolver", "[algebra]") SECTION("none symmetric system") { - DenseMatrix<double> A{5}; + SmallMatrix<double> A{5}; A = zero; A(0, 0) = 2; @@ -721,8 +721,8 @@ TEST_CASE("LinearSolver", "[algebra]") A(4, 3) = 1; A(4, 4) = 3; - Vector<const double> x_exact = [] { - Vector<double> y{5}; + SmallVector<const double> x_exact = [] { + SmallVector<double> y{5}; y[0] = 1; y[1] = 3; y[2] = 2; @@ -731,7 +731,7 @@ TEST_CASE("LinearSolver", "[algebra]") return y; }(); - Vector<double> b = A * x_exact; + SmallVector<double> b = A * x_exact; SECTION("builtin") { @@ -742,13 +742,13 @@ TEST_CASE("LinearSolver", "[algebra]") options.method() = LSMethod::bicgstab; options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -769,13 +769,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -783,13 +783,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::diagonal; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -797,13 +797,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::incomplete_LU; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -819,13 +819,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -833,13 +833,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::diagonal; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -855,13 +855,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -869,13 +869,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::diagonal; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } @@ -883,13 +883,13 @@ TEST_CASE("LinearSolver", "[algebra]") { options.precond() = LSPrecond::incomplete_LU; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } } @@ -901,13 +901,13 @@ TEST_CASE("LinearSolver", "[algebra]") options.method() = LSMethod::lu; options.precond() = LSPrecond::none; - Vector<double> x{5}; + SmallVector<double> x{5}; x = zero; LinearSolver solver{options}; solver.solveLocalSystem(A, x, b); - Vector error = x - x_exact; + SmallVector error = x - x_exact; REQUIRE(std::sqrt(dot(error, error)) < 1E-10 * std::sqrt(dot(x_exact, x_exact))); } diff --git a/tests/test_LinearSolverOptions.cpp b/tests/test_LinearSolverOptions.cpp index 3da7688892a736fe5f69c2adbab9c16cb6cd4fd9..90519ddf9797f0d6fa745cbc34e2f80443eed33d 100644 --- a/tests/test_LinearSolverOptions.cpp +++ b/tests/test_LinearSolverOptions.cpp @@ -17,7 +17,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") options.verbose() = true; options.library() = LSLibrary::builtin; options.method() = LSMethod::cg; - options.precond() = LSPrecond::incomplete_choleski; + options.precond() = LSPrecond::incomplete_cholesky; options.epsilon() = 1E-3; options.maximumIteration() = 100; @@ -28,7 +28,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") expected_output << R"( library: builtin method : CG - precond: ICholeski + precond: ICholesky epsilon: )" << 1E-3 << R"( maxiter: 100 verbose: true @@ -79,7 +79,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") REQUIRE(name(LSMethod::bicgstab2) == "BICGStab2"); REQUIRE(name(LSMethod::gmres) == "GMRES"); REQUIRE(name(LSMethod::lu) == "LU"); - REQUIRE(name(LSMethod::choleski) == "Choleski"); + REQUIRE(name(LSMethod::cholesky) == "Cholesky"); REQUIRE_THROWS_WITH(name(LSMethod::LS__end), "unexpected error: Linear system method name is not defined!"); } @@ -87,7 +87,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") { REQUIRE(name(LSPrecond::none) == "none"); REQUIRE(name(LSPrecond::diagonal) == "diagonal"); - REQUIRE(name(LSPrecond::incomplete_choleski) == "ICholeski"); + REQUIRE(name(LSPrecond::incomplete_cholesky) == "ICholesky"); REQUIRE(name(LSPrecond::incomplete_LU) == "ILU"); REQUIRE(name(LSPrecond::amg) == "AMG"); REQUIRE_THROWS_WITH(name(LSPrecond::LS__end), @@ -109,7 +109,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") REQUIRE(LSMethod::bicgstab == getLSEnumFromName<LSMethod>("BICGStab")); REQUIRE(LSMethod::bicgstab2 == getLSEnumFromName<LSMethod>("BICGStab2")); REQUIRE(LSMethod::lu == getLSEnumFromName<LSMethod>("LU")); - REQUIRE(LSMethod::choleski == getLSEnumFromName<LSMethod>("Choleski")); + REQUIRE(LSMethod::cholesky == getLSEnumFromName<LSMethod>("Cholesky")); REQUIRE(LSMethod::gmres == getLSEnumFromName<LSMethod>("GMRES")); REQUIRE_THROWS_WITH(getLSEnumFromName<LSMethod>("__invalid_method"), @@ -120,7 +120,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") { REQUIRE(LSPrecond::none == getLSEnumFromName<LSPrecond>("none")); REQUIRE(LSPrecond::diagonal == getLSEnumFromName<LSPrecond>("diagonal")); - REQUIRE(LSPrecond::incomplete_choleski == getLSEnumFromName<LSPrecond>("ICholeski")); + REQUIRE(LSPrecond::incomplete_cholesky == getLSEnumFromName<LSPrecond>("ICholesky")); REQUIRE(LSPrecond::incomplete_LU == getLSEnumFromName<LSPrecond>("ILU")); REQUIRE_THROWS_WITH(getLSEnumFromName<LSPrecond>("__invalid_precond"), @@ -153,7 +153,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") - BICGStab2 - GMRES - LU - - Choleski + - Cholesky )"; REQUIRE(os.str() == library_list); @@ -168,7 +168,7 @@ TEST_CASE("LinearSolverOptions", "[algebra]") const std::string library_list = R"( - none - diagonal - - ICholeski + - ICholesky - ILU - AMG )"; diff --git a/tests/test_OFStream.cpp b/tests/test_OFStream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32b4ff21b8e725dcaff822b586f9810d617d3a4d --- /dev/null +++ b/tests/test_OFStream.cpp @@ -0,0 +1,58 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <language/utils/OFStream.hpp> +#include <utils/Messenger.hpp> + +#include <filesystem> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("OFStream", "[language]") +{ + SECTION("ofstream") + { + const std::string basename = "ofstream_"; + const std::string filename = basename + std::to_string(parallel::rank()); + + // Ensures that the file is closed after this line + std::make_shared<OFStream>(filename) << "foo" << 3 << " bar\n"; + + if (parallel::rank() == 0) { + REQUIRE(std::filesystem::is_regular_file(filename)); + + std::ifstream is(filename); + + char file_content[10]; + for (size_t i = 0; i < 10; ++i) { + char c = is.get(); + + file_content[i] = c; + if (c == '\n') { + file_content[i + 1] = '\0'; + REQUIRE(i == 8); + + c = is.get(); + REQUIRE(is.eof()); + break; + } + } + + std::string content = file_content; + REQUIRE(content == "foo3 bar\n"); + + std::filesystem::remove(filename); + } + + REQUIRE(not std::filesystem::exists(filename)); + } + + SECTION("invalid filename") + { + if (parallel::rank() == 0) { + const std::string filename = "badpath/invalidpath/ofstream"; + + REQUIRE_THROWS_WITH(std::make_shared<OFStream>(filename), "error: cannot create file " + filename); + } + } +} diff --git a/tests/test_OStream.cpp b/tests/test_OStream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..417db374ee366531623af397e2d62e78d1c83475 --- /dev/null +++ b/tests/test_OStream.cpp @@ -0,0 +1,36 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <language/utils/OStream.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("OStream", "[language]") +{ + SECTION("null ostream") + { + std::shared_ptr os = std::make_shared<OStream>(); + + REQUIRE_NOTHROW(os << "foo" << 3 << " bar"); + } + + SECTION("valid ostream") + { + std::stringstream sstr; + + std::shared_ptr os = std::make_shared<OStream>(sstr); + os << "foo" << 3 << " bar"; + + REQUIRE(sstr.str() == "foo3 bar"); + } + +#ifndef NDEBUG + SECTION("non allocated stream") + { + std::shared_ptr<OStream> bad_os; + REQUIRE_THROWS_WITH((bad_os << 2), "non allocated stream"); + } +#endif // NDEBUG +} diff --git a/tests/test_OStreamProcessor.cpp b/tests/test_OStreamProcessor.cpp deleted file mode 100644 index 22213d64bcbb70adf6ea6fab93f82e641870da29..0000000000000000000000000000000000000000 --- a/tests/test_OStreamProcessor.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <language/ast/ASTBuilder.hpp> -#include <language/ast/ASTNodeDataTypeBuilder.hpp> -#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> -#include <language/ast/ASTNodeExpressionBuilder.hpp> -#include <language/ast/ASTNodeTypeCleaner.hpp> -#include <language/ast/ASTSymbolTableBuilder.hpp> -#include <language/node_processor/OStreamProcessor.hpp> -#include <utils/Demangle.hpp> - -#include <pegtl/string_input.hpp> - -#include <sstream> - -void -_replaceOStream(ASTNode& node, std::ostringstream& sout) -{ - if (node.is_type<language::cout_kw>() or node.is_type<language::cerr_kw>()) { - node.m_node_processor = std::make_unique<OStreamProcessor>(node, sout); - } else { - for (auto& child_node : node.children) { - _replaceOStream(*child_node, sout); - } - } -} - -#define CHECK_OSTREAM_EXPRESSION_RESULT(data, expected_value) \ - { \ - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ - auto ast = ASTBuilder::build(input); \ - \ - ASTSymbolTableBuilder{*ast}; \ - ASTNodeDataTypeBuilder{*ast}; \ - \ - ASTNodeDeclarationToAffectationConverter{*ast}; \ - ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ - \ - ASTNodeExpressionBuilder{*ast}; \ - ExecutionPolicy exec_policy; \ - \ - std::ostringstream sout; \ - _replaceOStream(*ast, sout); \ - \ - ast->execute(exec_policy); \ - \ - REQUIRE(sout.str() == expected_value); \ - } - -#define CHECK_OSTREAM_EXPRESSION_THROWS(data, expected_error) \ - { \ - static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ - static_assert((std::is_same_v<std::decay_t<decltype(expected_error)>, std::string_view>) or \ - (std::is_same_v<std::decay_t<decltype(expected_error)>, std::string>)); \ - \ - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ - auto ast = ASTBuilder::build(input); \ - \ - ASTSymbolTableBuilder{*ast}; \ - ASTNodeDataTypeBuilder{*ast}; \ - \ - ASTNodeDeclarationToAffectationConverter{*ast}; \ - ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ - \ - REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, expected_error); \ - } - -// clazy:excludeall=non-pod-global-static - -TEST_CASE("OStreamProcessor", "[language]") -{ - SECTION("cout") - { - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << 2;)", "2"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << true;)", "true"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << false;)", "false"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cout << "x=" << 2 << "\n";)", "x=2\n"); - } - - SECTION("cerr") - { - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << 2;)", "2"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << true;)", "true"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << false;)", "false"); - CHECK_OSTREAM_EXPRESSION_RESULT(R"(cerr << "x=" << 2 << "\n";)", "x=2\n"); - } - - SECTION("runtime error") - { - std::string_view data_type = R"( -let f : R -> R, x -> 2; -cerr << "f=" << f << "\n"; -)"; - - std::string error_msg = "invalid argument, cannot print a 'function'"; - CHECK_OSTREAM_EXPRESSION_THROWS(data_type, error_msg); - } -} diff --git a/tests/test_PETScUtils.cpp b/tests/test_PETScUtils.cpp index 2e0daa8519241fde2f7fd1749b40398977b839de..493d2dd445fd62f9712748137c806c4cd206f9b1 100644 --- a/tests/test_PETScUtils.cpp +++ b/tests/test_PETScUtils.cpp @@ -29,9 +29,9 @@ TEST_CASE("PETScUtils", "[algebra]") } } - SECTION("from DenseMatrix") + SECTION("from SmallMatrix") { - DenseMatrix<double> A(3, 3); + SmallMatrix<double> A(3, 3); for (size_t i = 0; i < 3; ++i) { for (size_t j = 0; j < 3; ++j) { A(i, j) = 1 + i * 3 + j; @@ -52,9 +52,9 @@ TEST_CASE("PETScUtils", "[algebra]") } } - SECTION("from DenseMatrix [non-square]") + SECTION("from SmallMatrix [non-square]") { - DenseMatrix<double> A(4, 3); + SmallMatrix<double> A(4, 3); for (size_t i = 0; i < 4; ++i) { for (size_t j = 0; j < 3; ++j) { A(i, j) = 1 + i * 3 + j; diff --git a/tests/test_SmallArray.cpp b/tests/test_SmallArray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b5d482791f9df0a19c41c64cb55070c5bf8be24 --- /dev/null +++ b/tests/test_SmallArray.cpp @@ -0,0 +1,285 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <utils/PugsAssert.hpp> +#include <utils/SmallArray.hpp> +#include <utils/Types.hpp> + +#include <deque> +#include <list> +#include <set> +#include <unordered_set> +#include <valarray> +#include <vector> + +// Instantiate to ensure full coverage is performed +template class SmallArray<int>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SmallArray", "[utils]") +{ + SmallArray<int> a(10); + REQUIRE(a.size() == 10); + + for (size_t i = 0; i < a.size(); ++i) { + a[i] = 2 * i; + } + + REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and + (a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18))); + + SECTION("checking for copies") + { + SmallArray<const int> b{a}; + + REQUIRE(((b[0] == 0) and (b[1] == 2) and (b[2] == 4) and (b[3] == 6) and (b[4] == 8) and (b[5] == 10) and + (b[6] == 12) and (b[7] == 14) and (b[8] == 16) and (b[9] == 18))); + + SmallArray<int> c{a}; + + REQUIRE(((c[0] == 0) and (c[1] == 2) and (c[2] == 4) and (c[3] == 6) and (c[4] == 8) and (c[5] == 10) and + (c[6] == 12) and (c[7] == 14) and (c[8] == 16) and (c[9] == 18))); + + SmallArray<int> d = std::move(c); + + REQUIRE(((d[0] == 0) and (d[1] == 2) and (d[2] == 4) and (d[3] == 6) and (d[4] == 8) and (d[5] == 10) and + (d[6] == 12) and (d[7] == 14) and (d[8] == 16) and (d[9] == 18))); + } + + SECTION("checking for fill") + { + SmallArray<int> b(10); + b.fill(3); + + REQUIRE(((b[0] == 3) and (b[1] == 3) and (b[2] == 3) and (b[3] == 3) and (b[4] == 3) and (b[5] == 3) and + (b[6] == 3) and (b[7] == 3) and (b[8] == 3) and (b[9] == 3))); + } + + SECTION("checking for affectations (shallow copy)") + { + SmallArray<const int> b; + b = a; + + REQUIRE(((b[0] == 0) and (b[1] == 2) and (b[2] == 4) and (b[3] == 6) and (b[4] == 8) and (b[5] == 10) and + (b[6] == 12) and (b[7] == 14) and (b[8] == 16) and (b[9] == 18))); + + SmallArray<int> c; + c = a; + + REQUIRE(((c[0] == 0) and (c[1] == 2) and (c[2] == 4) and (c[3] == 6) and (c[4] == 8) and (c[5] == 10) and + (c[6] == 12) and (c[7] == 14) and (c[8] == 16) and (c[9] == 18))); + + SmallArray<int> d; + d = std::move(c); + + REQUIRE(((d[0] == 0) and (d[1] == 2) and (d[2] == 4) and (d[3] == 6) and (d[4] == 8) and (d[5] == 10) and + (d[6] == 12) and (d[7] == 14) and (d[8] == 16) and (d[9] == 18))); + } + + SECTION("checking for affectations (deep copy)") + { + SmallArray<int> b(copy(a)); + + REQUIRE(((b[0] == 0) and (b[1] == 2) and (b[2] == 4) and (b[3] == 6) and (b[4] == 8) and (b[5] == 10) and + (b[6] == 12) and (b[7] == 14) and (b[8] == 16) and (b[9] == 18))); + + b.fill(2); + + REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and + (a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18))); + + REQUIRE(((b[0] == 2) and (b[1] == 2) and (b[2] == 2) and (b[3] == 2) and (b[4] == 2) and (b[5] == 2) and + (b[6] == 2) and (b[7] == 2) and (b[8] == 2) and (b[9] == 2))); + + SmallArray<int> c; + c = a; + + REQUIRE(((c[0] == 0) and (c[1] == 2) and (c[2] == 4) and (c[3] == 6) and (c[4] == 8) and (c[5] == 10) and + (c[6] == 12) and (c[7] == 14) and (c[8] == 16) and (c[9] == 18))); + + c = copy(b); + + REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and + (a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18))); + + REQUIRE(((c[0] == 2) and (c[1] == 2) and (c[2] == 2) and (c[3] == 2) and (c[4] == 2) and (c[5] == 2) and + (c[6] == 2) and (c[7] == 2) and (c[8] == 2) and (c[9] == 2))); + + SmallArray<int> d{a.size()}; + copy_to(a, d); + + REQUIRE(((d[0] == 0) and (d[1] == 2) and (d[2] == 4) and (d[3] == 6) and (d[4] == 8) and (d[5] == 10) and + (d[6] == 12) and (d[7] == 14) and (d[8] == 16) and (d[9] == 18))); + + REQUIRE(((c[0] == 2) and (c[1] == 2) and (c[2] == 2) and (c[3] == 2) and (c[4] == 2) and (c[5] == 2) and + (c[6] == 2) and (c[7] == 2) and (c[8] == 2) and (c[9] == 2))); + + copy_to(c, d); + + REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and + (a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18))); + + REQUIRE(((d[0] == 2) and (d[1] == 2) and (d[2] == 2) and (d[3] == 2) and (d[4] == 2) and (d[5] == 2) and + (d[6] == 2) and (d[7] == 2) and (d[8] == 2) and (d[9] == 2))); + } + + SECTION("checking for std container conversion") + { + { + std::vector<int> v{1, 2, 5, 3}; + { + SmallArray<int> v_array = convert_to_small_array(v); + + REQUIRE(v_array.size() == v.size()); + REQUIRE(((v_array[0] == 1) and (v_array[1] == 2) and (v_array[2] == 5) and (v_array[3] == 3))); + } + + { + SmallArray<const int> v_array = convert_to_small_array(v); + + REQUIRE(v_array.size() == v.size()); + REQUIRE(((v_array[0] == 1) and (v_array[1] == 2) and (v_array[2] == 5) and (v_array[3] == 3))); + } + } + + { + std::vector<int> w; + { + SmallArray<int> w_array = convert_to_small_array(w); + REQUIRE(w_array.size() == 0); + } + { + SmallArray<const int> w_array = convert_to_small_array(w); + REQUIRE(w_array.size() == 0); + } + } + + { + std::valarray<int> v{1, 2, 5, 3}; + SmallArray<int> v_array = convert_to_small_array(v); + + REQUIRE(v_array.size() == v.size()); + REQUIRE(((v_array[0] == 1) and (v_array[1] == 2) and (v_array[2] == 5) and (v_array[3] == 3))); + } + + { + std::set<int> s{4, 2, 5, 3, 1, 3, 2}; + SmallArray<int> s_array = convert_to_small_array(s); + + REQUIRE(s_array.size() == s.size()); + REQUIRE( + ((s_array[0] == 1) and (s_array[1] == 2) and (s_array[2] == 3) and (s_array[3] == 4) and (s_array[4] == 5))); + } + + { + std::unordered_set<int> us{4, 2, 5, 3, 1, 3, 2}; + SmallArray<int> us_array = convert_to_small_array(us); + + REQUIRE(us_array.size() == us.size()); + + std::set<int> s; + for (size_t i = 0; i < us_array.size(); ++i) { + REQUIRE((us.find(us_array[i]) != us.end())); + s.insert(us_array[i]); + } + REQUIRE(s.size() == us_array.size()); + } + + { + std::multiset<int> ms{4, 2, 5, 3, 1, 3, 2}; + SmallArray<int> ms_array = convert_to_small_array(ms); + + REQUIRE(ms_array.size() == ms.size()); + REQUIRE(((ms_array[0] == 1) and (ms_array[1] == 2) and (ms_array[2] == 2) and (ms_array[3] == 3) and + (ms_array[4] == 3) and (ms_array[5] == 4) and (ms_array[6] == 5))); + } + + { + std::list<int> l{1, 3, 5, 6, 2}; + SmallArray<int> l_array = convert_to_small_array(l); + + REQUIRE(l_array.size() == l.size()); + REQUIRE( + ((l_array[0] == 1) and (l_array[1] == 3) and (l_array[2] == 5) and (l_array[3] == 6) and (l_array[4] == 2))); + } + + { + std::deque<int> q{1, 3, 5, 6, 2}; + q.push_front(2); + SmallArray<int> q_array = convert_to_small_array(q); + + REQUIRE(q_array.size() == q.size()); + REQUIRE(((q_array[0] == 2) and (q_array[1] == 1) and (q_array[2] == 3) and (q_array[3] == 5) and + (q_array[4] == 6) and (q_array[5] == 2))); + } + } + + SECTION("output") + { + SmallArray<int> x{5}; + x[0] = 2; + x[1] = 6; + x[2] = 2; + x[3] = 3; + x[4] = 7; + + std::ostringstream array_ost; + array_ost << x; + std::ostringstream ref_ost; + ref_ost << 0 << ':' << x[0]; + for (size_t i = 1; i < x.size(); ++i) { + ref_ost << ' ' << i << ':' << x[i]; + } + REQUIRE(array_ost.str() == ref_ost.str()); + } + +#ifndef NDEBUG + + SECTION("output with signaling NaN") + { + SmallArray<double> x{5}; + x[0] = 2; + x[2] = 3; + + std::ostringstream array_ost; + array_ost << x; + std::ostringstream ref_ost; + ref_ost << 0 << ':' << 2 << ' '; + ref_ost << 1 << ":nan "; + ref_ost << 2 << ':' << 3 << ' '; + ref_ost << 3 << ":nan "; + ref_ost << 4 << ":nan"; + REQUIRE(array_ost.str() == ref_ost.str()); + } + + SECTION("checking for bounds violation") + { + REQUIRE_THROWS_AS(a[10], AssertError); + } + + SECTION("invalid copy_to") + { + SmallArray<int> b{2 * a.size()}; + REQUIRE_THROWS_AS(copy_to(a, b), AssertError); + } + + SECTION("checking for nan initialization") + { + SmallArray<double> array(10); + + for (size_t i = 0; i < array.size(); ++i) { + REQUIRE(std::isnan(array[i])); + } + } + + SECTION("checking for bad initialization") + { + SmallArray<int> array(10); + + for (size_t i = 0; i < array.size(); ++i) { + REQUIRE(array[i] == std::numeric_limits<int>::max() / 2); + } + } +#endif // NDEBUG +} diff --git a/tests/test_TinyMatrix.cpp b/tests/test_TinyMatrix.cpp index f50d2abc61f26bdbebbac4ba14ce884b352ec0aa..c9b72d5de9ecb6b047ae8c16ad832f8b29b38157 100644 --- a/tests/test_TinyMatrix.cpp +++ b/tests/test_TinyMatrix.cpp @@ -12,39 +12,41 @@ #include <sstream> // Instantiate to ensure full coverage is performed -template class TinyMatrix<1, int>; -template class TinyMatrix<2, int>; -template class TinyMatrix<3, int>; -template class TinyMatrix<4, double>; +template class TinyMatrix<1, 1, int>; +template class TinyMatrix<2, 2, int>; +template class TinyMatrix<3, 4, int>; +template class TinyMatrix<4, 4, double>; // clazy:excludeall=non-pod-global-static TEST_CASE("TinyMatrix", "[algebra]") { - TinyMatrix<3, int> A(1, 2, 3, 4, 5, 6, 7, 8, 9); - REQUIRE(((A(0, 0) == 1) and (A(0, 1) == 2) and (A(0, 2) == 3) and (A(1, 0) == 4) and (A(1, 1) == 5) and - (A(1, 2) == 6) and (A(2, 0) == 7) and (A(2, 1) == 8) and (A(2, 2) == 9))); + TinyMatrix<3, 4, int> A(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + REQUIRE(((A(0, 0) == 1) and (A(0, 1) == 2) and (A(0, 2) == 3) and (A(0, 3) == 4) and // + (A(1, 0) == 5) and (A(1, 1) == 6) and (A(1, 2) == 7) and (A(1, 3) == 8) and // + (A(2, 0) == 9) and (A(2, 1) == 10) and (A(2, 2) == 11) and (A(2, 3) == 12))); - TinyMatrix<3, int> B(6, 5, 3, 8, 34, 6, 35, 6, 7); + TinyMatrix<3, 4, int> B(6, 5, 3, 8, 34, 6, 35, 6, 7, 1, 3, 6); SECTION("checking for opposed matrix") { - const TinyMatrix<3, int> minus_A = -A; - REQUIRE(((minus_A(0, 0) == -1) and (minus_A(0, 1) == -2) and (minus_A(0, 2) == -3) and (minus_A(1, 0) == -4) and - (minus_A(1, 1) == -5) and (minus_A(1, 2) == -6) and (minus_A(2, 0) == -7) and (minus_A(2, 1) == -8) and - (minus_A(2, 2) == -9))); + const TinyMatrix minus_A = -A; + REQUIRE( + ((minus_A(0, 0) == -1) and (minus_A(0, 1) == -2) and (minus_A(0, 2) == -3) and (minus_A(0, 3) == -4) and // + (minus_A(1, 0) == -5) and (minus_A(1, 1) == -6) and (minus_A(1, 2) == -7) and (minus_A(1, 3) == -8) and // + (minus_A(2, 0) == -9) and (minus_A(2, 1) == -10) and (minus_A(2, 2) == -11) and (minus_A(2, 3) == -12))); } SECTION("checking for equality and difference tests") { - const TinyMatrix<3, int> copy_A = A; - REQUIRE(((copy_A(0, 0) == 1) and (copy_A(0, 1) == 2) and (copy_A(0, 2) == 3) and (copy_A(1, 0) == 4) and - (copy_A(1, 1) == 5) and (copy_A(1, 2) == 6) and (copy_A(2, 0) == 7) and (copy_A(2, 1) == 8) and - (copy_A(2, 2) == 9))); + const TinyMatrix copy_A = A; + REQUIRE(((copy_A(0, 0) == 1) and (copy_A(0, 1) == 2) and (copy_A(0, 2) == 3) and (copy_A(0, 3) == 4) and // + (copy_A(1, 0) == 5) and (copy_A(1, 1) == 6) and (copy_A(1, 2) == 7) and (copy_A(1, 3) == 8) and // + (copy_A(2, 0) == 9) and (copy_A(2, 1) == 10) and (copy_A(2, 2) == 11) and (copy_A(2, 3) == 12))); REQUIRE(copy_A == A); REQUIRE_FALSE(copy_A != A); - TinyMatrix<3, int> affected_A; + TinyMatrix<3, 4, int> affected_A; affected_A = A; REQUIRE(affected_A == A); REQUIRE_FALSE(affected_A != A); @@ -55,101 +57,109 @@ TEST_CASE("TinyMatrix", "[algebra]") SECTION("checking for scalar left product") { - const int a = 2; - const TinyMatrix<3, int> aA = a * A; + const int a = 2; + const TinyMatrix<3, 4, int> aA = a * A; - REQUIRE(aA == TinyMatrix<3, int>(2, 4, 6, 8, 10, 12, 14, 16, 18)); + REQUIRE(aA == TinyMatrix<3, 4, int>(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24)); } SECTION("checking for scalar seft product") { - const int a = 2; - TinyMatrix<3, int> copy_A = A; + const int a = 2; - REQUIRE((copy_A *= a) == TinyMatrix<3, int>(2, 4, 6, 8, 10, 12, 14, 16, 18)); + TinyMatrix copy_A = A; + + REQUIRE((copy_A *= a) == TinyMatrix<3, 4, int>(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24)); } SECTION("checking for null matrix management") { - TinyMatrix<3, int> Z = zero; - REQUIRE(Z == TinyMatrix<3, int>(0, 0, 0, 0, 0, 0, 0, 0, 0)); + TinyMatrix<4, 3, int> Z = zero; + REQUIRE(Z == TinyMatrix<4, 3, int>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - TinyMatrix<3, int> affected_Z; + TinyMatrix<4, 3, int> affected_Z; affected_Z = zero; REQUIRE(affected_Z == Z); } SECTION("checking for identity management") { - TinyMatrix<3, int> I = identity; - REQUIRE(I == TinyMatrix<3, int>(1, 0, 0, 0, 1, 0, 0, 0, 1)); + TinyMatrix<3, 3, int> I = identity; + REQUIRE(I == TinyMatrix<3, 3, int>(1, 0, 0, 0, 1, 0, 0, 0, 1)); - TinyMatrix<3, int> affected_I; + TinyMatrix<3, 3, int> affected_I; affected_I = identity; REQUIRE(affected_I == I); } SECTION("checking for matrices sum") { - REQUIRE(A + B == TinyMatrix<3, int>(7, 7, 6, 12, 39, 12, 42, 14, 16)); + REQUIRE(A + B == TinyMatrix<3, 4, int>(7, 7, 6, 12, 39, 12, 42, 14, 16, 11, 14, 18)); - TinyMatrix<3, int> ApB = A; + TinyMatrix<3, 4, int> ApB = A; ApB += B; REQUIRE(ApB == A + B); - TinyMatrix<3, int> Ap2B = A + 2 * B; + TinyMatrix<3, 4, int> Ap2B = A + 2 * B; REQUIRE(Ap2B == ApB + B); } SECTION("checking for matrices difference ") { - REQUIRE(A - B == TinyMatrix<3, int>(-5, -3, 0, -4, -29, 0, -28, 2, 2)); + REQUIRE(A - B == TinyMatrix<3, 4, int>(-5, -3, 0, -4, -29, 0, -28, 2, 2, 9, 8, 6)); - TinyMatrix<3, int> AmB = A; + TinyMatrix<3, 4, int> AmB = A; AmB -= B; REQUIRE(AmB == A - B); - TinyMatrix<3, int> Am2B = A - 2 * B; + TinyMatrix<3, 4, int> Am2B = A - 2 * B; REQUIRE(Am2B == AmB - B); } SECTION("checking for matrices product") { - REQUIRE(A * B == TinyMatrix<3, int>(127, 91, 36, 274, 226, 84, 421, 361, 132)); + TinyMatrix<4, 2, int> C{3, -2, 2, 6, -2, 5, 7, 2}; + REQUIRE(A * C == TinyMatrix<3, 2, int>(29, 33, 69, 77, 109, 121)); + + TinyMatrix<2, 3, int> D{-3, 2, 3, 2, 5, -7}; + REQUIRE(D * A == TinyMatrix<2, 4, int>(34, 36, 38, 40, -36, -36, -36, -36)); } SECTION("checking for matrix-vector product") { - REQUIRE(A * TinyVector<3, int>(2, -3, 5) == TinyVector<3, int>(11, 23, 35)); + REQUIRE(A * TinyVector<4, int>(2, -3, 5, 2) == TinyVector<3, int>(19, 43, 67)); } SECTION("checking for tensor product") { - const TinyVector<3, int> u(1, 3, 7); + const TinyVector<4, int> u(1, 3, 7, 5); const TinyVector<3, int> v(6, 2, -3); - REQUIRE(tensorProduct(u, v) == TinyMatrix<3, int>(6, 2, -3, 18, 6, -9, 42, 14, -21)); + REQUIRE(tensorProduct(u, v) == TinyMatrix<4, 3, int>(6, 2, -3, 18, 6, -9, 42, 14, -21, 30, 10, -15)); } SECTION("checking for minor calculation") { - TinyMatrix<3, int> A(1, 2, 3, 4, 5, 6, 7, 8, 9); - REQUIRE(getMinor(A, 0, 0) == TinyMatrix<2, int>(5, 6, 8, 9)); - REQUIRE(getMinor(A, 1, 0) == TinyMatrix<2, int>(2, 3, 8, 9)); - REQUIRE(getMinor(A, 2, 0) == TinyMatrix<2, int>(2, 3, 5, 6)); - - REQUIRE(getMinor(A, 0, 1) == TinyMatrix<2, int>(4, 6, 7, 9)); - REQUIRE(getMinor(A, 1, 1) == TinyMatrix<2, int>(1, 3, 7, 9)); - REQUIRE(getMinor(A, 2, 1) == TinyMatrix<2, int>(1, 3, 4, 6)); - - REQUIRE(getMinor(A, 0, 2) == TinyMatrix<2, int>(4, 5, 7, 8)); - REQUIRE(getMinor(A, 1, 2) == TinyMatrix<2, int>(1, 2, 7, 8)); - REQUIRE(getMinor(A, 2, 2) == TinyMatrix<2, int>(1, 2, 4, 5)); + REQUIRE(getMinor(A, 0, 0) == TinyMatrix<2, 3, int>(6, 7, 8, 10, 11, 12)); + REQUIRE(getMinor(A, 1, 0) == TinyMatrix<2, 3, int>(2, 3, 4, 10, 11, 12)); + REQUIRE(getMinor(A, 2, 0) == TinyMatrix<2, 3, int>(2, 3, 4, 6, 7, 8)); + + REQUIRE(getMinor(A, 0, 1) == TinyMatrix<2, 3, int>(5, 7, 8, 9, 11, 12)); + REQUIRE(getMinor(A, 1, 1) == TinyMatrix<2, 3, int>(1, 3, 4, 9, 11, 12)); + REQUIRE(getMinor(A, 2, 1) == TinyMatrix<2, 3, int>(1, 3, 4, 5, 7, 8)); + + REQUIRE(getMinor(A, 0, 2) == TinyMatrix<2, 3, int>(5, 6, 8, 9, 10, 12)); + REQUIRE(getMinor(A, 1, 2) == TinyMatrix<2, 3, int>(1, 2, 4, 9, 10, 12)); + REQUIRE(getMinor(A, 2, 2) == TinyMatrix<2, 3, int>(1, 2, 4, 5, 6, 8)); + + REQUIRE(getMinor(A, 0, 3) == TinyMatrix<2, 3, int>(5, 6, 7, 9, 10, 11)); + REQUIRE(getMinor(A, 1, 3) == TinyMatrix<2, 3, int>(1, 2, 3, 9, 10, 11)); + REQUIRE(getMinor(A, 2, 3) == TinyMatrix<2, 3, int>(1, 2, 3, 5, 6, 7)); } SECTION("checking for cofactors") { - TinyMatrix<3, int> A(1, 2, 3, 4, 5, 6, 7, 8, 9); + TinyMatrix<3, 3, int> A(1, 2, 3, 4, 5, 6, 7, 8, 9); REQUIRE(cofactor(A, 0, 0) == (5 * 9 - 8 * 6)); REQUIRE(cofactor(A, 1, 0) == -(2 * 9 - 8 * 3)); REQUIRE(cofactor(A, 2, 0) == (2 * 6 - 5 * 3)); @@ -165,26 +175,25 @@ TEST_CASE("TinyMatrix", "[algebra]") SECTION("checking for determinant calculations") { - REQUIRE(det(TinyMatrix<1, int>(6)) == 6); - REQUIRE(det(TinyMatrix<2, int>(3, 1, -3, 6)) == 21); - REQUIRE(det(TinyMatrix<3, int>(1, 1, 1, 1, 2, 1, 2, 1, 3)) == 1); - REQUIRE(det(B) == -1444); - REQUIRE(det(TinyMatrix<4, double>(1, 2.3, 7, -6.2, 3, 4, 9, 1, 4.1, 5, 2, -3, 2, 27, 3, 17.5)) == + REQUIRE(det(TinyMatrix<1, 1, int>(6)) == 6); + REQUIRE(det(TinyMatrix<2, 2, int>(3, 1, -3, 6)) == 21); + REQUIRE(det(TinyMatrix<3, 3, int>(1, 1, 1, 1, 2, 1, 2, 1, 3)) == 1); + REQUIRE(det(TinyMatrix<3, 3, int>(6, 5, 3, 8, 34, 6, 35, 6, 7)) == -1444); + REQUIRE(det(TinyMatrix<4>(1, 2.3, 7, -6.2, 3, 4, 9, 1, 4.1, 5, 2, -3, 2, 27, 3, 17.5)) == Catch::Approx(6661.455).epsilon(1E-14)); - - REQUIRE(det(TinyMatrix<4, double>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 0); + REQUIRE(det(TinyMatrix<4>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 0); } SECTION("checking for inverse calculations") { { - const TinyMatrix<1, double> A1(2); + const TinyMatrix<1> A1(2); REQUIRE(inverse(A1)(0, 0) == Catch::Approx(0.5).epsilon(1E-14)); } { - const TinyMatrix<2, double> A2(2, 3, 4, 1); - const TinyMatrix<2, double> I = inverse(A2) * A2; + const TinyMatrix<2> A2(2, 3, 4, 1); + const TinyMatrix<2> I = inverse(A2) * A2; REQUIRE(I(0, 0) == Catch::Approx(1).epsilon(1E-14)); REQUIRE(I(0, 1) == Catch::Approx(0).margin(1E-14)); @@ -193,8 +202,8 @@ TEST_CASE("TinyMatrix", "[algebra]") } { - const TinyMatrix<3, double> A3(2, 3, 1, 4, -1, 5, -2, 3, 4); - const TinyMatrix<3, double> I = inverse(A3) * A3; + const TinyMatrix<3> A3(2, 3, 1, 4, -1, 5, -2, 3, 4); + const TinyMatrix<3> I = inverse(A3) * A3; REQUIRE(I(0, 0) == Catch::Approx(1).epsilon(1E-14)); REQUIRE(I(0, 1) == Catch::Approx(0).margin(1E-14)); @@ -223,6 +232,11 @@ TEST_CASE("TinyMatrix", "[algebra]") REQUIRE(TinyMatrix<3>{}.numberOfColumns() == 3); REQUIRE(TinyMatrix<3>{}.dimension() == 9); REQUIRE(TinyMatrix<3>{}.numberOfValues() == 9); + + REQUIRE(TinyMatrix<3, 4>{}.numberOfRows() == 3); + REQUIRE(TinyMatrix<3, 4>{}.numberOfColumns() == 4); + REQUIRE(TinyMatrix<3, 4>{}.dimension() == 12); + REQUIRE(TinyMatrix<3, 4>{}.numberOfValues() == 12); } SECTION("is square matrix") @@ -230,26 +244,40 @@ TEST_CASE("TinyMatrix", "[algebra]") REQUIRE(TinyMatrix<1>{}.isSquare()); REQUIRE(TinyMatrix<2>{}.isSquare()); REQUIRE(TinyMatrix<3>{}.isSquare()); - REQUIRE(TinyMatrix<4>{}.isSquare()); + + REQUIRE_FALSE(TinyMatrix<3, 4>{}.isSquare()); + } + + SECTION("transpose") + { + TinyMatrix tA = transpose(A); + + REQUIRE(((tA(0, 0) == 1) and (tA(1, 0) == 2) and (tA(2, 0) == 3) and (tA(3, 0) == 4) and // + (tA(0, 1) == 5) and (tA(1, 1) == 6) and (tA(2, 1) == 7) and (tA(3, 1) == 8) and // + (tA(0, 2) == 9) and (tA(1, 2) == 10) and (tA(2, 2) == 11) and (tA(3, 2) == 12))); + + TinyMatrix ttA = transpose(tA); + REQUIRE(ttA == A); } SECTION("checking for matrices output") { - REQUIRE(Catch::Detail::stringify(A) == "[(1,2,3)(4,5,6)(7,8,9)]"); - REQUIRE(Catch::Detail::stringify(TinyMatrix<1, int>(7)) == "[(7)]"); + REQUIRE(Catch::Detail::stringify(A) == "[(1,2,3,4)(5,6,7,8)(9,10,11,12)]"); + REQUIRE(Catch::Detail::stringify(TinyMatrix<1, 1, int>(7)) == "[(7)]"); } #ifndef NDEBUG SECTION("output with signaling NaN") { - TinyMatrix<2> A; + TinyMatrix<2, 3> A; A(0, 0) = 1; + A(0, 2) = 3; A(1, 0) = 2; std::ostringstream A_ost; A_ost << A; std::ostringstream ref_ost; - ref_ost << "[(1,nan)(2,nan)]"; + ref_ost << "[(1,nan,3)(2,nan,nan)]"; REQUIRE(A_ost.str() == ref_ost.str()); } @@ -257,19 +285,19 @@ TEST_CASE("TinyMatrix", "[algebra]") SECTION("checking for bounds violation") { REQUIRE_THROWS_AS(A(3, 0), AssertError); - REQUIRE_THROWS_AS(A(0, 3), AssertError); + REQUIRE_THROWS_AS(A(0, 4), AssertError); REQUIRE_THROWS_AS(getMinor(A, 3, 0), AssertError); - REQUIRE_THROWS_AS(getMinor(A, 0, 3), AssertError); + REQUIRE_THROWS_AS(getMinor(A, 0, 4), AssertError); - const TinyMatrix<3, int>& constA = A; + const TinyMatrix<3, 4, int>& constA = A; REQUIRE_THROWS_AS(constA(3, 0), AssertError); - REQUIRE_THROWS_AS(constA(0, 3), AssertError); + REQUIRE_THROWS_AS(constA(0, 4), AssertError); } SECTION("checking for nan initialization") { - TinyMatrix<3, double> B; + TinyMatrix<3, 4, double> B; for (size_t i = 0; i < B.numberOfRows(); ++i) { for (size_t j = 0; j < B.numberOfColumns(); ++j) { @@ -280,7 +308,7 @@ TEST_CASE("TinyMatrix", "[algebra]") SECTION("checking for bad initialization") { - TinyMatrix<3, int> B; + TinyMatrix<3, 4, int> B; for (size_t i = 0; i < B.numberOfRows(); ++i) { for (size_t j = 0; j < B.numberOfColumns(); ++j) {