Skip to content

Conversation

polaris-3
Copy link
Contributor

@polaris-3 polaris-3 commented Jun 2, 2025

Improve the error message in numpy.testing.assert_array_compare to show the position of differing elements.

Currently, if there is an assertion error in functions like numpy.testing.assert_allclose, both arrays are printed. Typically the arrays are so large that they are truncated before being printed, making it hard to spot the differences. I suggest to print the indices of the differing elements as well as the corresponding values. To avoid excessive output, the number of printed out differences is limited to five.

…, showing the position of differing elements.
@seberg
Copy link
Member

seberg commented Jun 3, 2025

Thanks, looks like a nice idea on first thought! Could you show before/after outputs? Also at least the documentation test failures (circleci) are very much real here.

@polaris-3
Copy link
Contributor Author

Sure, here is an example with outputs before and after my changes.

Example code
`import numpy as np

a = np.random.rand(100, 100)
b = a.copy()
b[79, 83] = 0.5
b[24, 59] = 0.1
np.testing.assert_allclose(a,b)`

Before:
image
Note that there is no chance to see which of the two elements are different. The parts of the arrays being printed are identical.

After:
image

@charris charris changed the title ENH: more helpful error message in numpy.testing.assert_array_compare… ENH: Improve error message in numpy.testing.assert_array_compare Jun 3, 2025
@ngoldbaum ngoldbaum added the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Jun 3, 2025
@ngoldbaum
Copy link
Member

I like where this is going, but I think care needs to go into edge cases so we don't unnecessarily add noise.

If all the values are different in two 1000 element arrays, it's not particularly useful to print the first five indices, for example.

Maybe there should be a cutoff where the index display starts showing up?

Also for this to be mergeable you're going to need to get CI to pass and you're going to need to add a release note describing the change. Try to get the tests, docs build, doctests, and linter to pass locally before pushing here to run CI.

@polaris-3
Copy link
Contributor Author

I hope to have addressed all the edge cases now and have also adapted the tests and docs to the new error message.
@ngoldbaum I'm not sure I fully agree. Even if all entries of two 1000 element arrays disagree, it might still be nice to see a few examples of differing elements. On the other hand, the truncated arrays are printed anyway, so this might serves this purpose already.

@ngoldbaum ngoldbaum removed the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Jun 17, 2025
Copy link
Member

@ngoldbaum ngoldbaum left a comment

Choose a reason for hiding this comment

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

just a drive-by comment

Copy link
Member

@ngoldbaum ngoldbaum left a comment

Choose a reason for hiding this comment

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

I like it!

@polaris-3 polaris-3 requested a review from seberg July 7, 2025 11:57
@seberg seberg merged commit 85cb82c into numpy:main Jul 7, 2025
74 checks passed
@seberg
Copy link
Member

seberg commented Jul 7, 2025

Thanks, @polaris-3.

@danra
Copy link
Contributor

danra commented Jul 7, 2025

Nice! I have a similar feature in the pipeline for #28827

danra added a commit to danra/numpy that referenced this pull request Jul 14, 2025
Recently, numpy#29112 added showing first mismatches indices, but
assert_array_almost_equal.compare trips it up by returning a shape
different from its input, causing an IndexError:

```
                <...>
                if invalids.ndim != 0:
                    if flagged.ndim > 0:
>                       positions = np.argwhere(np.asarray(~flagged))[invalids]
E                       IndexError: boolean index did not match indexed array along axis 0; size of axis is 3 but size of corresponding boolean axis is 2
```
(traceback shown using pytest --full-trace)
danra added a commit to danra/numpy that referenced this pull request Jul 14, 2025
Recently, numpy#29112 added showing first mismatches indices, but
assert_array_almost_equal.compare trips it up by returning a shape
different from its input, causing an IndexError:

```
                <...>
                if invalids.ndim != 0:
                    if flagged.ndim > 0:
>                       positions = np.argwhere(np.asarray(~flagged))[invalids]
E                       IndexError: boolean index did not match indexed array along axis 0; size of axis is 3 but size of corresponding boolean axis is 2
```
(traceback shown using pytest --full-trace)
danra added a commit to danra/numpy that referenced this pull request Jul 14, 2025
Recently, numpy#29112 added showing first mismatches indices, but
assert_array_almost_equal.compare trips it up by returning a shape
different from its input, causing an IndexError:

```
    <...>
    if invalids.ndim != 0:
        if flagged.ndim > 0:
>           positions = np.argwhere(np.asarray(~flagged))[invalids]
E           IndexError: boolean index did not match indexed array along axis 0; size of axis is 3 but size of corresponding boolean axis is 2
```
(traceback shown using pytest --full-trace)
danra added a commit to danra/numpy that referenced this pull request Jul 19, 2025
Recently, numpy#29112 added showing first mismatches indices, but
assert_array_almost_equal.compare trips it up by returning a shape
different from its input, causing an IndexError:

```
    <...>
    if invalids.ndim != 0:
        if flagged.ndim > 0:
>           positions = np.argwhere(np.asarray(~flagged))[invalids]
E           IndexError: boolean index did not match indexed array along axis 0; size of axis is 3 but size of corresponding boolean axis is 2
```
(traceback shown using pytest --full-trace)
mhvk pushed a commit that referenced this pull request Jul 20, 2025
* TST: Add failing test showing shape mismatch issue

Recently, #29112 added showing first mismatches indices, but
assert_array_almost_equal.compare trips it up by returning a shape
different from its input, causing an IndexError:

```
    <...>
    if invalids.ndim != 0:
        if flagged.ndim > 0:
>           positions = np.argwhere(np.asarray(~flagged))[invalids]
E           IndexError: boolean index did not match indexed array along axis 0; size of axis is 3 but size of corresponding boolean axis is 2
```
(traceback shown using pytest --full-trace)

* MNT: Remove assert_array_almost_equal old infs logic, but tests fail

A nice cleanup (newer, similar inf handling already exists now in
assert_array_compare), and resolves the shape mismatch issue. However,
the removed logic was handling complex infs while the one isn't, causing
the new test and an existing one (TestInterp::test_complex_interp) to
now fail with RuntimeWarnings attempting to subtract the complex infs.

* MNT: assert_array_compare handles all inf values

assert_array_compare now tests all inf values for matching position
and value, including complex infs.

Fixes the failing tests.

* TST: Test array_allclose behavior for inf values

The behavior for real infs is the same is before.

For complex infs, demonstrates that the behavior for mismatching
values is now cleaner, showing a concise error message vs.
previously displaying nan max errors.

For complex infs with matching values, the behavior is the same as
before, accepting them as equal (although internally they would
now be filtered ahead of being passed to isclose, like real infs
already had been).

* TST: assert_allclose behavior with nans that are also infs

* MNT: Extract robust_any_difference() helper to DRY
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.

5 participants