From a6baa87d27567d2ff17bdb76f9534a112a172a22 Mon Sep 17 00:00:00 2001 From: Tobias Ribizel Date: Wed, 6 Oct 2021 14:12:38 +0200 Subject: [PATCH 1/3] allow creating matrices from const data --- core/test/base/array.cpp | 61 +++++++++ core/test/matrix/coo.cpp | 20 +++ core/test/matrix/csr.cpp | 24 ++++ core/test/matrix/dense.cpp | 19 +++ core/test/matrix/diagonal.cpp | 13 ++ core/test/matrix/ell.cpp | 17 +++ core/test/matrix/fbcsr.cpp | 26 ++++ core/test/matrix/permutation.cpp | 13 ++ core/test/matrix/sparsity_csr.cpp | 18 +++ include/ginkgo/core/base/array.hpp | 141 ++++++++++++++++++++ include/ginkgo/core/matrix/coo.hpp | 26 ++++ include/ginkgo/core/matrix/csr.hpp | 28 ++++ include/ginkgo/core/matrix/dense.hpp | 21 +++ include/ginkgo/core/matrix/diagonal.hpp | 19 +++ include/ginkgo/core/matrix/ell.hpp | 27 ++++ include/ginkgo/core/matrix/fbcsr.hpp | 27 ++++ include/ginkgo/core/matrix/permutation.hpp | 22 +++ include/ginkgo/core/matrix/sparsity_csr.hpp | 26 ++++ 18 files changed, 548 insertions(+) diff --git a/core/test/base/array.cpp b/core/test/base/array.cpp index 24fe9ed52c8..3b6c4cec096 100644 --- a/core/test/base/array.cpp +++ b/core/test/base/array.cpp @@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include @@ -591,4 +592,64 @@ TYPED_TEST(Array, MoveArrayToView) } +TYPED_TEST(Array, AsView) +{ + auto ptr = this->x.get_data(); + auto size = this->x.get_num_elems(); + auto exec = this->x.get_executor(); + auto view = this->x.as_view(); + + ASSERT_EQ(ptr, this->x.get_data()); + ASSERT_EQ(ptr, view.get_data()); + ASSERT_EQ(size, this->x.get_num_elems()); + ASSERT_EQ(size, view.get_num_elems()); + ASSERT_EQ(exec, this->x.get_executor()); + ASSERT_EQ(exec, view.get_executor()); + ASSERT_TRUE(this->x.is_owning()); + ASSERT_FALSE(view.is_owning()); +} + + +TYPED_TEST(Array, AsConstView) +{ + auto ptr = this->x.get_data(); + auto size = this->x.get_num_elems(); + auto exec = this->x.get_executor(); + auto view = this->x.as_const_view(); + + ASSERT_EQ(ptr, this->x.get_data()); + ASSERT_EQ(ptr, view.get_const_data()); + ASSERT_EQ(size, this->x.get_num_elems()); + ASSERT_EQ(size, view.get_num_elems()); + ASSERT_EQ(exec, this->x.get_executor()); + ASSERT_EQ(exec, view.get_executor()); + ASSERT_TRUE(this->x.is_owning()); + ASSERT_FALSE(view.is_owning()); +} + + +TYPED_TEST(Array, ArrayConstCastWorksOnView) +{ + auto ptr = this->x.get_data(); + auto size = this->x.get_num_elems(); + auto exec = this->x.get_executor(); + auto const_view = this->x.as_const_view(); + auto view = gko::detail::array_const_cast(const_view); + static_assert(std::is_samex)>::value, + "wrong return type"); + + ASSERT_EQ(ptr, const_view.get_const_data()); + ASSERT_EQ(size, const_view.get_num_elems()); + ASSERT_EQ(exec, const_view.get_executor()); + ASSERT_EQ(ptr, this->x.get_data()); + ASSERT_EQ(ptr, view.get_const_data()); + ASSERT_EQ(size, this->x.get_num_elems()); + ASSERT_EQ(size, view.get_num_elems()); + ASSERT_EQ(exec, this->x.get_executor()); + ASSERT_EQ(exec, view.get_executor()); + ASSERT_TRUE(this->x.is_owning()); + ASSERT_FALSE(view.is_owning()); +} + + } // namespace diff --git a/core/test/matrix/coo.cpp b/core/test/matrix/coo.cpp index 0047a336836..3605b65a619 100644 --- a/core/test/matrix/coo.cpp +++ b/core/test/matrix/coo.cpp @@ -152,6 +152,26 @@ TYPED_TEST(Coo, CanBeCreatedFromExistingData) } +TYPED_TEST(Coo, CanBeCreatedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + value_type values[] = {1.0, 2.0, 3.0, 4.0}; + index_type col_idxs[] = {0, 1, 1, 0}; + index_type row_idxs[] = {0, 0, 1, 2}; + + auto mtx = gko::matrix::Coo::create_const( + this->exec, gko::dim<2>{3, 2}, + gko::Array::const_view(this->exec, 4, values), + gko::Array::const_view(this->exec, 4, col_idxs), + gko::Array::const_view(this->exec, 4, row_idxs)); + + ASSERT_EQ(mtx->get_const_values(), values); + ASSERT_EQ(mtx->get_const_col_idxs(), col_idxs); + ASSERT_EQ(mtx->get_const_row_idxs(), row_idxs); +} + + TYPED_TEST(Coo, CanBeCopied) { using Mtx = typename TestFixture::Mtx; diff --git a/core/test/matrix/csr.cpp b/core/test/matrix/csr.cpp index 96b16267184..6287b7c2af8 100644 --- a/core/test/matrix/csr.cpp +++ b/core/test/matrix/csr.cpp @@ -160,6 +160,30 @@ TYPED_TEST(Csr, CanBeCreatedFromExistingData) } +TYPED_TEST(Csr, CanBeCreatedFromExistingConstData) +{ + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + value_type values[] = {1.0, 2.0, 3.0, 4.0}; + index_type col_idxs[] = {0, 1, 1, 0}; + index_type row_ptrs[] = {0, 2, 3, 4}; + + auto mtx = gko::matrix::Csr::create_const( + this->exec, gko::dim<2>{3, 2}, + gko::Array::const_view(this->exec, 4, values), + gko::Array::const_view(this->exec, 4, col_idxs), + gko::Array::const_view(this->exec, 4, row_ptrs), + std::make_shared(2)); + + ASSERT_EQ(mtx->get_num_srow_elements(), 1); + ASSERT_EQ(mtx->get_const_values(), values); + ASSERT_EQ(mtx->get_const_col_idxs(), col_idxs); + ASSERT_EQ(mtx->get_const_row_ptrs(), row_ptrs); + ASSERT_EQ(mtx->get_const_srow()[0], 0); +} + + TYPED_TEST(Csr, CanBeCopied) { using Mtx = typename TestFixture::Mtx; diff --git a/core/test/matrix/dense.cpp b/core/test/matrix/dense.cpp index 561fc230ade..0a66d92dc61 100644 --- a/core/test/matrix/dense.cpp +++ b/core/test/matrix/dense.cpp @@ -138,6 +138,25 @@ TYPED_TEST(Dense, CanBeConstructedFromExistingData) } +TYPED_TEST(Dense, CanBeConstructedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + // clang-format off + value_type data[] = { + 1.0, 2.0, -1.0, + 3.0, 4.0, -1.0, + 5.0, 6.0, -1.0}; + // clang-format on + + auto m = gko::matrix::Dense::create_const( + this->exec, gko::dim<2>{3, 2}, + gko::Array::const_view(this->exec, 9, data), 3); + + ASSERT_EQ(m->get_const_values(), data); + ASSERT_EQ(m->at(2, 1), value_type{6.0}); +} + + TYPED_TEST(Dense, CreateWithSameConfigKeepsStride) { auto m = diff --git a/core/test/matrix/diagonal.cpp b/core/test/matrix/diagonal.cpp index eca2892fdec..fbfde914d9c 100644 --- a/core/test/matrix/diagonal.cpp +++ b/core/test/matrix/diagonal.cpp @@ -114,6 +114,19 @@ TYPED_TEST(Diagonal, CanBeCreatedFromExistingData) } +TYPED_TEST(Diagonal, CanBeCreatedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + value_type values[] = {1.0, 2.0, 3.0}; + + auto diag = gko::matrix::Diagonal::create_const( + this->exec, 3, + gko::Array::const_view(this->exec, 3, values)); + + ASSERT_EQ(diag->get_const_values(), values); +} + + TYPED_TEST(Diagonal, CanBeCopied) { using Diag = typename TestFixture::Diag; diff --git a/core/test/matrix/ell.cpp b/core/test/matrix/ell.cpp index c8e6eeeef4b..93f2e0a5b0a 100644 --- a/core/test/matrix/ell.cpp +++ b/core/test/matrix/ell.cpp @@ -154,6 +154,23 @@ TYPED_TEST(Ell, CanBeCreatedFromExistingData) } +TYPED_TEST(Ell, CanBeCreatedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + value_type values[] = {1.0, 3.0, 4.0, -1.0, 2.0, 0.0, 0.0, -1.0}; + index_type col_idxs[] = {0, 1, 0, -1, 1, 0, 0, -1}; + + auto mtx = gko::matrix::Ell::create_const( + this->exec, gko::dim<2>{3, 2}, + gko::Array::const_view(this->exec, 8, values), + gko::Array::const_view(this->exec, 8, col_idxs), 2, 4); + + ASSERT_EQ(mtx->get_const_values(), values); + ASSERT_EQ(mtx->get_const_col_idxs(), col_idxs); +} + + TYPED_TEST(Ell, CanBeCopied) { using Mtx = typename TestFixture::Mtx; diff --git a/core/test/matrix/fbcsr.cpp b/core/test/matrix/fbcsr.cpp index f026ff5b673..fe34f0697fa 100644 --- a/core/test/matrix/fbcsr.cpp +++ b/core/test/matrix/fbcsr.cpp @@ -404,6 +404,32 @@ TYPED_TEST(Fbcsr, CanBeCreatedFromExistingData) } +TYPED_TEST(Fbcsr, CanBeCreatedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using size_type = gko::size_type; + const int bs = this->fbsample.bs; + const size_type nbrows = this->fbsample.nbrows; + const size_type nbcols = this->fbsample.nbcols; + const size_type bnnz = this->fbsample.nbnz; + auto refmat = this->fbsample.generate_fbcsr(); + value_type* const values = refmat->get_values(); + index_type* const col_idxs = refmat->get_col_idxs(); + index_type* const row_ptrs = refmat->get_row_ptrs(); + + auto mtx = gko::matrix::Fbcsr::create_const( + this->exec, gko::dim<2>{nbrows * bs, nbcols * bs}, bs, + gko::Array::const_view(this->exec, bnnz * bs * bs, values), + gko::Array::const_view(this->exec, bnnz, col_idxs), + gko::Array::const_view(this->exec, nbrows + 1, row_ptrs)); + + ASSERT_EQ(mtx->get_const_values(), values); + ASSERT_EQ(mtx->get_const_col_idxs(), col_idxs); + ASSERT_EQ(mtx->get_const_row_ptrs(), row_ptrs); +} + + TYPED_TEST(Fbcsr, CanBeCopied) { using Mtx = typename TestFixture::Mtx; diff --git a/core/test/matrix/permutation.cpp b/core/test/matrix/permutation.cpp index ad7e186e76f..dfe017a3fdc 100644 --- a/core/test/matrix/permutation.cpp +++ b/core/test/matrix/permutation.cpp @@ -142,6 +142,19 @@ TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingData) } +TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingConstData) +{ + using i_type = typename TestFixture::i_type; + using i_type = typename TestFixture::i_type; + i_type data[] = {1, 0, 2}; + + auto m = gko::matrix::Permutation::create_const( + this->exec, 3, gko::Array::const_view(this->exec, 3, data)); + + ASSERT_EQ(m->get_const_permutation(), data); +} + + TYPED_TEST(Permutation, CanBeConstructedWithSizeAndMask) { using i_type = typename TestFixture::i_type; diff --git a/core/test/matrix/sparsity_csr.cpp b/core/test/matrix/sparsity_csr.cpp index a815415c377..16474bf049f 100644 --- a/core/test/matrix/sparsity_csr.cpp +++ b/core/test/matrix/sparsity_csr.cpp @@ -165,6 +165,24 @@ TYPED_TEST(SparsityCsr, CanBeCreatedFromExistingData) } +TYPED_TEST(SparsityCsr, CanBeCreatedFromExistingConstData) +{ + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + index_type col_idxs[] = {0, 1, 1, 0}; + index_type row_ptrs[] = {0, 2, 3, 4}; + + auto mtx = gko::matrix::SparsityCsr::create_const( + this->exec, gko::dim<2>{3, 2}, + gko::Array::const_view(this->exec, 4, col_idxs), + gko::Array::const_view(this->exec, 4, row_ptrs), 2.0); + + ASSERT_EQ(mtx->get_const_col_idxs(), col_idxs); + ASSERT_EQ(mtx->get_const_row_ptrs(), row_ptrs); + ASSERT_EQ(mtx->get_const_value()[0], value_type{2.0}); +} + + TYPED_TEST(SparsityCsr, CanBeCopied) { using Mtx = typename TestFixture::Mtx; diff --git a/include/ginkgo/core/base/array.hpp b/include/ginkgo/core/base/array.hpp index 794f9589e29..bd829107276 100644 --- a/include/ginkgo/core/base/array.hpp +++ b/include/ginkgo/core/base/array.hpp @@ -65,6 +65,86 @@ void convert_data(std::shared_ptr exec, size_type size, const SourceType* src, TargetType* dst); +/** + * @internal + * + * Array-like non-owning wrapper for const data, to be used in conjunction with + * `array_const_cast` and `create_const` to create matrix type wrappers from + * constant data. + * + * @tparam ValueType the type of elements stored in the array view. + */ +template +class ConstArrayView { +public: + /** + * The type of elements stored in the array view. + */ + using value_type = ValueType; + + /** + * Constructs an array view from existing data. + * + * @param exec the executor in whose memory space the data resides. + * @param num_elems the number of elements in this array view. + * @param data a pointer to the first element of this array view. + */ + ConstArrayView(std::shared_ptr exec, size_type num_elems, + const ValueType* data) + : exec_{std::move(exec)}, num_elems_{num_elems}, data_{data} + {} + + /* + * To avoid any collisions with the value semantics of normal arrays, + * disable assignment altogether. + */ + ConstArrayView& operator=(const ConstArrayView&) = delete; + ConstArrayView& operator=(ConstArrayView&&) = delete; + + ConstArrayView(const ConstArrayView&) = default; + /* Move-construction uses copy-construction to preserve executors. */ + ConstArrayView(ConstArrayView&& other) : ConstArrayView{other} {} + + /** + * Returns the number of elements in the array view. + * + * @return the number of elements in the array view + */ + size_type get_num_elems() const noexcept { return num_elems_; } + + /** + * Returns a constant pointer to the first element of this array view. + * + * @return a constant pointer to the first element of this array view. + */ + const value_type* get_const_data() const noexcept { return data_; } + + /** + * Returns the Executor associated with the array view. + * + * @return the Executor associated with the array view + */ + std::shared_ptr get_executor() const noexcept + { + return exec_; + } + + /** + * Returns false, to be consistent with the Array interface. + */ + bool is_owning() const noexcept { return false; } + +private: + std::shared_ptr exec_; + size_type num_elems_; + const ValueType* data_; +}; + + +template +Array array_const_cast(ConstArrayView view); + + } // namespace detail @@ -288,6 +368,46 @@ class Array { return Array{exec, num_elems, data, view_deleter{}}; } + /** + * Creates a constant (immutable) Array from existing memory. + * + * The Array does not take ownership of the memory, and will not deallocate + * it once it goes out of scope. This array type cannot use the function + * `resize_and_reset` since it does not own the data it should resize. + * + * @param exec executor where `data` is located + * @param num_elems number of elements in `data` + * @param data chunk of memory used to create the array + * + * @return an Array constructed from `data` + */ + static detail::ConstArrayView const_view( + std::shared_ptr exec, size_type num_elems, + const value_type* data) + { + return {exec, num_elems, data}; + } + + /** + * Returns a non-owning view of the memory owned by this array. + * It can only be used until this array gets deleted, cleared or resized. + */ + Array as_view() + { + return view(this->get_executor(), this->get_num_elems(), + this->get_data()); + } + + /** + * Returns a non-owning constant view of the memory owned by this array. + * It can only be used until this array gets deleted, cleared or resized. + */ + detail::ConstArrayView as_const_view() const + { + return const_view(this->get_executor(), this->get_num_elems(), + this->get_const_data()); + } + /** * Copies data from another array or view. In the case of an array target, * the array is resized to match the source's size. In the case of a view @@ -627,6 +747,27 @@ class copy_back_deleter> { }; +/** + * @internal + * + * Casts away const-ness from a array view to get a Array representing the same + * data. This needs to be used carefully, as the class this array gets passed to + * must not modify its data. That is usually achieved by creating a `const` + * instance of the class. + * + * @param view the array view to be cast. + * @returns a non-const non-owning array wrapping the same pointer on the same + * executor as `view`. + */ +template +Array array_const_cast(ConstArrayView view) +{ + return Array::view( + view.get_executor(), view.get_num_elems(), + const_cast(view.get_const_data())); +} + + } // namespace detail } // namespace gko diff --git a/include/ginkgo/core/matrix/coo.hpp b/include/ginkgo/core/matrix/coo.hpp index ac2a501799c..7690ef80c56 100644 --- a/include/ginkgo/core/matrix/coo.hpp +++ b/include/ginkgo/core/matrix/coo.hpp @@ -258,6 +258,32 @@ class Coo : public EnableLinOp>, return this; } + /** + * Creates a constant (immutable) Coo matrix from a set of constant arrays. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param values the value array of the matrix + * @param col_idxs the column index array of the matrix + * @param row_ptrs the row index array of the matrix + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if they reside on the same executor as the matrix) or a copy of + * these arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, + gko::detail::ConstArrayView values, + gko::detail::ConstArrayView col_idxs, + gko::detail::ConstArrayView row_idxs) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr( + new Coo{exec, size, gko::detail::array_const_cast(values), + gko::detail::array_const_cast(col_idxs), + gko::detail::array_const_cast(row_idxs)}); + } + protected: /** * Creates an uninitialized COO matrix of the specified size. diff --git a/include/ginkgo/core/matrix/csr.hpp b/include/ginkgo/core/matrix/csr.hpp index a8de85ca93f..2ccf6eea881 100644 --- a/include/ginkgo/core/matrix/csr.hpp +++ b/include/ginkgo/core/matrix/csr.hpp @@ -922,6 +922,34 @@ class Csr : public EnableLinOp>, this->inv_scale_impl(make_temporary_clone(exec, alpha).get()); } + /* + * Creates a constant (immutable) Csr matrix from a set of constant arrays. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param values the value array of the matrix + * @param col_idxs the column index array of the matrix + * @param row_ptrs the row pointer array of the matrix + * @param strategy the strategy the matrix uses for SpMV operations + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if they reside on the same executor as the matrix) or a copy of + * these arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, + gko::detail::ConstArrayView values, + gko::detail::ConstArrayView col_idxs, + gko::detail::ConstArrayView row_ptrs, + std::shared_ptr strategy = std::make_shared()) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr( + new Csr{exec, size, gko::detail::array_const_cast(values), + gko::detail::array_const_cast(col_idxs), + gko::detail::array_const_cast(row_ptrs), strategy}); + } + protected: /** * Creates an uninitialized CSR matrix of the specified size. diff --git a/include/ginkgo/core/matrix/dense.hpp b/include/ginkgo/core/matrix/dense.hpp index 4f733534022..3f5753beb84 100644 --- a/include/ginkgo/core/matrix/dense.hpp +++ b/include/ginkgo/core/matrix/dense.hpp @@ -801,6 +801,27 @@ class Dense stride); } + /** + * Creates a constant (immutable) Dense matrix from a constant array. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param values the value array of the matrix + * @param stride the row-stride of the matrix + * @returns A smart pointer to the constant matrix wrapping the input array + * (if it resides on the same executor as the matrix) or a copy of + * the array on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, + gko::detail::ConstArrayView values, size_type stride) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr(new Dense{ + exec, size, gko::detail::array_const_cast(values), stride}); + } + protected: /** * Creates an uninitialized Dense matrix of the specified size. diff --git a/include/ginkgo/core/matrix/diagonal.hpp b/include/ginkgo/core/matrix/diagonal.hpp index c99d4c440f0..f4237b95c36 100644 --- a/include/ginkgo/core/matrix/diagonal.hpp +++ b/include/ginkgo/core/matrix/diagonal.hpp @@ -158,6 +158,25 @@ class Diagonal void write(mat_data32& data) const override; + /** + * Creates a constant (immutable) Diagonal matrix from a constant array. + * + * @param exec the executor to create the matrix on + * @param size the size of the square matrix + * @param values the value array of the matrix + * @returns A smart pointer to the constant matrix wrapping the input array + * (if it resides on the same executor as the matrix) or a copy of + * the array on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, size_type size, + gko::detail::ConstArrayView values) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr( + new Diagonal{exec, size, gko::detail::array_const_cast(values)}); + } protected: /** diff --git a/include/ginkgo/core/matrix/ell.hpp b/include/ginkgo/core/matrix/ell.hpp index f20a0c786d3..9ea16e79594 100644 --- a/include/ginkgo/core/matrix/ell.hpp +++ b/include/ginkgo/core/matrix/ell.hpp @@ -230,6 +230,33 @@ class Ell : public EnableLinOp>, return this->get_const_col_idxs()[this->linearize_index(row, idx)]; } + /** + * Creates a constant (immutable) Ell matrix from a set of constant arrays. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param values the value array of the matrix + * @param col_idxs the column index array of the matrix + * @param num_stored_elements_per_row the number of stored nonzeros per row + * @param stride the column-stride of the value and column index array + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if they reside on the same executor as the matrix) or a copy of + * the arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, + gko::detail::ConstArrayView values, + gko::detail::ConstArrayView col_idxs, + size_type num_stored_elements_per_row, size_type stride) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr( + new Ell{exec, size, gko::detail::array_const_cast(values), + gko::detail::array_const_cast(col_idxs), + num_stored_elements_per_row, stride}); + } + protected: /** * Creates an uninitialized Ell matrix of the specified size. diff --git a/include/ginkgo/core/matrix/fbcsr.hpp b/include/ginkgo/core/matrix/fbcsr.hpp index 11c6d29001f..90e1722cd59 100644 --- a/include/ginkgo/core/matrix/fbcsr.hpp +++ b/include/ginkgo/core/matrix/fbcsr.hpp @@ -320,6 +320,33 @@ class Fbcsr : public EnableLinOp>, */ index_type get_num_block_cols() const noexcept { return nbcols_; } + /** + * Creates a constant (immutable) Fbcsr matrix from a constant array. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param blocksize the block size of the matrix + * @param values the value array of the matrix + * @param col_idxs the block column index array of the matrix + * @param row_ptrs the block row pointer array of the matrix + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if they reside on the same executor as the matrix) or a copy of + * the arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, int blocksize, + gko::detail::ConstArrayView values, + gko::detail::ConstArrayView col_idxs, + gko::detail::ConstArrayView row_ptrs) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr(new Fbcsr{ + exec, size, blocksize, gko::detail::array_const_cast(values), + gko::detail::array_const_cast(col_idxs), + gko::detail::array_const_cast(row_ptrs)}); + } + protected: /** * Creates an uninitialized FBCSR matrix with the given block size. diff --git a/include/ginkgo/core/matrix/permutation.hpp b/include/ginkgo/core/matrix/permutation.hpp index 4cf252ba2b9..f468affbcbb 100644 --- a/include/ginkgo/core/matrix/permutation.hpp +++ b/include/ginkgo/core/matrix/permutation.hpp @@ -132,6 +132,28 @@ class Permutation : public EnableLinOp>, enabled_permute_ = permute_mask; } + /** + * Creates a constant (immutable) Permutation matrix from a constant array. + * + * @param exec the executor to create the matrix on + * @param size the size of the square matrix + * @param perm_idxs the permutation index array of the matrix + * @param enabled_permute the mask describing the type of permutation + * @returns A smart pointer to the constant matrix wrapping the input array + * (if it resides on the same executor as the matrix) or a copy of + * the array on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, size_type size, + gko::detail::ConstArrayView perm_idxs, + mask_type enabled_permute = row_permute) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr(new Permutation{ + exec, size, gko::detail::array_const_cast(perm_idxs), + enabled_permute}); + } protected: /** diff --git a/include/ginkgo/core/matrix/sparsity_csr.hpp b/include/ginkgo/core/matrix/sparsity_csr.hpp index 3ef651bf22a..5d1590fd0db 100644 --- a/include/ginkgo/core/matrix/sparsity_csr.hpp +++ b/include/ginkgo/core/matrix/sparsity_csr.hpp @@ -192,6 +192,32 @@ class SparsityCsr return col_idxs_.get_num_elems(); } + /** + * Creates a constant (immutable) SparsityCsr matrix from constant arrays. + * + * @param exec the executor to create the matrix on + * @param size the dimensions of the matrix + * @param values the value array of the matrix + * @param col_idxs the column index array of the matrix + * @param row_ptrs the row pointer array of the matrix + * @param strategy the strategy the matrix uses for SpMV operations + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if they reside on the same executor as the matrix) or a copy of + * these arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, const dim<2>& size, + gko::detail::ConstArrayView col_idxs, + gko::detail::ConstArrayView row_ptrs, + ValueType value = one()) + { + // cast const-ness away, but return a const object afterwards, + // so we can ensure that no modifications take place. + return std::unique_ptr( + new SparsityCsr{exec, size, gko::detail::array_const_cast(col_idxs), + gko::detail::array_const_cast(row_ptrs), value}); + } + protected: /** * Creates an uninitialized SparsityCsr matrix of the specified size. From a2d667e5b240a70a9c4510331e00b8fa3cdb38ec Mon Sep 17 00:00:00 2001 From: Tobias Ribizel Date: Fri, 8 Oct 2021 10:14:02 +0200 Subject: [PATCH 2/3] test create_const with actually const data Co-authored-by: Marcel Koch --- core/test/matrix/coo.cpp | 6 +++--- core/test/matrix/csr.cpp | 6 +++--- core/test/matrix/dense.cpp | 2 +- core/test/matrix/diagonal.cpp | 2 +- core/test/matrix/ell.cpp | 4 ++-- core/test/matrix/fbcsr.cpp | 6 +++--- core/test/matrix/permutation.cpp | 2 +- core/test/matrix/sparsity_csr.cpp | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/test/matrix/coo.cpp b/core/test/matrix/coo.cpp index 3605b65a619..5f98751236b 100644 --- a/core/test/matrix/coo.cpp +++ b/core/test/matrix/coo.cpp @@ -156,9 +156,9 @@ TYPED_TEST(Coo, CanBeCreatedFromExistingConstData) { using value_type = typename TestFixture::value_type; using index_type = typename TestFixture::index_type; - value_type values[] = {1.0, 2.0, 3.0, 4.0}; - index_type col_idxs[] = {0, 1, 1, 0}; - index_type row_idxs[] = {0, 0, 1, 2}; + const value_type values[] = {1.0, 2.0, 3.0, 4.0}; + const index_type col_idxs[] = {0, 1, 1, 0}; + const index_type row_idxs[] = {0, 0, 1, 2}; auto mtx = gko::matrix::Coo::create_const( this->exec, gko::dim<2>{3, 2}, diff --git a/core/test/matrix/csr.cpp b/core/test/matrix/csr.cpp index 6287b7c2af8..00af5fd70cc 100644 --- a/core/test/matrix/csr.cpp +++ b/core/test/matrix/csr.cpp @@ -165,9 +165,9 @@ TYPED_TEST(Csr, CanBeCreatedFromExistingConstData) using Mtx = typename TestFixture::Mtx; using value_type = typename TestFixture::value_type; using index_type = typename TestFixture::index_type; - value_type values[] = {1.0, 2.0, 3.0, 4.0}; - index_type col_idxs[] = {0, 1, 1, 0}; - index_type row_ptrs[] = {0, 2, 3, 4}; + const value_type values[] = {1.0, 2.0, 3.0, 4.0}; + const index_type col_idxs[] = {0, 1, 1, 0}; + const index_type row_ptrs[] = {0, 2, 3, 4}; auto mtx = gko::matrix::Csr::create_const( this->exec, gko::dim<2>{3, 2}, diff --git a/core/test/matrix/dense.cpp b/core/test/matrix/dense.cpp index 0a66d92dc61..35c9f276047 100644 --- a/core/test/matrix/dense.cpp +++ b/core/test/matrix/dense.cpp @@ -142,7 +142,7 @@ TYPED_TEST(Dense, CanBeConstructedFromExistingConstData) { using value_type = typename TestFixture::value_type; // clang-format off - value_type data[] = { + const value_type data[] = { 1.0, 2.0, -1.0, 3.0, 4.0, -1.0, 5.0, 6.0, -1.0}; diff --git a/core/test/matrix/diagonal.cpp b/core/test/matrix/diagonal.cpp index fbfde914d9c..f11f576dd12 100644 --- a/core/test/matrix/diagonal.cpp +++ b/core/test/matrix/diagonal.cpp @@ -117,7 +117,7 @@ TYPED_TEST(Diagonal, CanBeCreatedFromExistingData) TYPED_TEST(Diagonal, CanBeCreatedFromExistingConstData) { using value_type = typename TestFixture::value_type; - value_type values[] = {1.0, 2.0, 3.0}; + const value_type values[] = {1.0, 2.0, 3.0}; auto diag = gko::matrix::Diagonal::create_const( this->exec, 3, diff --git a/core/test/matrix/ell.cpp b/core/test/matrix/ell.cpp index 93f2e0a5b0a..9b7cfe3d058 100644 --- a/core/test/matrix/ell.cpp +++ b/core/test/matrix/ell.cpp @@ -158,8 +158,8 @@ TYPED_TEST(Ell, CanBeCreatedFromExistingConstData) { using value_type = typename TestFixture::value_type; using index_type = typename TestFixture::index_type; - value_type values[] = {1.0, 3.0, 4.0, -1.0, 2.0, 0.0, 0.0, -1.0}; - index_type col_idxs[] = {0, 1, 0, -1, 1, 0, 0, -1}; + const value_type values[] = {1.0, 3.0, 4.0, -1.0, 2.0, 0.0, 0.0, -1.0}; + const index_type col_idxs[] = {0, 1, 0, -1, 1, 0, 0, -1}; auto mtx = gko::matrix::Ell::create_const( this->exec, gko::dim<2>{3, 2}, diff --git a/core/test/matrix/fbcsr.cpp b/core/test/matrix/fbcsr.cpp index fe34f0697fa..04d008a22c1 100644 --- a/core/test/matrix/fbcsr.cpp +++ b/core/test/matrix/fbcsr.cpp @@ -414,9 +414,9 @@ TYPED_TEST(Fbcsr, CanBeCreatedFromExistingConstData) const size_type nbcols = this->fbsample.nbcols; const size_type bnnz = this->fbsample.nbnz; auto refmat = this->fbsample.generate_fbcsr(); - value_type* const values = refmat->get_values(); - index_type* const col_idxs = refmat->get_col_idxs(); - index_type* const row_ptrs = refmat->get_row_ptrs(); + auto values = refmat->get_const_values(); + auto col_idxs = refmat->get_const_col_idxs(); + auto row_ptrs = refmat->get_const_row_ptrs(); auto mtx = gko::matrix::Fbcsr::create_const( this->exec, gko::dim<2>{nbrows * bs, nbcols * bs}, bs, diff --git a/core/test/matrix/permutation.cpp b/core/test/matrix/permutation.cpp index dfe017a3fdc..4a7ac60f4d9 100644 --- a/core/test/matrix/permutation.cpp +++ b/core/test/matrix/permutation.cpp @@ -146,7 +146,7 @@ TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingConstData) { using i_type = typename TestFixture::i_type; using i_type = typename TestFixture::i_type; - i_type data[] = {1, 0, 2}; + const i_type data[] = {1, 0, 2}; auto m = gko::matrix::Permutation::create_const( this->exec, 3, gko::Array::const_view(this->exec, 3, data)); diff --git a/core/test/matrix/sparsity_csr.cpp b/core/test/matrix/sparsity_csr.cpp index 16474bf049f..edef2430bdf 100644 --- a/core/test/matrix/sparsity_csr.cpp +++ b/core/test/matrix/sparsity_csr.cpp @@ -169,8 +169,8 @@ TYPED_TEST(SparsityCsr, CanBeCreatedFromExistingConstData) { using value_type = typename TestFixture::value_type; using index_type = typename TestFixture::index_type; - index_type col_idxs[] = {0, 1, 1, 0}; - index_type row_ptrs[] = {0, 2, 3, 4}; + const index_type col_idxs[] = {0, 1, 1, 0}; + const index_type row_ptrs[] = {0, 2, 3, 4}; auto mtx = gko::matrix::SparsityCsr::create_const( this->exec, gko::dim<2>{3, 2}, From bd55c34ae28c7d71a104105109c4468efe6fbfb7 Mon Sep 17 00:00:00 2001 From: Tobias Ribizel Date: Fri, 8 Oct 2021 10:36:29 +0200 Subject: [PATCH 3/3] make ConstArrayView moved-from state empty --- core/test/base/array.cpp | 6 +++--- include/ginkgo/core/base/array.hpp | 17 ++++++++++++----- include/ginkgo/core/matrix/coo.hpp | 14 +++++++------- include/ginkgo/core/matrix/csr.hpp | 14 +++++++------- include/ginkgo/core/matrix/dense.hpp | 5 +++-- include/ginkgo/core/matrix/diagonal.hpp | 6 +++--- include/ginkgo/core/matrix/ell.hpp | 12 ++++++------ include/ginkgo/core/matrix/fbcsr.hpp | 15 ++++++++------- include/ginkgo/core/matrix/permutation.hpp | 4 ++-- include/ginkgo/core/matrix/sparsity_csr.hpp | 10 +++++----- 10 files changed, 56 insertions(+), 47 deletions(-) diff --git a/core/test/base/array.cpp b/core/test/base/array.cpp index 3b6c4cec096..8738035eb55 100644 --- a/core/test/base/array.cpp +++ b/core/test/base/array.cpp @@ -634,12 +634,12 @@ TYPED_TEST(Array, ArrayConstCastWorksOnView) auto size = this->x.get_num_elems(); auto exec = this->x.get_executor(); auto const_view = this->x.as_const_view(); - auto view = gko::detail::array_const_cast(const_view); + auto view = gko::detail::array_const_cast(std::move(const_view)); static_assert(std::is_samex)>::value, "wrong return type"); - ASSERT_EQ(ptr, const_view.get_const_data()); - ASSERT_EQ(size, const_view.get_num_elems()); + ASSERT_EQ(nullptr, const_view.get_const_data()); + ASSERT_EQ(0, const_view.get_num_elems()); ASSERT_EQ(exec, const_view.get_executor()); ASSERT_EQ(ptr, this->x.get_data()); ASSERT_EQ(ptr, view.get_const_data()); diff --git a/include/ginkgo/core/base/array.hpp b/include/ginkgo/core/base/array.hpp index bd829107276..9f02cbe3c3f 100644 --- a/include/ginkgo/core/base/array.hpp +++ b/include/ginkgo/core/base/array.hpp @@ -96,14 +96,21 @@ class ConstArrayView { /* * To avoid any collisions with the value semantics of normal arrays, - * disable assignment altogether. + * disable assignment and copy-construction altogether. */ ConstArrayView& operator=(const ConstArrayView&) = delete; ConstArrayView& operator=(ConstArrayView&&) = delete; - - ConstArrayView(const ConstArrayView&) = default; - /* Move-construction uses copy-construction to preserve executors. */ - ConstArrayView(ConstArrayView&& other) : ConstArrayView{other} {} + ConstArrayView(const ConstArrayView&) = delete; + /* + * TODO C++17: delete this overload as well, it is no longer necessary due + * to guaranteed RVO. + */ + ConstArrayView(ConstArrayView&& other) + : ConstArrayView{other.exec_, other.num_elems_, other.data_} + { + other.num_elems_ = 0; + other.data_ = nullptr; + } /** * Returns the number of elements in the array view. diff --git a/include/ginkgo/core/matrix/coo.hpp b/include/ginkgo/core/matrix/coo.hpp index 7690ef80c56..f7d5d1f985d 100644 --- a/include/ginkgo/core/matrix/coo.hpp +++ b/include/ginkgo/core/matrix/coo.hpp @@ -272,16 +272,16 @@ class Coo : public EnableLinOp>, */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, - gko::detail::ConstArrayView values, - gko::detail::ConstArrayView col_idxs, - gko::detail::ConstArrayView row_idxs) + gko::detail::ConstArrayView&& values, + gko::detail::ConstArrayView&& col_idxs, + gko::detail::ConstArrayView&& row_idxs) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr( - new Coo{exec, size, gko::detail::array_const_cast(values), - gko::detail::array_const_cast(col_idxs), - gko::detail::array_const_cast(row_idxs)}); + return std::unique_ptr(new Coo{ + exec, size, gko::detail::array_const_cast(std::move(values)), + gko::detail::array_const_cast(std::move(col_idxs)), + gko::detail::array_const_cast(std::move(row_idxs))}); } protected: diff --git a/include/ginkgo/core/matrix/csr.hpp b/include/ginkgo/core/matrix/csr.hpp index 2ccf6eea881..a9c9cc53255 100644 --- a/include/ginkgo/core/matrix/csr.hpp +++ b/include/ginkgo/core/matrix/csr.hpp @@ -937,17 +937,17 @@ class Csr : public EnableLinOp>, */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, - gko::detail::ConstArrayView values, - gko::detail::ConstArrayView col_idxs, - gko::detail::ConstArrayView row_ptrs, + gko::detail::ConstArrayView&& values, + gko::detail::ConstArrayView&& col_idxs, + gko::detail::ConstArrayView&& row_ptrs, std::shared_ptr strategy = std::make_shared()) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr( - new Csr{exec, size, gko::detail::array_const_cast(values), - gko::detail::array_const_cast(col_idxs), - gko::detail::array_const_cast(row_ptrs), strategy}); + return std::unique_ptr(new Csr{ + exec, size, gko::detail::array_const_cast(std::move(values)), + gko::detail::array_const_cast(std::move(col_idxs)), + gko::detail::array_const_cast(std::move(row_ptrs)), strategy}); } protected: diff --git a/include/ginkgo/core/matrix/dense.hpp b/include/ginkgo/core/matrix/dense.hpp index 3f5753beb84..84063e93b62 100644 --- a/include/ginkgo/core/matrix/dense.hpp +++ b/include/ginkgo/core/matrix/dense.hpp @@ -814,12 +814,13 @@ class Dense */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, - gko::detail::ConstArrayView values, size_type stride) + gko::detail::ConstArrayView&& values, size_type stride) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. return std::unique_ptr(new Dense{ - exec, size, gko::detail::array_const_cast(values), stride}); + exec, size, gko::detail::array_const_cast(std::move(values)), + stride}); } protected: diff --git a/include/ginkgo/core/matrix/diagonal.hpp b/include/ginkgo/core/matrix/diagonal.hpp index f4237b95c36..5b53248609f 100644 --- a/include/ginkgo/core/matrix/diagonal.hpp +++ b/include/ginkgo/core/matrix/diagonal.hpp @@ -170,12 +170,12 @@ class Diagonal */ static std::unique_ptr create_const( std::shared_ptr exec, size_type size, - gko::detail::ConstArrayView values) + gko::detail::ConstArrayView&& values) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr( - new Diagonal{exec, size, gko::detail::array_const_cast(values)}); + return std::unique_ptr(new Diagonal{ + exec, size, gko::detail::array_const_cast(std::move(values))}); } protected: diff --git a/include/ginkgo/core/matrix/ell.hpp b/include/ginkgo/core/matrix/ell.hpp index 9ea16e79594..74b2d14e8ae 100644 --- a/include/ginkgo/core/matrix/ell.hpp +++ b/include/ginkgo/core/matrix/ell.hpp @@ -245,16 +245,16 @@ class Ell : public EnableLinOp>, */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, - gko::detail::ConstArrayView values, - gko::detail::ConstArrayView col_idxs, + gko::detail::ConstArrayView&& values, + gko::detail::ConstArrayView&& col_idxs, size_type num_stored_elements_per_row, size_type stride) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr( - new Ell{exec, size, gko::detail::array_const_cast(values), - gko::detail::array_const_cast(col_idxs), - num_stored_elements_per_row, stride}); + return std::unique_ptr(new Ell{ + exec, size, gko::detail::array_const_cast(std::move(values)), + gko::detail::array_const_cast(std::move(col_idxs)), + num_stored_elements_per_row, stride}); } protected: diff --git a/include/ginkgo/core/matrix/fbcsr.hpp b/include/ginkgo/core/matrix/fbcsr.hpp index 90e1722cd59..cfb27350646 100644 --- a/include/ginkgo/core/matrix/fbcsr.hpp +++ b/include/ginkgo/core/matrix/fbcsr.hpp @@ -335,16 +335,17 @@ class Fbcsr : public EnableLinOp>, */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, int blocksize, - gko::detail::ConstArrayView values, - gko::detail::ConstArrayView col_idxs, - gko::detail::ConstArrayView row_ptrs) + gko::detail::ConstArrayView&& values, + gko::detail::ConstArrayView&& col_idxs, + gko::detail::ConstArrayView&& row_ptrs) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr(new Fbcsr{ - exec, size, blocksize, gko::detail::array_const_cast(values), - gko::detail::array_const_cast(col_idxs), - gko::detail::array_const_cast(row_ptrs)}); + return std::unique_ptr( + new Fbcsr{exec, size, blocksize, + gko::detail::array_const_cast(std::move(values)), + gko::detail::array_const_cast(std::move(col_idxs)), + gko::detail::array_const_cast(std::move(row_ptrs))}); } protected: diff --git a/include/ginkgo/core/matrix/permutation.hpp b/include/ginkgo/core/matrix/permutation.hpp index f468affbcbb..3b52e34c636 100644 --- a/include/ginkgo/core/matrix/permutation.hpp +++ b/include/ginkgo/core/matrix/permutation.hpp @@ -145,13 +145,13 @@ class Permutation : public EnableLinOp>, */ static std::unique_ptr create_const( std::shared_ptr exec, size_type size, - gko::detail::ConstArrayView perm_idxs, + gko::detail::ConstArrayView&& perm_idxs, mask_type enabled_permute = row_permute) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. return std::unique_ptr(new Permutation{ - exec, size, gko::detail::array_const_cast(perm_idxs), + exec, size, gko::detail::array_const_cast(std::move(perm_idxs)), enabled_permute}); } diff --git a/include/ginkgo/core/matrix/sparsity_csr.hpp b/include/ginkgo/core/matrix/sparsity_csr.hpp index 5d1590fd0db..fcc8a52b732 100644 --- a/include/ginkgo/core/matrix/sparsity_csr.hpp +++ b/include/ginkgo/core/matrix/sparsity_csr.hpp @@ -207,15 +207,15 @@ class SparsityCsr */ static std::unique_ptr create_const( std::shared_ptr exec, const dim<2>& size, - gko::detail::ConstArrayView col_idxs, - gko::detail::ConstArrayView row_ptrs, + gko::detail::ConstArrayView&& col_idxs, + gko::detail::ConstArrayView&& row_ptrs, ValueType value = one()) { // cast const-ness away, but return a const object afterwards, // so we can ensure that no modifications take place. - return std::unique_ptr( - new SparsityCsr{exec, size, gko::detail::array_const_cast(col_idxs), - gko::detail::array_const_cast(row_ptrs), value}); + return std::unique_ptr(new SparsityCsr{ + exec, size, gko::detail::array_const_cast(std::move(col_idxs)), + gko::detail::array_const_cast(std::move(row_ptrs)), value}); } protected: