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 all 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.
Jump to
Jump to file
Failed to load files.
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
316 changes: 316 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,316 @@
// Copyright (c) 2020-2022 STE||AR Group
//
// 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 <hpx/concepts/concepts.hpp>
#include <hpx/datastructures/optional.hpp>
#include <hpx/executors/execution_policy.hpp>
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
#include <hpx/parallel/algorithms/reduce.hpp>
#include <hpx/parallel/util/detail/sender_util.hpp>
#include <hpx/parallel/util/loop.hpp>
#include <hpx/parallel/util/result_types.hpp>

#include <cstddef>
#include <iterator>
#include <numeric>

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>
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::reduce(HPX_FORWARD(ExPolicy, policy), first, last, init,
HPX_FORWARD(F, f));
}

template <typename FwdIter, typename T, typename F>
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::reduce(
hpx::execution::seq, first, last, init, HPX_FORWARD(F, f));
}
} fold_left{};
} // namespace hpx

namespace hpx::parallel::detail {
template <typename ExPolicy, typename FwdIter, typename F>
auto fold_left_first_helper(
ExPolicy&& policy, FwdIter first, FwdIter 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++;

return hpx::optional<U>(hpx::fold_left(HPX_FORWARD(ExPolicy, policy),
first, last, HPX_MOVE(init), HPX_MOVE(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>
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.");

return ::hpx::parallel::detail::fold_left_first_helper(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(f));
}

template <typename FwdIter, typename F>
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.");

return ::hpx::parallel::detail::fold_left_first_helper(
hpx::execution::seq, first, last, HPX_MOVE(f));
}
} fold_left_first{};
} // namespace hpx

namespace hpx::parallel::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&& policy, FwdIter first, Sent last, T&& init, F&& f)
{
// last++ moves backward when its reverse iterator
return hpx::fold_left(HPX_FORWARD(ExPolicy, policy),
std::make_reverse_iterator(last),
std::make_reverse_iterator(first), HPX_FORWARD(T, init),
HPX_FORWARD(F, f));
}

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)
{
if (first == last)
{
return init;
}

auto ChunkReduce = [f = HPX_FORWARD(F, f),
policy = HPX_FORWARD(ExPolicy, policy)](
FwdIter it, std::size_t chunkSize) {
FwdIter endIter = it;
std::advance(endIter, --chunkSize);

T init = *endIter;

return sequential(policy, it, endIter, init, f);
};

auto RecursiveReduce = [f, policy, init](auto&& results) mutable {
auto begin = hpx::util::begin(results);
auto end = hpx::util::end(results);
return sequential(policy, begin, end, init, f);
};

return util::partitioner<ExPolicy, T>::call(
HPX_FORWARD(ExPolicy, policy), first,
std::distance(first, last), HPX_MOVE(ChunkReduce),
hpx::unwrapping(HPX_MOVE(RecursiveReduce)));
}
};
} // 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>
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_MOVE(init),
HPX_MOVE(f));
}

template <typename FwdIter, typename T, typename F>
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_MOVE(init),
HPX_MOVE(f));
}
} fold_right{};
} // namespace hpx

namespace hpx::parallel::detail {
template <typename ExPolicy, typename FwdIter, typename F>
auto fold_right_first_helper(
ExPolicy&& policy, FwdIter first, FwdIter last, F&& f)
{
using T = ::hpx::traits::iter_value_t<FwdIter>;
using U =
decltype(hpx::fold_right(HPX_MOVE(first), last, T(*first), f));

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

T init = *--last;

return hpx::optional<U>(hpx::fold_right(HPX_FORWARD(ExPolicy, policy),
first, last, HPX_MOVE(init), HPX_MOVE(f)));
}
} // namespace hpx::parallel::detail

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

return hpx::parallel::detail::fold_right_first_helper(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(f));
}

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

return hpx::parallel::detail::fold_right_first_helper(
hpx::execution::seq, first, last, HPX_MOVE(f));
}
} fold_right_first{};
} // namespace hpx

namespace hpx {
inline constexpr struct fold_left_with_iter_t final
: hpx::detail::tag_parallel_algorithm<fold_left_with_iter_t>
{
private:
template <typename Iter, typename T>
using fold_left_with_iter_ty = hpx::ranges::in_value_result<Iter, T>;

template <typename ExPolicy, typename FwdIter, typename T, typename F>
friend auto tag_fallback_invoke(fold_left_with_iter_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.");

T fold_left_value = hpx::fold_left(HPX_FORWARD(ExPolicy, policy),
first, last, init, HPX_FORWARD(F, f));

return fold_left_with_iter_ty<FwdIter, T>{
last, HPX_MOVE(fold_left_value)};
}

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

T fold_left_value = hpx::fold_left(
hpx::execution::seq, first, last, init, HPX_FORWARD(F, f));

return fold_left_with_iter_ty<FwdIter, T>{
last, HPX_MOVE(fold_left_value)};
}
} fold_left_with_iter{};
} // namespace hpx

namespace hpx::parallel::detail {

template <typename ExPolicy, typename FwdIter, typename Sent, typename F>
auto fold_left_first_with_iter_helper(
ExPolicy&& policy, FwdIter first, Sent last, F&& f)
{
using T = ::hpx::traits::iter_value_t<FwdIter>;
using fold_left_first_with_iter_ty =
hpx::ranges::in_value_result<FwdIter, hpx::optional<T>>;

return fold_left_first_with_iter_ty{last,
hpx::fold_left_first(
HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(f))};
}
} // namespace hpx::parallel::detail

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

return ::hpx::parallel::detail::fold_left_first_with_iter_helper(
HPX_FORWARD(ExPolicy, policy), first, last, f);
}

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

return ::hpx::parallel::detail::fold_left_first_with_iter_helper(
hpx::execution::seq, first, last, f);
}
} fold_left_first_with_iter{};
} // namespace hpx
20 changes: 20 additions & 0 deletions libs/core/algorithms/include/hpx/parallel/util/result_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,25 @@ namespace hpx::parallel::util {
}
};

template <typename Iter, typename T>
struct in_value_result
{
HPX_NO_UNIQUE_ADDRESS Iter in;
HPX_NO_UNIQUE_ADDRESS T value;

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

template <class I2, class T2>
constexpr operator in_value_result<I2, T2>() &&
{
return {HPX_MOVE(in), HPX_MOVE(value)};
}
};

///////////////////////////////////////////////////////////////////////
template <typename I, typename O>
std::pair<I, O> get_pair(util::in_out_result<I, O>&& p)
Expand Down Expand Up @@ -496,6 +515,7 @@ namespace hpx::ranges {
using hpx::parallel::util::in_in_result;
using hpx::parallel::util::in_out_out_result;
using hpx::parallel::util::in_out_result;
using hpx::parallel::util::in_value_result;
using hpx::parallel::util::min_max_result;
} // namespace hpx::ranges
// namespace hpx::ranges
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set(tests
findfirstof_binary
findif
findifnot
fold_
foreach
foreach_executors
foreach_prefetching
Expand Down