Skip to content
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

Raise TypeError in dpnp.ndarray.__array__ #2260

Merged
merged 12 commits into from
Jan 21, 2025

Conversation

antonwolfy
Copy link
Contributor

@antonwolfy antonwolfy commented Jan 14, 2025

The PR implements dpnp.ndarray.__array__ method that raises TypeError to disallow implicit conversion of dpnp.ndarray to numpy.ndarray.
While explicit conversion using dpnp.ndarray.asnumpy method is advised.

Disallowing implicit conversion prevents numpy.asarray(dpnp_arr) from creating an array of 0D dpnp.ndarray instances, because
using it is very costly due to multitude of short-array transfers from GPU to host.

  • Have you provided a meaningful PR description?
  • Have you added a test, reproducer or referred to issue with a reproducer?
  • Have you tested your changes locally for CPU and GPU devices?
  • Have you made sure that new changes do not introduce compiler warnings?
  • Have you checked performance impact of proposed changes?
  • If this PR is a work in progress, are you filing the PR as a draft?

@antonwolfy antonwolfy self-assigned this Jan 14, 2025
@antonwolfy antonwolfy force-pushed the ndrray-array-protocol-must-raise branch 2 times, most recently from 2891cdb to 0420fb2 Compare January 14, 2025 13:57
@antonwolfy antonwolfy marked this pull request as draft January 14, 2025 14:29
@antonwolfy antonwolfy force-pushed the ndrray-array-protocol-must-raise branch 2 times, most recently from 7fd98c5 to 61d61b4 Compare January 20, 2025 11:34
@antonwolfy antonwolfy force-pushed the ndrray-array-protocol-must-raise branch from 61d61b4 to d449db8 Compare January 20, 2025 14:50
antonwolfy added a commit that referenced this pull request Jan 20, 2025
…ry ops (#2266)

The PR proposes to follow NEP-13
[recommendations](https://numpy.org/neps/nep-0013-ufunc-overrides.html#behavior-in-combination-with-python-s-binary-operations)
on how to interact with `numpy.ndarray` in binary the operations.

It will set `__array_ufunc__ = None` which means that dpnp implements
Python binary operations freely and so `numpy.ufuncs` called on this
argument will raise `TypeError`:
```python
a = numpy.ones(10)
b = dpnp.ones(10)
a += b
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[9], line 1
----> 1 a += b

TypeError: operand 'dpnp_array' does not support ufuncs (__array_ufunc__=None)
```
And an elementwise operation with `numpy.ndarray` will cause an explicit
exception in dpnp:
```python
a + b
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 a + b

File ~/code/dpnp/dpnp/dpnp_array.py:518, in dpnp_array.__radd__(self, other)
    516 def __radd__(self, other):
    517     """Return ``value+self``."""
--> 518     return dpnp.add(other, self)

File ~/code/dpnp/dpnp/dpnp_algo/dpnp_elementwise_common.py:314, in DPNPBinaryFunc.__call__(self, x1, x2, out, where, order, dtype, subok, **kwargs)
    303 def __call__(
    304     self,
    305     x1,
   (...)
    312     **kwargs,
    313 ):
--> 314     dpnp.check_supported_arrays_type(
    315         x1, x2, scalar_type=True, all_scalars=False
    316     )
    317     if kwargs:
    318         raise NotImplementedError(
    319             f"Requested function={self.name_} with kwargs={kwargs} "
    320             "isn't currently supported."
    321         )

File ~/code/dpnp/dpnp/dpnp_iface.py:400, in check_supported_arrays_type(scalar_type, all_scalars, *arrays)
    397     if scalar_type and dpnp.isscalar(a):
    398         continue
--> 400     raise TypeError(
    401         f"An array must be any of supported type, but got {type(a)}"
    402     )
    404 if len(arrays) > 0 and not (all_scalars or any_is_array):
    405     raise TypeError(
    406         "At least one input must be of supported array type, "
    407         "but got all scalars."
    408     )

TypeError: An array must be any of supported type, but got <class 'numpy.ndarray'>
```

Previously it works as in a way:
```python
a = numpy.ones(10)
b = dpnp.ones(10)

a + b
# Out:
# array([array(2.), array(2.), array(2.), array(2.), array(2.), array(2.),
#        array(2.), array(2.), array(2.), array(2.)], dtype=object)
```

Note, some updates in tests from #2260 have been mapped to that PR.
@antonwolfy antonwolfy force-pushed the ndrray-array-protocol-must-raise branch from 228447f to b131ba2 Compare January 20, 2025 18:21
github-actions bot added a commit that referenced this pull request Jan 20, 2025
…ry ops (#2266)

The PR proposes to follow NEP-13
[recommendations](https://numpy.org/neps/nep-0013-ufunc-overrides.html#behavior-in-combination-with-python-s-binary-operations)
on how to interact with `numpy.ndarray` in binary the operations.

It will set `__array_ufunc__ = None` which means that dpnp implements
Python binary operations freely and so `numpy.ufuncs` called on this
argument will raise `TypeError`:
```python
a = numpy.ones(10)
b = dpnp.ones(10)
a += b
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[9], line 1
----> 1 a += b

TypeError: operand 'dpnp_array' does not support ufuncs (__array_ufunc__=None)
```
And an elementwise operation with `numpy.ndarray` will cause an explicit
exception in dpnp:
```python
a + b
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 a + b

File ~/code/dpnp/dpnp/dpnp_array.py:518, in dpnp_array.__radd__(self, other)
    516 def __radd__(self, other):
    517     """Return ``value+self``."""
--> 518     return dpnp.add(other, self)

File ~/code/dpnp/dpnp/dpnp_algo/dpnp_elementwise_common.py:314, in DPNPBinaryFunc.__call__(self, x1, x2, out, where, order, dtype, subok, **kwargs)
    303 def __call__(
    304     self,
    305     x1,
   (...)
    312     **kwargs,
    313 ):
--> 314     dpnp.check_supported_arrays_type(
    315         x1, x2, scalar_type=True, all_scalars=False
    316     )
    317     if kwargs:
    318         raise NotImplementedError(
    319             f"Requested function={self.name_} with kwargs={kwargs} "
    320             "isn't currently supported."
    321         )

File ~/code/dpnp/dpnp/dpnp_iface.py:400, in check_supported_arrays_type(scalar_type, all_scalars, *arrays)
    397     if scalar_type and dpnp.isscalar(a):
    398         continue
--> 400     raise TypeError(
    401         f"An array must be any of supported type, but got {type(a)}"
    402     )
    404 if len(arrays) > 0 and not (all_scalars or any_is_array):
    405     raise TypeError(
    406         "At least one input must be of supported array type, "
    407         "but got all scalars."
    408     )

TypeError: An array must be any of supported type, but got <class 'numpy.ndarray'>
```

Previously it works as in a way:
```python
a = numpy.ones(10)
b = dpnp.ones(10)

a + b
# Out:
# array([array(2.), array(2.), array(2.), array(2.), array(2.), array(2.),
#        array(2.), array(2.), array(2.), array(2.)], dtype=object)
```

Note, some updates in tests from #2260 have been mapped to that PR. 13816bd
@coveralls
Copy link
Collaborator

Coverage Status

coverage: 70.856% (+0.01%) from 70.845%
when pulling b131ba2 on ndrray-array-protocol-must-raise
into 13816bd on master.

Copy link
Contributor

Array API standard conformance tests for dpnp=0.17.0dev4=py312he4f9c94_22 ran successfully.
Passed: 949
Failed: 1
Skipped: 50

@antonwolfy antonwolfy marked this pull request as ready for review January 21, 2025 08:11
Copy link
Collaborator

@vlad-perevezentsev vlad-perevezentsev left a comment

Choose a reason for hiding this comment

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

Looks good!
Thank you @antonwolfy

@antonwolfy antonwolfy merged commit 356184a into master Jan 21, 2025
46 of 53 checks passed
@antonwolfy antonwolfy deleted the ndrray-array-protocol-must-raise branch January 21, 2025 14:20
github-actions bot added a commit that referenced this pull request Jan 21, 2025
The PR implements `dpnp.ndarray.__array__` method that raises
`TypeError` to disallow implicit conversion of `dpnp.ndarray` to
`numpy.ndarray`.
While explicit conversion using `dpnp.ndarray.asnumpy` method is
advised.

Disallowing implicit conversion prevents `numpy.asarray(dpnp_arr)` from
creating an array of 0D `dpnp.ndarray` instances, because
using it is very costly due to multitude of short-array transfers from
GPU to host. 356184a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants