From 81db5e5e5b5cbe63d820f80c70f9781109beb6be Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk <21087696+oleksandr-pavlyk@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:00:53 -0600 Subject: [PATCH 1/4] Implement usm_ndarray.__arrray__ method The property raises TypeError informing user that implicit conversions from usm_ndarray to numpy.ndarray are not permitted. Explicit conversion using `dpctl.tensor.asnumpy` is advised. Disallowing implicit conversion prevents `np.asarray(usm_ar)` from creating an array of 0D usm_ndarray instances, because using it is very costly due to multitude of short-array transfers from GPU to host. --- dpctl/tensor/_usmarray.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index f61651d4b3..150f0b3b65 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -1552,6 +1552,14 @@ cdef class usm_ndarray: def __repr__(self): return usm_ndarray_repr(self) + def __array__(self, dtype=None, copy=None): + "NumPy array protocol" + raise TypeError( + "Implicit conversion to a NumPy array is not allowed. " + "Use `dpctl.tensor.asnumpy` to copy data from this " + "`dpctl.tensor.usm_ndarray` instance to NumPy array" + ) + cdef usm_ndarray _real_view(usm_ndarray ary): """ From d34bad946cc828eb0051bfb22357bc641ec00437 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk <21087696+oleksandr-pavlyk@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:03:36 -0600 Subject: [PATCH 2/4] Add test that np.asarray(usm_ar) raises TypeError --- dpctl/tests/test_usm_ndarray_ctor.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dpctl/tests/test_usm_ndarray_ctor.py b/dpctl/tests/test_usm_ndarray_ctor.py index 227cd683dc..ccfc655bfc 100644 --- a/dpctl/tests/test_usm_ndarray_ctor.py +++ b/dpctl/tests/test_usm_ndarray_ctor.py @@ -2659,3 +2659,12 @@ def test_setitem_copy_as_contig_alignment(dt): x[1:, ...] = vals assert dpt.all(x[0] == 0) assert dpt.all(x[1:, :] == vals) + + +def test_asarray_property(): + get_queue_or_skip() + + x = dpt.ones(11, dtype="i4") + + with pytest.raises(TypeError): + np.asarray(x) From b6e3afe7e06c0f21b178e66fec4953bc43d52319 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk <21087696+oleksandr-pavlyk@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:41:51 -0600 Subject: [PATCH 3/4] Record addition of __array__ method change in changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c0133e63..88936d5dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Improved performance of `tensor.cumulative_sum`, `tensor.cumulative_prod`, `tensor.cumulative_logsumexp` as well as performance of boolean indexing [gh-1923](https://github.com/IntelPython/dpctl/pull/1923) * Improved performance of `tensor.min`, `tensor.max`, `tensor.logsumexp`, `tensor.reduce_hypot` for floating point type arrays by at least 2x [gh-1932](https://github.com/IntelPython/dpctl/pull/1932) * Extended `tensor.asarray` to support objects that implement `__usm_ndarray__` property to be interpreted as `usm_ndarray` objects [gh-1959](https://github.com/IntelPython/dpctl/pull/1959) +* `dpctl.tensor.usm_ndarray` object disallows implicit conversions to NumPy array [gh-1964](https://github.com/IntelPython/dpctl/pull/1964) ### Fixed From 8393a759b6942d33ebc09beb690b2bd0b97da68d Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk <21087696+oleksandr-pavlyk@users.noreply.github.com> Date: Tue, 14 Jan 2025 08:25:25 -0600 Subject: [PATCH 4/4] Make copy argument of __array__ method keyword-only --- dpctl/tensor/_usmarray.pyx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index 150f0b3b65..668e17bd79 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -1552,8 +1552,15 @@ cdef class usm_ndarray: def __repr__(self): return usm_ndarray_repr(self) - def __array__(self, dtype=None, copy=None): - "NumPy array protocol" + def __array__(self, dtype=None, /, *, copy=None): + """NumPy's array protocol method to disallow implicit conversion. + + Without this definition, `numpy.asarray(usm_ar)` converts + usm_ndarray instance into NumPy array with data type `object` + and every element being 0d usm_ndarray. + + https://github.com/IntelPython/dpctl/pull/1384#issuecomment-1707212972 + """ raise TypeError( "Implicit conversion to a NumPy array is not allowed. " "Use `dpctl.tensor.asnumpy` to copy data from this "