From 32567b1af577051af812502b61f3c8acc44acd07 Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Fri, 2 Aug 2019 19:13:06 +0200 Subject: [PATCH] Add a bunch of improvements and test for PCG - Vector<const T> should now be supported - CRSMatrix data is constant --- src/algebra/CRSMatrix.hpp | 16 ++++++-- src/algebra/PCG.hpp | 3 ++ src/algebra/Vector.hpp | 77 +++++++++++++++++++++++++-------------- tests/CMakeLists.txt | 1 + tests/test_PCG.cpp | 50 +++++++++++++++++++++++++ tests/test_main.cpp | 3 ++ 6 files changed, 119 insertions(+), 31 deletions(-) create mode 100644 tests/test_PCG.cpp diff --git a/src/algebra/CRSMatrix.hpp b/src/algebra/CRSMatrix.hpp index 224b09c21..740343cd6 100644 --- a/src/algebra/CRSMatrix.hpp +++ b/src/algebra/CRSMatrix.hpp @@ -14,11 +14,13 @@ template <typename DataType = double, typename IndexType = size_t> class CRSMatrix { + using MutableDataType = std::remove_const_t<DataType>; + private: using HostMatrix = Kokkos::StaticCrsGraph<IndexType, Kokkos::HostSpace>; HostMatrix m_host_matrix; - Array<DataType> m_values; + Array<const DataType> m_values; public: PUGS_INLINE @@ -28,16 +30,22 @@ class CRSMatrix return m_host_matrix.numRows(); } - Vector<DataType> operator*(const Vector<DataType>& x) const + template <typename DataType2> + Vector<MutableDataType> operator*(const Vector<DataType2>& x) const { - Vector<DataType> Ax{m_host_matrix.numRows()}; + static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(), + "Cannot multiply matrix and vector of different type"); + + Assert(x.size() == m_host_matrix.numRows()); + + Vector<MutableDataType> Ax{m_host_matrix.numRows()}; auto host_row_map = m_host_matrix.row_map; parallel_for( m_host_matrix.numRows(), PUGS_LAMBDA(const IndexType& i_row) { const auto row_begin = host_row_map(i_row); const auto row_end = host_row_map(i_row + 1); - DataType sum{0}; + MutableDataType sum{0}; for (IndexType j = row_begin; j < row_end; ++j) { sum += m_values[j] * x[m_host_matrix.entries(j)]; } diff --git a/src/algebra/PCG.hpp b/src/algebra/PCG.hpp index 2a979af2b..74c17ee40 100644 --- a/src/algebra/PCG.hpp +++ b/src/algebra/PCG.hpp @@ -1,6 +1,9 @@ #ifndef PCG_HPP #define PCG_HPP +#include <iomanip> +#include <iostream> + struct PCG { template <typename VectorType, typename MatrixType, typename PreconditionerType> diff --git a/src/algebra/Vector.hpp b/src/algebra/Vector.hpp index f8bbf5313..43865dae1 100644 --- a/src/algebra/Vector.hpp +++ b/src/algebra/Vector.hpp @@ -19,29 +19,40 @@ class Vector // LCOV_EXCL_LINE Array<DataType> m_values; static_assert(std::is_same_v<typename decltype(m_values)::index_type, index_type>); + // Allows const version to access our data + friend Vector<std::add_const_t<DataType>>; + public: - friend PUGS_INLINE Vector + friend Vector<std::remove_const_t<DataType>> copy(const Vector& x) { auto values = copy(x.m_values); - Vector x_copy{0}; + Vector<std::remove_const_t<DataType>> x_copy{0}; x_copy.m_values = values; return x_copy; } - template <typename DataType2> - friend Vector operator*(const DataType2& a, const Vector& x) + friend Vector operator*(const DataType& a, const Vector& x) { - Vector y = copy(x); + Vector<std::remove_const_t<DataType>> y = copy(x); return y *= a; } + template <typename DataType2> PUGS_INLINE - DataType - operator,(const Vector& y) + auto + operator,(const Vector<DataType2>& y) { - DataType sum = 0; + Assert(this->size() == y.size()); + // 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 < this->size(); ++i) { @@ -65,56 +76,55 @@ class Vector // LCOV_EXCL_LINE { parallel_for( this->size(), PUGS_LAMBDA(const index_type& i) { m_values[i] *= a; }); - return *this; } - PUGS_INLINE - Vector& - operator-=(const Vector& y) + template <typename DataType2> + PUGS_INLINE Vector& + operator-=(const Vector<DataType2>& y) { Assert(this->size() == y.size()); parallel_for( - this->size(), PUGS_LAMBDA(const index_type& i) { m_values[i] -= y.m_values[i]; }); + this->size(), PUGS_LAMBDA(const index_type& i) { m_values[i] -= y[i]; }); return *this; } - PUGS_INLINE - Vector& - operator+=(const Vector& y) + template <typename DataType2> + PUGS_INLINE Vector& + operator+=(const Vector<DataType2>& y) { Assert(this->size() == y.size()); parallel_for( - this->size(), PUGS_LAMBDA(const index_type& i) { m_values[i] += y.m_values[i]; }); + this->size(), PUGS_LAMBDA(const index_type& i) { m_values[i] += y[i]; }); return *this; } - PUGS_INLINE - Vector - operator+(const Vector& y) const + template <typename DataType2> + PUGS_INLINE Vector<std::remove_const_t<DataType>> + operator+(const Vector<DataType2>& y) const { Assert(this->size() == y.size()); - Vector sum{y.size()}; + Vector<std::remove_const_t<DataType>> sum{y.size()}; parallel_for( - this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] + y.m_values[i]; }); + this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] + y[i]; }); return sum; } - PUGS_INLINE - Vector - operator-(const Vector& y) const + template <typename DataType2> + PUGS_INLINE Vector<std::remove_const_t<DataType>> + operator-(const Vector<DataType2>& y) const { Assert(this->size() == y.size()); - Vector sum{y.size()}; + Vector<std::remove_const_t<DataType>> sum{y.size()}; parallel_for( - this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] - y.m_values[i]; }); + this->size(), PUGS_LAMBDA(const index_type& i) { sum.m_values[i] = m_values[i] - y[i]; }); return sum; } @@ -153,6 +163,19 @@ class Vector // LCOV_EXCL_LINE PUGS_INLINE Vector& operator=(Vector&&) = default; + template <typename DataType2> + Vector(const Vector<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 Vector 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 Vector of const to Vector of non-const"); + + this->operator=(x); + } + Vector(const Vector&) = default; Vector(Vector&&) = default; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2d0ec377d..a3becc009 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable (unit_tests test_ArrayUtils.cpp test_CRSMatrix.cpp test_ItemType.cpp + test_PCG.cpp test_PugsAssert.cpp test_RevisionInfo.cpp test_SparseMatrixDescriptor.cpp diff --git a/tests/test_PCG.cpp b/tests/test_PCG.cpp new file mode 100644 index 000000000..11636132c --- /dev/null +++ b/tests/test_PCG.cpp @@ -0,0 +1,50 @@ +#include <catch2/catch.hpp> + +#include <CRSMatrix.hpp> +#include <PCG.hpp> + +TEST_CASE("PCG", "[algebra]") +{ + SECTION("no preconditionner") + { + SparseMatrixDescriptor S{5}; + S(0, 0) = 2; + S(0, 1) = -1; + + S(1, 0) = -1; + S(1, 1) = 2; + S(1, 2) = -1; + + S(2, 1) = -1; + S(2, 2) = 2; + S(2, 3) = -1; + + S(3, 2) = -1; + S(3, 3) = 2; + S(3, 4) = -1; + + S(4, 3) = -1; + S(4, 4) = 2; + + CRSMatrix A{S}; + + Vector<const double> x_exact = [] { + Vector<double> y{5}; + y[0] = 1; + y[1] = 3; + y[2] = 2; + y[3] = 4; + y[4] = 5; + return y; + }(); + + Vector<double> b = A * x_exact; + + Vector<double> x{5}; + x = 0; + + PCG{b, A, A, x, 10, 1e-12}; + Vector error = x - x_exact; + REQUIRE(std::sqrt((error, error)) < 1E-10 * std::sqrt((x, x))); + } +} diff --git a/tests/test_main.cpp b/tests/test_main.cpp index e0ed7b5fe..c7355e990 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -8,6 +8,9 @@ main(int argc, char* argv[]) { Kokkos::initialize({4, -1, -1, true}); + // Disable outputs from tested classes to the standard output + std::cout.setstate(std::ios::badbit); + int result = Catch::Session().run(argc, argv); Kokkos::finalize(); -- GitLab