Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8d0149e
Remove __bool__ fallback from _is_boolean in _slicing.pxi
vlad-perevezentsev Apr 24, 2026
672a45c
Support range/list as advanced index keys in dpnp_array
vlad-perevezentsev Apr 24, 2026
7ef44b7
Add tests for range/list advanced indexing
vlad-perevezentsev Apr 24, 2026
5f5b0b1
Update changelog
vlad-perevezentsev Apr 24, 2026
830ef88
Handle list/empty list advanced indexing correctly
vlad-perevezentsev Apr 24, 2026
18bb358
Apply remark
vlad-perevezentsev Apr 28, 2026
e64845c
Merge master into fix_inplace_indexind_4d
vlad-perevezentsev Apr 28, 2026
87388b4
Merge master into fix_inplace_indexind_4d
vlad-perevezentsev Apr 29, 2026
688a9bf
Merge branch 'master' into fix_inplace_indexind_4d
vlad-perevezentsev May 4, 2026
4523353
Support buffer protocol objects as index keys
vlad-perevezentsev May 4, 2026
fc5b54f
Add tests for buffer protocol advanced indexing
vlad-perevezentsev May 4, 2026
c883880
Update changelog
vlad-perevezentsev May 4, 2026
e667acb
Merge master into support_buffer_protocol_indexing
vlad-perevezentsev May 6, 2026
dc77d6e
Apply remarks
vlad-perevezentsev May 6, 2026
f00b22e
Add test_invalid_index to TestIndexing
vlad-perevezentsev May 6, 2026
8d4b426
Merge remote-tracking branch 'origin' into support_buffer_protocol_in…
vlad-perevezentsev May 11, 2026
a41a494
Apply remark
vlad-perevezentsev May 11, 2026
150d7a3
Merge remote-tracking branch 'origin/master' into support_buffer_prot…
vlad-perevezentsev May 13, 2026
f8a5f40
Merge remote-tracking branch 'origin/master' into support_buffer_prot…
vlad-perevezentsev May 19, 2026
4a5023e
Apply remark
vlad-perevezentsev May 19, 2026
de9938d
Merge branch 'master' into support_buffer_protocol_indexing
antonwolfy May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This release is compatible with NumPy 2.4.5.
### Added

* Added C API functions for `dpnp.tensor.usm_ndarray` setters and getters to avoid ABI breakage if `dpnp.tensor.usm_ndarray` is modified [gh-2866](https://github.com/IntelPython/dpnp/pull/2866)
* Added support for buffer protocol objects as advanced index keys in `dpnp.ndarray` [#2889](https://github.com/IntelPython/dpnp/pull/2889)

### Changed

Expand Down
38 changes: 22 additions & 16 deletions dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,35 +52,41 @@ def _unwrap_index_element(x):
"""
Unwrap a single index element for the tensor indexing layer.

Converts dpnp arrays to usm_ndarray and array-like objects (range, list)
to numpy arrays with intp dtype for NumPy-compatible advanced indexing.
Converts dpnp arrays to usm_ndarray and array-like objects (range, list,
Comment thread
vlad-perevezentsev marked this conversation as resolved.
buffer protocol objects) to numpy arrays for NumPy-compatible advanced
indexing. Scalars and slices pass through to the tensor layer.

"""

if isinstance(x, dpt.usm_ndarray):
if (
x is None
or x is Ellipsis
or isinstance(x, (dpt.usm_ndarray, slice, numpy.ndarray))
):
return x
if isinstance(x, dpnp_array):
return x.get_array()
if isinstance(x, range):
return numpy.asarray(x, dtype=numpy.intp)
if isinstance(x, list):
# keep boolean lists as boolean
arr = numpy.asarray(x)
# cast empty lists (float64 in NumPy) to intp
# for correct tensor indexing
if arr.size == 0:
arr = arr.astype(numpy.intp)
return arr
return x
# scalars (int, bool, numpy scalars) pass through to the tensor layer
if isinstance(x, (int, numpy.generic)):
return x

# convert array-like objects (range, list, buffer protocol) to numpy
arr = numpy.asarray(x)
# cast empty arrays (float64 in NumPy) to intp
# for correct tensor indexing
if arr.size == 0:
arr = arr.astype(numpy.intp)
return arr


def _get_unwrapped_index_key(key):
"""
Get an unwrapped index key.

Return a key where each nested instance of DPNP array is unwrapped into
USM ndarray, and array-like objects (range, list) are converted to numpy
arrays for further processing in advanced indexing functions.
USM ndarray, and array-like objects (range, list, buffer protocol objects)
are converted to numpy arrays for further processing in advanced
indexing functions.

"""

Expand Down
60 changes: 60 additions & 0 deletions dpnp/tests/test_indexing.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import array
import functools

import dpctl
Expand Down Expand Up @@ -406,6 +407,65 @@ def test_array_like_single_index(self, idx):
dp_a = dpnp.arange(24).reshape(2, 3, 4)
assert_array_equal(dp_a[idx], np_a[idx])

def test_buffer_protocol_getitem(self):
inds = array.array("l")
inds.frombytes(numpy.arange(3).tobytes())
np_a = numpy.arange(12).reshape(3, 4)
dp_a = dpnp.arange(12).reshape(3, 4)
assert_array_equal(dp_a[inds], np_a[inds])

def test_buffer_protocol_paired_index(self):
inds = array.array("l")
inds.frombytes(numpy.arange(3).tobytes())
np_a = numpy.arange(12).reshape(3, 4)
dp_a = dpnp.arange(12).reshape(3, 4)
assert_array_equal(dp_a[inds, inds], np_a[inds, inds])

def test_buffer_protocol_setitem(self):
inds = array.array("l")
inds.frombytes(numpy.arange(3).tobytes())
np_a = numpy.arange(12).reshape(3, 4)
dp_a = dpnp.arange(12).reshape(3, 4)
np_a[inds, inds] = 0
dp_a[inds, inds] = 0
assert_array_equal(dp_a, np_a)

def test_memoryview_getitem(self):
inds = memoryview(array.array("l", [0, 1, 2]))
np_a = numpy.arange(12).reshape(3, 4)
dp_a = dpnp.arange(12).reshape(3, 4)
assert_array_equal(dp_a[inds], np_a[inds])

def test_bytearray_getitem(self):
inds = bytearray(b"\x00\x01\x02")
np_a = numpy.arange(10)
dp_a = dpnp.arange(10)
assert_array_equal(dp_a[inds], np_a[inds])

@pytest.mark.parametrize(
"idx",
[
1.0,
1 + 0j,
numpy.float64(1.0),
numpy.complex128(1.0),
"a",
[0.5, 1.5],
],
ids=[
"float",
"complex",
"np.float64",
"np.complex128",
"str",
"float_list",
],
)
def test_invalid_index(self, idx):
dp_a = dpnp.arange(12).reshape(3, 4)
with pytest.raises((IndexError, TypeError)):
dp_a[idx]


class TestIx:
@pytest.mark.parametrize(
Expand Down
Loading