Implement minmax_element to use less comparisons#7363
Conversation
|
Can one of the admins verify this patch? |
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe sequential ChangesPairwise minmax_element refactor
Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Up to standards ✅🟢 Issues
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@libs/core/algorithms/include/hpx/parallel/algorithms/minmax.hpp`:
- Around line 1237-1300: The `detail::minmax_element::sequential` identity
overload has the same tie-breaking regression in its pair comparison logic,
where the strict `HPX_INVOKE(f, curr_value, next_value)` path can mishandle
equal elements and violate the first-smallest/last-largest guarantee. Update the
pair-processing branch in `minmax.hpp` so equal pairs are treated consistently
with the intended tie-breaking behavior, and make sure the `min`/`max` updates
in the `sequential` implementation preserve the correct earliest minimum and
latest maximum selection.
- Around line 1153-1216: The projected comparator path in
detail::minmax_element::sequential still has the same tie-breaking regression
when comparing curr_value and next_value. Update the pair-processing logic in
minmax_element::sequential so equal elements are handled consistently with the
non-regressed behavior, ensuring min/max updates do not depend on the strict
curr-vs-next ordering alone. Use the existing min, max, curr_value, next_value,
and HPX_INVOKE(f, ...) flow in this function to apply the same fix as the other
branch.
- Around line 976-1040: The identity overload in the minmax routine has the same
tie-breaking bug as the projected version: the paired comparison in the minmax
loop currently uses a strict order check in the pair test, which makes equal
elements choose the wrong min/max candidate. Update the logic in the minmax
implementation around the `HPX_INVOKE(f, curr_value, next_value)` branch so
equal-valued pairs preserve first-smallest for `result.min` and last-largest for
`result.max`, matching the contract used by the surrounding
`minmax`/`result.min`/`result.max` handling.
- Around line 892-956: The pairwise comparison logic in minmax_element is using
the wrong tie-break when values are equal, which can swap the earlier/later
iterator selection. Update the comparisons in the minmax implementation in
minmax.hpp so that pair ordering is decided with the reverse-argument check,
using the existing helpers around HPX_INVOKE(f, ...) in the minmax_element path.
Apply the same correction to the other three pairwise comparison sites in this
file so the first-smallest / last-largest behavior is preserved consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3e9f7b57-aa87-488f-b9e1-0c171f8cecd7
📒 Files selected for processing (1)
libs/core/algorithms/include/hpx/parallel/algorithms/minmax.hpp
hkaiser
left a comment
There was a problem hiding this comment.
Could you please add the tests you created to verify correctness of strict-weak orderings?
350421a to
c6c9ec5
Compare
- Improved minmax_element by now using floor(3/2*(N-1)) comparisons
instead of 2*(N-1) comparisons.
- minmax_element no longer has contradictory information in HPX
documentation versus its actual implementation.
HPX's implementation of minmax_element uses 2*(N-1) comparisons despite
stating in its documentation that it uses floor(3/2*(N-1)) comparisons
like std::minmax_element.
The algorithm is reimplemented so that all execution policies now use
floor(3/2*(N-1)) comparisons. By now iterating over two elements at
once, comparing those elements to find which is smaller and which is
larger, and then comparing those respective elements to the known
minimum and known maximum, there are now three comparisons for every
two elements rather than four comparisons for every two elements.
Signed-off-by: Ryan Thomas <rthomas12599@gmail.com>
- Fixed a condition in minmax_element such that equivalent-valued elements do not fail. - Changing HPX_INVOKE(f, curr_value, next_value) into !HPX_INVOKE(f, next_value, curr_value) means that in the case of a tie, curr_value will correctly be compared to min_value instead of next_value being incorrectly compared to min_value. - This follows the implementation in std::minmax_element where the first reference to the minimum element and the last reference to the maximum element is supposed to be returned. Signed-off-by: Ryan Thomas <rthomas12599@gmail.com>
- The implementations of minmax_element for the hpx::execution::seq and hpx::execution::unseq policies no longer have an unused parameter that is not referenced in their code body. Signed-off-by: Ryan Thomas <rthomas12599@gmail.com>
- Added test case to check minmax_element compatibility for strict weak orderings (i.e., that equivalent-valued elements will indeed return the first reference to the smallest element and the last reference to the largest element). Signed-off-by: Ryan Thomas <rthomas12599@gmail.com>
0e1d946 to
7e50f4b
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
libs/core/algorithms/tests/unit/algorithms/minmax_element.cpp (1)
67-94: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAssert the optimized comparison count.
These tests validate results but still pass with the old
2*(N-1)implementation. Add a counting comparator for sequential odd and even ranges and assert at most3 * (N - 1) / 2calls, directly protecting this PR’s primary objective.Also applies to: 147-174
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@libs/core/algorithms/tests/unit/algorithms/minmax_element.cpp` around lines 67 - 94, Add a counting comparator to the minmax_element tests covering both sequential odd- and even-sized ranges, and assert the comparison count is at most 3 * (N - 1) / 2. Apply the same assertions to the additional test block around the second referenced range while preserving the existing result checks and comparator behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@libs/core/algorithms/tests/unit/algorithms/minmax_element.cpp`:
- Around line 67-94: Add a counting comparator to the minmax_element tests
covering both sequential odd- and even-sized ranges, and assert the comparison
count is at most 3 * (N - 1) / 2. Apply the same assertions to the additional
test block around the second referenced range while preserving the existing
result checks and comparator behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: efe0cd63-24e7-4810-8d10-86d4f7d0f64b
📒 Files selected for processing (2)
libs/core/algorithms/include/hpx/parallel/algorithms/minmax.hpplibs/core/algorithms/tests/unit/algorithms/minmax_element.cpp
Proposed Changes
hpx::minmax_elementby now using floor(3/2*(N-1)) comparisons instead of 2*(N-1) comparisons.hpx::minmax_elementno longer has contradictory information in HPX documentation versus its actual implementation.Any background context you want to provide?
The algorithm
std::minmax_elementreturns the first reference to the smallest element and the last reference to the largest element of a container using floor(3/2*(N-1)) comparisons. HPX documentation states thathpx::minmax_elementhas the same complexity; however, the current implementation actually uses 2*(N-1) comparisons by explicitly comparing the known minimum and maximum values against each individual element in the container.This pull request reimplements
hpx::minmax_elementso that all execution policies now use floor(3/2*(N-1)) comparisons. By now iterating over two elements at once, comparing those elements to find which is smaller and which is larger, and then comparing those respective elements to the known minimum and known maximum, there are now three comparisons for every two elements rather than four comparisons for every two elements.Checklist
Not all points below apply to all pull requests.