Support axes argument of gufuncs for Masked inputs - #16121
Conversation
|
Thank you for your contribution to Astropy! π This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.
|
|
I think we should fix #16123 before merging this |
|
Ok then. I can review this one after #16120 goes in ! |
|
#16120 is merged. |
d875da2 to
651e9c0
Compare
neutrinoceros
left a comment
There was a problem hiding this comment.
Looks good, mostly minor questions (and nits) !
| mxm2 = np.matmul(m1, m2, axes=[(0, 2), (-2, -1), (0, 1)]) | ||
| exp2 = np.matmul(m1.unmasked, m2.unmasked, axes=[(0, 2), (-2, -1), (0, 1)]) | ||
| mask2 = ( | ||
| np.matmul( | ||
| (~m1.mask).astype(int), | ||
| (~m2.mask).astype(int), | ||
| axes=[(0, 2), (-2, -1), (0, 1)], |
There was a problem hiding this comment.
Just so that it's crystal clear that these are the same thing
| mxm2 = np.matmul(m1, m2, axes=[(0, 2), (-2, -1), (0, 1)]) | |
| exp2 = np.matmul(m1.unmasked, m2.unmasked, axes=[(0, 2), (-2, -1), (0, 1)]) | |
| mask2 = ( | |
| np.matmul( | |
| (~m1.mask).astype(int), | |
| (~m2.mask).astype(int), | |
| axes=[(0, 2), (-2, -1), (0, 1)], | |
| axes = [(0, 2), (-2, -1), (0, 1)] | |
| mxm2 = np.matmul(m1, m2, axes=axes) | |
| exp2 = np.matmul(m1.unmasked, m2.unmasked, axes=axes) | |
| mask2 = ( | |
| np.matmul( | |
| (~m1.mask).astype(int), | |
| (~m2.mask).astype(int), | |
| axes=axes, |
| (~m2.mask).astype(int), | ||
| axes=[(0, 2), (-2, -1), (0, 1)], | ||
| ) | ||
| != 3 |
There was a problem hiding this comment.
I think this would be the correct generalisation ? I'm not convinced that my suggestion actually makes the code clearer, but it took me a minute to check what's going here so maybe a comment would help ?
| != 3 | |
| != len(axes) |
There was a problem hiding this comment.
It is meant to be the size of the dimension that is operated on; I've replaced with m1.shape[axes[0][1]] (which will at least hint at what this is).
EDIT: also added a comment. In the test, I didn't want to re-use the nan logic of the code itself, since then the result is somewhat circular.
| if out is not None: | ||
| np.copyto(out, False, where=where) |
There was a problem hiding this comment.
while this seems correct, I'm slightly confused that out and the return value may differ here (if out is an actual array). I can't help but notice that it doesn't follow the convention from numpy's API, though I'm honestly not sure what to suggest instead.
There was a problem hiding this comment.
You're right, this is inconsistent. Changed...
| keepdims = kwargs.get("keepdims", False) | ||
| in_masks = [] | ||
| for sig, mask in zip(in_sig, masks): | ||
| for sig, mask, axis in zip(in_sig, masks, axes[: ufunc.nin]): |
There was a problem hiding this comment.
Here too, I'm wondering about arguments being ignored silently (specifically, what happens if axes has more elements than ufunc.nin). Also, wouldn't zip already drop extraneous elements even if we didn't slice here ?
There was a problem hiding this comment.
axes will have been checked already to have the right length.
There was a problem hiding this comment.
Well, that's not completely true: it will have at least nin elements, but nout can be omitted if they're all (). I'll adjust!
| # Here, some masks may need expansion, so we forego in-place. | ||
| mask = self._combine_masks(in_masks, copy=False) | ||
| result_masks = [] | ||
| for os, omask, axis in zip(out_sig, out_masks, axes[ufunc.nin :]): |
There was a problem hiding this comment.
same question as earlier with zip
There was a problem hiding this comment.
This one was indeed right. Now added test...
|
@neutrinoceros - thanks for the careful look! I think I addressed your comments (and also tried to add some extra tests to cover the somewhat rarer branches of the code). |
54ee9ca to
8710e38
Compare
neutrinoceros
left a comment
There was a problem hiding this comment.
All good now, thanks for walking me through this !
pllim
left a comment
There was a problem hiding this comment.
Again, I am approving by proxy to unblock merge. I'll let mhvk decide when to merge.
Thanks!
|
Thanks, @pllim and @neutrinoceros! |
|
You did the hard work. Thank YOU! |
This pull request builds on #16120 to add support for
axesfor gufuncs withMaskedinputs or outputs. It also refactors__array_ufunc__a little, ensuring that ifMaskedoutput is passed in, its mask always get used for possible in-place mask calculations.