diff --git a/CHANGELOG.md b/CHANGELOG.md index 61cde1ddfefc..b6f419f215c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum * Resolved an issue causing `dpnp.linspace` to return an incorrect output shape when inputs were passed as arrays [#2712](https://github.com/IntelPython/dpnp/pull/2712) * Resolved an issue where `dpnp` always returns the base allocation pointer, when the view start is expected [#2651](https://github.com/IntelPython/dpnp/pull/2651) * Fixed an issue causing an exception in `dpnp.geomspace` and `dpnp.logspace` when called with explicit `device` keyword but any input array is allocated on another device [#2723](https://github.com/IntelPython/dpnp/pull/2723) +* Fixed `.data.ptr` property on array views to correctly return the pointer to the view's data location instead of the base allocation pointer [#2812](https://github.com/IntelPython/dpnp/pull/2812) ### Security diff --git a/dpnp/memory/_memory.py b/dpnp/memory/_memory.py index f978c5e50db2..70d93c04d6a5 100644 --- a/dpnp/memory/_memory.py +++ b/dpnp/memory/_memory.py @@ -98,13 +98,18 @@ def create_data(x): usm_data = x.usm_data if isinstance(usm_data, tuple(dispatch.values())): - return usm_data - - cls = dispatch.get(type(usm_data), None) - if cls: - data = cls(usm_data) - # `ptr` is expecting to point at the start of the array's data, - # while `usm_data._pointer` is a pointer at the start of memory buffer - data.ptr = x._pointer - return data - raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + # usm_data is already an instance of MemoryUSM class + cls = usm_data.__class__ + elif (cls := dispatch.get(type(usm_data))) is not None: + pass # cls is set + else: + raise TypeError(f"Expected USM memory, but got {type(usm_data)}") + + # create a new instance each time since usm_data might be a view + # of another array + data = cls(usm_data) + + # `ptr` is expecting to point at the start of the array's data, + # while `usm_data._pointer` is a pointer at the start of memory buffer + data.ptr = x._pointer + return data diff --git a/dpnp/tests/test_memory.py b/dpnp/tests/test_memory.py index 1bc0da8c1535..80d75f32a437 100644 --- a/dpnp/tests/test_memory.py +++ b/dpnp/tests/test_memory.py @@ -42,3 +42,62 @@ def test_view_non_zero_offset(self): pl = dpnp.ndarray((n, m), dtype=a.dtype, buffer=sl) assert pl.data.ptr == sl.data.ptr assert a.data.ptr != sl.data.ptr + + def test_slices_2d(self): + # Create 2D array and verify slices have different pointers + a = dpnp.arange(12, dtype=dpnp.float32).reshape(3, 4) + + # Each row should have a different pointer + row0_ptr = a[0].data.ptr + row1_ptr = a[1].data.ptr + row2_ptr = a[2].data.ptr + + assert ( + row0_ptr != row1_ptr + ), "a[0] and a[1] should have different pointers" + assert ( + row1_ptr != row2_ptr + ), "a[1] and a[2] should have different pointers" + + # Check byte offsets match expected stride + stride = a.strides[0] # stride between rows in bytes + assert row1_ptr - row0_ptr == stride + assert row2_ptr - row1_ptr == stride + + def test_slices_multidimensional(self): + # 3D array + a = dpnp.zeros((5, 10, 20), dtype=dpnp.int32) + + # Different slices along first axis should have different pointers + slice0_ptr = a[0].data.ptr + slice1_ptr = a[1].data.ptr + + assert slice0_ptr != slice1_ptr + assert slice1_ptr - slice0_ptr == a.strides[0] + + def test_repeated_access(self): + a = dpnp.arange(20).reshape(4, 5) + + # Multiple accesses to same slice should give same ptr value + ptr1 = a[2].data.ptr + ptr2 = a[2].data.ptr + + assert ptr1 == ptr2, "Same slice should have consistent ptr value" + + # But different slices should have different ptrs + assert a[0].data.ptr != a[2].data.ptr + + def test_array_on_view_with_slicing(self): + # Original array + a = dpnp.arange(24, dtype=dpnp.float32).reshape(6, 4) + + # Create view using slicing + view = a[2:5] + + # Construct new array from view + new_arr = dpnp.ndarray(view.shape, dtype=view.dtype, buffer=view) + + # Pointers should match + assert new_arr.data.ptr == view.data.ptr + # And should be different from base array + assert new_arr.data.ptr != a.data.ptr