diff --git a/CMakeLists.txt b/CMakeLists.txt index b21b7238c03c472741e381368f1713a6d22babf9..d040d874b16a42bb6afc0bb38de61fd2ebd398da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,14 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") set(GCOVR_EXTRA "--gcov-executable=${LLVM_COV} gcov") endif() - set(GCOVR_OPTIONS --object-directory="${PASTIS_BINARY_DIR}" -r "${PASTIS_SOURCE_DIR}/src" -e "${PASTIS_SOURCE_DIR}/src/experimental" -e "${PASTIS_SOURCE_DIR}/src/main.cpp" ${GCOVR_EXTRA}) + set (GCOVR_EXCLUDE + -e "${PASTIS_SOURCE_DIR}/src/experimental" + -e "${PASTIS_SOURCE_DIR}/src/main.cpp" + -e "${PASTIS_SOURCE_DIR}/src/utils/BacktraceManager.cpp" + -e "${PASTIS_SOURCE_DIR}/src/utils/BacktraceManager.hpp" + ) + + set(GCOVR_OPTIONS --object-directory="${PASTIS_BINARY_DIR}" -r "${PASTIS_SOURCE_DIR}/src" ${GCOVR_EXCLUDE} ${GCOVR_EXTRA}) add_custom_target(run_unit_tests ALL diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp index 577bd4fa045eda648034c339663d146c0ad5be77..9a9e9aa2239de844fb8e01d38c73cec514b32687 100644 --- a/src/algebra/TinyMatrix.hpp +++ b/src/algebra/TinyMatrix.hpp @@ -52,11 +52,11 @@ public: TinyMatrix AB; for (size_t i=0; i<N; ++i) { for (size_t j=0; j<N; ++j) { - T sum = A(i,0)*B(0,j); - for (size_t k=1; k<N; ++k) { - sum += A(i,k)*B(k,j); - } - AB(i,j) = sum; + T sum = A(i,0)*B(0,j); + for (size_t k=1; k<N; ++k) { + sum += A(i,k)*B(k,j); + } + AB(i,j) = sum; } } return std::move(AB); @@ -71,7 +71,7 @@ public: for (size_t i=0; i<N; ++i) { T sum = A(i,0)*x[0]; for (size_t j=1; j<N; ++j) { - sum += A(i,j)*x[j]; + sum += A(i,j)*x[j]; } Ax[i] = sum; } @@ -83,22 +83,37 @@ public: friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A) { if constexpr(N==1) { - os << A(0,0); + os << A(0,0); } else { os << '['; for (size_t i=0; i<N; ++i) { - os << '(' << A(i,0); - for (size_t j=1; j<N; ++j) { - os << ',' << A(i,j); - } - os << ')'; + os << '(' << A(i,0); + for (size_t j=1; j<N; ++j) { + os << ',' << A(i,j); + } + os << ')'; } os << ']'; } return os; } + KOKKOS_INLINE_FUNCTION + bool operator==(const TinyMatrix& A) const + { + for (size_t i=0; i<N*N; ++i) { + if (m_values[i] != A.m_values[i]) return false; + } + return true; + } + + KOKKOS_INLINE_FUNCTION + bool operator!=(const TinyMatrix& A) const + { + return not this->operator==(A); + } + KOKKOS_INLINE_FUNCTION TinyMatrix operator+(const TinyMatrix& A) const { @@ -167,14 +182,14 @@ public: 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 j=0; j<N; ++j) { - m_values[_index(i,j)] = (i==j) ? 1 : 0; + m_values[_index(i,j)] = (i==j) ? 1 : 0; } } return *this; } KOKKOS_INLINE_FUNCTION - const TinyMatrix& operator=(const TinyMatrix& A) + TinyMatrix& operator=(const TinyMatrix& A) { for (size_t i=0; i<N*N; ++i) { m_values[i] = A.m_values[i]; @@ -194,10 +209,7 @@ public: } KOKKOS_INLINE_FUNCTION - TinyMatrix() - { - ; - } + TinyMatrix()=default; KOKKOS_INLINE_FUNCTION TinyMatrix(const ZeroType& z) @@ -214,7 +226,7 @@ public: 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 j=0; j<N; ++j) { - m_values[_index(i,j)] = (i==j) ? 1 : 0; + m_values[_index(i,j)] = (i==j) ? 1 : 0; } } } @@ -231,16 +243,13 @@ public: TinyMatrix(TinyMatrix&& A) = default; KOKKOS_INLINE_FUNCTION - ~TinyMatrix() - { - ; - } + ~TinyMatrix()=default; }; template <size_t N, typename T> KOKKOS_INLINE_FUNCTION TinyMatrix<N,T> tensorProduct(const TinyVector<N,T>& x, - const TinyVector<N,T>& y) + const TinyVector<N,T>& y) { TinyMatrix<N,T> A; for (size_t i=0; i<N; ++i) { @@ -256,39 +265,40 @@ KOKKOS_INLINE_FUNCTION T det(const TinyMatrix<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 point types only"); TinyMatrix<N,T> M = A; - TinyVector<N, int> index; - for (int i=0; i<N; ++i) index[i]=i; + TinyVector<N, size_t> index; + for (size_t i=0; i<N; ++i) index[i]=i; T determinent = 1; - for (int i=0; i<N; ++i) { - for (int j=i; j<N; ++j) { - int l = j; - const int J = index[j]; - for (int k=j+1; k<N; ++k) { - if (std::abs(M(index[k],i)) > std::abs(M(J,i))) { - l=k; - } + for (size_t i=0; i<N; ++i) { + for (size_t j=i; j<N; ++j) { + 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))) { + l=k; + } } if (l != j) { - std::swap(index[l], index[j]); - determinent *= -1; + std::swap(index[l], index[j]); + determinent *= -1; } } - const int I = index[i]; + const size_t I = index[i]; if (M(I,i)==0) return 0; - double inv_Mii = 1./M(I,i); - for (int k=i+1; k<N; ++k) { - const int K = index[k]; + const T inv_Mii = 1./M(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; - for (int l=i+1; l<N; ++l) { - M(K,l) -= factor*M(I,l); + for (size_t l=i+1; l<N; ++l) { + M(K,l) -= factor*M(I,l); } } } - for (int i=0; i<N; ++i) { + for (size_t i=0; i<N; ++i) { determinent *= M(index[i],i); } return determinent; diff --git a/src/utils/BacktraceManager.cpp b/src/utils/BacktraceManager.cpp index eef178b9a89d6fd96c1e54644f99c51d8eeac45a..dd65bb9071f569c2104a6225aae8b4d86ac92c2f 100644 --- a/src/utils/BacktraceManager.cpp +++ b/src/utils/BacktraceManager.cpp @@ -25,7 +25,7 @@ BacktraceManager() } std::ostream& operator<<(std::ostream& os, - const BacktraceManager& btm) + const BacktraceManager& btm) { const std::vector<std::string>& lines = btm.m_lines; @@ -41,16 +41,16 @@ std::ostream& operator<<(std::ostream& os, 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) { - char* demangled = abi::__cxa_demangle(function.c_str(), NULL, NULL, &status); - if (status==0) { - os << rang::style::bold << demangled << rang::style::reset; - free(demangled); - } else { - os << rang::style::bold << function << rang::style::reset; - } + char* demangled = abi::__cxa_demangle(function.c_str(), NULL, NULL, &status); + if (status==0) { + os << rang::style::bold << demangled << rang::style::reset; + free(demangled); + } else { + os << rang::style::bold << function << rang::style::reset; + } } os<< '+' << suffix << '\n'; } else { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 21ba01a73f832740577e6862c402022c56cb57ba..38635a1d76bccde15b7e0ec9edce17c334b7f0ad 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,7 +3,9 @@ include_directories("${CATCH_INCLUDE_PATH}") set(EXECUTABLE_OUTPUT_PATH ${PASTIS_BINARY_DIR}) add_executable (unit_tests test_main.cpp + test_PastisAssert.cpp test_RevisionInfo.cpp + test_TinyMatrix.cpp test_TinyVector.cpp) target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}) diff --git a/tests/test_PastisAssert.cpp b/tests/test_PastisAssert.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d07321a113be496a220cbfe62934248c3c8907b --- /dev/null +++ b/tests/test_PastisAssert.cpp @@ -0,0 +1,17 @@ +#include <catch.hpp> + +#include <PastisAssert.hpp> +#include <string> + +TEST_CASE("PastisAssert", "[assert]") { + SECTION("checking for assert error") { + const std::string filename = "filename"; + const int line = 10; + const std::string function = "function"; + const std::string message = "message"; + + AssertError assert_error(filename, line, function, message); + + REQUIRE(Catch::Detail::stringify(assert_error) == "\n*** Assertion error ***\n at filename:10\n in function\n*** message\n"); + } +} diff --git a/tests/test_TinyMatrix.cpp b/tests/test_TinyMatrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0bc8e843304dd734cb566ede45f2b49e60f391d --- /dev/null +++ b/tests/test_TinyMatrix.cpp @@ -0,0 +1,129 @@ +#include <catch.hpp> + +#include <TinyMatrix.hpp> +#include <PastisAssert.hpp> + +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,int> B(6,5,3, + 8,34,6, + 35,6,7); + + 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))); + REQUIRE(copy_A==A); + REQUIRE_FALSE(copy_A!=A); + + TinyMatrix<3, int> affected_A; affected_A = A; + REQUIRE(affected_A==A); + REQUIRE_FALSE(affected_A!=A); + + REQUIRE(A!=B); + REQUIRE_FALSE(A==B); + } + + SECTION("checking for scalar left product") { + const int a = 2; + const TinyMatrix<3, int> aA = a*A; + + REQUIRE(aA == TinyMatrix<3,int>(2, 4, 6, + 8, 10, 12, + 14, 16, 18)); + } + + 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<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, 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)); + + TinyMatrix<3, int> ApB = A; + ApB += B; + REQUIRE(ApB==A+B); + } + + SECTION("checking for matrices difference ") { + REQUIRE(A-B == TinyMatrix<3,int>(-5, -3, 0, + -4, -29, 0, + -28, 2, 2)); + + TinyMatrix<3, int> AmB = A; + AmB -= B; + REQUIRE(AmB==A-B); + } + + SECTION("checking for matrices product") { + REQUIRE(A*B == TinyMatrix<3,int>(127,91,36, + 274,226,84, + 421,361,132)); + } + + SECTION("checking for matrix-vector product") { + REQUIRE(A*TinyVector<3,int>(2,-3,5) == TinyVector<3,int>(11,23,35)); + } + + SECTION("checking for tensor product") { + const TinyVector<3,int> u(1,3,7); + const TinyVector<3,int> v(6,2,-3); + + REQUIRE(tensorProduct(u,v)==TinyMatrix<3,int>(6,2,-3, + 18,6,-9, + 42,14,-21)); + } + + SECTION("checking for determinant calculations") { + REQUIRE(det(TinyMatrix<1,int>(6))==6); + REQUIRE(det(TinyMatrix<2,int>(3,1, + -3,6))==21); + 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))== Approx(6661.455).epsilon(1E-14)); + } + + 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"); + } + +#ifndef NDEBUG + SECTION("checking for bounds vioation") { + REQUIRE_THROWS_AS(A(3,0), AssertError); + REQUIRE_THROWS_AS(A(0,3), AssertError); + + const TinyMatrix<3,int>& constA = A; + REQUIRE_THROWS_AS(constA(3,0), AssertError); + REQUIRE_THROWS_AS(constA(0,3), AssertError); + } +#endif // NDEBUG +} diff --git a/tests/test_TinyVector.cpp b/tests/test_TinyVector.cpp index e61942a7fdc15c99b801c2f6bf6f6b10d260a530..38588a6b4bed4a4440bf1a320ac8e4c9c23a38cc 100644 --- a/tests/test_TinyVector.cpp +++ b/tests/test_TinyVector.cpp @@ -5,18 +5,18 @@ TEST_CASE("TinyVector", "[algebra]") { TinyVector<3,int> v(1,2,3); - REQUIRE_NOTHROW(((v[0] == 1) and (v[1] == 2) and (v[2] == 3))); + REQUIRE(((v[0] == 1) and (v[1] == 2) and (v[2] == 3))); REQUIRE(v.dimension() == 3); const TinyVector<3,int> z = zero; - REQUIRE_NOTHROW(((z[0] == 0) and (z[1] == 0) and (z[2] == 0))); + REQUIRE(((z[0] == 0) and (z[1] == 0) and (z[2] == 0))); v = TinyVector<3,int>(3,2,4); TinyVector<3,int> w(1,2,6); REQUIRE((v,w)==31); w = 2*v; - REQUIRE_NOTHROW(((w[0] == 2*v[0]) and (w[1]==2*v[1]) and (w[2]==2*v[2]))); + REQUIRE(((w[0] == 2*v[0]) and (w[1]==2*v[1]) and (w[2]==2*v[2]))); TinyVector<3,int> x = v; REQUIRE(x==v); @@ -43,7 +43,7 @@ TEST_CASE("TinyVector", "[algebra]") { REQUIRE(x==v); TinyVector<3,int> z1; z1 = zero; - REQUIRE_NOTHROW(((z1[0] == 0) and (z1[1] == 0) and (z1[2] == 0))); + REQUIRE(((z1[0] == 0) and (z1[1] == 0) and (z1[2] == 0))); REQUIRE(Catch::Detail::stringify(x) == "(3,2,4)");