-
Notifications
You must be signed in to change notification settings - Fork 7
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
ENH: allow python scalars in binary elementwise functions #100
base: main
Are you sure you want to change the base?
Conversation
TODO:
What's here now is likely too simple because this way python scalars can upcast arrays. So depending on what ends up in the standard this might need a tweak for "weak scalars" in the NEP 50 sense. |
cross-ref data-apis/array-api#862 |
We need to make sure this properly disallows cross-kind combinations that aren't supported. That will presumably match the text here https://data-apis.org/array-api/latest/API_specification/type_promotion.html#mixing-arrays-with-python-scalars (if data-apis/array-api#841 is implemented, real -> complex will also be allowed). |
The whole binop/binary elementwise functions is probably worth a larger rework. ATM there is duplication of logic in matching pairs, like Maybe the right thing to do is to transfer the logic from array methods to elementwise functions and delegate from functions to array methods. There's a precedent in torch dynamo, which just registers ufuncs as ndarray methods: https://github.com/pytorch/pytorch/blob/main/torch/_numpy/_ndarray.py#L197. This nicely avoids duplication and slight incompatibilities. |
In the last commit,
|
f705419
to
f173afc
Compare
Allow func(array, scalar) and func(scalar, array), raise on func(scalar, scalar) if API_VERSION>=2024.12 cross-ref data-apis/array-api#807 To make sure it is all uniform, 1. Generate all binary "ufuncs" in a uniform way, with a decorator 2. Make binary "ufuncs" follow the same logic of the binary operators 3. Reuse the test loop of Array.__binop__ for binary "ufuncs" 4. (minor) in tests, reuse canonical names for dtype categories ("integer or boolean" vs "integer_or_boolean")
The CI failure is unrelated: data-apis/array-api-tests#280, hopefully worked around by data-apis/array-api-tests#325 |
@@ -234,6 +234,8 @@ def _check_device(self, other): | |||
elif isinstance(other, Array): | |||
if self.device != other.device: | |||
raise ValueError(f"Arrays from two different devices ({self.device} and {other.device}) can not be combined.") | |||
else: | |||
raise TypeError(f"Cannot combine an Array with {type(other)}.") |
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.
When does it happen that we get here with other
being neither a scalar nor an array? My expectation was somehow that this wouldn't happen
Maybe worth adding a comment given that it isn't immediately obvious to me now and probably also not obvious to readers from the future.
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.
Good catch, thank you! This is interference from #103.
Should probably decide on that PR one way or another and rebase this one.
"__truediv__": "floating-point", | ||
"__xor__": "integer or boolean", |
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.
For my education, is there a reason for renaming these other than aesthetics? In particular the integer_or_boolean
makes me wonder if there was a reason why it was created without spaces in it
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.
Totally not aesthetics! This is to match the keys from https://github.com/data-apis/array-api-strict/blob/main/array_api_strict/_dtypes.py#L117 , which are "integer or boolean"
without underscores. Now that _check_op_array_scalar
from test_array_object.py
is reused in test_elementwise_functions.py
, and there is looping over the keys of the _dtype_categories
dict, it saves a bit of gymnastics to map different spellings onto each other.
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.
Aha! That sounds totally sensible, less 🤸
I'm a little undecided on the changes to |
Re copy-paste vs generate functions: while I'm definitely not too attached to the current way (it's borderline too meta to my tastes TBH), what I'd be worried about is consistency. Too easy for different functions to drift apart slightly, and we're trying to be super-consistent here, so I'd guess this way will be a little less maintenance going forward. Even at an expense of an initial "what on earth is this" kind of first reaction. |
Let's see what others think. My main worry with the code generation approach is that we forget to do something which leads to some subtle breakage somewhere in a way that will be tricky to debug. A bit similar to how you should use Let's see what opinions and feelings others have. |
towards #96