[parallel] Add projection support to hpx::is_sorted, hpx::is_sorted_until, and hpx::is_partitioned CPOs#7220
Conversation
|
Can one of the admins verify this patch? |
Up to standards ✅🟢 Issues
|
hkaiser
left a comment
There was a problem hiding this comment.
Thanks for your work on this.
We generally try to stay as close to the C++ Standard as possible. For this reason I don't think that we should go ahead with adding projections to the algorithms in namespace hpx.
Does this PR add anything in addition to the API extensions that would be worth keeping?
53efabd to
aab602f
Compare
…ntil, and hpx::is_partitioned CPOs The hpx:: (non-ranges) CPOs for is_sorted, is_sorted_until, and is_partitioned did not expose a Proj parameter in their tag_fallback_invoke overloads, despite the internal algorithm implementations (hpx::parallel::detail::is_sorted, is_sorted_until, is_partitioned) fully supporting projections via the Proj template parameter. This adds new tag_fallback_invoke overloads with Proj defaulting to hpx::identity alongside the existing overloads (which are unchanged for full backward compatibility). The constraint uses hpx::parallel::traits::is_projected_v<Proj, FwdIter> to maintain proper SFINAE behavior. Also adds hpx/algorithms/traits/projected.hpp include to both headers and a new regression test is_sorted_projection.cpp that exercises seq, par, and par(task) policies with all three algorithms. Closes: projection gap between hpx:: and hpx::ranges:: algorithm APIs
4ae69b8 to
aba2785
Compare
f25e11d to
4809671
Compare
| bool fst_bool = HPX_INVOKE(pred_projected, *part_begin); | ||
| if (part_count == 1) | ||
| return fst_bool; | ||
| return fst_bool ? 1 : 0; |
There was a problem hiding this comment.
Please use an enum class for this.
There was a problem hiding this comment.
Fixed. I've introduced enum class partition_status to handle the different partitioning states clearly.
| return hpx::parallel::detail::is_partitioned<FwdIter, FwdIter>() | ||
| .call(HPX_FORWARD(ExPolicy, policy), first, last, | ||
| HPX_MOVE(pred), HPX_MOVE(proj)); | ||
| } |
There was a problem hiding this comment.
Please revert the API changes.
| FwdIter>::type | ||
| is_sorted_until( | ||
| ExPolicy&& policy, FwdIter first, FwdIter last, Pred&& pred = Pred()); | ||
| } // namespace hpx |
There was a problem hiding this comment.
WHy have you removed the documentation?
| #include <hpx/modules/iterator_support.hpp> | ||
| #include <hpx/parallel/algorithms/detail/dispatch.hpp> | ||
|
|
||
| #include <hpx/algorithms/traits/projected.hpp> |
There was a problem hiding this comment.
Please always use the generated module headers to avoid problems with C++ modules.
| -> intermediate_result_t { | ||
| FwdIter_ trail = part_begin++; | ||
| util::loop_n<std::decay_t<ExPolicy>>(part_begin, | ||
| util::loop_n<hpx::execution::sequenced_policy>(part_begin, |
There was a problem hiding this comment.
This may lose context (such like vectorization, etc.)
| auto f2 = [](auto&& results) { | ||
| return std::all_of(hpx::util::begin(results), | ||
| hpx::util::end(results), hpx::functional::unwrap{}); | ||
| hpx::util::end(results), [](auto x) { return x; }); |
There was a problem hiding this comment.
What is the rationale of this change, please explain. Did some tests fail?
| using partitioner_type = | ||
| util::partitioner<policy_type, FwdIter_, void>; | ||
| return partitioner_type::call_with_index( | ||
| return util::partitioner<ExPolicy, FwdIter_>::call_with_index( |
There was a problem hiding this comment.
This will again lose context.
| return hpx::parallel::detail::is_sorted<FwdIter, FwdIter>().call( | ||
| HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(pred), | ||
| HPX_MOVE(proj)); | ||
| } |
There was a problem hiding this comment.
Please roll back all API changes.
| iterator_type>() | ||
| .call(hpx::execution::seq, std::begin(rng), std::end(rng), | ||
| HPX_MOVE(pred), HPX_MOVE(proj)); | ||
| .call(hpx::execution::seq, hpx::util::begin(rng), |
There was a problem hiding this comment.
What's the rationale of this change? I'd have expected to see changes the other way around (i.e., moving towards the standard, not away from it).
…or is_sorted and is_partitioned Standardized iterator and reference deduction using hpx::traits and corrected CRTP base class initialization to resolve dispatch errors in segmented contexts. Verified fixes with partitioned_vector test suite.
1. Reintroduced enum class for partition_status. 2. Restored module-style headers. 3. Reverted to std::begin/end for ranges. 4. Fixed execution context loss in local loops by using conditional unsequenced_policy. 5. Restored clear_container in results aggregation.
| namespace detail { | ||
| enum class partition_status : std::uint8_t | ||
| { | ||
| false_ = 0, |
There was a problem hiding this comment.
Could you come up with slightly more descriptive names, please? What is false_, what is true_? Does it refer to whether a given chunk is partitioned? Why not call it is_partitioned and is_not_partitioned in this case?
| hpx::is_unsequenced_execution_policy_v< | ||
| std::decay_t<ExPolicy>>, | ||
| hpx::execution::unsequenced_policy, | ||
| hpx::execution::sequenced_policy>; |
Summary
This PR enhances the
hpx::is_sorted,hpx::is_sorted_until, andhpx::is_partitionedalgorithms by exposing projection support at the CPO level. While the underlying parallel implementations already supported projections through theProjtemplate parameter, the user-facinghpx::namespace CPOs lacked the necessarytag_fallback_invokeoverloads to forward these arguments.Changes
Algorithm Headers
libs/core/algorithms/include/hpx/parallel/algorithms/is_sorted.hpphpx::is_sorted_tandhpx::is_sorted_until_tthat accept an optionalProjparameter.hpx::parallel::traits::is_projected_vandhpx::util::invoke_result_tfor robust type checking.#include <hpx/algorithms/traits/projected.hpp>for required traits.libs/core/algorithms/include/hpx/parallel/algorithms/is_partitioned.hpphpx::is_partitioned_tthat forward the projection to the internal implementation.Test Suite
libs/core/algorithms/tests/unit/algorithms/is_sorted_projection.cpp(new)std::pairand custom lambda projections.hpx::execution::seq,hpx::execution::par, andhpx::execution::par(task).libs/core/algorithms/tests/unit/algorithms/CMakeLists.txtTechnical Rationale
Previously, calling
hpx::is_sorted(first, last, comp, proj)would fail to compile because the CPO only recognized overloads with up to three arguments (iterators and predicate). Since HPX's internal parallel algorithms are already projection-aware (viainvoke_projected), this fix simply involves threading the projection argument from the user-facing CPO down to the algorithm dispatcher. This aligns thehpx::namespace API with thehpx::ranges::API, improving consistency for users who prefer iterator-based overloads.Testing
is_sorted_projectionpasses across all execution policies.is_sorted,is_sorted_until, andis_partitioned(without projections) continue to compile and run correctly, as the new overloads are purely additive and use default arguments for the projection.requiresclauses correctly handle invalid projections via SFINAE.