Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support axes argument of gufuncs for Masked inputs - #16121

Merged
mhvk merged 4 commits into
astropy:mainfrom
mhvk:masked-gufunc-axes-support
Feb 28, 2024
Merged

mhvk merged 4 commits into
astropy:mainfrom
mhvk:masked-gufunc-axes-support

Conversation

@mhvk

@mhvk mhvk commented Feb 28, 2024

Copy link
Copy Markdown
Contributor

This pull request builds on #16120 to add support for axes for gufuncs with Masked inputs or outputs. It also refactors __array_ufunc__ a little, ensuring that if Masked output is passed in, its mask always get used for possible in-place mask calculations.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@github-actions

Copy link
Copy Markdown
Contributor

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.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@neutrinoceros

Copy link
Copy Markdown
Contributor

I think we should fix #16123 before merging this

@mhvk

mhvk commented Feb 28, 2024

Copy link
Copy Markdown
Contributor Author

I think we should fix #16123 before merging this

I think it is somewhat orthogonal to what goes wrong in #16123, so it would seem fine to deal with this PR independently (#16123 will require changes to the __call__ path, which this PR barely touches, so it won't be much trouble to rebase/backport).

@neutrinoceros

Copy link
Copy Markdown
Contributor

Ok then. I can review this one after #16120 goes in !

@pllim

pllim commented Feb 28, 2024

Copy link
Copy Markdown
Member

#16120 is merged.

@mhvk
mhvk force-pushed the masked-gufunc-axes-support branch from d875da2 to 651e9c0 Compare February 28, 2024 17:06

@neutrinoceros neutrinoceros left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good, mostly minor questions (and nits) !

Comment on lines +755 to +761
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)],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just so that it's crystal clear that these are the same thing

Suggested change
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,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea!

(~m2.mask).astype(int),
axes=[(0, 2), (-2, -1), (0, 1)],
)
!= 3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 ?

Suggested change
!= 3
!= len(axes)

@mhvk mhvk Feb 28, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Comment thread astropy/utils/masked/core.py Outdated
Comment on lines +692 to +693
if out is not None:
np.copyto(out, False, where=where)

@neutrinoceros neutrinoceros Feb 28, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, this is inconsistent. Changed...

Comment thread astropy/utils/masked/core.py Outdated
Comment thread astropy/utils/masked/core.py Outdated
Comment thread astropy/utils/masked/core.py
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]):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

axes will have been checked already to have the right length.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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!

Comment thread astropy/utils/masked/core.py
# 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 :]):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same question as earlier with zip

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one was indeed right. Now added test...

Comment thread astropy/utils/masked/core.py
@mhvk

mhvk commented Feb 28, 2024

Copy link
Copy Markdown
Contributor Author

@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).

@mhvk
mhvk force-pushed the masked-gufunc-axes-support branch from 54ee9ca to 8710e38 Compare February 28, 2024 19:57

@neutrinoceros neutrinoceros left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All good now, thanks for walking me through this !

@pllim pllim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Again, I am approving by proxy to unblock merge. I'll let mhvk decide when to merge.

Thanks!

@mhvk
mhvk merged commit ac2427c into astropy:main Feb 28, 2024
@mhvk
mhvk deleted the masked-gufunc-axes-support branch February 28, 2024 22:30
@mhvk

mhvk commented Feb 28, 2024

Copy link
Copy Markdown
Contributor Author

Thanks, @pllim and @neutrinoceros!

@pllim

pllim commented Feb 28, 2024

Copy link
Copy Markdown
Member

You did the hard work. Thank YOU!

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.

3 participants