-
-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds the functionality of Ufunc to NDCube #666
base: main
Are you sure you want to change the base?
Conversation
Thanks @ViciousEagle03 for this PR and for opening it earlier rather than later so we can discuss the approach. Firstly, I'll say that I'm not an expert in ufuncs so it's possible I've misunderstood some details in your implementation. Secondly, despite my concerns below, I think supporting ufuncs is a useful feature for users. The question is how to do this, and this PR is a great chance to discuss it. My understanding is that the API you're implementing for ufuncs is different to that for the arithmetic operators. The ufuncs basically extract the data array and then proceed as normal, whereas the arithmetic operations try to take the uncertainties and mask into account, where appropriate. For example, Assuming that it is, this opens an important discussion. My intuition as a user would be that If we continue to assume that ufuncs should also consider the wcs, mask and uncertainty, it has implications for As for Fundamentally, the issue lies in how to treat the wcs, mask and uncertainty, whether it be arithmetic operators or ufuncs. If these are going to be ignored and a numpy array returned, users can easily perform their operation on What are your thoughts? And have I misunderstood your implementation? |
Hey @DanRyanIrish, Thanks for the feedback
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ViciousEagle03. Thanks for the update to your PR and apologies for the delay in my reply. I am still consumed with another project. I am still trying to understand exactly the API you're implementing. I've left some in line comments in places where I'm confused.
Perhaps it would be a good idea to list out as a comment on this PR the exact behaviour you are trying to implement. For example, the output types of
np.add(cube1, array2)
np.add(cube1, cube2)
np.add(array1, cube2)
and what attributes are considered in the calculation, i.e..data
,.mask
,.uncertainty
. And the same fornp.subtract
, andnp.multiply
.
@@ -886,28 +886,32 @@ def _new_instance_from_op(self, new_data, new_unit, new_uncertainty): | |||
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): | |||
if method == '__call__': | |||
if ufunc == np.add: | |||
if isinstance(inputs[0], NDCube): | |||
if isinstance(inputs[0], NDCube) and kwargs.get("dunder"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is "dunder"
a standard kwarg or custom for this implementation? And what does it mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have used the dunder
(not a standard kwarg) kwarg here to distinguish between the operators and numpy ufuncs to properly handle the operator overloading.
@@ -886,28 +886,32 @@ def _new_instance_from_op(self, new_data, new_unit, new_uncertainty): | |||
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): | |||
if method == '__call__': | |||
if ufunc == np.add: | |||
if isinstance(inputs[0], NDCube): | |||
if isinstance(inputs[0], NDCube) and kwargs.get("dunder"): | |||
new_data = inputs[0].data + inputs[1] | |||
return new_data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that np.add(cube1, array2)
would return an array?
This looks different to the implementation for np.sub
which appears like it would return an NDCube
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
np.add(cube1, array2)
would return an NDCube.
The np.subtract
utilises the dunder method __sub__
and in turn the __sub__
dunder method uses the __add__
dunder method and since np.subtract
utilises the __add__
so we don't need to check the way we did in np.add
as __add__
dunder method will call the np.add
which in turn will do the checking and hence both returns the same type.
Hey @DanRyanIrish, |
Hello 👋, Thanks for your contribution to ndcube! |
Hello again 👋, We want to thank you again for your contribution to ndcube! |
PR Description
This PR address the issue: #591
I've tried to add the support of Arithmetic operations to NDCube using Numpy Ufunc
I have removed the test cases in
ndcube/tests/test_ndcube.py
in the arithmetic section which doesn't support__array_ufunc__
Note: Before proceeding to add the remaining test cases and Changelog, I wanted to ensure that the proof of concept is correct.