From 76a65bba66e16780ddb7895890ee15631c78380e Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 10:03:16 +0200 Subject: [PATCH 1/8] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff154638f9..9e6ed9f7b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* `dpctl.tensor.usm_ndarray` object allows implicit conversions to NumPy array changing implementation from [gh-1964](https://github.com/IntelPython/dpctl/pull/1964) for a more user-friendly behavior. + ### Maintenance ## [0.20.2] - Jun. 26, 2025 From 16c8996b47650156b8bfbd3cb9e0555788bfec68 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 10:21:31 +0200 Subject: [PATCH 2/8] Update _usmarray.pyx --- dpctl/tensor/_usmarray.pyx | 41 ++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index 0e42b42faf..1f328c2055 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -1585,20 +1585,35 @@ cdef class usm_ndarray: return usm_ndarray_repr(self) 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 " - "`dpctl.tensor.usm_ndarray` instance to NumPy array" + if copy is False: + raise TypeError("dpctl.tensors must copy data from device") + + # it is assumed that copy=None requires a copy due to + # the change of a dpctl dtype to a NumPy dtype therefore + # not violating the NumPy standard for the __array__ + # method. + + if self.size == 0: + # no data needs to be copied for zero sized array + return np.ndarray(self.shape, dtype=self.dtype) + nb = self.usm_data.nbytes + q = self.sycl_queue + hh = dpmem.MemoryUSMHost(nb, queue=q) + h = np.ndarray(nb, dtype="u1", buffer=hh).view(self.dtype) + itsz = self.itemsize + strides_bytes = tuple(si * itsz for si in self.strides) + offset = self._element_offset * itsz + # ensure that content of ary.usm_data is final + q.wait() + hh.copy_from_device(self.usm_data) + ndarray = np.ndarray( + self.shape, + dtype=self.dtype, + buffer=h, + strides=strides_bytes, + offset=offset, ) - + return ndarray if dtype is None else ndarray.astype(dtype) cdef usm_ndarray _real_view(usm_ndarray ary): """ From d6495c4eeab11d16a45449205e78f66674ef7783 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 10:23:29 +0200 Subject: [PATCH 3/8] Update _copy_utils.py --- dpctl/tensor/_copy_utils.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/dpctl/tensor/_copy_utils.py b/dpctl/tensor/_copy_utils.py index 3af5ebbe19..e23ba6eb6f 100644 --- a/dpctl/tensor/_copy_utils.py +++ b/dpctl/tensor/_copy_utils.py @@ -41,26 +41,7 @@ def _copy_to_numpy(ary): if not isinstance(ary, dpt.usm_ndarray): raise TypeError(f"Expected dpctl.tensor.usm_ndarray, got {type(ary)}") - if ary.size == 0: - # no data needs to be copied for zero sized array - return np.ndarray(ary.shape, dtype=ary.dtype) - nb = ary.usm_data.nbytes - q = ary.sycl_queue - hh = dpm.MemoryUSMHost(nb, queue=q) - h = np.ndarray(nb, dtype="u1", buffer=hh).view(ary.dtype) - itsz = ary.itemsize - strides_bytes = tuple(si * itsz for si in ary.strides) - offset = ary._element_offset * itsz - # ensure that content of ary.usm_data is final - q.wait() - hh.copy_from_device(ary.usm_data) - return np.ndarray( - ary.shape, - dtype=ary.dtype, - buffer=h, - strides=strides_bytes, - offset=offset, - ) + return ary.__array__() def _copy_from_numpy(np_ary, usm_type="device", sycl_queue=None): From 5ab4d3b142a093eda75962ea914b78eb8a337805 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 10:47:21 +0200 Subject: [PATCH 4/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e6ed9f7b1..ce01d083d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -### Fixed +* `dpctl.tensor.usm_ndarray` object allows implicit conversions to NumPy array changing implementation from [gh-1964](https://github.com/IntelPython/dpctl/pull/1964) for a more user-friendly behavior [gh-2131](https://github.com/IntelPython/dpctl/pull/2131). -* `dpctl.tensor.usm_ndarray` object allows implicit conversions to NumPy array changing implementation from [gh-1964](https://github.com/IntelPython/dpctl/pull/1964) for a more user-friendly behavior. +### Fixed ### Maintenance From e0d249f77e0662cd88840bea93ceb2f783e935b6 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 10:50:52 +0200 Subject: [PATCH 5/8] Update _usmarray.pyx --- dpctl/tensor/_usmarray.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index 1f328c2055..a418072dd9 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -1592,7 +1592,7 @@ cdef class usm_ndarray: # the change of a dpctl dtype to a NumPy dtype therefore # not violating the NumPy standard for the __array__ # method. - + if self.size == 0: # no data needs to be copied for zero sized array return np.ndarray(self.shape, dtype=self.dtype) From ce0d3e63890ac8e5d213375f3ef40a4edfdb87e2 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 12:10:58 +0200 Subject: [PATCH 6/8] Update test_usm_ndarray_ctor.py --- dpctl/tests/test_usm_ndarray_ctor.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dpctl/tests/test_usm_ndarray_ctor.py b/dpctl/tests/test_usm_ndarray_ctor.py index df55dcfc48..44c6e865c1 100644 --- a/dpctl/tests/test_usm_ndarray_ctor.py +++ b/dpctl/tests/test_usm_ndarray_ctor.py @@ -2768,10 +2768,16 @@ def test_setitem_copy_as_contig_alignment(dt): assert dpt.all(x[1:, :] == vals) +@pytest.mark.parametrize("dt", _all_dtypes) def test_asarray_property(): - get_queue_or_skip() + q = get_queue_or_skip() - x = dpt.ones(11, dtype="i4") + dtype_ = dpt.dtype(dt) + n0, n1 = 8, 23 - with pytest.raises(TypeError): - np.asarray(x) + x = dpt.eye(n0, n1, dtype=dtype_, sycl_queue=q) + x_np = np.eye(n0, n1, dtype=dt) + + # test __array__ attribute + x_cvt = np.asarray(x) + np.testing.assert_array_equal(x_np, x_cvt) From f184e3cc0c52351bbadcc8458fd46315551c9238 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 12:18:07 +0200 Subject: [PATCH 7/8] Update test_usm_ndarray_ctor.py --- dpctl/tests/test_usm_ndarray_ctor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpctl/tests/test_usm_ndarray_ctor.py b/dpctl/tests/test_usm_ndarray_ctor.py index 44c6e865c1..70938b5d8a 100644 --- a/dpctl/tests/test_usm_ndarray_ctor.py +++ b/dpctl/tests/test_usm_ndarray_ctor.py @@ -2769,7 +2769,7 @@ def test_setitem_copy_as_contig_alignment(dt): @pytest.mark.parametrize("dt", _all_dtypes) -def test_asarray_property(): +def test_asarray_property(dt): q = get_queue_or_skip() dtype_ = dpt.dtype(dt) From 1b8b30b3cc443fd0ab6b2ba76bc0b70b6a74e807 Mon Sep 17 00:00:00 2001 From: Ian Faust Date: Tue, 5 Aug 2025 12:21:05 +0200 Subject: [PATCH 8/8] Update test_usm_ndarray_ctor.py --- dpctl/tests/test_usm_ndarray_ctor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dpctl/tests/test_usm_ndarray_ctor.py b/dpctl/tests/test_usm_ndarray_ctor.py index 70938b5d8a..25d083ca2d 100644 --- a/dpctl/tests/test_usm_ndarray_ctor.py +++ b/dpctl/tests/test_usm_ndarray_ctor.py @@ -2781,3 +2781,7 @@ def test_asarray_property(dt): # test __array__ attribute x_cvt = np.asarray(x) np.testing.assert_array_equal(x_np, x_cvt) + + # test that copy=False is not supported + with pytest.raises(TypeError): + np.asarray(x, copy=False)