You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BUG: Surprising difference between array scalar and array in casting in ufuncs #23247
In selecting an inner loop for a ufunc in which one argument is a scalar, array scalars are not treated the same way as regular arrays, which leads to surprises.
It would seem best to treat any array the same way with regards to loop selection.
1.25.0.dev0+606.ga1f3cbd85
3.11.1 (main, Dec 31 2022, 10:23:59) [GCC 12.2.0]
Context for the issue:
In astropy's Latitude class, a test is done that input angles are between -90 and 90 degrees, or, equivalently, between -pi/2 and pi/2. The tests fail with scalar array float32 inputs of pi/2.
Should have a few duplicate issues about this, as it is the "normal" value-based promotion rule. I.e.:
In [1]: import numpy as np
In [2]: np._set_promotion_state("weak")
In [3]: a = np.array(np.pi, dtype='f4')
...: a <= np.pi
...:
Out[3]: True
In [4]: a[np.newaxis] <= np.pi
Out[4]: array([ True])
(Better using the env variable probably.)
I will admit, I am still struggling with the whole ufuncs are the same as operators story though, w.r.t. NEP 50. There is always a problem whether a user should expect weak promotion for a function call:
some_function(float32_arr, 234.1)
``
or not. If we would not use weak promotion for "normal" ufunc calls, then the pattern seems easier to make clear to me (always convert, never weak). OTOH, ufuncs and operators are slightly different then. Which makes that `OperatorMixin` that falls back the ufunc complicated to ensure identical behavior.
Nice to see that it is possible to avoid! Is this meant to be in 2.0?
Though here perhaps the main question is whether how an array is treated should depend on its dimension in any way... I feel it should not, though realize it still is super tricky.
For my specific problem, I wish I could think of something smarter (right now, I ended up just adding an axis before doing the comparison to force doing it at the array dtype).
🤷 it doesn't depend on it the shape with weak promotion. There is also np.geater_requal.resolve_dtypes() now which implicitly opts you in to weak promotion, but that will hardly help you for now (more something that might be useful in the future).
Yes, this is part of what I would want in a 2.0 (probably the biggest single item). The main issue is making sure we get those details right...
In a sense, both results could be acceptable above, one enforcing that the Python float is a float64, the other not. The issue is mainly the shape dependency.
There is a fun N.B. to the above, since we could have a Constants DType that specifically always does weak casting, so that Constant(pi) could have arbitrary precision in theory, but always defers to the other sides precision.
Activity
seberg commentedon Feb 20, 2023
Should have a few duplicate issues about this, as it is the "normal" value-based promotion rule. I.e.:
(Better using the env variable probably.)
I will admit, I am still struggling with the whole ufuncs are the same as operators story though, w.r.t. NEP 50. There is always a problem whether a user should expect weak promotion for a function call:
mhvk commentedon Feb 20, 2023
Nice to see that it is possible to avoid! Is this meant to be in 2.0?
Though here perhaps the main question is whether how an array is treated should depend on its dimension in any way... I feel it should not, though realize it still is super tricky.
For my specific problem, I wish I could think of something smarter (right now, I ended up just adding an axis before doing the comparison to force doing it at the array dtype).
seberg commentedon Feb 20, 2023
🤷 it doesn't depend on it the shape with weak promotion. There is also
np.geater_requal.resolve_dtypes()now which implicitly opts you in to weak promotion, but that will hardly help you for now (more something that might be useful in the future).Yes, this is part of what I would want in a 2.0 (probably the biggest single item). The main issue is making sure we get those details right...
seberg commentedon Feb 20, 2023
In a sense, both results could be acceptable above, one enforcing that the Python float is a float64, the other not. The issue is mainly the shape dependency.
There is a fun N.B. to the above, since we could have a
ConstantsDType that specifically always does weak casting, so thatConstant(pi)could have arbitrary precision in theory, but always defers to the other sides precision.mhvk commentedon Feb 20, 2023
The always-defer dtype seems a nice idea - covers both explicit is better than implicit and refuse the temptation to guess!
mhvk commentedon Jan 11, 2024
Closing this, since the particular issue is solved in 2.0, and a clear choice was made.
(There still is the nice idea of a
ConstantsDType that always defers, but not sure making that its own issue will help anything)