Skip to content

[parallel] Add projection support to hpx::is_sorted, hpx::is_sorted_until, and hpx::is_partitioned CPOs#7220

Open
aneek22112007-tech wants to merge 12 commits intoTheHPXProject:masterfrom
aneek22112007-tech:fix/is-sorted-is-partitioned-projection
Open

[parallel] Add projection support to hpx::is_sorted, hpx::is_sorted_until, and hpx::is_partitioned CPOs#7220
aneek22112007-tech wants to merge 12 commits intoTheHPXProject:masterfrom
aneek22112007-tech:fix/is-sorted-is-partitioned-projection

Conversation

@aneek22112007-tech
Copy link
Copy Markdown
Contributor

Summary

This PR enhances the hpx::is_sorted, hpx::is_sorted_until, and hpx::is_partitioned algorithms by exposing projection support at the CPO level. While the underlying parallel implementations already supported projections through the Proj template parameter, the user-facing hpx:: namespace CPOs lacked the necessary tag_fallback_invoke overloads to forward these arguments.

Changes

  • Algorithm Headers

    • libs/core/algorithms/include/hpx/parallel/algorithms/is_sorted.hpp
      • Added new overloads for hpx::is_sorted_t and hpx::is_sorted_until_t that accept an optional Proj parameter.
      • Updated SFINAE constraints to use hpx::parallel::traits::is_projected_v and hpx::util::invoke_result_t for robust type checking.
      • Added #include <hpx/algorithms/traits/projected.hpp> for required traits.
    • libs/core/algorithms/include/hpx/parallel/algorithms/is_partitioned.hpp
      • Added overloads for hpx::is_partitioned_t that forward the projection to the internal implementation.
      • Standardized the CPO dispatch to match current HPX patterns for projection-aware algorithms.
  • Test Suite

    • libs/core/algorithms/tests/unit/algorithms/is_sorted_projection.cpp (new)
      • Implemented a comprehensive test suite using std::pair and custom lambda projections.
      • Validates sequential dispatch, hpx::execution::seq, hpx::execution::par, and hpx::execution::par(task).
      • Covers edge cases including empty ranges and single-element ranges to ensure no regression in algorithm logic.
    • libs/core/algorithms/tests/unit/algorithms/CMakeLists.txt
      • Registered the new unit test target.

Technical 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 (via invoke_projected), this fix simply involves threading the projection argument from the user-facing CPO down to the algorithm dispatcher. This aligns the hpx:: namespace API with the hpx::ranges:: API, improving consistency for users who prefer iterator-based overloads.

Testing

  • New Regression Test: is_sorted_projection passes across all execution policies.
  • Backward Compatibility: Verified that existing calls to is_sorted, is_sorted_until, and is_partitioned (without projections) continue to compile and run correctly, as the new overloads are purely additive and use default arguments for the projection.
  • Trait Validation: Confirmed that the requires clauses correctly handle invalid projections via SFINAE.

@StellarBot
Copy link
Copy Markdown
Collaborator

Can one of the admins verify this patch?

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 22, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copy link
Copy Markdown
Contributor

@hkaiser hkaiser left a comment

Choose a reason for hiding this comment

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

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?

@aneek22112007-tech aneek22112007-tech force-pushed the fix/is-sorted-is-partitioned-projection branch from 53efabd to aab602f Compare April 22, 2026 22:33
…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
@aneek22112007-tech aneek22112007-tech force-pushed the fix/is-sorted-is-partitioned-projection branch from 4ae69b8 to aba2785 Compare April 23, 2026 17:41
@aneek22112007-tech aneek22112007-tech force-pushed the fix/is-sorted-is-partitioned-projection branch from f25e11d to 4809671 Compare April 23, 2026 18:26
bool fst_bool = HPX_INVOKE(pred_projected, *part_begin);
if (part_count == 1)
return fst_bool;
return fst_bool ? 1 : 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please use an enum class for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please revert the API changes.

FwdIter>::type
is_sorted_until(
ExPolicy&& policy, FwdIter first, FwdIter last, Pred&& pred = Pred());
} // namespace hpx
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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; });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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).

dasaneek007-cpu and others added 3 commits April 24, 2026 15:50
…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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants