Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#6224, fold algorithms #6255

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e9d0be6
fold_left, need to add concepts
May 23, 2023
6bcc03f
added fold_left
May 23, 2023
7bbd465
fixed unused error, added parallel overload
May 23, 2023
0011e7c
fixed var names
May 23, 2023
68ddc70
forgot template name
May 23, 2023
eb4cd7e
changed var name to adhere to convention, clang-format
May 24, 2023
6ec4f4c
fold_leftfirst added
May 24, 2023
f0ebc37
fold_left_first implemented
May 26, 2023
5d289f4
fold_right seq implemented, par remaining
May 27, 2023
9a93cd1
changed std::move to hpHPX_MOVE
May 27, 2023
2f9efe8
clang-format
May 27, 2023
f08d599
fixed unused errors
May 28, 2023
3928743
fixed few inspect errors
May 31, 2023
f2a7f4a
fixed licenses, clang-format
Jun 5, 2023
e3a89ca
moved in_value_result to parallel/algorithms/util
Jun 6, 2023
c6a229d
using util loo instead of std::reduce
Jun 10, 2023
f6e22c7
fixed unused error
Jun 10, 2023
9b0c65a
fixed clang-format buug, avoid namespace foo { namespace bar
Jun 10, 2023
c7b7fa2
adding headers
Jun 11, 2023
d833bff
inncluded dispatch_header
Jun 14, 2023
9b2ba13
added return
Jun 15, 2023
3a7ef64
tests +parallel policy
Jun 17, 2023
29304b6
fold tests
Jun 17, 2023
22e045f
fold tests
Jun 17, 2023
b257f40
fold_right_first
Jun 18, 2023
177ec74
fixed forwarding error, added header, cf
Jun 18, 2023
80ce830
fixed forwarding error
Jun 18, 2023
cd8bfa4
fold with iter implemented
Jun 18, 2023
301630c
removed unnecessery semi colon
Jun 18, 2023
dbde51b
fold first tests
Jul 16, 2023
8820151
all tests implemented
Johan511 Jul 17, 2023
be6f45a
cf
Johan511 Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/core/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set(algorithms_headers
hpx/parallel/algorithms/exclusive_scan.hpp
hpx/parallel/algorithms/fill.hpp
hpx/parallel/algorithms/find.hpp
hpx/parallel/algorithms/fold.hpp
hpx/parallel/algorithms/for_each.hpp
hpx/parallel/algorithms/for_loop.hpp
hpx/parallel/algorithms/for_loop_induction.hpp
Expand Down
1 change: 1 addition & 0 deletions libs/core/algorithms/include/hpx/parallel/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <hpx/parallel/algorithms/equal.hpp>
#include <hpx/parallel/algorithms/fill.hpp>
#include <hpx/parallel/algorithms/find.hpp>
#include <hpx/parallel/algorithms/fold.hpp>
#include <hpx/parallel/algorithms/for_each.hpp>
#include <hpx/parallel/algorithms/generate.hpp>
#include <hpx/parallel/algorithms/includes.hpp>
Expand Down
253 changes: 253 additions & 0 deletions libs/core/algorithms/include/hpx/parallel/algorithms/fold.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
#pragma once

#include <hpx/concepts/concepts.hpp>
#include <hpx/datastructures/optional.hpp>
#include <hpx/parallel/algorithms/reduce.hpp>

#include <iterator>
#include <numeric>

namespace hpx::parallel { namespace detail {

template <typename T_>
struct fold_left : public algorithm<fold_left<T_>, T_>
{
constexpr fold_left() noexcept
: algorithm<fold_left, T_>("fold_left")
{
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename T, typename F>
HPX_HOST_DEVICE static constexpr T sequential(
ExPolicy&&, FwdIter first, Sent last, T&& init, F&& f)
{
if (first == last)
return HPX_MOVE(init);
T acc = HPX_MOVE(init);
Johan511 marked this conversation as resolved.
Show resolved Hide resolved
while (first != last)
acc = HPX_MOVE(f(HPX_MOVE(acc), *first++));
return HPX_MOVE(acc);
Johan511 marked this conversation as resolved.
Show resolved Hide resolved
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename T, typename F>
static constexpr auto parallel(
ExPolicy&& policy, FwdIter first, Sent last, T&& init, F&& f)
{
#ifdef HPX_WITH_CXX17_STD_EXECUTION_POLICES
return std::reduce(HPX_FORWARD(ExPolicy, policy), first, last,
HPX_FORWARD(T, init), HPX_FORWARD(F, f));
#else
HPX_UNUSED(policy); // TODO : par support
return std::reduce(
first, last, HPX_FORWARD(T, init), HPX_FORWARD(F, f));
#endif
}
};

}} // namespace hpx::parallel::detail

namespace hpx {
inline constexpr struct fold_left_t final
: hpx::detail::tag_parallel_algorithm<fold_left_t>
{
private:
template <typename ExPolicy, typename FwdIter, typename T,
typename F> // TODO : add concept
friend T tag_fallback_invoke(fold_left_t, ExPolicy&& policy, FwdIter first,
FwdIter last, T init, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

return hpx::parallel::detail::fold_left<T>().call(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_FORWARD(T, init),
HPX_FORWARD(F, f));
}

template <typename FwdIter, typename T,
typename F> // TODO : add concept
friend T tag_fallback_invoke(
fold_left_t, FwdIter first, FwdIter last, T init, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

return hpx::parallel::detail::fold_left<T>().call(hpx::execution::seq,
first, last, HPX_FORWARD(T, init), HPX_FORWARD(F, f));
}
} fold_left{};
} // namespace hpx

namespace hpx::parallel { namespace detail {

template <typename T_>
struct fold_left_first : public algorithm<fold_left_first<T_>, T_>
{
constexpr fold_left_first() noexcept
: algorithm<fold_left_first, T_>("fold_left_first")
{
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename F>
HPX_HOST_DEVICE static constexpr auto sequential(
ExPolicy&&, FwdIter first, Sent last, F&& f)
{
using T = ::hpx::traits::iter_value_t<FwdIter>;
using U =
decltype(hpx::fold_left(HPX_MOVE(first), last, T(*first), f));

if (first == last)
return hpx::optional<U>();

T init = *first;

std::advance(first, 1);

return hpx::optional<U>(
hpx::parallel::detail::fold_left<T>().call(hpx::execution::seq,
first, last, HPX_FORWARD(T, init), HPX_FORWARD(F, f)));
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename F>
static constexpr auto parallel(
ExPolicy&& policy, FwdIter first, Sent last, F&& f)
{
using T = ::hpx::traits::iter_value_t<FwdIter>;
using U =
decltype(hpx::fold_left(HPX_MOVE(first), last, T(*first), f));

if (first == last)
return hpx::optional<U>();

T init = *first;

std::advance(first, 1);

return hpx::optional<U>(hpx::parallel::detail::fold_left<T>().call(
HPX_FORWARD(ExPolicy, policy), first, last,
HPX_FORWARD(T, init), HPX_FORWARD(F, f)));
}
};

}} // namespace hpx::parallel::detail

namespace hpx {
inline constexpr struct fold_left_first_t final
: hpx::detail::tag_parallel_algorithm<fold_left_first_t>
{
private:
template <typename ExPolicy, typename FwdIter,
typename F> // TODO : add concept
friend auto tag_fallback_invoke(
fold_left_first_t, ExPolicy&& policy, FwdIter first, FwdIter last, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

using result_type =
typename hpx::parallel::util::detail::algorithm_result<
ExPolicy>::type;

using U = decltype(hpx::fold_left(HPX_MOVE(first), last,
::hpx::traits::iter_value_t<FwdIter>(*first), f));

return hpx::parallel::detail::fold_left_first<hpx::optional<U>>().call(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_FORWARD(F, f));
}

template <typename FwdIter, typename F> // TODO : add concept
friend auto tag_fallback_invoke(
fold_left_first_t, FwdIter first, FwdIter last, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

using U = decltype(hpx::fold_left(HPX_MOVE(first), last,
::hpx::traits::iter_value_t<FwdIter>(*first), f));

return hpx::parallel::detail::fold_left_first<hpx::optional<U>>().call(
hpx::execution::seq, first, last, HPX_FORWARD(F, f));
}
} fold_left_first{};
} // namespace hpx

namespace hpx::parallel { namespace detail {

template <typename T_>
struct fold_right : public algorithm<fold_right<T_>, T_>
{
constexpr fold_right() noexcept
: algorithm<fold_right, T_>("fold_right")
{
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename T, typename F>
HPX_HOST_DEVICE static constexpr auto sequential(
ExPolicy&&, FwdIter first, Sent last, T&& init, F&& f)
{
using U = std::decay_t<std::invoke_result_t<F&,
hpx::traits::iter_reference_t<FwdIter>, T>>;
if (first == last)
return U(HPX_MOVE(init));

U accum = f(*--last, HPX_MOVE(init));
while (first != last)
accum = f(*--last, HPX_MOVE(accum));
return accum;
}

template <typename ExPolicy, typename FwdIter, typename Sent,
typename T, typename F>
static constexpr auto parallel(
ExPolicy&& policy, FwdIter first, Sent last, T&& init, F&& f)
{
HPX_UNUSED(policy);
HPX_UNUSED(first);
HPX_UNUSED(last);
HPX_UNUSED(init);
HPX_UNUSED(f);

exit(
1); // parallel version of fold_right has not been implemented
return f(first, init);
}
};

}} // namespace hpx::parallel::detail

namespace hpx {
inline constexpr struct fold_right_t final
: hpx::detail::tag_parallel_algorithm<fold_right_t>
{
private:
template <typename ExPolicy, typename FwdIter, typename T,
typename F> // TODO : add concept
friend T tag_fallback_invoke(fold_right_t, ExPolicy&& policy, FwdIter first,
FwdIter last, T init, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

return hpx::parallel::detail::fold_right<T>().call(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_FORWARD(T, init),
HPX_FORWARD(F, f));
}

template <typename FwdIter, typename T,
typename F> // TODO : add concept
friend T tag_fallback_invoke(
fold_right_t, FwdIter first, FwdIter last, T init, F f)
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");

return hpx::parallel::detail::fold_right<T>().call(hpx::execution::seq,
first, last, HPX_FORWARD(T, init), HPX_FORWARD(F, f));
}
} fold_right{};
} // namespace hpx
1 change: 1 addition & 0 deletions libs/core/datastructures/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(datastructures_headers
hpx/datastructures/member_pack.hpp
hpx/datastructures/optional.hpp
hpx/datastructures/tuple.hpp
hpx/datastructures/in_value_result.hpp
hpx/datastructures/traits/supports_streaming_with_any.hpp
hpx/datastructures/traits/is_tuple_like.hpp
hpx/datastructures/variant.hpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

namespace hpx::experimental { namespace ranges {
template <typename Iter, typename T>
struct in_value_result
{
[[no_unique_address]] Iter in;
[[no_unique_address]] T value;

template <class I2, class T2>
// hpx::convertible?
constexpr operator in_value_result<I2, T2>() const&
{
return {in, value};
}

template <class I2, class T2>
// hpx::convertible?
constexpr operator in_value_result<I2, T2>() &&
{
return {std::move(in), std::move(value)};
}
};
}} // namespace hpx::experimental::ranges
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@Johan511 Johan511 Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://en.cppreference.com/w/cpp/algorithm/ranges/fold_left_with_iter

The examples here seem to suggest that the member variables are to be named as in and value

https://en.cppreference.com/w/cpp/algorithm/ranges/return_types/in_value_result#Notes
also mentions that

Unlike std::pair and std::tuple, this class template has data members of meaningful names.