Fix fallback percentile calculation - #957
Conversation
06f20bf to
c684ea7
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #957 +/- ##
==========================================
+ Coverage 96.70% 96.72% +0.02%
==========================================
Files 8 8
Lines 1576 1589 +13
==========================================
+ Hits 1524 1537 +13
Misses 52 52 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
e5066ba to
170af0f
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes ccdproc.core._percentile_fallback so it computes percentile indices correctly for Array API namespaces that don’t implement percentile, including device-aware behavior for array-api-strict, and adds a targeted regression test to exercise the fallback path under both NumPy-coverage and strict backends.
Changes:
- Rework fallback percentile index calculation to be percent-scale correct (
/100), shape-based, dtype/device-aware, and clamp the 100th percentile ton-1. - Add a regression test that forces the fallback path for the NumPy lane (via a namespace proxy without
percentile) and runs on a non-default device forarray-api-strict. - Document the bug fix in
CHANGES.rst.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
CHANGES.rst |
Adds a changelog entry describing the fallback percentile fix. |
ccdproc/tests/test_ccdmask.py |
Adds regression coverage for _percentile_fallback across NumPy and array-api-strict (non-default device). |
ccdproc/core.py |
Fixes fallback percentile index computation using Array API-friendly operations and clamps the 100th percentile index. |
Comments suppressed due to low confidence (1)
ccdproc/core.py:103
- Docstring typo: "implmentation" should be "implementation".
def _percentile_fallback(array, percentiles, xp=None):
"""
Try calculating percentile using namespace, otherwise fall back to
an implmentation that uses sort. As of the 2023 version of the array API
there is no percentile function in the API but there is a sort function.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mwcraig
left a comment
There was a problem hiding this comment.
Thanks for the fix — the approach here is right, and I appreciate the fallback finally getting real test coverage on both the numpy and array-api-strict lanes. Verifying against the pre-PR code confirmed the tests genuinely exercise the fixed path.
One change requested before this is ready:
The index clamp is one-sided. The new code clamps the high end:
indexes = xp.minimum(
indexes,
xp.asarray(sorted_array.shape[0] - 1, ...),
)but there's no low-side clamp or range validation. A negative percentile produces a negative index, which wraps Python-style to the top of the sorted array. I verified: with an array of 0..99, _percentile_fallback(arr, -5) returns 95.0, where np.percentile raises ValueError. Similarly, percentiles above 100 silently clamp to the maximum instead of raising. So both out-of-range directions silently return large values, and the fallback disagrees with the namespace-percentile branch on error behavior — the same call would raise under numpy but return garbage under a fallback namespace.
The current callers hard-code 30.9/69.1 so this is latent today, but since this PR is establishing the fallback's contract, could you either:
- validate
0 <= p <= 100up front and raiseValueError(preferred — matchesnp.percentile), or - at minimum add the low-side clamp (
xp.maximum(indexes, 0)),
and add an out-of-range case to test_percentile_fallback? That's exactly the region the current parametrization doesn't touch.
Everything else looks good — the shape[0]/÷100/dtype/device handling is exactly what strict-on-non-default-device needs, and keeping floor-rank order statistics rather than picking an interpolation convention is the right call for ccdmask's use.
This review comment was written by Claude (via Claude Code) following Matt's review of the PR; Matt has reviewed and approved its content before posting.
Fixes astropy#888 Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
170af0f to
2c8dadb
Compare
Summary
_percentile_fallbackwith both the ordinary NumPy coverage lane and the existingarray-api-strictbackend on a non-default deviceFixes #888
Validation
len(Array)before the original fixpercentileso the production fallback executes in the coverage job[0, 50, 100]endpointsgit diff --checkChecklist
For documentation changes:
For bugfixes:
For new functionality:
AI assistance
OpenAI Codex was used for source inspection, test design, implementation, and automated review. The contributor has completed the final review and takes responsibility for the contribution's correctness and maintenance.