Repository navigation
BUG: fix nanmax/nanmin initial argument misbehaving in slow path - #31102
joshuaswanson wants to merge 4 commits into
Conversation
|
I'm going to try to look at this before 2.6 is branched. Thanks for the contribution, sorry it got lost in the churn. |
|
@ngoldbaum ping |
|
I don't think this is the right fix. First and foremost, this introduced a regression for one of the cases from #31087. Before the PR, The same problem exists for The bug isn't that |
|
Thanks for the review. You're right. I've pushed a commit that replaces NaN initial with the operation's identity (+inf for nanmin, -inf for nanmax) and keeps the original RuntimeWarning + NaN behavior for the all-NaN path. Added tests covering both the empty-input case and where= masks that exclude everything. |
|
Overall much better. Minor comment: please rebase on or merge with current Two big comments:
In particular, the following before this PR: And after this PR: IMO this is a correct, useful change, but it bears noting.
I would also add a test that a |
f528476 to
695e47b
Compare
| # the same way it ignores NaN in array elements. | ||
| initial_is_nan = ( | ||
| initial is not np._NoValue | ||
| and np.ndim(initial) == 0 |
There was a problem hiding this comment.
Hmmm, I don't love np.ndim (it converts to an array on the way just to check that this is a scalar). initial must be a scalar, and maybe it is OK if
There are a couple of subtle things, that I am a bit unsure about whether we should address them here:
np.isnan(...)will actually currently fail for things likedecimal.Decimal(0)coming in, which isn't an unreasonable initial value.- That this path is taken at all for list inputs is a bit grotesque... The input is a list, which is converted to an array. This isn't some subclass that needs special handling.
(The problem with this is, whether we can just reasonably switch to aarray_converter/__array_wrap__pattern to begin with?! This would side-step the.max()dispatching though...) - Existing issue: I am actually unhappy about the warning being issued. The warning is a bit dubious either way, but we shouldn't issue a warning at all (on either path) is passed whether
NaNis returned or not.
The reason is that we should issue a warning only when the normal reduction would fail after removing all NaNs, butnp.fmin.reduce([], initial=np.nan)succeeds. (Maybe slightly debatable due to the NaN result, but I'd argue the user asked for it explicitly, so a warning makes no sense.)
In some sense these don't matter, but it does make this feel a bit like a band-aid and the decimal.Decimal(0) input failing seems like a problem.
|
Switched to the initial != initial self-inequality check and added a test for that path. |
|
@seberg would you mind giving this another look when you have a chance? |
There was a problem hiding this comment.
I think this is an OK fix now, thanks. We still have two annoying things that would be nice to clean up, but while to me they seem like bigger issues than this one, they are distinct.
- It isn't really forgivable that we call
asanyarray()unnecessarily late and are hitting the slow path at all here for non-object input. - The warning is wrong on both paths, it should only be given if
initial is np._NoValue or initial is None.
Fixes #31087.
nanmin/nanmaxmisbehave with theinitialargument in the slow path (non-ndarray input like lists). Two issues:nanmax([1.0], initial=nan)returnsnanbecause the slow path usesnp.amaxwhich propagates NaN frominitial, unlikenp.fmax.reduceused in the fast path. Fixed by stripping NaNinitialbefore passing toamax/amin, sincenanmax/nanminshould ignore NaN ininitialthe same way they ignore NaN in array elements.nanmax([], initial=1.0)returnsnanbecause the all-NaN check (np.all(mask)) returnsTrueon an empty mask and unconditionally overwrites the result with NaN. Fixed by usinginitialas the result for all-NaN slices when it's a valid (non-NaN) value.