From fcce3e17d4b3ca027f15a79d2f6fee143a772b0c Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Fri, 28 Apr 2023 13:38:25 -0500 Subject: [PATCH] Adding tests for array iteration --- library/include/chplx/adapt_array.hpp | 2 +- library/include/chplx/array.hpp | 22 ++- library/include/chplx/coforall_loop.hpp | 4 +- library/include/chplx/for_loop.hpp | 8 + library/include/chplx/write.hpp | 6 + library/test/unit/CMakeLists.txt | 3 + library/test/unit/coforall_loop_array.cpp | 222 ++++++++++++++++++++++ library/test/unit/for_loop_array.cpp | 211 ++++++++++++++++++++ library/test/unit/forall_loop_array.cpp | 219 +++++++++++++++++++++ 9 files changed, 691 insertions(+), 6 deletions(-) create mode 100644 library/test/unit/coforall_loop_array.cpp create mode 100644 library/test/unit/for_loop_array.cpp create mode 100644 library/test/unit/forall_loop_array.cpp diff --git a/library/include/chplx/adapt_array.hpp b/library/include/chplx/adapt_array.hpp index 5ae4bb57..b666e626 100644 --- a/library/include/chplx/adapt_array.hpp +++ b/library/include/chplx/adapt_array.hpp @@ -20,7 +20,7 @@ namespace chplx { //----------------------------------------------------------------------------- // 1D iteration support template -hpx::generator iterate( +hpx::generator iterate( detail::IteratorGenerator> a) noexcept { auto size = a.size; diff --git a/library/include/chplx/array.hpp b/library/include/chplx/array.hpp index e61f6755..d9bc0cf1 100644 --- a/library/include/chplx/array.hpp +++ b/library/include/chplx/array.hpp @@ -28,15 +28,15 @@ template class Array { public: static constexpr int rank = Domain::rank(); static constexpr bool Stridable = Domain::stridable(); + using idxType = typename Domain::idxType; + using indexType = typename Domain::indexType; + using indicesType = typename Domain::indicesType; private: using arrayHandle = domains::BaseRectangularArray; - using indexType = typename Domain::indexType; - using indicesType = typename Domain::indicesType; - public: Array() = default; @@ -156,6 +156,22 @@ template class Array { return array->dsiGetBaseDomain()->dsiDim(i); } + // Returns an integer representing the zero-based ordinal value of ind within + // the domain's sequence of values if it is a member of the sequence. + // Otherwise, returns -1. The indexOrder procedure is the reverse of + // orderToIndex. + [[nodiscard]] constexpr std::int64_t + indexOrder(indexType idx) const noexcept { + return array->dsiGetBaseDomain()->dsiIndexOrder(idx); + } + + // Returns the zero-based ord-th element of this domain's represented + // sequence. The orderToIndex procedure is the reverse of indexOrder. + [[nodiscard]] constexpr indexType + orderToIndex(std::int64_t order) const noexcept { + return array->dsiGetBaseDomain()->dsiOrderToIndex(order); + } + // return the location of this array instance chplx::locale locale = chplx::here; diff --git a/library/include/chplx/coforall_loop.hpp b/library/include/chplx/coforall_loop.hpp index 6de2f83d..ec9f2df6 100644 --- a/library/include/chplx/coforall_loop.hpp +++ b/library/include/chplx/coforall_loop.hpp @@ -159,7 +159,7 @@ void coforall(detail::ZipRange const &zr, F &&f, Args &&...args) { } //----------------------------------------------------------------------------- -// forall loop for aray iteration +// forall loop for array iteration template void coforall(Array const &a, F &&f, Args &&...args) { @@ -170,7 +170,7 @@ void coforall(Array const &a, F &&f, Args &&...args) { hpx::wait_all(hpx::parallel::execution::bulk_async_execute( policy.executor(), [&](std::size_t idx, auto &&...fargs) { - return f(a.orderToIndex(idx), std::forward(fargs)...); + return f(a(idx), std::forward(fargs)...); }, a.size(), detail::task_intent>::call( diff --git a/library/include/chplx/for_loop.hpp b/library/include/chplx/for_loop.hpp index ab48b0e8..776b773d 100644 --- a/library/include/chplx/for_loop.hpp +++ b/library/include/chplx/for_loop.hpp @@ -104,4 +104,12 @@ void forLoop(Array const &a, F &&f) { } } +template +void forLoop(Array &a, F &&f) { + + for (auto &e : a.these()) { + f(e); + } +} + } // namespace chplx diff --git a/library/include/chplx/write.hpp b/library/include/chplx/write.hpp index 9c0186d6..57015681 100644 --- a/library/include/chplx/write.hpp +++ b/library/include/chplx/write.hpp @@ -11,6 +11,7 @@ namespace chplx { +//----------------------------------------------------------------------------- template void write_one(std::ostream &os, T &&t) { os << t; } template void write(std::ostream &os, Ts &&...ts) { @@ -22,6 +23,9 @@ template void writeln(std::ostream &os, Ts &&...ts) { os << "\n"; } +inline void writeln(std::ostream &os) { os << "\n"; } + +//----------------------------------------------------------------------------- template requires(!std::is_convertible_v &, std::ostream &>) void write(T &&t, Ts &&...ts) { @@ -34,4 +38,6 @@ void writeln(T &&t, Ts &&...ts) { writeln(std::cout, std::forward(t), std::forward(ts)...); } +inline void writeln() { writeln(std::cout); } + } // namespace chplx diff --git a/library/test/unit/CMakeLists.txt b/library/test/unit/CMakeLists.txt index 15486ab8..7bbf42d3 100644 --- a/library/test/unit/CMakeLists.txt +++ b/library/test/unit/CMakeLists.txt @@ -11,17 +11,20 @@ set(tests atomic begin cobegin + coforall_loop_array coforall_loop_assoc_domain coforall_loop_domain coforall_loop_range coforall_loop_tuple coforall_loop_zip domain + forall_loop_array forall_loop_assoc_domain forall_loop_domain forall_loop_range forall_loop_tuple forall_loop_zip + for_loop_array for_loop_assoc_domain for_loop_domain for_loop_range diff --git a/library/test/unit/coforall_loop_array.cpp b/library/test/unit/coforall_loop_array.cpp new file mode 100644 index 00000000..d069eb87 --- /dev/null +++ b/library/test/unit/coforall_loop_array.cpp @@ -0,0 +1,222 @@ +// Copyright (c) 2023 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +#include +#include +#include + +template +void testCoforallLoopArray(chplx::Array d) { + + std::set values; + hpx::mutex mtx; + + std::size_t count = 0; + + chplx::coforall( + d, + [&](auto &value, int fortytwo) { + HPX_TEST_EQ(fortytwo, 42); + std::lock_guard l(mtx); + ++count; + auto p = values.insert(value); + HPX_TEST(p.second); + }, + 42); + + HPX_TEST_EQ(count, static_cast(d.size())); + count = 0; + + for (auto val : d.these()) { + ++count; + HPX_TEST(values.contains(val)); + } + + HPX_TEST_EQ(count, values.size()); +} + +namespace detail { + +//----------------------------------------------------------------------------- +template auto initArray1D(R &&r) { + + auto array = chplx::Array(chplx::Domain(r), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testCoforallLoopArrays1D(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArray(initArray1D(std::get(r))), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray2D(R1 &&r1, R2 &&r2) { + + auto array = chplx::Array(chplx::Domain(r1, r2), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testCoforallLoopArrays2D(chplx::Tuple const &r, + std::index_sequence) { + + (testCoforallLoopArray(initArray2D(std::get(r), std::get(r))), ...); +} + +template +void testCoforallLoopArrays2D(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays2D(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray3D(R1 &&r1, R2 &&r2, R3 &&r3) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testCoforallLoopArrays3D_2(chplx::Tuple const &r, + std::index_sequence) { + + (testCoforallLoopArray( + initArray3D(std::get(r), std::get(r), std::get(r))), + ...); +} + +template +void testCoforallLoopArrays3D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays3D_2(r, s), ...); +} + +template +void testCoforallLoopArrays3D(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays3D_1(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray4D(R1 &&r1, R2 &&r2, R3 &&r3, R4 &&r4) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3, r4), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testCoforallLoopArrays4D_3(chplx::Tuple const &r, + std::index_sequence) { + + (testCoforallLoopArray(initArray4D(std::get(r), std::get(r), + std::get(r), std::get(r))), + ...); +} + +template +void testCoforallLoopArrays4D_2(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays4D_3(r, s), ...); +} + +template +void testCoforallLoopArrays4D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays4D_2(r, s), ...); +} + +template +void testCoforallLoopArrays4D(chplx::Tuple const &r, + std::index_sequence s) { + + (testCoforallLoopArrays4D_1(r, s), ...); +} + +} // namespace detail + +template +void testCoforallLoopArrays1D(chplx::Tuple r) { + + detail::testCoforallLoopArrays1D( + r, std::make_index_sequence()); +} + +template +void testCoforallLoopArrays2D(chplx::Tuple r) { + + detail::testCoforallLoopArrays2D( + r, std::make_index_sequence()); +} + +template +void testCoforallLoopArrays3D(chplx::Tuple r) { + + detail::testCoforallLoopArrays3D( + r, std::make_index_sequence()); +} + +template +void testCoforallLoopArrays4D(chplx::Tuple r) { + + detail::testCoforallLoopArrays4D( + r, std::make_index_sequence()); +} + +int main() { + + { + auto constexpr r1 = chplx::Range(0, 10); + auto constexpr r2 = chplx::BoundedRange(0, 10, -1); + auto constexpr r3 = chplx::BoundedRange(0, 10, 2); + auto constexpr r4 = chplx::BoundedRange(0, 10, -2); + + testCoforallLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + { + auto constexpr r1 = chplx::Range(1, 9); + auto constexpr r2 = chplx::BoundedRange(1, 9, -1); + auto constexpr r3 = chplx::BoundedRange(1, 9, 2); + auto constexpr r4 = chplx::BoundedRange(1, 9, -2); + + testCoforallLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testCoforallLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + return hpx::util::report_errors(); +} diff --git a/library/test/unit/for_loop_array.cpp b/library/test/unit/for_loop_array.cpp new file mode 100644 index 00000000..b4ed511d --- /dev/null +++ b/library/test/unit/for_loop_array.cpp @@ -0,0 +1,211 @@ +// Copyright (c) 2023 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include + +#include +#include + +template +void testForLoopArray(chplx::Array d) { + + std::set values; + + std::size_t count = 0; + + chplx::forLoop(d, [&](auto value) { + ++count; + auto p = values.insert(value); + HPX_TEST(p.second); + }); + + HPX_TEST_EQ(count, static_cast(d.size())); + + count = 0; + for (auto const &e : d.these()) { + + ++count; + HPX_TEST(values.contains(e)); + } + + HPX_TEST_EQ(count, values.size()); +} + +namespace detail { + +//----------------------------------------------------------------------------- +template auto initArray1D(R &&r) { + + auto array = chplx::Array(chplx::Domain(r), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForLoopArrays1D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArray(initArray1D(std::get(r))), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray2D(R1 &&r1, R2 &&r2) { + + auto array = chplx::Array(chplx::Domain(r1, r2), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForLoopArrays2D(chplx::Tuple const &r, + std::index_sequence) { + + (testForLoopArray(initArray2D(std::get(r), std::get(r))), ...); +} + +template +void testForLoopArrays2D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays2D(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray3D(R1 &&r1, R2 &&r2, R3 &&r3) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForLoopArrays3D_2(chplx::Tuple const &r, + std::index_sequence) { + + (testForLoopArray( + initArray3D(std::get(r), std::get(r), std::get(r))), + ...); +} + +template +void testForLoopArrays3D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays3D_2(r, s), ...); +} + +template +void testForLoopArrays3D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays3D_1(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray4D(R1 &&r1, R2 &&r2, R3 &&r3, R4 &&r4) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3, r4), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForLoopArrays4D_3(chplx::Tuple const &r, + std::index_sequence) { + + (testForLoopArray(initArray4D(std::get(r), std::get(r), + std::get(r), std::get(r))), + ...); +} + +template +void testForLoopArrays4D_2(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays4D_3(r, s), ...); +} + +template +void testForLoopArrays4D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays4D_2(r, s), ...); +} + +template +void testForLoopArrays4D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForLoopArrays4D_1(r, s), ...); +} + +} // namespace detail + +template +void testForLoopArrays1D(chplx::Tuple r) { + + detail::testForLoopArrays1D(r, std::make_index_sequence()); +} + +template +void testForLoopArrays2D(chplx::Tuple r) { + + detail::testForLoopArrays2D(r, std::make_index_sequence()); +} + +template +void testForLoopArrays3D(chplx::Tuple r) { + + detail::testForLoopArrays3D(r, std::make_index_sequence()); +} + +template +void testForLoopArrays4D(chplx::Tuple r) { + + detail::testForLoopArrays4D(r, std::make_index_sequence()); +} + +int main() { + + { + auto constexpr r1 = chplx::Range(0, 10); + auto constexpr r2 = chplx::BoundedRange(0, 10, -1); + auto constexpr r3 = chplx::BoundedRange(0, 10, 2); + auto constexpr r4 = chplx::BoundedRange(0, 10, -2); + + testForLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + { + auto constexpr r1 = chplx::Range(1, 9); + auto constexpr r2 = chplx::BoundedRange(1, 9, -1); + auto constexpr r3 = chplx::BoundedRange(1, 9, 2); + auto constexpr r4 = chplx::BoundedRange(1, 9, -2); + + testForLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testForLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + return hpx::util::report_errors(); +} diff --git a/library/test/unit/forall_loop_array.cpp b/library/test/unit/forall_loop_array.cpp new file mode 100644 index 00000000..b3f64aa3 --- /dev/null +++ b/library/test/unit/forall_loop_array.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2023 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +#include +#include +#include + +template +void testForallLoopArray(chplx::Array d) { + + std::set values; + hpx::mutex mtx; + + std::size_t count = 0; + + chplx::forall(d, [&](auto value) { + std::lock_guard l(mtx); + ++count; + auto p = values.insert(value); + HPX_TEST(p.second); + }); + + HPX_TEST_EQ(count, static_cast(d.size())); + count = 0; + + for (auto const &e : d.these()) { + + ++count; + HPX_TEST(values.contains(e)); + } + + HPX_TEST_EQ(count, values.size()); +} + +namespace detail { + +//----------------------------------------------------------------------------- +template auto initArray1D(R &&r) { + + auto array = chplx::Array(chplx::Domain(r), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForallLoopArrays1D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArray(initArray1D(std::get(r))), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray2D(R1 &&r1, R2 &&r2) { + + auto array = chplx::Array(chplx::Domain(r1, r2), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForallLoopArrays2D(chplx::Tuple const &r, + std::index_sequence) { + + (testForallLoopArray(initArray2D(std::get(r), std::get(r))), ...); +} + +template +void testForallLoopArrays2D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays2D(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray3D(R1 &&r1, R2 &&r2, R3 &&r3) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForallLoopArrays3D_2(chplx::Tuple const &r, + std::index_sequence) { + + (testForallLoopArray( + initArray3D(std::get(r), std::get(r), std::get(r))), + ...); +} + +template +void testForallLoopArrays3D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays3D_2(r, s), ...); +} + +template +void testForallLoopArrays3D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays3D_1(r, s), ...); +} + +//----------------------------------------------------------------------------- +template +auto initArray4D(R1 &&r1, R2 &&r2, R3 &&r3, R4 &&r4) { + + auto array = chplx::Array(chplx::Domain(r1, r2, r3, r4), T()); + T value = T(); + chplx::forLoop(array, [&](auto &v) { v = ++value; }); + return array; +} + +template +void testForallLoopArrays4D_3(chplx::Tuple const &r, + std::index_sequence) { + + (testForallLoopArray(initArray4D(std::get(r), std::get(r), + std::get(r), std::get(r))), + ...); +} + +template +void testForallLoopArrays4D_2(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays4D_3(r, s), ...); +} + +template +void testForallLoopArrays4D_1(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays4D_2(r, s), ...); +} + +template +void testForallLoopArrays4D(chplx::Tuple const &r, + std::index_sequence s) { + + (testForallLoopArrays4D_1(r, s), ...); +} + +} // namespace detail + +template +void testForallLoopArrays1D(chplx::Tuple r) { + + detail::testForallLoopArrays1D(r, + std::make_index_sequence()); +} + +template +void testForallLoopArrays2D(chplx::Tuple r) { + + detail::testForallLoopArrays2D(r, + std::make_index_sequence()); +} + +template +void testForallLoopArrays3D(chplx::Tuple r) { + + detail::testForallLoopArrays3D(r, + std::make_index_sequence()); +} + +template +void testForallLoopArrays4D(chplx::Tuple r) { + + detail::testForallLoopArrays4D(r, + std::make_index_sequence()); +} + +int main() { + + { + auto constexpr r1 = chplx::Range(0, 10); + auto constexpr r2 = chplx::BoundedRange(0, 10, -1); + auto constexpr r3 = chplx::BoundedRange(0, 10, 2); + auto constexpr r4 = chplx::BoundedRange(0, 10, -2); + + testForallLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + { + auto constexpr r1 = chplx::Range(1, 9); + auto constexpr r2 = chplx::BoundedRange(1, 9, -1); + auto constexpr r3 = chplx::BoundedRange(1, 9, 2); + auto constexpr r4 = chplx::BoundedRange(1, 9, -2); + + testForallLoopArrays1D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays2D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays3D(chplx::Tuple(r1, r2, r3, r4)); + testForallLoopArrays4D(chplx::Tuple(r1, r2, r3, r4)); + } + + return hpx::util::report_errors(); +}