Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2a00b75
BUG: Random integer ranges should use uint internally
antonwolfy Aug 13, 2026
e08a5dc
Avoid extra host copy when uploading a non-contiguous NumPy array
antonwolfy Aug 13, 2026
b6755c2
Reject CUB block reduction for short (<128) partial reductions
antonwolfy Aug 13, 2026
d06b5d1
Migrate test_raw.py to using pytest
antonwolfy Aug 13, 2026
9875eb9
Fix typo in imports in test_generator_api.py
antonwolfy Aug 13, 2026
4772462
Add cumulative_sum and cumulative_prod (Array API)
antonwolfy Aug 17, 2026
8bd072e
Address casting negative stride as unsigned int in dlpack
antonwolfy Sep 7, 2026
432c20a
TST: Mark test as thread-unsafe (mutates global pinned allocator)
antonwolfy Sep 7, 2026
55b0b2a
Support Numpy 2.5
antonwolfy Sep 7, 2026
17d211d
Fix rfftn/fftn shape mismatch when s and non-default axes are given t…
antonwolfy Sep 10, 2026
2a59f73
Harden custom scan along axes against overflows
antonwolfy Sep 10, 2026
6da39f4
Support and test SciPy 1.18
antonwolfy Sep 25, 2026
9770345
API: Add shape argument to cupy.reshape
antonwolfy Sep 25, 2026
2b4992a
Add cupy.linalg.tensordot
antonwolfy Sep 25, 2026
b06958a
Keep old PlanNd arguments (and attributes)
antonwolfy Sep 25, 2026
1da7fd1
Guard batch-scan cum(sum|prod) tests against non-fp64 devices
antonwolfy Sep 29, 2026
d0df49c
Mute expected float32 overflow warning in batch cumprod test
antonwolfy Sep 29, 2026
8870286
Merge branch 'master' into update-third-party-tests
antonwolfy Sep 30, 2026
f20a03d
Use device-supported float dtype in argmax/argmin overflow tests
antonwolfy Oct 1, 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
26 changes: 20 additions & 6 deletions dpnp/tests/third_party/cupy/core_tests/test_cub_reduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,22 @@ def _test_can_use(self, i_shape, o_shape, r_axis, o_axis, order, expected):
assert result is expected


@pytest.mark.parametrize("shape", [(2,), (2, 3), (2, 3, 4), (2, 3, 4, 5)])
@pytest.mark.parametrize("order", ["C", "F"])
_MIN_SIZE = cupy._core._cub_reduction._CUB_REDUCE_SIZE_THRESHOLD


@pytest.mark.parametrize(
"shape",
[
(_MIN_SIZE,),
(_MIN_SIZE, _MIN_SIZE + 1),
(_MIN_SIZE, 3, _MIN_SIZE + 1),
(_MIN_SIZE, 3, 4, _MIN_SIZE + 1),
],
)
@pytest.mark.parametrize(
"order",
["C", "F"],
)
class TestSimpleCubReductionKernelContiguity(CubReductionTestBase):

@testing.for_contiguous_axes()
Expand Down Expand Up @@ -139,15 +153,15 @@ def test_can_use_cub_oversize_input4(self):
b = cupy.empty((), dtype=cupy.int8)
assert self.can_use([a], [b], (1,), (0,)) is None

# thread_unsafe marker requires pytest-run-parallel, not used by dpnp
# @pytest.mark.thread_unsafe(
# reason="AssertFunctionIsCalled and accelerate mutation.")
@pytest.mark.thread_unsafe(
reason="AssertFunctionIsCalled and accelerate mutation."
)
def test_can_use_accelerator_set_unset(self):
# ensure we use CUB block reduction and not CUB device reduction
old_routine_accelerators = _accelerator.get_routine_accelerators()
_accelerator.set_routine_accelerators([])

a = cupy.random.random((10, 10))
a = cupy.random.random((10, _cub_reduction._CUB_REDUCE_SIZE_THRESHOLD))
# this is the only function we can mock; the rest is cdef'd
func_name = "".join(
(
Expand Down
85 changes: 85 additions & 0 deletions dpnp/tests/third_party/cupy/core_tests/test_dlpack.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import ctypes

import dpctl
import numpy
import pytest
Expand All @@ -8,6 +10,12 @@
import dpnp.tensor._dlpack as dlp
from dpnp.tests.third_party.cupy import testing

ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [
ctypes.py_object,
ctypes.c_char_p,
]


# TODO: to roll back the changes once the issue with CUDA support is resolved for random
def _gen_array(dtype, alloc_q=None):
Expand All @@ -29,6 +37,32 @@ def _gen_array(dtype, alloc_q=None):
return cupy.asarray(array, sycl_queue=alloc_q).astype(dtype)


def _inspect_dlpack(capsule):
ptr = ctypes.pythonapi.PyCapsule_GetPointer(capsule, b"dltensor")
managed = ctypes.cast(ptr, ctypes.POINTER(DLManagedTensor)).contents
tensor = managed.dl_tensor

shape = [tensor.shape[i] for i in range(tensor.ndim)]
strides = None
if tensor.strides:
strides = [tensor.strides[i] for i in range(tensor.ndim)]

return {
"data": tensor.data,
"device_type": tensor.device.device_type,
"device_id": tensor.device.device_id,
"ndim": tensor.ndim,
"dtype": {
"code": tensor.dtype.code,
"bits": tensor.dtype.bits,
"lanes": tensor.dtype.lanes,
},
"shape": shape,
"strides": strides,
"byte_offset": tensor.byte_offset,
}


class DLDummy:
"""Dummy object to wrap a __dlpack__ capsule, so we can use from_dlpack."""

Expand All @@ -43,6 +77,41 @@ def __dlpack_device__(self):
return self.device


class DLDevice(ctypes.Structure):
_fields_ = [
("device_type", ctypes.c_int32),
("device_id", ctypes.c_int32),
]


class DLDataType(ctypes.Structure):
_fields_ = [
("code", ctypes.c_uint8),
("bits", ctypes.c_uint8),
("lanes", ctypes.c_uint16),
]


class DLTensor(ctypes.Structure):
_fields_ = [
("data", ctypes.c_void_p),
("device", DLDevice),
("ndim", ctypes.c_int32),
("dtype", DLDataType),
("shape", ctypes.POINTER(ctypes.c_int64)),
("strides", ctypes.POINTER(ctypes.c_int64)),
("byte_offset", ctypes.c_uint64),
]


class DLManagedTensor(ctypes.Structure):
_fields_ = [
("dl_tensor", DLTensor),
("manager_ctx", ctypes.c_void_p),
("deleter", ctypes.c_void_p),
]


@pytest.mark.skip("toDlpack() and fromDlpack() are not supported")
class TestDLPackConversion:

Expand Down Expand Up @@ -295,3 +364,19 @@ def test_multiple_consumption_error(self, recwarn):
assert "consumed multiple times" in str(e.value)
for w in recwarn:
assert issubclass(w.category, cupy.VisibleDeprecationWarning)


class TestDLTensorContent:
@pytest.fixture(scope="class")
@classmethod
def configure(cls):
arr = _gen_array("uint32")
arr_flip = cupy.transpose(cupy.flip(arr, axis=1), (1, 0))
info = _inspect_dlpack(arr_flip.__dlpack__())
yield arr_flip, info

def test_strides(self, configure):
arr, dlpack_interface = configure
array_strides = tuple(s // arr.itemsize for s in arr.strides)
dlpack_strides = tuple(dlpack_interface["strides"])
assert array_strides == dlpack_strides
110 changes: 101 additions & 9 deletions dpnp/tests/third_party/cupy/core_tests/test_ndarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,56 @@ class UserNdarray(cupy.ndarray):
b.custom_attr = 100


@testing.parameterize(
*testing.product(
{
"np_order": ["C", "F"],
"np_pinned": [False], # no pinned memory
"pinned_alloc_fails": [False], # no pinned memory
"cp_setup": [
("C", False, (48, 16, 4)),
("C", True, (16, 4)),
("F", False, (4, 8, 24)),
("F", True, (4, 8)),
],
}
)
)
class TestAsarray(unittest.TestCase):
# @pytest.mark.thread_unsafe(reason="mutates global pinned allocator.")
def test_asarray(self):
cp_order, view, strides = self.cp_setup
shape = (2, 3, 4)
if self.np_pinned:
count = numpy.prod(shape)
dtype = numpy.float32()
pinned_ptr = cupy.cuda.alloc_pinned_memory(count * dtype.itemsize)
a_cpu = numpy.frombuffer(
pinned_ptr, dtype=dtype, count=count
).reshape(shape)
else:
a_cpu = numpy.ndarray(
shape, dtype=numpy.float32, order=self.np_order
)
a_cpu[...] = numpy.arange(a_cpu.size).reshape(a_cpu.shape)
if view:
a_cpu = a_cpu[:, 1, :]
try:
if self.pinned_alloc_fails:
cupy.cuda.set_pinned_memory_allocator(lambda _: None)
a = cupy.asarray(a_cpu, order=cp_order)
finally:
# None means "no pool", not "the default pool"
# cupy.cuda.set_pinned_memory_allocator(
# cupy.get_default_pinned_memory_pool().malloc
# )
pass
assert a.flags.c_contiguous == (cp_order == "C")
assert a.flags.f_contiguous == (cp_order == "F")
assert a.strides == strides
testing.assert_array_equal(a_cpu, a)


@testing.parameterize(
*testing.product(
{
Expand Down Expand Up @@ -249,9 +299,11 @@ def test_copy_multi_device_non_contiguous_K(self):
@testing.multi_gpu(2)
# @pytest.mark.xfail(
# runtime.is_hip,
# reason='ROCm may work differently in async D2D copy with streams')
# reason="ROCm may work differently in async D2D copy with streams",
# )
# @pytest.mark.thread_unsafe(
# reason="order is unclear multithread. Also, hard crash in threaded!")
# reason="order is unclear multithread. Also, hard crash in threaded!"
# )
def test_copy_multi_device_with_stream(self):
# Kernel that takes long enough then finally writes values.
src = _test_copy_multi_device_with_stream_src
Expand All @@ -278,14 +330,16 @@ def test_copy_multi_device_with_stream(self):
)


@pytest.mark.filterwarnings(
# Shape setting is deprecated starting NumPy 2.5
"ignore::DeprecationWarning"
)
class TestNdarrayShape(unittest.TestCase):

@testing.with_requires("numpy>=2.5")
@testing.numpy_cupy_array_equal()
def test_shape_set(self, xp):
arr = xp.ndarray((2, 3))
with testing.assert_warns(DeprecationWarning):
arr.shape = (3, 2)
arr.shape = (3, 2)
return xp.array(arr.shape)

@pytest.mark.skip(
Expand All @@ -298,15 +352,12 @@ def test_shape_set_infer(self, xp):
arr.shape = (3, -1)
return xp.array(arr.shape)

@testing.with_requires("numpy>=2.5")
@testing.numpy_cupy_array_equal()
def test_shape_set_int(self, xp):
arr = xp.ndarray((2, 3))
with testing.assert_warns(DeprecationWarning):
arr.shape = 6
arr.shape = 6
return xp.array(arr.shape)

@pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_shape_need_copy(self):
# from cupy/cupy#5470
for xp in (numpy, cupy):
Expand Down Expand Up @@ -563,6 +614,47 @@ def test_shape_mismatch(self):
wrap_take(a, i, out=o)


@testing.parameterize(
{"shape": (3, 4, 5), "indices": (2, 3), "out_shape": (2, 3)},
{"shape": (), "indices": (), "out_shape": ()},
)
class TestNdarrayTakeTypeMismatch(unittest.TestCase):
# NOTE(seberg): Historically cupy was always fully restrictive
# while NumPy was just wrong: https://github.com/numpy/numpy/pull/30615
# As of CuPy 14.2, CuPy uses 2.5+ (future) behavior.

@testing.with_requires("numpy>=2.5")
@testing.numpy_cupy_array_equal()
# incorrectly given by numpy (presumably until Deprecation is finalized)
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
def test_output_dtype_same_kind_ok(self, xp):
# After NumPy 2.5, NumPy gets the cast safety right, the following
# is OK under same-kind casting rules.
a = testing.shaped_arange(self.shape, xp, numpy.int64)
i = testing.shaped_arange(self.indices, xp, numpy.int32) % 3
results = []
for out_dtype in (numpy.complex64, numpy.int32):
o = testing.shaped_arange(self.out_shape, xp, out_dtype)
results.append(wrap_take(a, i, out=o))
return results

@pytest.mark.skip()
@pytest.mark.filterwarnings(
"error:Implicit casting of output dtype:DeprecationWarning"
)
def test_output_dtype_unsafe_rejected(self):
for xp in (numpy, cupy):
a = testing.shaped_arange(self.shape, xp, numpy.float32)
i = testing.shaped_arange(self.indices, xp, numpy.int32) % 3
o = testing.shaped_arange(self.out_shape, xp, numpy.int32)
# As of NumPy 2.5 this is a deprecation warning, but CuPy never
# allowed it (so no deprecation required)
if xp is numpy and not testing.numpy_satisfies(">=2.5"):
continue
with pytest.warns((TypeError, DeprecationWarning)):
wrap_take(a, i, out=o)


@testing.parameterize(
{"shape": (0,), "indices": (0,), "axis": None},
{"shape": (0,), "indices": (0, 1), "axis": None},
Expand Down
27 changes: 12 additions & 15 deletions dpnp/tests/third_party/cupy/core_tests/test_ndarray_reduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import pytest

import dpnp as cupy

# import cupy._core._accelerator as _acc
# from cupy._core import _cub_reduction
from dpnp.tests.third_party.cupy import testing


Expand Down Expand Up @@ -34,11 +37,10 @@ def exclude_cutensor(cls):
# pass
# _acc.set_reduction_accelerators(red_acc)

# yield
yield

# _acc.set_routine_accelerators(old_routine_accelerators)
# _acc.set_reduction_accelerators(old_reduction_accelerators)
pass

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose(contiguous_check=False)
Expand Down Expand Up @@ -298,15 +300,7 @@ def _axes_for_shape(shape):
"shape,axis",
[
(shape, axis)
for shape in [
(),
(0,),
(0, 2),
(2, 0),
(0, 2, 3),
(2, 0, 3),
(2, 3, 0),
]
for shape in [(), (0,), (0, 2), (2, 0), (0, 2, 3), (2, 0, 3), (2, 3, 0)]
for axis in _axes_for_shape(shape)
],
)
Expand All @@ -331,13 +325,16 @@ def test_zero_size(self, xp, shape, axis, order, func):

# This class compares CUB results against NumPy's. ("fallback" is CuPy's
# original kernel, also tested here to reduce code duplication.)
# Non-empty shapes keep both the first and last axis >= 128 so the
# contiguous reduction stays on the CUB block-reduction path rather than
# the short-axis fallback.
@pytest.mark.parametrize(
"shape",
[
(10,),
(10, 20),
(10, 20, 30),
(10, 20, 30, 40),
(128,),
(128, 128),
(128, 2, 128),
(128, 2, 2, 128),
# skip (2, 3, 0) because it would not hit the CUB code path
(0,),
(2, 0),
Expand Down
Loading
Loading