From beb604bcb34e40a7379ff9f7289e652c0fee0d99 Mon Sep 17 00:00:00 2001 From: srinivasyadav18 Date: Tue, 4 Oct 2022 15:50:22 -0500 Subject: [PATCH 1/3] Move replace impl to detail/replace.hpp --- libs/core/algorithms/CMakeLists.txt | 1 + .../parallel/algorithms/detail/replace.hpp | 265 ++++++++++++++++++ .../hpx/parallel/algorithms/replace.hpp | 193 +++---------- 3 files changed, 301 insertions(+), 158 deletions(-) create mode 100644 libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp diff --git a/libs/core/algorithms/CMakeLists.txt b/libs/core/algorithms/CMakeLists.txt index 573e3d74035f..8bc965fbfa94 100644 --- a/libs/core/algorithms/CMakeLists.txt +++ b/libs/core/algorithms/CMakeLists.txt @@ -35,6 +35,7 @@ set(algorithms_headers hpx/parallel/algorithms/detail/parallel_stable_sort.hpp hpx/parallel/algorithms/detail/pivot.hpp hpx/parallel/algorithms/detail/reduce.hpp + hpx/parallel/algorithms/detail/replace.hpp hpx/parallel/algorithms/detail/rotate.hpp hpx/parallel/algorithms/detail/sample_sort.hpp hpx/parallel/algorithms/detail/search.hpp diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp new file mode 100644 index 000000000000..246bbb72f426 --- /dev/null +++ b/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp @@ -0,0 +1,265 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace hpx { namespace parallel { inline namespace v1 { namespace detail { + + /////////////////////////////////////////////////////////////////////////// + template + struct sequential_replace_t final + : hpx::functional::detail::tag_fallback> + { + private: + template + friend inline constexpr auto tag_fallback_invoke(sequential_replace_t, + ExPolicy&& policy, InIter first, InIter last, T1 const& old_value, + T2 const& new_value, Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + return util::loop(HPX_FORWARD(ExPolicy, policy), first, last, + [old_value, new_value, &proj](auto& v) { + if (HPX_INVOKE(proj, *v) == old_value) + { + *v = new_value; + } + }); + } + else + { + typedef typename std::iterator_traits::value_type type; + + return for_each_n().call( + HPX_FORWARD(ExPolicy, policy), first, + std::distance(first, last), + [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( + type& t) -> void { + if (HPX_INVOKE(proj, t) == old_value) + { + t = new_value; + } + }, + util::projection_identity()); + } + } + }; + +#if !defined(HPX_COMPUTE_DEVICE_CODE) + template + inline constexpr sequential_replace_t sequential_replace = + sequential_replace_t{}; +#else + template + HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace(Args&&... args) + { + return sequential_replace_t{}(std::forward(args)...); + } +#endif + + /////////////////////////////////////////////////////////////////////////// + template + struct sequential_replace_if_t final + : hpx::functional::detail::tag_fallback> + { + private: + template + friend inline constexpr auto tag_fallback_invoke( + sequential_replace_if_t, ExPolicy&& policy, InIter first, Sent last, + F&& f, T const& new_value, Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + return util::loop(HPX_FORWARD(ExPolicy, policy), first, last, + [&f, new_value, &proj](auto& v) { + if (HPX_INVOKE(f, HPX_INVOKE(proj, *v))) + { + *v = new_value; + } + }); + } + else + { + typedef typename std::iterator_traits::value_type type; + + return for_each_n().call( + HPX_FORWARD(ExPolicy, policy), first, + detail::distance(first, last), + [new_value, f = HPX_FORWARD(F, f), + proj = HPX_FORWARD(Proj, proj)]( + type& t) mutable -> void { + if (HPX_INVOKE(f, HPX_INVOKE(proj, t))) + { + t = new_value; + } + }, + util::projection_identity()); + } + } + }; + +#if !defined(HPX_COMPUTE_DEVICE_CODE) + template + inline constexpr sequential_replace_if_t sequential_replace_if = + sequential_replace_if_t{}; +#else + template + HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_if(Args&&... args) + { + return sequential_replace_if_t{}(std::forward(args)...); + } +#endif + + /////////////////////////////////////////////////////////////////////////// + template + struct sequential_replace_copy_t final + : hpx::functional::detail::tag_fallback< + sequential_replace_copy_t> + { + private: + template + friend inline constexpr auto tag_fallback_invoke( + sequential_replace_copy_t, ExPolicy&& policy, InIter first, + Sent sent, OutIter dest, T const& old_value, T const& new_value, + Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + for (/* */; first != sent; ++first) + { + if (HPX_INVOKE(proj, *first) == old_value) + *dest++ = new_value; + else + *dest++ = *first; + } + return util::in_out_result(first, dest); + } + else + { + typedef hpx::util::zip_iterator zip_iterator; + typedef typename zip_iterator::reference reference; + + return util::detail::get_in_out_result( + for_each_n().call( + HPX_FORWARD(ExPolicy, policy), + hpx::util::make_zip_iterator(first, dest), + detail::distance(first, sent), + [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( + reference t) -> void { + using hpx::get; + if (HPX_INVOKE(proj, get<0>(t)) == old_value) + get<1>(t) = new_value; + else + get<1>(t) = get<0>(t); //-V573 + }, + util::projection_identity())); + } + } + }; + +#if !defined(HPX_COMPUTE_DEVICE_CODE) + template + inline constexpr sequential_replace_copy_t + sequential_replace_copy = sequential_replace_copy_t{}; +#else + template + HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_copy(Args&&... args) + { + return sequential_replace_copy_t{}( + std::forward(args)...); + } +#endif + + /////////////////////////////////////////////////////////////////////////// + template + struct sequential_replace_copy_if_t final + : hpx::functional::detail::tag_fallback< + sequential_replace_copy_if_t> + { + private: + template + friend inline constexpr auto tag_fallback_invoke( + sequential_replace_copy_if_t, ExPolicy&& policy, InIter first, + Sent sent, OutIter dest, F&& f, T const& new_value, Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + for (/* */; first != sent; ++first) + { + if (HPX_INVOKE(f, HPX_INVOKE(proj, *first))) + { + *dest++ = new_value; + } + else + { + *dest++ = *first; + } + } + return util::in_out_result{first, dest}; + } + else + { + typedef hpx::util::zip_iterator zip_iterator; + typedef typename zip_iterator::reference reference; + + return util::detail::get_in_out_result( + for_each_n().call( + HPX_FORWARD(ExPolicy, policy), + hpx::util::make_zip_iterator(first, dest), + detail::distance(first, sent), + [new_value, f = HPX_FORWARD(F, f), + proj = HPX_FORWARD(Proj, proj)]( + reference t) mutable -> void { + using hpx::get; + if (HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(t)))) + { + get<1>(t) = new_value; + } + else + { + get<1>(t) = get<0>(t); //-V573 + } + }, + util::projection_identity())); + } + } + }; + +#if !defined(HPX_COMPUTE_DEVICE_CODE) + template + inline constexpr sequential_replace_copy_if_t + sequential_replace_copy_if = sequential_replace_copy_if_t{}; +#else + template + HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_copy_if( + Args&&... args) + { + return sequential_replace_copy_if_t{}( + std::forward(args)...); + } +#endif + +}}}} // namespace hpx::parallel::v1::detail diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp index 47d78e8a8444..04197914a9f5 100644 --- a/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp +++ b/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp @@ -481,6 +481,7 @@ namespace hpx { #include #include #include +#include #include #include #include @@ -497,21 +498,6 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { /// \cond NOINTERNAL - // sequential replace - template - inline InIter sequential_replace(InIter first, InIter last, - T1 const& old_value, T2 const& new_value, Proj&& proj) - { - for (/* */; first != last; ++first) - { - if (HPX_INVOKE(proj, *first) == old_value) - { - *first = new_value; - } - } - return first; - } - template struct replace : public detail::algorithm, Iter> { @@ -522,11 +508,13 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static InIter sequential(ExPolicy, InIter first, InIter last, - T1 const& old_value, T2 const& new_value, Proj&& proj) + static InIter sequential(ExPolicy&& policy, InIter first, + InIter last, T1 const& old_value, T2 const& new_value, + Proj&& proj) { - return sequential_replace( - first, last, old_value, new_value, HPX_FORWARD(Proj, proj)); + return sequential_replace( + HPX_FORWARD(ExPolicy, policy), first, last, old_value, + new_value, HPX_FORWARD(Proj, proj)); } template ::value_type type; - - return for_each_n().call( - HPX_FORWARD(ExPolicy, policy), first, - std::distance(first, last), - [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( - type& t) -> void { - if (HPX_INVOKE(proj, t) == old_value) - { - t = new_value; - } - }, - util::projection_identity()); + return sequential_replace( + HPX_FORWARD(ExPolicy, policy), first, last, old_value, + new_value, HPX_FORWARD(Proj, proj)); } }; /// \endcond @@ -585,22 +563,6 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { /// \cond NOINTERNAL - // sequential replace_if - template - inline InIter sequential_replace_if( - InIter first, Sent sent, F&& f, T const& new_value, Proj&& proj) - { - for (/* */; first != sent; ++first) - { - if (HPX_INVOKE(f, HPX_INVOKE(proj, *first))) - { - *first = new_value; - } - } - return first; - } - template struct replace_if : public detail::algorithm, Iter> { @@ -611,11 +573,12 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static InIter sequential(ExPolicy, InIter first, Sent last, F&& f, - T const& new_value, Proj&& proj) + static InIter sequential(ExPolicy&& policy, InIter first, Sent last, + F&& f, T const& new_value, Proj&& proj) { - return sequential_replace_if(first, last, HPX_FORWARD(F, f), - new_value, HPX_FORWARD(Proj, proj)); + return sequential_replace_if( + HPX_FORWARD(ExPolicy, policy), first, last, + HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); } template ::value_type type; - - return for_each_n().call( - HPX_FORWARD(ExPolicy, policy), first, - detail::distance(first, last), - [new_value, f = HPX_FORWARD(F, f), - proj = HPX_FORWARD(Proj, proj)]( - type& t) mutable -> void { - if (HPX_INVOKE(f, HPX_INVOKE(proj, t))) - { - t = new_value; - } - }, - util::projection_identity()); + return sequential_replace_if( + HPX_FORWARD(ExPolicy, policy), first, last, + HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); } }; /// \endcond @@ -673,23 +625,6 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { /// \cond NOINTERNAL - // sequential replace_copy - template - inline util::in_out_result sequential_replace_copy( - InIter first, Sent sent, OutIter dest, T const& old_value, - T const& new_value, Proj&& proj) - { - for (/* */; first != sent; ++first) - { - if (HPX_INVOKE(proj, *first) == old_value) - *dest++ = new_value; - else - *dest++ = *first; - } - return util::in_out_result(first, dest); - } - template struct replace_copy : public detail::algorithm, IterPair> @@ -701,11 +636,12 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static util::in_out_result sequential(ExPolicy, - InIter first, Sent sent, OutIter dest, T const& old_value, - T const& new_value, Proj&& proj) + static util::in_out_result sequential( + ExPolicy&& policy, InIter first, Sent sent, OutIter dest, + T const& old_value, T const& new_value, Proj&& proj) { - return sequential_replace_copy(first, sent, dest, old_value, + return sequential_replace_copy( + HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value, new_value, HPX_FORWARD(Proj, proj)); } @@ -717,24 +653,9 @@ namespace hpx { namespace parallel { inline namespace v1 { FwdIter2 dest, T const& old_value, T const& new_value, Proj&& proj) { - typedef hpx::util::zip_iterator - zip_iterator; - typedef typename zip_iterator::reference reference; - - return util::detail::get_in_out_result( - for_each_n().call( - HPX_FORWARD(ExPolicy, policy), - hpx::util::make_zip_iterator(first, dest), - detail::distance(first, sent), - [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( - reference t) -> void { - using hpx::get; - if (HPX_INVOKE(proj, get<0>(t)) == old_value) - get<1>(t) = new_value; - else - get<1>(t) = get<0>(t); //-V573 - }, - util::projection_identity())); + return sequential_replace_copy( + HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value, + new_value, HPX_FORWARD(Proj, proj)); } }; /// \endcond @@ -777,27 +698,6 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { /// \cond NOINTERNAL - // sequential replace_copy_if - template - inline util::in_out_result sequential_replace_copy_if( - InIter first, Sent sent, OutIter dest, F&& f, T const& new_value, - Proj&& proj) - { - for (/* */; first != sent; ++first) - { - if (HPX_INVOKE(f, HPX_INVOKE(proj, *first))) - { - *dest++ = new_value; - } - else - { - *dest++ = *first; - } - } - return util::in_out_result{first, dest}; - } - template struct replace_copy_if : public detail::algorithm, IterPair> @@ -809,11 +709,12 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static util::in_out_result sequential(ExPolicy, - InIter first, Sent sent, OutIter dest, F&& f, + static util::in_out_result sequential( + ExPolicy&& policy, InIter first, Sent sent, OutIter dest, F&& f, T const& new_value, Proj&& proj) { - return sequential_replace_copy_if(first, sent, dest, + return sequential_replace_copy_if( + HPX_FORWARD(ExPolicy, policy), first, sent, dest, HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); } @@ -824,29 +725,9 @@ namespace hpx { namespace parallel { inline namespace v1 { parallel(ExPolicy&& policy, FwdIter1 first, Sent sent, FwdIter2 dest, F&& f, T const& new_value, Proj&& proj) { - typedef hpx::util::zip_iterator - zip_iterator; - typedef typename zip_iterator::reference reference; - - return util::detail::get_in_out_result( - for_each_n().call( - HPX_FORWARD(ExPolicy, policy), - hpx::util::make_zip_iterator(first, dest), - detail::distance(first, sent), - [new_value, f = HPX_FORWARD(F, f), - proj = HPX_FORWARD(Proj, proj)]( - reference t) mutable -> void { - using hpx::get; - if (HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(t)))) - { - get<1>(t) = new_value; - } - else - { - get<1>(t) = get<0>(t); //-V573 - } - }, - util::projection_identity())); + return sequential_replace_copy_if( + HPX_FORWARD(ExPolicy, policy), first, sent, dest, + HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); } }; /// \endcond @@ -984,11 +865,9 @@ namespace hpx { static_assert((hpx::traits::is_forward_iterator::value), "Required at least forward iterator."); - typedef typename std::iterator_traits::value_type Type; - return hpx::replace_if( HPX_FORWARD(ExPolicy, policy), first, last, - [old_value](Type const& a) -> bool { return old_value == a; }, + [old_value](auto const& a) { return old_value == a; }, new_value); } } replace{}; @@ -1114,11 +993,9 @@ namespace hpx { static_assert((hpx::traits::is_forward_iterator::value), "Required at least forward iterator."); - typedef typename std::iterator_traits::value_type Type; - return hpx::replace_copy_if( HPX_FORWARD(ExPolicy, policy), first, last, dest, - [old_value](Type const& a) -> bool { return old_value == a; }, + [old_value](auto const& a) { return old_value == a; }, new_value); } } replace_copy{}; From d78b1583685832f9d1ed3fdcdb5dbd89ff64071e Mon Sep 17 00:00:00 2001 From: srinivasyadav18 Date: Tue, 4 Oct 2022 15:51:15 -0500 Subject: [PATCH 2/3] Add datapar replace implementation --- libs/core/algorithms/CMakeLists.txt | 1 + .../include/hpx/parallel/datapar.hpp | 1 + .../include/hpx/parallel/datapar/replace.hpp | 306 ++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp diff --git a/libs/core/algorithms/CMakeLists.txt b/libs/core/algorithms/CMakeLists.txt index 8bc965fbfa94..260dbd7f5505 100644 --- a/libs/core/algorithms/CMakeLists.txt +++ b/libs/core/algorithms/CMakeLists.txt @@ -169,6 +169,7 @@ set(algorithms_headers hpx/parallel/datapar/loop.hpp hpx/parallel/datapar/mismatch.hpp hpx/parallel/datapar/reduce.hpp + hpx/parallel/datapar/replace.hpp hpx/parallel/datapar/transfer.hpp hpx/parallel/datapar/transform_loop.hpp hpx/parallel/datapar/zip_iterator.hpp diff --git a/libs/core/algorithms/include/hpx/parallel/datapar.hpp b/libs/core/algorithms/include/hpx/parallel/datapar.hpp index 1d2b67c916bd..f4973727628b 100644 --- a/libs/core/algorithms/include/hpx/parallel/datapar.hpp +++ b/libs/core/algorithms/include/hpx/parallel/datapar.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp b/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp new file mode 100644 index 000000000000..888fa1e5f4f3 --- /dev/null +++ b/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp @@ -0,0 +1,306 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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) + +#pragma once + +#include + +#if defined(HPX_HAVE_DATAPAR) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace hpx { namespace parallel { inline namespace v1 { namespace detail { + + /////////////////////////////////////////////////////////////////////////// + template + struct datapar_replace + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy, + InIter first, InIter last, T1 const& old_value, T2 const& new_value, + Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + return util::loop_ind(HPX_FORWARD(ExPolicy, policy), first, + last, [old_value, new_value, &proj](auto& v) { + using var_type = std::decay_t; + traits::mask_assign( + HPX_INVOKE(proj, v) == var_type(old_value), v, + var_type(new_value)); + }); + } + else + { + return for_each_n().call( + HPX_FORWARD(ExPolicy, policy), first, + std::distance(first, last), + [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( + auto& v) -> void { + traits::mask_assign( + HPX_INVOKE(proj, v) == var_type(old_value), v, + var_type(new_value)); + }, + util::projection_identity()); + } + } + }; + + template ::value)> + HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke( + sequential_replace_t, ExPolicy&& policy, InIter first, + InIter last, T1 const& old_value, T2 const& new_value, Proj&& proj) + { + if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible< + InIter>::value) + { + return datapar_replace::call( + HPX_FORWARD(ExPolicy, policy), first, last, old_value, + new_value, HPX_FORWARD(Proj, proj)); + } + else + { + using base_policy_type = + decltype((hpx::execution::experimental::to_non_simd( + std::declval()))); + return sequential_replace( + hpx::execution::experimental::to_non_simd(policy), first, last, + old_value, new_value, HPX_FORWARD(Proj, proj)); + } + } + + /////////////////////////////////////////////////////////////////////////// + template + struct datapar_replace_if + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy, + InIter first, Sent last, F&& f, T const& new_value, Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + return util::loop_ind(HPX_FORWARD(ExPolicy, policy), first, + last, [&f, new_value, &proj](auto& v) { + using var_type = std::decay_t; + traits::mask_assign(HPX_INVOKE(f, HPX_INVOKE(proj, v)), + v, var_type(new_value)); + }); + } + else + { + return for_each_n().call( + HPX_FORWARD(ExPolicy, policy), first, + detail::distance(first, last), + [new_value, f = HPX_FORWARD(F, f), + proj = HPX_FORWARD(Proj, proj)]( + auto& v) mutable -> void { + using var_type = std::decay_t; + traits::mask_assign( + HPX_INVOKE(f, (HPX_INVOKE(proj, v))), v, + var_type(new_value)); + }, + util::projection_identity()); + } + } + }; + + template ::value)> + HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke( + sequential_replace_if_t, ExPolicy&& policy, InIter first, + Sent last, F&& f, T const& new_value, Proj&& proj) + { + if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible< + InIter>::value) + { + return datapar_replace_if::call( + HPX_FORWARD(ExPolicy, policy), first, last, HPX_FORWARD(F, f), + new_value, HPX_FORWARD(Proj, proj)); + } + else + { + using base_policy_type = + decltype((hpx::execution::experimental::to_non_simd( + std::declval()))); + return sequential_replace_if( + hpx::execution::experimental::to_non_simd(policy), first, last, + HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); + } + } + + /////////////////////////////////////////////////////////////////////////// + template + struct datapar_replace_copy + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy, + InIter first, Sent sent, OutIter dest, T const& old_value, + T const& new_value, Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + std::size_t n = detail::distance(first, sent); + + util::loop_n_ind( + hpx::util::make_zip_iterator(first, dest), sent, + [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( + auto& v) { + using var_type = std::decay_t(v))>; + get<1>(v) = traits::choose( + HPX_INVOKE(proj, get<0>(v)) == var_type(old_value), + var_type(new_value), get<0>(v)); + }); + + return util::in_out_result( + first + n, dest + n); + } + else + { + typedef hpx::util::zip_iterator zip_iterator; + + return util::detail::get_in_out_result( + for_each_n().call( + HPX_FORWARD(ExPolicy, policy), + hpx::util::make_zip_iterator(first, dest), + detail::distance(first, sent), + [old_value, new_value, proj = HPX_FORWARD(Proj, proj)]( + auto& v) -> void { + using hpx::get; + using var_type = std::decay_t(v))>; + get<1>(v) = + traits::choose(HPX_INVOKE(proj, get<0>(v)) == + var_type(old_value), + var_type(new_value), get<0>(v)); + }, + util::projection_identity())); + } + } + }; + + template ::value)> + HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke( + sequential_replace_copy_t, ExPolicy&& policy, InIter first, + Sent sent, OutIter dest, T const& old_value, T const& new_value, + Proj&& proj) + { + if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible< + InIter>::value) + { + return datapar_replace_copy::call( + (HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value, + new_value, HPX_FORWARD(Proj, proj))); + } + else + { + using base_policy_type = + decltype((hpx::execution::experimental::to_non_simd( + std::declval()))); + return sequential_replace_copy( + hpx::execution::experimental::to_non_simd(policy), first, sent, + dest, old_value, new_value, HPX_FORWARD(Proj, proj)); + } + } + + /////////////////////////////////////////////////////////////////////////// + template + struct datapar_replace_copy_if + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy, + InIter first, Sent last, OutIter dest, F&& f, T const& new_value, + Proj&& proj) + { + if constexpr (hpx::is_sequenced_execution_policy_v) + { + std::size_t n = detail::distance(first, last); + + util::loop_n_ind( + hpx::util::make_zip_iterator(first, dest), n, + [new_value, f = HPX_FORWARD(F, f), + proj = HPX_FORWARD(Proj, proj)]( + auto& v) mutable -> void { + using hpx::get; + using var_type = std::decay_t(v))>; + get<1>(v) = traits::choose( + HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(v))), + var_type(new_value), get<0>(v)); + }); + return util::in_out_result( + first + n, dest + n); + } + else + { + typedef hpx::util::zip_iterator zip_iterator; + + return util::detail::get_in_out_result( + for_each_n().call( + HPX_FORWARD(ExPolicy, policy), + hpx::util::make_zip_iterator(first, dest), + detail::distance(first, last), + [new_value, f = HPX_FORWARD(F, f), + proj = HPX_FORWARD(Proj, proj)]( + auto& v) mutable -> void { + using hpx::get; + using var_type = std::decay_t(v))>; + get<1>(v) = traits::choose( + HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(v))), + var_type(new_value), get<0>(v)); + }, + util::projection_identity())); + } + } + }; + + template ::value)> + HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke( + sequential_replace_copy_if_t, ExPolicy&& policy, InIter first, + Sent last, OutIter dest, F&& f, T const& new_value, Proj&& proj) + { + if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible< + InIter>::value) + { + return datapar_replace_copy_if::call( + HPX_FORWARD(ExPolicy, policy), first, last, dest, + HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); + } + else + { + using base_policy_type = + decltype((hpx::execution::experimental::to_non_simd( + std::declval()))); + return sequential_replace_copy_if( + hpx::execution::experimental::to_non_simd(policy), first, last, + dest, HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj)); + } + } +}}}} // namespace hpx::parallel::v1::detail +#endif From 16c46ba1fd8605429a8ab9933348403e9bfad1e0 Mon Sep 17 00:00:00 2001 From: srinivasyadav18 Date: Tue, 4 Oct 2022 16:33:43 -0500 Subject: [PATCH 3/3] Add datapar replace unit tests --- .../unit/datapar_algorithms/CMakeLists.txt | 4 + .../replace_copy_datapar.cpp | 138 ++++++++++++++++ .../replace_copy_if_datapar.cpp | 153 ++++++++++++++++++ .../datapar_algorithms/replace_datapar.cpp | 134 +++++++++++++++ .../datapar_algorithms/replace_if_datapar.cpp | 150 +++++++++++++++++ 5 files changed, 579 insertions(+) create mode 100644 libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp create mode 100644 libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp create mode 100644 libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp create mode 100644 libs/core/algorithms/tests/unit/datapar_algorithms/replace_if_datapar.cpp diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt b/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt index 9cc59a8fa4bb..cd15949a449c 100644 --- a/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt +++ b/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt @@ -35,6 +35,10 @@ if(HPX_WITH_DATAPAR) mismatch_datapar none_of_datapar reduce_datapar + replace_copy_if_datapar + replace_copy_datapar + replace_datapar + replace_if_datapar transform_binary_datapar transform_binary2_datapar transform_datapar diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp new file mode 100644 index 000000000000..03fdd259cc6f --- /dev/null +++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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 +#include +#include +#include + +#include "../algorithms/test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy(ExPolicy policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(std::begin(c), std::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::replace_copy(policy, iterator(std::begin(c)), iterator(std::end(c)), + std::begin(d1), c[idx], c[idx] + 1); + + std::replace_copy( + std::begin(c), std::end(c), std::begin(d2), c[idx], c[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(std::begin(c), std::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = hpx::replace_copy(p, iterator(std::begin(c)), + iterator(std::end(c)), std::begin(d1), c[idx], c[idx] + 1); + f.wait(); + + std::replace_copy( + std::begin(c), std::end(c), std::begin(d2), c[idx], c[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy() +{ + using namespace hpx::execution; + test_replace_copy(simd, IteratorTag()); + test_replace_copy(par_simd, IteratorTag()); + + test_replace_copy_async(simd(task), IteratorTag()); + test_replace_copy_async(par_simd(task), IteratorTag()); +} + +void replace_copy_test() +{ + test_replace_copy(); + test_replace_copy(); +} + +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_copy_test(); + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + hpx::local::init_params init_args; + init_args.desc_cmdline = desc_commandline; + init_args.cfg = cfg; + + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp new file mode 100644 index 000000000000..5410e0c8b011 --- /dev/null +++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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 +#include +#include +#include + +#include "../algorithms/test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct equal_f +{ + equal_f(int val) + : val_(val) + { + } + + template + auto operator()(T lhs) const + { + return lhs == val_; + } + + int val_; +}; + +template +void test_replace_copy_if(ExPolicy policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(std::begin(c), std::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::replace_copy_if(policy, iterator(std::begin(c)), iterator(std::end(c)), + std::begin(d1), equal_f(c[idx]), c[idx] + 1); + + std::replace_copy_if(std::begin(c), std::end(c), std::begin(d2), + equal_f(c[idx]), c[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_if_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(std::begin(c), std::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = hpx::replace_copy_if(p, iterator(std::begin(c)), + iterator(std::end(c)), std::begin(d1), equal_f(c[idx]), c[idx] + 1); + f.wait(); + + std::replace_copy_if(std::begin(c), std::end(c), std::begin(d2), + equal_f(c[idx]), c[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_if() +{ + using namespace hpx::execution; + test_replace_copy_if(simd, IteratorTag()); + test_replace_copy_if(par_simd, IteratorTag()); + + test_replace_copy_if_async(simd(task), IteratorTag()); + test_replace_copy_if_async(par_simd(task), IteratorTag()); +} + +void replace_copy_if_test() +{ + test_replace_copy_if(); + test_replace_copy_if(); +} + +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_copy_if_test(); + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + hpx::local::init_params init_args; + init_args.desc_cmdline = desc_commandline; + init_args.cfg = cfg; + + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp new file mode 100644 index 000000000000..4c462be731d2 --- /dev/null +++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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 +#include +#include +#include + +#include "../algorithms/test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace(ExPolicy policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(std::begin(c), std::end(c), std::rand()); + std::copy(std::begin(c), std::end(c), std::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::replace(policy, iterator(std::begin(c)), iterator(std::end(c)), c[idx], + c[idx] + 1); + + std::replace(std::begin(d), std::end(d), d[idx], d[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d), + [&count](auto v1, auto v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(std::begin(c), std::end(c), std::rand()); + std::copy(std::begin(c), std::end(c), std::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::future f = hpx::replace( + p, iterator(std::begin(c)), iterator(std::end(c)), c[idx], c[idx] + 1); + f.wait(); + + std::replace(std::begin(d), std::end(d), d[idx], d[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d), + [&count](auto v1, auto v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace() +{ + using namespace hpx::execution; + test_replace(simd, IteratorTag()); + test_replace(par_simd, IteratorTag()); + + test_replace_async(simd(task), IteratorTag()); + test_replace_async(par_simd(task), IteratorTag()); +} + +void replace_test() +{ + test_replace(); + test_replace(); +} + +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_test(); + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + hpx::local::init_params init_args; + init_args.desc_cmdline = desc_commandline; + init_args.cfg = cfg; + + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_if_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_if_datapar.cpp new file mode 100644 index 000000000000..d93e57178a0f --- /dev/null +++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_if_datapar.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2022 Srinivas Yadav +// +// 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 +#include +#include +#include + +#include "../algorithms/test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct equal_f +{ + equal_f(int val) + : val_(val) + { + } + + template + auto operator()(T lhs) const + { + return lhs == T(val_); + } + + int val_; +}; + +template +void test_replace_if(ExPolicy policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(std::begin(c), std::end(c), std::rand()); + std::copy(std::begin(c), std::end(c), std::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::replace_if(policy, iterator(std::begin(c)), iterator(std::end(c)), + equal_f(c[idx]), c[idx] + 1); + + std::replace_if(std::begin(d), std::end(d), equal_f(d[idx]), d[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_if_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(std::begin(c), std::end(c), std::rand()); + std::copy(std::begin(c), std::end(c), std::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::future f = hpx::replace_if(p, iterator(std::begin(c)), + iterator(std::end(c)), equal_f(c[idx]), c[idx] + 1); + f.wait(); + + std::replace_if(std::begin(d), std::end(d), equal_f(d[idx]), d[idx] + 1); + + std::size_t count = 0; + HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_if() +{ + using namespace hpx::execution; + test_replace_if(simd, IteratorTag()); + test_replace_if(par_simd, IteratorTag()); + + test_replace_if_async(simd(task), IteratorTag()); + test_replace_if_async(par_simd(task), IteratorTag()); +} + +void replace_if_test() +{ + test_replace_if(); + test_replace_if(); +} + +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_if_test(); + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + hpx::local::init_params init_args; + init_args.desc_cmdline = desc_commandline; + init_args.cfg = cfg; + + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +}