From 426da5179345158f9f60390f576453ff2fc1a5ea Mon Sep 17 00:00:00 2001 From: Alexander Kalistratov Date: Fri, 14 Feb 2025 01:58:46 +0100 Subject: [PATCH] Add integer dtypes (int8, int16, uint8-uint64) to dpnp interface (#2230) Add missing aliases to integer types: [u]byte, ushort, [u]longlong Not adding [u]long aliases as it is removed from NumPy (https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations) Removed int alias as it is depricate in NumPy Extend tests types matrix by these types Add environment variable DPNP_TEST_ALL_INT_TYPES to enable/disable these types in tests. --- .github/workflows/array-api-skips.txt | 3 - .github/workflows/conda-package.yml | 37 ++- doc/reference/dtypes_table.rst | 15 +- dpnp/dpnp_algo/dpnp_elementwise_common.py | 16 +- dpnp/dpnp_iface_linearalgebra.py | 32 ++- dpnp/dpnp_iface_manipulation.py | 13 + dpnp/dpnp_iface_types.py | 32 ++- dpnp/dpnp_utils/dpnp_utils_linearalgebra.py | 234 +++++++++--------- dpnp/fft/dpnp_utils_fft.py | 5 +- dpnp/tests/config.py | 6 + dpnp/tests/helper.py | 48 +++- dpnp/tests/test_absolute.py | 4 +- dpnp/tests/test_amin_amax.py | 32 ++- dpnp/tests/test_array_api_info.py | 38 +-- dpnp/tests/test_arraycreation.py | 25 +- dpnp/tests/test_arraypad.py | 30 ++- dpnp/tests/test_binary_ufuncs.py | 118 ++++++--- dpnp/tests/test_bitwise.py | 81 ++++-- dpnp/tests/test_dtype_routines.py | 3 +- dpnp/tests/test_fft.py | 5 +- dpnp/tests/test_histogram.py | 29 ++- dpnp/tests/test_indexing.py | 213 ++++++++-------- dpnp/tests/test_linalg.py | 15 +- dpnp/tests/test_manipulation.py | 6 +- dpnp/tests/test_mathematical.py | 200 +++++++++------ dpnp/tests/test_nanfunctions.py | 7 +- dpnp/tests/test_ndarray.py | 7 +- dpnp/tests/test_outer.py | 6 +- dpnp/tests/test_product.py | 117 +++++---- dpnp/tests/test_random_state.py | 22 +- dpnp/tests/test_sort.py | 9 +- dpnp/tests/test_statistics.py | 10 +- dpnp/tests/test_strides.py | 33 ++- dpnp/tests/test_sum.py | 23 +- dpnp/tests/test_sycl_queue.py | 1 + dpnp/tests/test_umath.py | 27 +- dpnp/tests/test_usm_type.py | 1 + .../cupy/core_tests/test_elementwise.py | 46 +++- .../core_tests/test_ndarray_complex_ops.py | 5 +- .../core_tests/test_ndarray_copy_and_view.py | 2 +- .../cupy/creation_tests/test_ranges.py | 8 +- .../cupy/indexing_tests/test_indexing.py | 4 + .../cupy/linalg_tests/test_einsum.py | 16 +- .../cupy/linalg_tests/test_product.py | 27 +- .../cupy/logic_tests/test_comparison.py | 3 +- .../cupy/math_tests/test_matmul.py | 19 +- .../third_party/cupy/math_tests/test_misc.py | 3 +- .../cupy/math_tests/test_trigonometric.py | 4 +- .../cupy/random_tests/test_distributions.py | 6 +- .../cupy/random_tests/test_permutations.py | 30 +++ .../cupy/sorting_tests/test_sort.py | 3 + dpnp/tests/third_party/cupy/testing/_loops.py | 102 ++++++-- 52 files changed, 1154 insertions(+), 627 deletions(-) create mode 100644 dpnp/tests/config.py diff --git a/.github/workflows/array-api-skips.txt b/.github/workflows/array-api-skips.txt index 1da2bc1ee5d..6582f9d7cca 100644 --- a/.github/workflows/array-api-skips.txt +++ b/.github/workflows/array-api-skips.txt @@ -1,8 +1,5 @@ # array API tests to be skipped -# no 'uint8' dtype -array_api_tests/test_array_object.py::test_getitem_masking - # missing unique-like functions array_api_tests/test_has_names.py::test_has_names[set-unique_all] array_api_tests/test_has_names.py::test_has_names[set-unique_counts] diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 39f0cf21fa5..8994eb72473 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -16,6 +16,7 @@ env: CONDA_BUILD_INDEX_ENV_PY_VER: '3.12' # conda does not support python 3.13 CONDA_BUILD_VERSION: '25.1.1' CONDA_INDEX_VERSION: '0.5.0' + LATEST_PYTHON: '3.13' RERUN_TESTS_ON_FAILURE: 'true' RUN_TESTS_MAX_ATTEMPTS: 2 TEST_ENV_NAME: 'test' @@ -189,7 +190,7 @@ jobs: id: install_dpnp continue-on-error: true run: | - mamba install ${{ env.PACKAGE_NAME }}=${{ env.PACKAGE_VERSION }} pytest python=${{ matrix.python }} ${{ env.TEST_CHANNELS }} + mamba install ${{ env.PACKAGE_NAME }}=${{ env.PACKAGE_VERSION }} pytest pytest-xdist python=${{ matrix.python }} ${{ env.TEST_CHANNELS }} env: TEST_CHANNELS: '-c ${{ env.channel-path }} ${{ env.CHANNELS }}' @@ -211,14 +212,19 @@ jobs: - name: Run tests if: env.RERUN_TESTS_ON_FAILURE != 'true' run: | - python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + if [[ ${{ matrix.python }} == ${{ env.LATEST_PYTHON }} ]]; then + export DPNP_TEST_ALL_INT_TYPES=1 + python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + else + python -m pytest -n auto -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + fi - name: Run tests if: env.RERUN_TESTS_ON_FAILURE == 'true' id: run_tests_linux uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 with: - timeout_minutes: 15 + timeout_minutes: 25 max_attempts: ${{ env.RUN_TESTS_MAX_ATTEMPTS }} retry_on: any command: | @@ -226,7 +232,12 @@ jobs: . $CONDA/etc/profile.d/mamba.sh mamba activate ${{ env.TEST_ENV_NAME }} - python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + if [[ ${{ matrix.python }} == ${{ env.LATEST_PYTHON }} ]]; then + export DPNP_TEST_ALL_INT_TYPES=1 + python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + else + python -m pytest -n auto -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + fi test_windows: name: Test @@ -319,7 +330,7 @@ jobs: - name: Install dpnp run: | @echo on - mamba install ${{ env.PACKAGE_NAME }}=${{ env.PACKAGE_VERSION }} pytest python=${{ matrix.python }} ${{ env.TEST_CHANNELS }} + mamba install ${{ env.PACKAGE_NAME }}=${{ env.PACKAGE_VERSION }} pytest pytest-xdist python=${{ matrix.python }} ${{ env.TEST_CHANNELS }} env: TEST_CHANNELS: '-c ${{ env.channel-path }} ${{ env.CHANNELS }}' MAMBA_NO_LOW_SPEED_LIMIT: 1 @@ -348,18 +359,28 @@ jobs: - name: Run tests if: env.RERUN_TESTS_ON_FAILURE != 'true' run: | - pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + if (${{ matrix.python }} -eq ${{ env.LATEST_PYTHON }}) { + set DPNP_TEST_ALL_INT_TYPES=1 + python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + } else { + python -m pytest -n auto -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + } - name: Run tests if: env.RERUN_TESTS_ON_FAILURE == 'true' id: run_tests_win uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 with: - timeout_minutes: 17 + timeout_minutes: 35 max_attempts: ${{ env.RUN_TESTS_MAX_ATTEMPTS }} retry_on: any command: | - python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + if ( ${{ matrix.python }} -eq ${{ env.LATEST_PYTHON }} ) { + set DPNP_TEST_ALL_INT_TYPES=1 + python -m pytest -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + } else { + python -m pytest -n auto -ra --pyargs ${{ env.PACKAGE_NAME }}.tests + } upload: name: Upload diff --git a/doc/reference/dtypes_table.rst b/doc/reference/dtypes_table.rst index 6d851da401a..40cf3d742b3 100644 --- a/doc/reference/dtypes_table.rst +++ b/doc/reference/dtypes_table.rst @@ -13,22 +13,35 @@ Table below shows a list of all supported data types (dtypes) and constants of t - Constants * - - :obj:`bool ` + - :obj:`int8 ` + - :obj:`int16 ` - :obj:`int32 ` - :obj:`int64 ` + - :obj:`uint8 ` + - :obj:`uint16 ` + - :obj:`uint32 ` + - :obj:`uint64 ` - :obj:`float32 ` - :obj:`float64 ` - :obj:`complex64 ` - :obj:`complex128 ` - - :obj:`bool_ ` + - :obj:`byte ` - :obj:`cdouble ` - :obj:`csingle ` - :obj:`double ` - :obj:`float16 ` - - :obj:`int ` - :obj:`int_ ` - :obj:`intc ` + - :obj:`intp ` + - :obj:`longlong ` - :obj:`single ` + - :obj:`ubyte ` + - :obj:`uintc ` + - :obj:`uintp ` + - :obj:`ushort ` + - :obj:`ulonglong ` - - :obj:`e ` - :obj:`euler_gamma ` diff --git a/dpnp/dpnp_algo/dpnp_elementwise_common.py b/dpnp/dpnp_algo/dpnp_elementwise_common.py index 815eca64b9c..be0e357a0cc 100644 --- a/dpnp/dpnp_algo/dpnp_elementwise_common.py +++ b/dpnp/dpnp_algo/dpnp_elementwise_common.py @@ -600,12 +600,18 @@ def __init__( def __call__(self, x, decimals=0, out=None, dtype=None): if decimals != 0: x_usm = dpnp.get_usm_ndarray(x) - if dpnp.issubdtype(x_usm.dtype, dpnp.integer) and dtype is None: - dtype = x_usm.dtype - out_usm = None if out is None else dpnp.get_usm_ndarray(out) - x_usm = dpt.round(x_usm * 10**decimals, out=out_usm) - res_usm = dpt.divide(x_usm, 10**decimals, out=out_usm) + + if dpnp.issubdtype(x_usm.dtype, dpnp.integer): + if decimals < 0: + dtype = x_usm.dtype + x_usm = dpt.round(x_usm * 10**decimals, out=out_usm) + res_usm = dpt.divide(x_usm, 10**decimals, out=out_usm) + else: + res_usm = dpt.round(x_usm, out=out_usm) + else: + x_usm = dpt.round(x_usm * 10**decimals, out=out_usm) + res_usm = dpt.divide(x_usm, 10**decimals, out=out_usm) if dtype is not None: res_usm = dpt.astype(res_usm, dtype, copy=False) diff --git a/dpnp/dpnp_iface_linearalgebra.py b/dpnp/dpnp_iface_linearalgebra.py index 8c199bdd375..24303ba8c70 100644 --- a/dpnp/dpnp_iface_linearalgebra.py +++ b/dpnp/dpnp_iface_linearalgebra.py @@ -37,10 +37,12 @@ """ +# pylint: disable=no-name-in-module import numpy import dpnp +from .dpnp_utils import map_dtype_to_device from .dpnp_utils.dpnp_utils_einsum import dpnp_einsum from .dpnp_utils.dpnp_utils_linearalgebra import ( dpnp_dot, @@ -66,6 +68,20 @@ ] +# TODO: implement a specific scalar-array kernel +def _call_multiply(a, b, out=None): + """Call multiply function for special cases of scalar-array dots.""" + + sc, arr = (a, b) if dpnp.isscalar(a) else (b, a) + sc_dtype = map_dtype_to_device(type(sc), arr.sycl_device) + res_dtype = dpnp.result_type(sc_dtype, arr) + if out is not None and out.dtype == arr.dtype: + res = dpnp.multiply(a, b, out=out) + else: + res = dpnp.multiply(a, b, dtype=res_dtype) + return dpnp.get_result_array(res, out, casting="no") + + def dot(a, b, out=None): """ Dot product of `a` and `b`. @@ -139,8 +155,7 @@ def dot(a, b, out=None): raise ValueError("Only C-contiguous array is acceptable.") if dpnp.isscalar(a) or dpnp.isscalar(b): - # TODO: use specific scalar-vector kernel - return dpnp.multiply(a, b, out=out) + return _call_multiply(a, b, out=out) a_ndim = a.ndim b_ndim = b.ndim @@ -635,8 +650,7 @@ def inner(a, b): dpnp.check_supported_arrays_type(a, b, scalar_type=True) if dpnp.isscalar(a) or dpnp.isscalar(b): - # TODO: use specific scalar-vector kernel - return dpnp.multiply(a, b) + return _call_multiply(a, b) if a.ndim == 0 or b.ndim == 0: # TODO: use specific scalar-vector kernel @@ -714,8 +728,7 @@ def kron(a, b): dpnp.check_supported_arrays_type(a, b, scalar_type=True) if dpnp.isscalar(a) or dpnp.isscalar(b): - # TODO: use specific scalar-vector kernel - return dpnp.multiply(a, b) + return _call_multiply(a, b) a_ndim = a.ndim b_ndim = b.ndim @@ -1199,8 +1212,7 @@ def tensordot(a, b, axes=2): raise ValueError( "One of the inputs is scalar, axes should be zero." ) - # TODO: use specific scalar-vector kernel - return dpnp.multiply(a, b) + return _call_multiply(a, b) return dpnp_tensordot(a, b, axes=axes) @@ -1263,13 +1275,13 @@ def vdot(a, b): if b.size != 1: raise ValueError("The second array should be of size one.") a_conj = numpy.conj(a) - return dpnp.multiply(a_conj, b) + return _call_multiply(a_conj, b) if dpnp.isscalar(b): if a.size != 1: raise ValueError("The first array should be of size one.") a_conj = dpnp.conj(a) - return dpnp.multiply(a_conj, b) + return _call_multiply(a_conj, b) if a.ndim == 1 and b.ndim == 1: return dpnp_dot(a, b, out=None, conjugate=True) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 0c796c61961..8234bb7916a 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -1494,7 +1494,20 @@ def copyto(dst, src, casting="same_kind", where=True): f"but got {type(dst)}" ) if not dpnp.is_supported_array_type(src): + no_dtype_attr = not hasattr(src, "dtype") src = dpnp.array(src, sycl_queue=dst.sycl_queue) + if no_dtype_attr: + # This case (scalar, list, etc) needs special handling to + # behave similar to NumPy + if dpnp.issubdtype(src, dpnp.integer) and dpnp.issubdtype( + dst, dpnp.unsignedinteger + ): + if dpnp.any(src < 0): + raise OverflowError( + "Cannot copy negative values to an unsigned int array" + ) + + src = src.astype(dst.dtype) if not dpnp.can_cast(src.dtype, dst.dtype, casting=casting): raise TypeError( diff --git a/dpnp/dpnp_iface_types.py b/dpnp/dpnp_iface_types.py index 97a90d213b4..20ffa55f3c4 100644 --- a/dpnp/dpnp_iface_types.py +++ b/dpnp/dpnp_iface_types.py @@ -40,6 +40,7 @@ __all__ = [ "bool", "bool_", + "byte", "cdouble", "complex128", "complex64", @@ -57,8 +58,9 @@ "iinfo", "inexact", "inf", - "int", "int_", + "int8", + "int16", "int32", "int64", "integer", @@ -67,12 +69,24 @@ "isdtype", "issubdtype", "is_type_supported", + "longlong", "nan", "newaxis", "number", "pi", + "short", "signedinteger", "single", + "ubyte", + "uint8", + "uint16", + "uint32", + "uint64", + "uintc", + "uintp", + "unsignedinteger", + "ushort", + "ulonglong", ] @@ -82,6 +96,7 @@ # ============================================================================= bool = numpy.bool_ bool_ = numpy.bool_ +byte = numpy.byte cdouble = numpy.cdouble complex128 = numpy.complex128 complex64 = numpy.complex64 @@ -94,16 +109,29 @@ float64 = numpy.float64 floating = numpy.floating inexact = numpy.inexact -int = numpy.int_ int_ = numpy.int_ +int8 = numpy.int8 +int16 = numpy.int16 int32 = numpy.int32 int64 = numpy.int64 integer = numpy.integer intc = numpy.intc intp = numpy.intp +longlong = numpy.longlong number = numpy.number +short = numpy.short signedinteger = numpy.signedinteger single = numpy.single +ubyte = numpy.ubyte +uint8 = numpy.uint8 +uint16 = numpy.uint16 +uint32 = numpy.uint32 +uint64 = numpy.uint64 +uintc = numpy.uintc +uintp = numpy.uintp +unsignedinteger = numpy.unsignedinteger +ushort = numpy.ushort +ulonglong = numpy.ulonglong # ============================================================================= diff --git a/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py b/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py index 5767fdd4e52..5d200b2ed0f 100644 --- a/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py +++ b/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py @@ -231,6 +231,123 @@ def _define_dim_flags(x, axis): return x_is_2D, x_is_1D, x_base_is_1D +def _gemm_batch_matmul(exec_q, x1, x2, res): + # arrays here are already at least 3D, make them 3D + x1_shape = x1.shape + x2_shape = x2.shape + x1 = dpnp.reshape(x1, (-1, x1_shape[-2], x1_shape[-1])) + x2 = dpnp.reshape(x2, (-1, x2_shape[-2], x2_shape[-1])) + orig_shape = res.shape + res = dpnp.reshape(res, (-1, orig_shape[-2], orig_shape[-1])) + res_shape = res.shape + + # gemm_batch does not handle negative strides, make a copy if needed + x1 = _copy_array(x1, copy_flag=x1.strides[0] < 0) + x2 = _copy_array(x2, copy_flag=x2.strides[0] < 0) + res = _copy_array(res, copy_flag=res.strides[0] < 0) + + _manager = dpu.SequentialOrderManager[exec_q] + + # onemkl::blas::gemm_bacth throws an exception (Provided range is out + # of integer limits) if the batch_size is too large, so we need to + # split the batch into smaller chunks, the size depnends on device + chunk = 4096 * 4096 - 2 + batch_size = res_shape[0] + for i in range(0, batch_size, chunk): + if x1_shape[0] == 1: + # x1 is repeatedly multiplied with each matrix in x2 + x1_usm = dpnp.get_usm_ndarray(x1) + x2_usm = dpnp.get_usm_ndarray(x2[i : i + chunk, ...]) + elif x2_shape[0] == 1: + x1_usm = dpnp.get_usm_ndarray(x1[i : i + chunk, ...]) + x2_usm = dpnp.get_usm_ndarray(x2) + else: + x1_usm = dpnp.get_usm_ndarray(x1[i : i + chunk, ...]) + x2_usm = dpnp.get_usm_ndarray(x2[i : i + chunk, ...]) + res_usm = dpnp.get_usm_ndarray(res[i : i + chunk, ...]) + + ht_ev, blas_ev, row_major = bi._gemm_batch( + exec_q, + x1_usm, + x2_usm, + res_usm, + depends=_manager.submitted_events, + ) + _manager.add_event_pair(ht_ev, blas_ev) + + _, res_is_c_contig, res_is_f_contig = _define_contig_flag(res) + if row_major: + if res_is_f_contig: + # Considering the multiplication for one of the batches, + # we have result[0, 1] = a[0, :]*b[1, :]. In row_major mode, + # it is assumed result array is c-contiguous, i.e. the value of + # result[0, 1] is has the second place memory. + # however, the result array is batches of 2D f-contiguous array, + # i.e. the second place of memory points out to res[1, 0]. + # So, we need to read data of each 2D array in the batch in + # "F" order and write it in "C" order + res = ( + res.ravel(order="F") + .reshape(res_shape[1], res_shape[2], batch_size) + .transpose(2, 0, 1) + ) + else: + if res_is_c_contig: + # read data of each 2D array in the batch in "C" order and + # write it in "F" order + res = ( + res.ravel(order="C") + .reshape(batch_size, res_shape[2], res_shape[1]) + .transpose(0, 2, 1) + ) + + if res_shape != orig_shape: + res = res.reshape(orig_shape) + + return res + + +def _gemm_matmul(exec_q, x1, x2, res): + _manager = dpu.SequentialOrderManager[exec_q] + + ht_ev, gemm_ev, row_major = bi._gemm( + exec_q, + dpnp.get_usm_ndarray(x1), + dpnp.get_usm_ndarray(x2), + dpnp.get_usm_ndarray(res), + depends=_manager.submitted_events, + ) + _manager.add_event_pair(ht_ev, gemm_ev) + + if row_major: + if res.flags.f_contiguous: + # read data in "F" order and write it in "C" order + res = dpnp.ravel(res, order="F").reshape(res.shape, order="C") + else: + if res.flags.c_contiguous: + # read data in "C" order and write it in "F" order + res = dpnp.ravel(res, order="C").reshape(res.shape, order="F") + + return res + + +def _gemm_special_case(x1, x2, res_dtype, call_flag): + """ + `gemm` and `gemm_batch` support these special cases of data types + while `gemv` does not. + + """ + + is_int8 = x1.dtype == dpnp.int8 and x2.dtype == dpnp.int8 + is_int32_or_f32 = res_dtype in [dpnp.int32, dpnp.float32] + flag = is_int8 and is_int32_or_f32 and call_flag in ["gemm", "gemm_batch"] + + # onemkl_interfaces does not support these data types + onemkl_interfaces = bi._using_onemkl_interfaces() + + return flag and not onemkl_interfaces + + def _get_result_shape(x1, x2, out, func, _get_result_shape_fn, np_flag): """ Three task are completed in this function: @@ -403,123 +520,6 @@ def _get_signature(func): return signature, distinct_core -def _gemm_batch_matmul(exec_q, x1, x2, res): - # arrays here are already at least 3D, make them 3D - x1_shape = x1.shape - x2_shape = x2.shape - x1 = dpnp.reshape(x1, (-1, x1_shape[-2], x1_shape[-1])) - x2 = dpnp.reshape(x2, (-1, x2_shape[-2], x2_shape[-1])) - orig_shape = res.shape - res = dpnp.reshape(res, (-1, orig_shape[-2], orig_shape[-1])) - res_shape = res.shape - - # gemm_batch does not handle negative strides, make a copy if needed - x1 = _copy_array(x1, copy_flag=x1.strides[0] < 0) - x2 = _copy_array(x2, copy_flag=x2.strides[0] < 0) - res = _copy_array(res, copy_flag=res.strides[0] < 0) - - _manager = dpu.SequentialOrderManager[exec_q] - - # onemkl::blas::gemm_bacth throws an exception (Provided range is out - # of integer limits) if the batch_size is too large, so we need to - # split the batch into smaller chunks, the size depnends on device - chunk = 4096 * 4096 - 2 - batch_size = res_shape[0] - for i in range(0, batch_size, chunk): - if x1_shape[0] == 1: - # x1 is repeatedly multiplied with each matrix in x2 - x1_usm = dpnp.get_usm_ndarray(x1) - x2_usm = dpnp.get_usm_ndarray(x2[i : i + chunk, ...]) - elif x2_shape[0] == 1: - x1_usm = dpnp.get_usm_ndarray(x1[i : i + chunk, ...]) - x2_usm = dpnp.get_usm_ndarray(x2) - else: - x1_usm = dpnp.get_usm_ndarray(x1[i : i + chunk, ...]) - x2_usm = dpnp.get_usm_ndarray(x2[i : i + chunk, ...]) - res_usm = dpnp.get_usm_ndarray(res[i : i + chunk, ...]) - - ht_ev, blas_ev, row_major = bi._gemm_batch( - exec_q, - x1_usm, - x2_usm, - res_usm, - depends=_manager.submitted_events, - ) - _manager.add_event_pair(ht_ev, blas_ev) - - _, res_is_c_contig, res_is_f_contig = _define_contig_flag(res) - if row_major: - if res_is_f_contig: - # Considering the multiplication for one of the batches, - # we have result[0, 1] = a[0, :]*b[1, :]. In row_major mode, - # it is assumed result array is c-contiguous, i.e. the value of - # result[0, 1] is has the second place memory. - # however, the result array is batches of 2D f-contiguous array, - # i.e. the second place of memory points out to res[1, 0]. - # So, we need to read data of each 2D array in the batch in - # "F" order and write it in "C" order - res = ( - res.ravel(order="F") - .reshape(res_shape[1], res_shape[2], batch_size) - .transpose(2, 0, 1) - ) - else: - if res_is_c_contig: - # read data of each 2D array in the batch in "C" order and - # write it in "F" order - res = ( - res.ravel(order="C") - .reshape(batch_size, res_shape[2], res_shape[1]) - .transpose(0, 2, 1) - ) - - if res_shape != orig_shape: - res = res.reshape(orig_shape) - - return res - - -def _gemm_matmul(exec_q, x1, x2, res): - _manager = dpu.SequentialOrderManager[exec_q] - - ht_ev, gemm_ev, row_major = bi._gemm( - exec_q, - dpnp.get_usm_ndarray(x1), - dpnp.get_usm_ndarray(x2), - dpnp.get_usm_ndarray(res), - depends=_manager.submitted_events, - ) - _manager.add_event_pair(ht_ev, gemm_ev) - - if row_major: - if res.flags.f_contiguous: - # read data in "F" order and write it in "C" order - res = dpnp.ravel(res, order="F").reshape(res.shape, order="C") - else: - if res.flags.c_contiguous: - # read data in "C" order and write it in "F" order - res = dpnp.ravel(res, order="C").reshape(res.shape, order="F") - - return res - - -def _gemm_special_case(x1, x2, res_dtype, call_flag): - """ - `gemm` and `gemm_batch` support these special cases of data types - while `gemv` does not. - - """ - # TODO: replace with dpnp.int8 when it is added - is_int8 = x1.dtype == numpy.int8 and x2.dtype == numpy.int8 - is_int32_or_f32 = res_dtype in [dpnp.int32, dpnp.float32] - flag = is_int8 and is_int32_or_f32 and call_flag in ["gemm", "gemm_batch"] - - # onemkl_interfaces does not support these data types - onemkl_interfaces = bi._using_onemkl_interfaces() - - return flag and not onemkl_interfaces - - def _shape_error(shape1, shape2, func, err_msg): """Validate the shapes of input and output arrays.""" diff --git a/dpnp/fft/dpnp_utils_fft.py b/dpnp/fft/dpnp_utils_fft.py index 721c5282c8e..70d117c52e2 100644 --- a/dpnp/fft/dpnp_utils_fft.py +++ b/dpnp/fft/dpnp_utils_fft.py @@ -282,7 +282,10 @@ def _copy_array(x, complex_input): # r2c FFT, if input is integer or float16 dtype, convert to # float32 or float64 depending on device capabilities copy_flag = True - dtype = map_dtype_to_device(dpnp.float64, x.sycl_device) + if dtype == dpnp.float16: + dtype = dpnp.float32 + else: + dtype = map_dtype_to_device(dpnp.float64, x.sycl_device) if copy_flag: x_copy = dpnp.empty_like(x, dtype=dtype, order="C") diff --git a/dpnp/tests/config.py b/dpnp/tests/config.py new file mode 100644 index 00000000000..0069efe23ee --- /dev/null +++ b/dpnp/tests/config.py @@ -0,0 +1,6 @@ +import os + +all_int_types = int(os.getenv("DPNP_TEST_ALL_INT_TYPES", 0)) +float16_types = int(os.getenv("DPNP_TEST_FLOAT_16", 0)) +complex_types = int(os.getenv("DPNP_TEST_COMPLEX_TYPES", 0)) +bool_types = int(os.getenv("DPNP_TEST_BOOL_TYPES", 0)) diff --git a/dpnp/tests/helper.py b/dpnp/tests/helper.py index be72c570cfc..eafe86db69a 100644 --- a/dpnp/tests/helper.py +++ b/dpnp/tests/helper.py @@ -2,9 +2,11 @@ import dpctl import numpy +import pytest from numpy.testing import assert_allclose, assert_array_equal import dpnp +from dpnp.tests import config def assert_dtype_allclose( @@ -84,12 +86,19 @@ def assert_dtype_allclose( assert dpnp_arr.dtype == numpy_arr.dtype -def get_integer_dtypes(): +def get_integer_dtypes(no_unsigned=False): """ Build a list of integer types supported by DPNP. """ - return [dpnp.int32, dpnp.int64] + dtypes = [dpnp.int32, dpnp.int64] + + if config.all_int_types: + dtypes += [dpnp.int8, dpnp.int16] + if not no_unsigned: + dtypes += [dpnp.uint8, dpnp.uint16, dpnp.uint32, dpnp.uint64] + + return dtypes def get_complex_dtypes(device=None): @@ -134,11 +143,25 @@ def get_float_complex_dtypes(no_float16=True, device=None): return dtypes +def get_abs_array(data, dtype=None): + if numpy.issubdtype(dtype, numpy.unsignedinteger): + data = numpy.abs(data) + return numpy.array(data, dtype=dtype) + + def get_all_dtypes( - no_bool=False, no_float16=True, no_complex=False, no_none=False, device=None + no_bool=False, + no_float16=True, + no_complex=False, + no_none=False, + xfail_dtypes=None, + exclude=None, + no_unsigned=False, + device=None, ): """ - Build a list of types supported by DPNP based on input flags and device capabilities. + Build a list of types supported by DPNP based on + input flags and device capabilities. """ dev = dpctl.select_default_device() if device is None else device @@ -147,7 +170,7 @@ def get_all_dtypes( dtypes = [dpnp.bool] if not no_bool else [] # add integer types - dtypes.extend(get_integer_dtypes()) + dtypes.extend(get_integer_dtypes(no_unsigned=no_unsigned)) # add floating types dtypes.extend(get_float_dtypes(no_float16=no_float16, device=dev)) @@ -159,6 +182,18 @@ def get_all_dtypes( # add None value to validate a default dtype if not no_none: dtypes.append(None) + + def mark_xfail(dtype): + if xfail_dtypes is not None and dtype in xfail_dtypes: + return pytest.param(dtype, marks=pytest.mark.xfail) + return dtype + + def not_excluded(dtype): + if exclude is None: + return True + return dtype not in exclude + + dtypes = [mark_xfail(dtype) for dtype in dtypes if not_excluded(dtype)] return dtypes @@ -241,6 +276,9 @@ def generate_random_numpy_array( seed_value = 42 numpy.random.seed(seed_value) + if numpy.issubdtype(dtype, numpy.unsignedinteger): + low = 0 + # dtype=int is needed for 0d arrays size = numpy.prod(shape, dtype=int) if dtype == dpnp.bool: diff --git a/dpnp/tests/test_absolute.py b/dpnp/tests/test_absolute.py index 1c6a42e98c6..3f5c4860f24 100644 --- a/dpnp/tests/test_absolute.py +++ b/dpnp/tests/test_absolute.py @@ -13,9 +13,9 @@ @pytest.mark.parametrize("func", ["abs", "absolute"]) -@pytest.mark.parametrize("dtype", get_all_dtypes()) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) def test_abs(func, dtype): - a = numpy.array([1, 0, 2, -3, -1, 2, 21, -9], dtype=dtype) + a = numpy.array([1, 0, 2, -3, -1, 2, 21, -9]).astype(dtype=dtype) ia = dpnp.array(a) result = getattr(dpnp, func)(ia) diff --git a/dpnp/tests/test_amin_amax.py b/dpnp/tests/test_amin_amax.py index 1b119ab225b..35f45cd4082 100644 --- a/dpnp/tests/test_amin_amax.py +++ b/dpnp/tests/test_amin_amax.py @@ -4,21 +4,19 @@ import dpnp -from .helper import get_all_dtypes +from .helper import get_abs_array, get_all_dtypes @pytest.mark.parametrize("func", ["amax", "amin"]) @pytest.mark.parametrize("keepdims", [True, False]) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_amax_amin(func, keepdims, dtype): - a = numpy.array( - [ - [[-2.0, 3.0], [9.1, 0.2]], - [[-2.0, 5.0], [-2, -1.2]], - [[1.0, -2.0], [5.0, -1.1]], - ], - dtype=dtype, - ) + a = [ + [[-2.0, 3.0], [9.1, 0.2]], + [[-2.0, 5.0], [-2, -1.2]], + [[1.0, -2.0], [5.0, -1.1]], + ] + a = get_abs_array(a, dtype) ia = dpnp.array(a) for axis in range(len(a)): @@ -28,20 +26,20 @@ def test_amax_amin(func, keepdims, dtype): def _get_min_max_input(type, shape): - size = 1 - for i in range(len(shape)): - size *= shape[i] - + size = numpy.prod(shape) a = numpy.arange(size, dtype=type) - a[int(size / 2)] = size * size - a[int(size / 3)] = -(size * size) + a[int(size / 2)] = size + 5 + if numpy.issubdtype(type, numpy.unsignedinteger): + a[int(size / 3)] = size + else: + a[int(size / 3)] = -(size + 5) return a.reshape(shape) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize( - "shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2,3)", "(4,5,6)"] + "shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2, 3)", "(4, 5, 6)"] ) def test_amax_diff_shape(dtype, shape): a = _get_min_max_input(dtype, shape) @@ -59,7 +57,7 @@ def test_amax_diff_shape(dtype, shape): @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize( - "shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2,3)", "(4,5,6)"] + "shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2, 3)", "(4, 5, 6)"] ) def test_amin_diff_shape(dtype, shape): a = _get_min_max_input(dtype, shape) diff --git a/dpnp/tests/test_array_api_info.py b/dpnp/tests/test_array_api_info.py index ef30b19eca4..c3c8d687b03 100644 --- a/dpnp/tests/test_array_api_info.py +++ b/dpnp/tests/test_array_api_info.py @@ -56,14 +56,14 @@ def test_dtypes_all(): assert dtypes == ( { "bool": dpnp.bool_, - "int8": numpy.int8, # TODO: replace with dpnp.int8 - "int16": numpy.int16, # TODO: replace with dpnp.int16 + "int8": dpnp.int8, + "int16": dpnp.int16, "int32": dpnp.int32, "int64": dpnp.int64, - "uint8": numpy.uint8, # TODO: replace with dpnp.uint8 - "uint16": numpy.uint16, # TODO: replace with dpnp.uint16 - "uint32": numpy.uint32, # TODO: replace with dpnp.uint32 - "uint64": numpy.uint64, # TODO: replace with dpnp.uint64 + "uint8": dpnp.uint8, + "uint16": dpnp.uint16, + "uint32": dpnp.uint32, + "uint64": dpnp.uint64, "float32": dpnp.float32, } | ({"float64": dpnp.float64} if has_support_aspect64() else {}) @@ -75,16 +75,16 @@ def test_dtypes_all(): dtype_categories = { "bool": {"bool": dpnp.bool_}, "signed integer": { - "int8": numpy.int8, # TODO: replace with dpnp.int8 - "int16": numpy.int16, # TODO: replace with dpnp.int16 + "int8": dpnp.int8, + "int16": dpnp.int16, "int32": dpnp.int32, "int64": dpnp.int64, }, - "unsigned integer": { # TODO: replace with dpnp dtypes once available - "uint8": numpy.uint8, - "uint16": numpy.uint16, - "uint32": numpy.uint32, - "uint64": numpy.uint64, + "unsigned integer": { + "uint8": dpnp.uint8, + "uint16": dpnp.uint16, + "uint32": dpnp.uint32, + "uint64": dpnp.uint64, }, "integral": ("signed integer", "unsigned integer"), "real floating": {"float32": dpnp.float32} @@ -108,14 +108,14 @@ def test_dtypes_tuple(): dtypes = info.dtypes(kind=("bool", "integral")) assert dtypes == { "bool": dpnp.bool_, - "int8": numpy.int8, # TODO: replace with dpnp.int8 - "int16": numpy.int16, # TODO: replace with dpnp.int16 + "int8": dpnp.int8, + "int16": dpnp.int16, "int32": dpnp.int32, "int64": dpnp.int64, - "uint8": numpy.uint8, # TODO: replace with dpnp.uint8 - "uint16": numpy.uint16, # TODO: replace with dpnp.uint16 - "uint32": numpy.uint32, # TODO: replace with dpnp.uint32 - "uint64": numpy.uint64, # TODO: replace with dpnp.uint64 + "uint8": dpnp.uint8, + "uint16": dpnp.uint16, + "uint32": dpnp.uint32, + "uint64": dpnp.uint64, } diff --git a/dpnp/tests/test_arraycreation.py b/dpnp/tests/test_arraycreation.py index 2cc38c4a844..bf6d31b120e 100644 --- a/dpnp/tests/test_arraycreation.py +++ b/dpnp/tests/test_arraycreation.py @@ -177,16 +177,18 @@ def test_exception_subok(func, args): @pytest.mark.parametrize("start", [0, -5, 10, -2.5, 9.7]) -@pytest.mark.parametrize("stop", [None, 10, -2, 20.5, 1000]) -@pytest.mark.parametrize("step", [None, 1, 2.7, -1.6, 100]) +@pytest.mark.parametrize("stop", [None, 10, -2, 20.5, 100]) +@pytest.mark.parametrize("step", [None, 1, 2.7, -1.6, 80]) @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_float16=False) ) def test_arange(start, stop, step, dtype): - rtol_mult = 2 - if dpnp.issubdtype(dtype, dpnp.float16): - # numpy casts to float32 type when computes float16 data - rtol_mult = 4 + if numpy.issubdtype(dtype, numpy.unsignedinteger): + start = abs(start) + stop = abs(stop) if stop else None + + # numpy casts to float32 type when computes float16 data + rtol_mult = 4 if dpnp.issubdtype(dtype, dpnp.float16) else 2 func = lambda xp: xp.arange(start, stop=stop, step=step, dtype=dtype) @@ -707,17 +709,22 @@ def test_dpctl_tensor_input(func, args): @pytest.mark.parametrize("start", [0, -5, 10, -2.5, 9.7]) -@pytest.mark.parametrize("stop", [0, 10, -2, 20.5, 1000]) +@pytest.mark.parametrize("stop", [0, 10, -2, 20.5, 120]) @pytest.mark.parametrize( "num", [1, 5, numpy.array(10), dpnp.array(17), dpt.asarray(100)], ids=["1", "5", "numpy.array(10)", "dpnp.array(17)", "dpt.asarray(100)"], ) @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_float16=False) + "dtype", + get_all_dtypes(no_bool=True, no_float16=False), ) @pytest.mark.parametrize("retstep", [True, False]) def test_linspace(start, stop, num, dtype, retstep): + if numpy.issubdtype(dtype, numpy.unsignedinteger): + start = abs(start) + stop = abs(stop) + res_np = numpy.linspace(start, stop, num, dtype=dtype, retstep=retstep) res_dp = dpnp.linspace(start, stop, num, dtype=dtype, retstep=retstep) @@ -851,7 +858,7 @@ def test_space_num_error(): @pytest.mark.parametrize("endpoint", [True, False]) def test_geomspace(sign, dtype, num, endpoint): start = 2 * sign - stop = 256 * sign + stop = 127 * sign func = lambda xp: xp.geomspace( start, stop, num, endpoint=endpoint, dtype=dtype diff --git a/dpnp/tests/test_arraypad.py b/dpnp/tests/test_arraypad.py index 34a71eec707..16b7c23c75e 100644 --- a/dpnp/tests/test_arraypad.py +++ b/dpnp/tests/test_arraypad.py @@ -30,7 +30,11 @@ class TestPad: "empty": {}, } - @pytest.mark.parametrize("mode", _all_modes.keys()) + # .keys() returns set which is not ordered + # consistent order is required by xdist plugin + _modes = sorted(_all_modes.keys()) + + @pytest.mark.parametrize("mode", _modes) def test_basic(self, mode): a_np = numpy.arange(100) a_dp = dpnp.array(a_np) @@ -43,7 +47,7 @@ def test_basic(self, mode): else: assert_array_equal(result, expected) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_memory_layout_persistence(self, mode): """Test if C and F order is preserved for all pad modes.""" x = dpnp.ones((5, 10), order="C") @@ -52,13 +56,13 @@ def test_memory_layout_persistence(self, mode): assert dpnp.pad(x, 5, mode).flags.f_contiguous @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_dtype_persistence(self, dtype, mode): arr = dpnp.zeros((3, 2, 1), dtype=dtype) result = dpnp.pad(arr, 1, mode=mode) assert result.dtype == dtype - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_non_contiguous_array(self, mode): a_np = numpy.arange(24).reshape(4, 6)[::2, ::2] a_dp = dpnp.arange(24).reshape(4, 6)[::2, ::2] @@ -73,12 +77,14 @@ def test_non_contiguous_array(self, mode): # TODO: include "linear_ramp" when dpnp issue gh-2084 is resolved @pytest.mark.parametrize("pad_width", [0, (0, 0), ((0, 0), (0, 0))]) - @pytest.mark.parametrize("mode", _all_modes.keys() - {"linear_ramp"}) + @pytest.mark.parametrize( + "mode", [m for m in _modes if m not in {"linear_ramp"}] + ) def test_zero_pad_width(self, pad_width, mode): arr = dpnp.arange(30).reshape(6, 5) assert_array_equal(arr, dpnp.pad(arr, pad_width, mode=mode)) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_pad_non_empty_dimension(self, mode): a_np = numpy.ones((2, 0, 2)) a_dp = dpnp.array(a_np) @@ -95,14 +101,14 @@ def test_pad_non_empty_dimension(self, mode): ((3, 4, 5), (0, 1, 2)), ], ) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_misshaped_pad_width1(self, pad_width, mode): arr = dpnp.arange(30).reshape((6, 5)) match = "operands could not be broadcast together" with pytest.raises(ValueError, match=match): dpnp.pad(arr, pad_width, mode) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_misshaped_pad_width2(self, mode): arr = dpnp.arange(30).reshape((6, 5)) match = ( @@ -115,7 +121,7 @@ def test_misshaped_pad_width2(self, mode): @pytest.mark.parametrize( "pad_width", [-2, (-2,), (3, -1), ((5, 2), (-2, 3)), ((-4,), (2,))] ) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_negative_pad_width(self, pad_width, mode): arr = dpnp.arange(30).reshape((6, 5)) match = "index can't contain negative values" @@ -126,14 +132,14 @@ def test_negative_pad_width(self, pad_width, mode): "pad_width", ["3", "word", None, 3.4, complex(1, -1), ((-2.1, 3), (3, 2))], ) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_bad_type(self, pad_width, mode): arr = dpnp.arange(30).reshape((6, 5)) match = "`pad_width` must be of integral type." with pytest.raises(TypeError, match=match): dpnp.pad(arr, pad_width, mode) - @pytest.mark.parametrize("mode", _all_modes.keys()) + @pytest.mark.parametrize("mode", _modes) def test_kwargs(self, mode): """Test behavior of pad's kwargs for the given mode.""" allowed = self._all_modes[mode] @@ -439,7 +445,7 @@ def test_pad_empty_dim_valid(self, mode): @pytest.mark.parametrize( "mode", - _all_modes.keys() - {"constant", "empty"}, + [m for m in _modes if m not in {"constant", "empty"}], ) def test_pad_empty_dim_invalid(self, mode): match = ( diff --git a/dpnp/tests/test_binary_ufuncs.py b/dpnp/tests/test_binary_ufuncs.py index 6fae555194e..5bf64684e6f 100644 --- a/dpnp/tests/test_binary_ufuncs.py +++ b/dpnp/tests/test_binary_ufuncs.py @@ -9,15 +9,18 @@ ) import dpnp +from dpnp.dpnp_utils import map_dtype_to_device from .helper import ( assert_dtype_allclose, + get_abs_array, get_all_dtypes, get_complex_dtypes, get_float_complex_dtypes, get_float_dtypes, get_integer_dtypes, has_support_aspect16, + numpy_version, ) from .test_umath import ( _get_numpy_arrays_2in_1out, @@ -72,11 +75,19 @@ def test_inplace_strides(self, dtype): @pytest.mark.parametrize("dtype1", ALL_DTYPES) @pytest.mark.parametrize("dtype2", ALL_DTYPES) def test_inplace_dtype(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a += b + ia += ib + assert_dtype_allclose(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a += b ia += ib assert_dtype_allclose(ia, a) @@ -90,11 +101,18 @@ def test_inplace_dtype(self, dtype1, dtype2): @pytest.mark.parametrize("dtype1", ALL_DTYPES) @pytest.mark.parametrize("dtype2", ALL_DTYPES) def test_inplace_dtype_explicit(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + result = dpnp.add(ia, ib, out=ia) + expected = numpy.add(a, b.astype(numpy.int64), out=a) + assert_dtype_allclose(result, expected) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): result = dpnp.add(ia, ib, out=ia) expected = numpy.add(a, b, out=a) assert_dtype_allclose(result, expected) @@ -196,7 +214,10 @@ def test_divide(self, dtype): ) ia, ib = dpnp.array(a), dpnp.array(b) - out_dtype = _get_output_data_type(dtype) + if numpy.issubdtype(dtype, numpy.integer): + out_dtype = map_dtype_to_device(dpnp.float64, ia.sycl_device) + else: + out_dtype = _get_output_data_type(dtype) iout = dpnp.empty(expected.shape, dtype=out_dtype) result = dpnp.divide(ia, ib, out=iout) @@ -229,8 +250,8 @@ def test_inplace_strides(self, dtype): @pytest.mark.parametrize("dtype1", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype2", get_float_complex_dtypes()) def test_inplace_dtype(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, -10, 1, 10], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, -10, 1, 10], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) if numpy.can_cast(dtype2, dtype1, casting="same_kind"): @@ -247,8 +268,8 @@ def test_inplace_dtype(self, dtype1, dtype2): @pytest.mark.parametrize("dtype1", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype2", get_float_complex_dtypes()) def test_inplace_dtype_explicit(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, -10, 1, 10], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, -10, 1, 10], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) if numpy.can_cast(dtype2, dtype1, casting="same_kind"): @@ -334,8 +355,8 @@ def test_inplace_scalar(self, func, dtype): @pytest.mark.parametrize("dtype1", [dpnp.bool] + ALL_DTYPES) @pytest.mark.parametrize("dtype2", get_float_dtypes()) def test_inplace_dtype(self, func, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, -10, 1, 10], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, -10, 1, 10], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) if numpy.can_cast(dtype2, dtype1, casting="same_kind"): @@ -460,8 +481,8 @@ def test_basic(self, val, dt): "b_dt", get_all_dtypes(no_none=True, no_complex=True) ) def test_both_input_as_arrays(self, a_dt, b_dt): - a = numpy.array([-1.5, 0, 2.0], dtype=a_dt) - b = numpy.array([-0, 0.5, 1.0], dtype=b_dt) + a = get_abs_array([-1.5, 0, 2.0], a_dt) + b = get_abs_array([-0, 0.5, 1.0], b_dt) ia, ib = dpnp.array(a), dpnp.array(b) result = dpnp.heaviside(ia, ib) @@ -480,7 +501,7 @@ class TestLdexp: @pytest.mark.parametrize("exp_dt", get_integer_dtypes()) def test_basic(self, mant_dt, exp_dt): if ( - numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" + numpy_version() < "2.0.0" and exp_dt == numpy.int64 and numpy.dtype("l") != numpy.int64 ): @@ -490,9 +511,18 @@ def test_basic(self, mant_dt, exp_dt): exp = numpy.array(3, dtype=exp_dt) imant, iexp = dpnp.array(mant), dpnp.array(exp) - result = dpnp.ldexp(imant, iexp) - expected = numpy.ldexp(mant, exp) - assert_almost_equal(result, expected) + if dpnp.issubdtype(exp_dt, dpnp.uint64): + assert_raises(ValueError, dpnp.ldexp, imant, iexp) + assert_raises(TypeError, numpy.ldexp, mant, exp) + elif numpy_version() < "2.0.0" and dpnp.issubdtype(exp_dt, dpnp.uint32): + # For this special case, NumPy < "2.0.0" raises an error on Windows + result = dpnp.ldexp(imant, iexp) + expected = numpy.ldexp(mant, exp.astype(numpy.int32)) + assert_almost_equal(result, expected) + else: + result = dpnp.ldexp(imant, iexp) + expected = numpy.ldexp(mant, exp) + assert_almost_equal(result, expected) def test_float_scalar(self): a = numpy.array(3) @@ -598,11 +628,19 @@ def test_inplace_strides(self, dtype): @pytest.mark.parametrize("dtype1", ALL_DTYPES) @pytest.mark.parametrize("dtype2", ALL_DTYPES) def test_inplace_dtype(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a *= b + ia *= ib + assert_dtype_allclose(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a *= b ia *= ib assert_dtype_allclose(ia, a) @@ -768,7 +806,7 @@ class TestPower: @pytest.mark.parametrize("val_type", ALL_DTYPES) @pytest.mark.parametrize("data_type", ALL_DTYPES) - @pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"]) + @pytest.mark.parametrize("val", [1.5, 1, 3], ids=["1.5", "1", "3"]) @pytest.mark.parametrize( "array", [ @@ -840,11 +878,19 @@ def test_inplace_strided_out(self, dtype): @pytest.mark.parametrize("dtype1", ALL_DTYPES) @pytest.mark.parametrize("dtype2", ALL_DTYPES) def test_inplace_dtype(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, 2, 0, 1, 3], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, 2, 0, 1, 3], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind") and not ( + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a **= b + ia **= ib + assert_dtype_allclose(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind") and not ( dtype1 == dtype2 == dpnp.bool ): a **= b @@ -889,7 +935,7 @@ def test_integer_power_of_0_or_1(self, val, dtype): assert_equal(func(ia), func(a)) - @pytest.mark.parametrize("dtype", get_integer_dtypes()) + @pytest.mark.parametrize("dtype", get_integer_dtypes(no_unsigned=True)) def test_integer_to_negative_power(self, dtype): a = dpnp.arange(2, 10, dtype=dtype) b = dpnp.full(8, -2, dtype=dtype) @@ -950,8 +996,8 @@ def test_alias(self): class TestRationalFunctions: @pytest.mark.parametrize("func", ["gcd", "lcm"]) - @pytest.mark.parametrize("dt1", get_integer_dtypes()) - @pytest.mark.parametrize("dt2", get_integer_dtypes()) + @pytest.mark.parametrize("dt1", get_integer_dtypes(no_unsigned=True)) + @pytest.mark.parametrize("dt2", get_integer_dtypes(no_unsigned=True)) def test_basic(self, func, dt1, dt2): a = numpy.array([12, 120], dtype=dt1) b = numpy.array([20, 120], dtype=dt2) @@ -1047,11 +1093,19 @@ def test_inplace_strides(self, dtype): @pytest.mark.parametrize("dtype1", ALL_DTYPES) @pytest.mark.parametrize("dtype2", ALL_DTYPES) def test_inplace_dtype(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = dpnp.array(a), dpnp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a -= b + ia -= ib + assert_dtype_allclose(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a -= b ia -= ib assert_dtype_allclose(ia, a) diff --git a/dpnp/tests/test_bitwise.py b/dpnp/tests/test_bitwise.py index 220a7a1eacd..d41a4900c8e 100644 --- a/dpnp/tests/test_bitwise.py +++ b/dpnp/tests/test_bitwise.py @@ -4,7 +4,7 @@ import dpnp as inp -from .helper import assert_dtype_allclose, get_integer_dtypes +from .helper import assert_dtype_allclose, get_abs_array, get_integer_dtypes @pytest.mark.parametrize( @@ -32,6 +32,8 @@ def array_or_scalar(xp, data, dtype=None): return numpy.dtype(dtype).type(data) return data + if numpy.issubdtype(dtype, numpy.unsignedinteger): + data = xp.abs(xp.array(data)) return xp.array(data, dtype=dtype) def _test_unary_int(self, name, data, dtype): @@ -167,7 +169,8 @@ def test_bitwise_aliase2(self, lhs, rhs, dtype): @pytest.mark.parametrize("dtype", get_integer_dtypes()) def test_invert_out(dtype): - np_a = numpy.arange(-5, 5, dtype=dtype) + low = 0 if numpy.issubdtype(dtype, numpy.unsignedinteger) else -5 + np_a = numpy.arange(low, 5, dtype=dtype) dp_a = inp.array(np_a) expected = numpy.invert(np_a) @@ -181,15 +184,23 @@ def test_invert_out(dtype): @pytest.mark.parametrize("dtype2", [inp.bool] + get_integer_dtypes()) class TestBitwiseInplace: def test_bitwise_and(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) a &= True ia &= True assert_array_equal(ia, a) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a &= b + ia &= ib + assert_array_equal(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a &= b ia &= ib assert_array_equal(ia, a) @@ -201,15 +212,23 @@ def test_bitwise_and(self, dtype1, dtype2): ia &= ib def test_bitwise_or(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) a |= False ia |= False assert_array_equal(ia, a) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a |= b + ia |= ib + assert_array_equal(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a |= b ia |= ib assert_array_equal(ia, a) @@ -221,18 +240,26 @@ def test_bitwise_or(self, dtype1, dtype2): ia |= ib def test_bitwise_xor(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) a ^= False ia ^= False assert_array_equal(ia, a) - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, -2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, -2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a ^= b + ia ^= ib + assert_array_equal(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a ^= b ia ^= ib assert_array_equal(ia, a) @@ -248,15 +275,23 @@ def test_bitwise_xor(self, dtype1, dtype2): @pytest.mark.parametrize("dtype2", get_integer_dtypes()) class TestBitwiseShiftInplace: def test_bitwise_left_shift(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, 2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, 2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) a <<= True ia <<= True assert_array_equal(ia, a) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a <<= b + ia <<= ib + assert_array_equal(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a <<= b ia <<= ib assert_array_equal(ia, a) @@ -268,15 +303,23 @@ def test_bitwise_left_shift(self, dtype1, dtype2): ia <<= ib def test_bitwise_right_shift(self, dtype1, dtype2): - a = numpy.array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) - b = numpy.array([5, 2, 0, 1, 0], dtype=dtype2) + a = get_abs_array([[-7, 6, -3, 2, -1], [0, -3, 4, 5, -6]], dtype=dtype1) + b = get_abs_array([5, 2, 0, 1, 0], dtype=dtype2) ia, ib = inp.array(a), inp.array(b) a >>= True ia >>= True assert_array_equal(ia, a) - if numpy.can_cast(dtype2, dtype1, casting="same_kind"): + if numpy.issubdtype(dtype1, numpy.signedinteger) and numpy.issubdtype( + dtype2, numpy.uint64 + ): + # For this special case, NumPy raises an error but dpnp works + b = b.astype(numpy.int64) + a >>= b + ia >>= ib + assert_array_equal(ia, a) + elif numpy.can_cast(dtype2, dtype1, casting="same_kind"): a >>= b ia >>= ib assert_array_equal(ia, a) diff --git a/dpnp/tests/test_dtype_routines.py b/dpnp/tests/test_dtype_routines.py index 8fab16c7093..21c42bbf89b 100644 --- a/dpnp/tests/test_dtype_routines.py +++ b/dpnp/tests/test_dtype_routines.py @@ -30,9 +30,8 @@ class TestIsDType: @pytest.mark.parametrize( "dt, close_dt", [ - # TODO: replace with (dpnp.uint64, dpnp.uint32) once available (dpnp.int64, dpnp.int32), - (numpy.uint64, numpy.uint32), + (dpnp.uint64, dpnp.uint32), (dpnp.float64, dpnp.float32), (dpnp.complex128, dpnp.complex64), ], diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 418f05f47c6..c32fce96442 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -834,7 +834,10 @@ def test_rfft_1D(self, dtype, n, norm): result = dpnp.fft.rfft(a, n=n, norm=norm) expected = numpy.fft.rfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + factor = 120 if dtype in [dpnp.int8, dpnp.uint8] else 8 + assert_dtype_allclose( + result, expected, factor=factor, check_only_type_kind=True + ) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) diff --git a/dpnp/tests/test_histogram.py b/dpnp/tests/test_histogram.py index 6d9f53ed920..baa601be70e 100644 --- a/dpnp/tests/test_histogram.py +++ b/dpnp/tests/test_histogram.py @@ -14,6 +14,7 @@ from .helper import ( assert_dtype_allclose, + get_abs_array, get_all_dtypes, get_float_dtypes, get_integer_dtypes, @@ -44,7 +45,12 @@ class TestDigitize: ], ) def test_digitize(self, x, bins, dtype, right): - x = x.astype(dtype) + x = get_abs_array(x, dtype) + if numpy.issubdtype(dtype, numpy.unsignedinteger): + min_bin = bins.min() + if min_bin < 0: + # bins should be monotonically increasing, cannot use get_abs_array + bins -= min_bin bins = bins.astype(dtype) x_dp = dpnp.array(x) bins_dp = dpnp.array(bins) @@ -533,18 +539,27 @@ def test_rand_data(self, dtype): v = numpy.random.randint(0, upper_bound, size=n, dtype=dtype) iv = dpnp.array(v) - expected_hist = numpy.bincount(v) - result_hist = dpnp.bincount(iv) - assert_array_equal(result_hist, expected_hist) + if numpy.issubdtype(dtype, numpy.uint64): + # discussed in numpy issue 17760 + assert_raises(TypeError, numpy.bincount, v) + assert_raises(ValueError, dpnp.bincount, iv) + else: + expected_hist = numpy.bincount(v) + result_hist = dpnp.bincount(iv) + assert_array_equal(result_hist, expected_hist) @pytest.mark.parametrize("dtype", get_integer_dtypes()) def test_arange_data(self, dtype): v = numpy.arange(100).astype(dtype) iv = dpnp.array(v) - expected_hist = numpy.bincount(v) - result_hist = dpnp.bincount(iv) - assert_array_equal(result_hist, expected_hist) + if numpy.issubdtype(dtype, numpy.uint64): + assert_raises(TypeError, numpy.bincount, v) + assert_raises(ValueError, dpnp.bincount, iv) + else: + expected_hist = numpy.bincount(v) + result_hist = dpnp.bincount(iv) + assert_array_equal(result_hist, expected_hist) @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_negative_values(self, xp): diff --git a/dpnp/tests/test_indexing.py b/dpnp/tests/test_indexing.py index 5a91ad3e07f..1efef172cf6 100644 --- a/dpnp/tests/test_indexing.py +++ b/dpnp/tests/test_indexing.py @@ -19,10 +19,13 @@ from dpnp.dpnp_array import dpnp_array from .helper import ( + get_abs_array, get_all_dtypes, get_array, get_integer_dtypes, has_support_aspect64, + is_win_platform, + numpy_version, ) from .third_party.cupy import testing @@ -49,12 +52,12 @@ class TestDiagonal: "shape", [(2, 2), (3, 3), (2, 5), (3, 2, 2), (2, 2, 2, 2), (2, 2, 2, 3)], ids=[ - "(2,2)", - "(3,3)", - "(2,5)", - "(3,2,2)", - "(2,2,2,2)", - "(2,2,2,3)", + "(2, 2)", + "(3, 3)", + "(2, 5)", + "(3, 2, 2)", + "(2, 2, 2, 2)", + "(2, 2, 2, 3)", ], ) def test_diagonal_offset(self, shape, dtype, offset): @@ -128,8 +131,8 @@ def test_extract(self, dt): @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("cond_dt", get_all_dtypes(no_none=True)) def test_extract_diff_dtypes(self, a_dt, cond_dt): - a = numpy.array([-2, -1, 0, 1, 2, 3], dtype=a_dt) - cond = numpy.array([1, -1, 2, 0, -2, 3], dtype=cond_dt) + a = get_abs_array([-2, -1, 0, 1, 2, 3], a_dt) + cond = get_abs_array([1, -1, 2, 0, -2, 3], cond_dt) ia, icond = dpnp.array(a), dpnp.array(cond) result = dpnp.extract(icond, ia) @@ -138,7 +141,7 @@ def test_extract_diff_dtypes(self, a_dt, cond_dt): @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) def test_extract_list_cond(self, a_dt): - a = numpy.array([-2, -1, 0, 1, 2, 3], dtype=a_dt) + a = get_abs_array([-2, -1, 0, 1, 2, 3], a_dt) cond = [1, -1, 2, 0, -2, 3] ia = dpnp.array(a) @@ -171,7 +174,7 @@ def test_place_diff_dtypes(self, a_dt, mask_dt, vals_dt): dtype=mask_dt, ) vals = numpy.array( - [100, 200, 300, 400, 500, 600, 800, 900], dtype=vals_dt + [101, 102, 103, 104, 105, 106, 108, 109], dtype=vals_dt ) ia, imask, ivals = dpnp.array(a), dpnp.array(mask), dpnp.array(vals) @@ -391,7 +394,7 @@ def test_0d(self, val): @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) def test_1d(self, dtype): - a = numpy.array([1, 0, 2, -1, 0, 0, 8], dtype=dtype) + a = get_abs_array([1, 0, 2, -1, 0, 0, 8], dtype) ia = dpnp.array(a) np_res = numpy.nonzero(a) @@ -443,21 +446,21 @@ def test_array_method(self, dtype): class TestPut: @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( - "indices", [[0, 2], [-5, 4]], ids=["[0, 2]", "[-5, 4]"] + "indices", [[0, 2], [-3, 4]], ids=["[0, 2]", "[-3, 4]"] ) @pytest.mark.parametrize("ind_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "ivals", [0, [1, 2], (2, 2), dpnp.array([1, 2])], - ids=["0", "[1, 2]", "(2, 2)", "dpnp.array([1,2])"], + ids=["0", "[1, 2]", "(2, 2)", "dpnp.array([1, 2])"], ) @pytest.mark.parametrize("mode", ["clip", "wrap"]) def test_input_1d(self, a_dt, indices, ind_dt, ivals, mode): - a = numpy.array([-2, -1, 0, 1, 2], dtype=a_dt) + a = get_abs_array([-2, -1, 0, 1, 2], a_dt) b, vals = numpy.copy(a), get_array(numpy, ivals) ia, ib = dpnp.array(a), dpnp.array(b) - ind = numpy.array(indices, dtype=ind_dt) + ind = get_abs_array(indices, ind_dt) if ind_dt == dpnp.bool and ind.all(): ind[0] = False # to get rid of duplicate indices iind = dpnp.array(ind) @@ -470,6 +473,18 @@ def test_input_1d(self, a_dt, indices, ind_dt, ivals, mode): b.put(ind, vals, mode=mode) ib.put(iind, ivals, mode=mode) assert_array_equal(ib, b) + elif ind_dt == numpy.uint64: + # For this special case, NumPy raises an error but dpnp works + assert_raises(TypeError, numpy.put, a, ind, vals, mode=mode) + assert_raises(TypeError, b.put, ind, vals, mode=mode) + + numpy.put(a, ind.astype(numpy.int64), vals, mode=mode) + dpnp.put(ia, iind, vals, mode=mode) + assert_array_equal(ia, a) + + b.put(ind.astype(numpy.int64), vals, mode=mode) + ib.put(iind, vals, mode=mode) + assert_array_equal(ib, b) else: assert_raises(TypeError, numpy.put, a, ind, vals, mode=mode) assert_raises(TypeError, dpnp.put, ia, iind, ivals, mode=mode) @@ -480,30 +495,30 @@ def test_input_1d(self, a_dt, indices, ind_dt, ivals, mode): @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "indices", - [ - [0, 7], - [3, 4], - [-9, 8], - ], - ids=[ - "[0, 7]", - "[3, 4]", - "[-9, 8]", - ], + [[0, 7], [3, 4], [-7, 8]], + ids=["[0, 7]", "[3, 4]", "[-7, 8]"], ) @pytest.mark.parametrize("ind_dt", get_integer_dtypes()) - @pytest.mark.parametrize("vals", [[10, 20]], ids=["[10, 20]"]) @pytest.mark.parametrize("mode", ["clip", "wrap"]) - def test_input_2d(self, a_dt, indices, ind_dt, vals, mode): - a = numpy.array([[-1, 0, 1], [-2, -3, -4], [2, 3, 4]], dtype=a_dt) + def test_input_2d(self, a_dt, indices, ind_dt, mode): + a = get_abs_array([[-1, 0, 1], [-2, -3, -4], [2, 3, 4]], a_dt) ia = dpnp.array(a) + vals = [10, 20] - ind = numpy.array(indices, dtype=ind_dt) + ind = get_abs_array(indices, ind_dt) iind = dpnp.array(ind) - numpy.put(a, ind, vals, mode=mode) - dpnp.put(ia, iind, vals, mode=mode) - assert_array_equal(ia, a) + if ind_dt == numpy.uint64: + # For this special case, NumPy raises an error but dpnp works + assert_raises(TypeError, numpy.put, a, ind, vals, mode=mode) + + numpy.put(a, ind.astype(numpy.int64), vals, mode=mode) + dpnp.put(ia, iind, vals, mode=mode) + assert_array_equal(ia, a) + else: + numpy.put(a, ind, vals, mode=mode) + dpnp.put(ia, iind, vals, mode=mode) + assert_array_equal(ia, a) def test_indices_2d(self): a = numpy.arange(5) @@ -541,17 +556,7 @@ def test_empty_input(self, mode): with pytest.raises(IndexError): empty.put(1, 1, mode=mode) - @pytest.mark.parametrize( - "shape", - [ - (3,), - (4,), - ], - ids=[ - "(3,)", - "(4,)", - ], - ) + @pytest.mark.parametrize("shape", [(3,), (4,)], ids=["(3,)", "(4,)"]) @pytest.mark.parametrize("mode", ["clip", "wrap"]) def test_invalid_shape(self, shape, mode): a = dpnp.arange(7) @@ -563,17 +568,7 @@ def test_invalid_shape(self, shape, mode): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( - "axis", - [ - 1.0, - (0,), - [0, 1], - ], - ids=[ - "1.0", - "(0,)", - "[0, 1]", - ], + "axis", [1.0, (0,), [0, 1]], ids=["1.0", "(0,)", "[0, 1]"] ) def test_invalid_axis(self, xp, axis): a = xp.arange(6).reshape(2, 3) @@ -604,7 +599,8 @@ def test_replace_max(self, arr_dt, axis): # replace the max with a small value i_max = _add_keepdims(dpnp.argmax)(a, axis=axis) - dpnp.put_along_axis(a, i_max, -99, axis=axis) + val = 0 if numpy.issubdtype(arr_dt, numpy.unsignedinteger) else -99 + dpnp.put_along_axis(a, i_max, val, axis=axis) # find the new minimum, which should max i_min = _add_keepdims(dpnp.argmin)(a, axis=axis) @@ -618,8 +614,8 @@ def test_replace_max(self, arr_dt, axis): @pytest.mark.parametrize( "values", [ - 777, - [100, 200, 300, 400], + 77, + [101, 102, 103, 104], (42,), range(4), numpy.arange(4), @@ -660,9 +656,10 @@ def test_broadcast(self, arr_dt, idx_dt): ind = numpy.arange(10, dtype=idx_dt).reshape((1, 2, 5)) % 4 ia, iind = dpnp.array(a), dpnp.array(ind) - numpy.put_along_axis(a, ind, 20, axis=1) - dpnp.put_along_axis(ia, iind, 20, axis=1) - assert_array_equal(ia, a) + if idx_dt == numpy.uint64: + numpy.put_along_axis(a, ind, 20, axis=1) + dpnp.put_along_axis(ia, iind, 20, axis=1) + assert_array_equal(ia, a) def test_mode_wrap(self): a = numpy.array([-2, -1, 0, 1, 2]) @@ -692,18 +689,27 @@ class TestTake: @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("ind_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( - "indices", [[-2, 2], [-5, 4]], ids=["[-2, 2]", "[-5, 4]"] + "indices", [[-2, 2], [-4, 4]], ids=["[-2, 2]", "[-4, 4]"] ) @pytest.mark.parametrize("mode", ["clip", "wrap"]) def test_1d(self, a_dt, ind_dt, indices, mode): - a = numpy.array([-2, -1, 0, 1, 2], dtype=a_dt) - ind = numpy.array(indices, dtype=ind_dt) + a = get_abs_array([-2, -1, 0, 1, 2], a_dt) + ind = get_abs_array(indices, ind_dt) ia, iind = dpnp.array(a), dpnp.array(ind) if numpy.can_cast(ind_dt, numpy.intp, casting="safe"): result = dpnp.take(ia, iind, mode=mode) expected = numpy.take(a, ind, mode=mode) assert_array_equal(result, expected) + elif ind_dt == numpy.uint64: + # For this special case, although casting `ind_dt` to numpy.intp + # is not safe, both NumPy and dpnp work properly + # NumPy < "2.2.0" raises an error + if numpy_version() < "2.2.0": + ind = ind.astype(numpy.int64) + result = dpnp.take(ia, iind, mode=mode) + expected = numpy.take(a, ind, mode=mode) + assert_array_equal(result, expected) else: assert_raises(TypeError, ia.take, iind, mode=mode) assert_raises(TypeError, a.take, ind, mode=mode) @@ -711,28 +717,34 @@ def test_1d(self, a_dt, ind_dt, indices, mode): @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("ind_dt", get_integer_dtypes()) @pytest.mark.parametrize( - "indices", [[-1, 0], [-3, 2]], ids=["[-1, 0]", "[-3, 2]"] + "indices", [[-1, 0], [-2, 2]], ids=["[-1, 0]", "[-2, 2]"] ) @pytest.mark.parametrize("mode", ["clip", "wrap"]) - @pytest.mark.parametrize("axis", [0, 1], ids=["0", "1"]) + @pytest.mark.parametrize("axis", [0, 1]) def test_2d(self, a_dt, ind_dt, indices, mode, axis): - a = numpy.array([[-1, 0, 1], [-2, -3, -4], [2, 3, 4]], dtype=a_dt) - ind = numpy.array(indices, dtype=ind_dt) + a = get_abs_array([[-1, 0, 1], [-2, -3, -4], [2, 3, 4]], a_dt) + ind = get_abs_array(indices, ind_dt) ia, iind = dpnp.array(a), dpnp.array(ind) - result = ia.take(iind, axis=axis, mode=mode) - expected = a.take(ind, axis=axis, mode=mode) - assert_array_equal(result, expected) + if ind_dt == numpy.uint64: + # For this special case, NumPy raises an error on Windows + result = ia.take(iind, axis=axis, mode=mode) + expected = a.take(ind.astype(numpy.int64), axis=axis, mode=mode) + assert_array_equal(result, expected) + else: + result = ia.take(iind, axis=axis, mode=mode) + expected = a.take(ind, axis=axis, mode=mode) + assert_array_equal(result, expected) @pytest.mark.parametrize("a_dt", get_all_dtypes(no_none=True)) - @pytest.mark.parametrize("indices", [[-5, 5]], ids=["[-5, 5]"]) @pytest.mark.parametrize("mode", ["clip", "wrap"]) - def test_over_index(self, a_dt, indices, mode): - a = dpnp.array([-2, -1, 0, 1, 2], dtype=a_dt) - ind = dpnp.array(indices, dtype=numpy.intp) + def test_over_index(self, a_dt, mode): + a = get_abs_array([-2, -1, 0, 1, 2], a_dt) + a = dpnp.array(a) + ind = dpnp.array([-5, 5], dtype=numpy.intp) result = dpnp.take(a, ind, mode=mode) - expected = dpnp.array([-2, 2], dtype=a.dtype) + expected = get_abs_array([-2, 2], a_dt) assert_array_equal(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) @@ -880,7 +892,7 @@ def test_mode_clip(self): assert (result == dpnp.array([-2, 0, -2, 2])).all() -@pytest.mark.parametrize("val", [-1, 0, 1], ids=["-1", "0", "1"]) +@pytest.mark.parametrize("val", [-1, 0, 1]) @pytest.mark.parametrize( "array", [ @@ -929,7 +941,7 @@ def test_fill_diagonal(array, val): ], ) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) -@pytest.mark.parametrize("sparse", [True, False], ids=["True", "False"]) +@pytest.mark.parametrize("sparse", [True, False]) def test_indices(dimension, dtype, sparse): expected = numpy.indices(dimension, dtype=dtype, sparse=sparse) result = dpnp.indices(dimension, dtype=dtype, sparse=sparse) @@ -937,7 +949,6 @@ def test_indices(dimension, dtype, sparse): assert_array_equal(Xnp, X) -@pytest.mark.parametrize("vals", [[100, 200]], ids=["[100, 200]"]) @pytest.mark.parametrize( "mask", [ @@ -956,12 +967,12 @@ def test_indices(dimension, dtype, sparse): [[[0, 0], [0, 0]], [[1, 2], [1, 2]], [[1, 2], [3, 4]]], ids=["[[0, 0], [0, 0]]", "[[1, 2], [1, 2]]", "[[1, 2], [3, 4]]"], ) -def test_putmask1(arr, mask, vals): +def test_putmask1(arr, mask): a = numpy.array(arr) ia = dpnp.array(a) m = numpy.array(mask) im = dpnp.array(m) - v = numpy.array(vals) + v = numpy.array([100, 200]) iv = dpnp.array(v) numpy.putmask(a, m, v) dpnp.putmask(ia, im, iv) @@ -1060,24 +1071,16 @@ def test_putmask3(arr, mask, vals): assert_array_equal(a, ia) -@pytest.mark.parametrize( - "m", [None, 0, 1, 2, 3, 4], ids=["None", "0", "1", "2", "3", "4"] -) -@pytest.mark.parametrize( - "k", [-3, -2, -1, 0, 1, 2, 3], ids=["-3", "-2", "-1", "0", "1", "2", "3"] -) -@pytest.mark.parametrize( - "n", [1, 2, 3, 4, 5, 6], ids=["1", "2", "3", "4", "5", "6"] -) +@pytest.mark.parametrize("m", [None, 0, 1, 2, 3, 4]) +@pytest.mark.parametrize("k", [-3, -2, -1, 0, 1, 2, 3]) +@pytest.mark.parametrize("n", [1, 2, 3, 4, 5, 6]) def test_tril_indices(n, k, m): result = dpnp.tril_indices(n, k, m) expected = numpy.tril_indices(n, k, m) assert_array_equal(expected, result) -@pytest.mark.parametrize( - "k", [-3, -2, -1, 0, 1, 2, 3], ids=["-3", "-2", "-1", "0", "1", "2", "3"] -) +@pytest.mark.parametrize("k", [-3, -2, -1, 0, 1, 2, 3]) @pytest.mark.parametrize( "array", [ @@ -1095,24 +1098,16 @@ def test_tril_indices_from(array, k): assert_array_equal(expected, result) -@pytest.mark.parametrize( - "m", [None, 0, 1, 2, 3, 4], ids=["None", "0", "1", "2", "3", "4"] -) -@pytest.mark.parametrize( - "k", [-3, -2, -1, 0, 1, 2, 3], ids=["-3", "-2", "-1", "0", "1", "2", "3"] -) -@pytest.mark.parametrize( - "n", [1, 2, 3, 4, 5, 6], ids=["1", "2", "3", "4", "5", "6"] -) +@pytest.mark.parametrize("m", [None, 0, 1, 2, 3, 4]) +@pytest.mark.parametrize("k", [-3, -2, -1, 0, 1, 2, 3]) +@pytest.mark.parametrize("n", [1, 2, 3, 4, 5, 6]) def test_triu_indices(n, k, m): result = dpnp.triu_indices(n, k, m) expected = numpy.triu_indices(n, k, m) assert_array_equal(expected, result) -@pytest.mark.parametrize( - "k", [-3, -2, -1, 0, 1, 2, 3], ids=["-3", "-2", "-1", "0", "1", "2", "3"] -) +@pytest.mark.parametrize("k", [-3, -2, -1, 0, 1, 2, 3]) @pytest.mark.parametrize( "array", [ @@ -1466,6 +1461,16 @@ def test_choose_inds_all_dtypes(self, dtype): chcs = dpnp.ones(1, dtype=dtype) with pytest.raises(TypeError): dpnp.choose(inds, chcs) + elif dtype == numpy.uint64: + # For this special case, NumPy raises an error but dpnp works + inds_np = numpy.array([1, 0, 1], dtype=dtype) + inds = dpnp.array(inds_np) + chcs_np = numpy.array([1, 2, 3], dtype=dtype) + chcs = dpnp.array(chcs_np) + assert_raises(TypeError, numpy.choose, inds_np, chcs_np) + expected = numpy.choose(inds_np.astype(numpy.int64), chcs_np) + result = dpnp.choose(inds, chcs) + assert_array_equal(expected, result) else: inds_np = numpy.array([1, 0, 1], dtype=dtype) inds = dpnp.array(inds_np) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index d67e859c267..50482b929ae 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2132,7 +2132,7 @@ def test_0D(self, ord, axis): assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") - @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 0, 1, 2, 3.5, dpnp.inf] ) @@ -2147,7 +2147,7 @@ def test_1D(self, dtype, ord, axis, keepdims): assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") - @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 1, 2, 3, dpnp.inf, "fro", "nuc"] ) @@ -2172,7 +2172,10 @@ def test_2D(self, dtype, ord, axis, keepdims): assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") - @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) + @pytest.mark.parametrize( + "dtype", + get_all_dtypes(no_none=True), + ) @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 1, 2, 3, dpnp.inf, "fro", "nuc"] ) @@ -2203,7 +2206,7 @@ def test_ND(self, dtype, ord, axis, keepdims): assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") - @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 1, 2, 3, dpnp.inf, "fro", "nuc"] ) @@ -2402,10 +2405,10 @@ def test_qr(self, dtype, shape, mode): ) else: # mode=="raw" dpnp_q, dpnp_r = dpnp.linalg.qr(ia, mode) - assert_dtype_allclose(dpnp_q, np_q) + assert_dtype_allclose(dpnp_q, np_q, factor=24) if mode in ("raw", "r"): - assert_dtype_allclose(dpnp_r, np_r) + assert_dtype_allclose(dpnp_r, np_r, factor=24) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize( diff --git a/dpnp/tests/test_manipulation.py b/dpnp/tests/test_manipulation.py index 7436d43afff..4dcfe02862f 100644 --- a/dpnp/tests/test_manipulation.py +++ b/dpnp/tests/test_manipulation.py @@ -31,7 +31,9 @@ ] testdata += [ ([1, -1, 0], dtype) - for dtype in get_all_dtypes(no_none=True, no_bool=True, no_complex=True) + for dtype in get_all_dtypes( + no_none=True, no_bool=True, no_complex=True, no_unsigned=True + ) ] testdata += [([0.1, 0.0, -0.1], dtype) for dtype in get_float_dtypes()] testdata += [([1j, -1j, 1 - 2j], dtype) for dtype in get_complex_dtypes()] @@ -1744,7 +1746,7 @@ def test_7d_axis_zeros(self, axis): expected = numpy.unique(a, axis=axis) assert_array_equal(result, expected) - @pytest.mark.parametrize("dt", get_integer_dtypes()) + @pytest.mark.parametrize("dt", get_integer_dtypes(no_unsigned=True)) def test_2d_axis_signed_inetger(self, dt): a = numpy.array([[-1], [0]], dtype=dt) ia = dpnp.array(a) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 75c18075d3c..3f64695ddf5 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -23,6 +23,7 @@ from .helper import ( assert_dtype_allclose, generate_random_numpy_array, + get_abs_array, get_all_dtypes, get_complex_dtypes, get_float_complex_dtypes, @@ -30,6 +31,7 @@ get_integer_dtypes, has_support_aspect16, has_support_aspect64, + numpy_version, ) from .test_umath import ( _get_numpy_arrays_1in_1out, @@ -39,8 +41,8 @@ from .third_party.cupy import testing +@pytest.mark.parametrize("deg", [True, False]) class TestAngle: - @pytest.mark.parametrize("deg", [True, False]) def test_angle_bool(self, deg): dp_a = dpnp.array([True, False]) np_a = dp_a.asnumpy() @@ -56,7 +58,6 @@ def test_angle_bool(self, deg): @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_complex=True) ) - @pytest.mark.parametrize("deg", [True, False]) def test_angle(self, dtype, deg): dp_a = dpnp.arange(10, dtype=dtype) np_a = dp_a.asnumpy() @@ -64,10 +65,11 @@ def test_angle(self, dtype, deg): expected = numpy.angle(np_a, deg=deg) result = dpnp.angle(dp_a, deg=deg) - assert_dtype_allclose(result, expected) + # For dtype=int8, uint8, NumPy returns float16, but dpnp returns float32 + dt_int8 = dtype in [dpnp.int8, dpnp.uint8] + assert_dtype_allclose(result, expected, check_only_type_kind=dt_int8) @pytest.mark.parametrize("dtype", get_complex_dtypes()) - @pytest.mark.parametrize("deg", [True, False]) def test_angle_complex(self, dtype, deg): a = numpy.random.rand(10) b = numpy.random.rand(10) @@ -258,7 +260,8 @@ def test_basic(self, dtype, axis, include_initial): res = dpnp.cumlogsumexp(a, axis=axis, include_initial=include_initial) exp_dt = None - if dtype == dpnp.bool: + dtype_list = [dpnp.bool, dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + if dtype in dtype_list: exp_dt = dpnp.default_float_type(a.device) exp = self._get_exp_array(a, axis, exp_dt) @@ -311,7 +314,9 @@ def test_dtype(self, in_dtype, out_dtype): exp = numpy.logaddexp.accumulate(dpnp.asnumpy(a)) exp = exp.astype(out_dtype) - assert_allclose(res, exp, rtol=1e-06) + dtype_list = [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + tol = 1e-2 if in_dtype in dtype_list else 1e-6 + assert_allclose(res, exp, rtol=tol) @pytest.mark.usefixtures("suppress_invalid_numpy_warnings") @pytest.mark.parametrize( @@ -391,7 +396,7 @@ def test_usm_ndarray(self, sh, xp_in, xp_out, check): @pytest.mark.parametrize("out_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_out_dtype(self, arr_dt, out_dt, dtype): - a = numpy.arange(5, 10).astype(dtype=arr_dt) + a = numpy.arange(1, 6).astype(dtype=arr_dt) out = numpy.zeros_like(a, dtype=out_dt) ia = dpnp.array(a) @@ -495,7 +500,7 @@ def test_usm_ndarray(self, sh, xp_in, xp_out, check): @pytest.mark.parametrize("out_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_out_dtype(self, arr_dt, out_dt, dtype): - a = numpy.arange(10, 20).astype(dtype=arr_dt) + a = numpy.arange(5, 15).astype(dtype=arr_dt) out = numpy.zeros_like(a, dtype=out_dt) ia = dpnp.array(a) @@ -869,9 +874,7 @@ class TestFix: "dt", get_all_dtypes(no_none=True, no_complex=True) ) def test_basic(self, dt): - a = numpy.array( - [[1.0, 1.1, 1.5, 1.8], [-1.0, -1.1, -1.5, -1.8]], dtype=dt - ) + a = get_abs_array([[1.0, 1.1, 1.5, 1.8], [-1.0, -1.1, -1.5, -1.8]], dt) ia = dpnp.array(a) result = dpnp.fix(ia) @@ -889,15 +892,12 @@ def test_complex(self, xp, dt): "a_dt", get_all_dtypes(no_none=True, no_bool=True, no_complex=True) ) def test_out(self, a_dt): - a = numpy.array( - [[1.0, 1.1, 1.5, 1.8], [-1.0, -1.1, -1.5, -1.8]], dtype=a_dt + a = get_abs_array( + [[1.0, 1.1, 1.5, 1.8], [-1.0, -1.1, -1.5, -1.8]], a_dt ) ia = dpnp.array(a) - if a.dtype != numpy.float32 and has_support_aspect64(): - out_dt = numpy.float64 - else: - out_dt = numpy.float32 + out_dt = _get_output_data_type(a.dtype) out = numpy.zeros_like(a, dtype=out_dt) iout = dpnp.array(out) @@ -1314,7 +1314,10 @@ def test_1d(self, dt): result = dpnp.i0(ia) expected = numpy.i0(a) - assert_dtype_allclose(result, expected) + # NumPy promotes result of integer inputs to float64, but dpnp + # follows Type Promotion Rules + flag = dt in [numpy.int8, numpy.int16, numpy.uint8, numpy.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) @pytest.mark.parametrize("dt", get_float_dtypes()) def test_2d(self, dt): @@ -1664,7 +1667,7 @@ def test_prod_out(self): @pytest.mark.parametrize("out_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_prod_out_dtype(self, arr_dt, out_dt, dtype): - a = numpy.arange(10, 20).reshape((2, 5)).astype(dtype=arr_dt) + a = numpy.arange(1, 7).reshape((2, 3)).astype(dtype=arr_dt) out = numpy.zeros_like(a, shape=(2,), dtype=out_dt) ia = dpnp.array(a) @@ -1726,12 +1729,16 @@ class TestSinc: "dt", get_all_dtypes(no_none=True, no_bool=True, no_float16=False) ) def test_basic(self, dt): + low = 0 if dpnp.issubdtype(dt, dpnp.integer) else -1 a = numpy.linspace(-1, 1, 100, dtype=dt) ia = dpnp.array(a) result = dpnp.sinc(ia) expected = numpy.sinc(a) - assert_dtype_allclose(result, expected) + # numpy promotes result for integer inputs to float64 dtype, but dpnp + # follows Type Promotion Rules similar to other trigonometric functions + flag = dt in [numpy.int8, numpy.int16, numpy.uint8, numpy.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) def test_bool(self): a = numpy.array([True, False, True]) @@ -1749,7 +1756,10 @@ def test_zero(self, dt): result = dpnp.sinc(ia) expected = numpy.sinc(a) - assert_dtype_allclose(result, expected) + # numpy promotes result for integer inputs to float64 dtype, but dpnp + # follows Type Promotion Rules similar to other trigonometric functions + flag = dt in [numpy.int8, numpy.int16, numpy.uint8, numpy.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) # TODO: add a proper NumPy version once resolved @testing.with_requires("numpy>=2.0.0") @@ -1825,7 +1835,7 @@ def test_zeros(self, dt): result = dpnp.spacing(ia) expected = numpy.spacing(a) tol = numpy.finfo(expected.dtype).resolution - if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": + if numpy_version() < "2.0.0": assert_allclose(result, expected, rtol=tol, atol=tol) else: # numpy.spacing(-0.0) == numpy.spacing(0.0), i.e. NumPy returns @@ -1865,7 +1875,7 @@ def test_fp16(self): @pytest.mark.parametrize("dt", get_integer_dtypes()) def test_integer(self, dt): - a = numpy.array([1, 0, -3], dtype=dt) + a = get_abs_array([1, 0, -3], dt) ia = dpnp.array(a) result = dpnp.spacing(ia) @@ -1888,7 +1898,7 @@ def test_complex(self, xp): class TestTrapezoid: def get_numpy_func(self): - if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": + if numpy_version() < "2.0.0": # `trapz` is deprecated in NumPy 2.0 return numpy.trapz return numpy.trapezoid @@ -2022,27 +2032,32 @@ def test_rand(self, dt): assert_dtype_allclose(result, expected) @pytest.mark.parametrize( - "dt", get_all_dtypes(no_none=True, no_bool=True, no_complex=True) + "dt", + get_all_dtypes( + no_none=True, no_bool=True, no_complex=True, no_unsigned=True + ), ) def test_period(self, dt): - a = numpy.array([1, 1 + 256], dtype=dt) + a = numpy.array([1, 1 + 108], dtype=dt) ia = dpnp.array(a) - # unwrap removes jumps greater than 255 - result = dpnp.unwrap(ia, period=255) - expected = numpy.unwrap(a, period=255) + # unwrap removes jumps greater than 107 + result = dpnp.unwrap(ia, period=107) + expected = numpy.unwrap(a, period=107) assert_array_equal(result, expected) @pytest.mark.parametrize( - "dt", get_all_dtypes(no_none=True, no_bool=True, no_complex=True) + "dt", + get_all_dtypes( + no_none=True, no_bool=True, no_complex=True, no_unsigned=True + ), ) def test_rand_period(self, dt): - a = generate_random_numpy_array(10) * 1000 - a = a.astype(dtype=dt) + a = generate_random_numpy_array(10, dt, low=-100, high=100) ia = dpnp.array(a) - result = dpnp.unwrap(ia, period=255) - expected = numpy.unwrap(a, period=255) + result = dpnp.unwrap(ia, period=25) + expected = numpy.unwrap(a, period=25) assert_dtype_allclose(result, expected) def test_simple_seq(self): @@ -2056,19 +2071,21 @@ def test_simple_seq(self): assert_array_equal(result, isimple_seq) @pytest.mark.parametrize( - "dt", get_all_dtypes(no_none=True, no_complex=True) + "dt", + get_all_dtypes( + no_bool=True, no_none=True, no_complex=True, no_unsigned=True + ), ) def test_discont(self, dt): - a = numpy.array([0, 75, 150, 225, 300, 430], dtype=dt) - a = numpy.mod(a, 250) + a = numpy.array([0, 8, 20, 25, 35, 50], dtype=dt) ia = dpnp.array(a) - result = dpnp.unwrap(ia, period=250) - expected = numpy.unwrap(a, period=250) + result = dpnp.unwrap(ia, period=20) + expected = numpy.unwrap(a, period=20) assert_array_equal(result, expected) - result = dpnp.unwrap(ia, period=250, discont=140) - expected = numpy.unwrap(a, period=250, discont=140) + result = dpnp.unwrap(ia, period=20, discont=14) + expected = numpy.unwrap(a, period=20, discont=14) assert_array_equal(result, expected) assert result.dtype == ia.dtype == a.dtype @@ -2183,10 +2200,12 @@ def test_divide_scalar(shape, dtype): [[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]], ids=["[[1., -1.], [0.1, -0.1]]", "[-2, -1, 0, 1, 2]"], ) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_unsigned=True) +) def test_negative(data, dtype): np_a = numpy.array(data, dtype=dtype) - dpnp_a = dpnp.array(data, dtype=dtype) + dpnp_a = dpnp.array(np_a) result = dpnp.negative(dpnp_a) expected = numpy.negative(np_a) @@ -2218,8 +2237,8 @@ def test_negative_boolean(): ) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) def test_positive(data, dtype): - np_a = numpy.array(data, dtype=dtype) - dpnp_a = dpnp.array(data, dtype=dtype) + np_a = get_abs_array(data, dtype=dtype) + dpnp_a = dpnp.array(np_a) result = dpnp.positive(dpnp_a) expected = numpy.positive(np_a) @@ -2295,7 +2314,9 @@ def test_float_remainder_fmod_nans_inf(func, dtype, lhs, rhs): [[2, 0, -2], [1.1, -1.1]], ids=["[2, 0, -2]", "[1.1, -1.1]"], ) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_unsigned=True) +) def test_sign(data, dtype): np_a = numpy.array(data, dtype=dtype) dpnp_a = dpnp.array(data, dtype=dtype) @@ -2324,7 +2345,9 @@ def test_sign_boolean(): [[2, 0, -2], [1.1, -1.1]], ids=["[2, 0, -2]", "[1.1, -1.1]"], ) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_complex=True, no_unsigned=True) +) def test_signbit(data, dtype): np_a = numpy.array(data, dtype=dtype) dpnp_a = dpnp.array(data, dtype=dtype) @@ -2433,10 +2456,7 @@ def test_out(self, func_params, dtype): # NumPy < 2.0.0 while output has the dtype of input for NumPy >= 2.0.0 # (dpnp follows the latter behavior except for boolean dtype where it # returns int8) - if ( - numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" - or dtype == numpy.bool - ): + if numpy_version() < "2.0.0" or dtype == numpy.bool: check_type = False else: check_type = True @@ -2525,11 +2545,14 @@ class TestLogSumExp: def test_logsumexp(self, dtype, axis, keepdims): a = dpnp.ones((3, 4, 5, 6, 7), dtype=dtype) res = dpnp.logsumexp(a, axis=axis, keepdims=keepdims) - exp_dtype = ( - dpnp.default_float_type(a.device) if dtype == dpnp.bool else None - ) + + exp_dt = None + dtype_list = [dpnp.bool, dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + if dtype in dtype_list: + exp_dt = dpnp.default_float_type(a.device) + exp = numpy.logaddexp.reduce( - dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dtype + dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dt ) assert_dtype_allclose(res, exp) @@ -2539,17 +2562,18 @@ def test_logsumexp(self, dtype, axis, keepdims): @pytest.mark.parametrize("keepdims", [True, False]) def test_logsumexp_out(self, dtype, axis, keepdims): a = dpnp.ones((3, 4, 5, 6, 7), dtype=dtype) - exp_dtype = ( - dpnp.default_float_type(a.device) if dtype == dpnp.bool else None - ) + exp_dt = None + dtype_list = [dpnp.bool, dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + if dtype in dtype_list: + exp_dt = dpnp.default_float_type(a.device) exp = numpy.logaddexp.reduce( - dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dtype + dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dt ) - exp_dtype = exp.dtype - if exp_dtype == numpy.float64 and not has_support_aspect64(): - exp_dtype = numpy.float32 - dpnp_out = dpnp.empty_like(a, shape=exp.shape, dtype=exp_dtype) + exp_dt = exp.dtype + if exp_dt == numpy.float64 and not has_support_aspect64(): + exp_dt = numpy.float32 + dpnp_out = dpnp.empty_like(a, shape=exp.shape, dtype=exp_dt) res = dpnp.logsumexp(a, axis=axis, out=dpnp_out, keepdims=keepdims) assert res is dpnp_out @@ -2565,7 +2589,9 @@ def test_logsumexp_dtype(self, in_dtype, out_dtype): exp = numpy.logaddexp.reduce(dpnp.asnumpy(a)) exp = exp.astype(out_dtype) - assert_allclose(res, exp, rtol=1e-06) + dtype_list = [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + tol = 1e-2 if in_dtype in dtype_list else 1e-6 + assert_allclose(res, exp, rtol=tol) @testing.with_requires("numpy>=1.26.4") @pytest.mark.usefixtures("suppress_invalid_numpy_warnings") @@ -2577,15 +2603,23 @@ def test_logsumexp_dtype(self, in_dtype, out_dtype): ) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_logsumexp_out_dtype(self, arr_dt, out_dt, dtype): - a = numpy.arange(10, 20).reshape((2, 5)).astype(dtype=arr_dt) + a = numpy.arange(1, 11).reshape((2, 5)).astype(dtype=arr_dt) out = numpy.zeros_like(a, shape=(2,), dtype=out_dt) ia = dpnp.array(a) iout = dpnp.array(out) result = dpnp.logsumexp(ia, out=iout, dtype=dtype, axis=1) - exp = numpy.logaddexp.reduce(a, out=out, axis=1) - assert_allclose(result, exp.astype(dtype), rtol=1e-06) + if numpy.issubdtype(out_dt, numpy.uint64): + # NumPy returns incorrect results for this case if out kwarg is used + exp = numpy.logaddexp.reduce(a, axis=1) + exp = exp.astype(out_dt) + else: + exp = numpy.logaddexp.reduce(a, out=out, axis=1) + + dtype_list = [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + tol = 1e-2 if arr_dt in dtype_list else 1e-6 + assert_allclose(result, exp.astype(dtype), rtol=tol) assert result is iout @@ -2596,11 +2630,14 @@ class TestReduceHypot: def test_reduce_hypot(self, dtype, axis, keepdims): a = dpnp.ones((3, 4, 5, 6, 7), dtype=dtype) res = dpnp.reduce_hypot(a, axis=axis, keepdims=keepdims) - exp_dtype = ( - dpnp.default_float_type(a.device) if dtype == dpnp.bool else None - ) + + exp_dt = None + dtype_list = [dpnp.bool, dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + if dtype in dtype_list: + exp_dt = dpnp.default_float_type(a.device) + exp = numpy.hypot.reduce( - dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dtype + dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dt ) assert_dtype_allclose(res, exp) @@ -2610,17 +2647,18 @@ def test_reduce_hypot(self, dtype, axis, keepdims): @pytest.mark.parametrize("keepdims", [True, False]) def test_reduce_hypot_out(self, dtype, axis, keepdims): a = dpnp.ones((3, 4, 5, 6, 7), dtype=dtype) - exp_dtype = ( - dpnp.default_float_type(a.device) if dtype == dpnp.bool else None - ) + exp_dt = None + dtype_list = [dpnp.bool, dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + if dtype in dtype_list: + exp_dt = dpnp.default_float_type(a.device) exp = numpy.hypot.reduce( - dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dtype + dpnp.asnumpy(a), axis=axis, keepdims=keepdims, dtype=exp_dt ) - exp_dtype = exp.dtype - if exp_dtype == numpy.float64 and not has_support_aspect64(): - exp_dtype = numpy.float32 - dpnp_out = dpnp.empty_like(a, shape=exp.shape, dtype=exp_dtype) + exp_dt = exp.dtype + if exp_dt == numpy.float64 and not has_support_aspect64(): + exp_dt = numpy.float32 + dpnp_out = dpnp.empty_like(a, shape=exp.shape, dtype=exp_dt) res = dpnp.reduce_hypot(a, axis=axis, out=dpnp_out, keepdims=keepdims) assert res is dpnp_out @@ -2636,7 +2674,9 @@ def test_reduce_hypot_dtype(self, in_dtype, out_dtype): exp = numpy.hypot.reduce(dpnp.asnumpy(a)) exp = exp.astype(out_dtype) - assert_allclose(res, exp, rtol=1e-06) + dtype_list = [dpnp.int8, dpnp.uint8] + tol = 1e-2 if in_dtype in dtype_list else 1e-6 + assert_allclose(res, exp, rtol=tol) @pytest.mark.parametrize( "arr_dt", get_all_dtypes(no_none=True, no_complex=True) diff --git a/dpnp/tests/test_nanfunctions.py b/dpnp/tests/test_nanfunctions.py index 19ffb28e92b..a0b5d808697 100644 --- a/dpnp/tests/test_nanfunctions.py +++ b/dpnp/tests/test_nanfunctions.py @@ -17,6 +17,7 @@ from .helper import ( assert_dtype_allclose, generate_random_numpy_array, + get_abs_array, get_all_dtypes, get_complex_dtypes, get_float_complex_dtypes, @@ -590,7 +591,7 @@ def test_nanprod_out(self): @pytest.mark.parametrize("out_dt", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_nanprod_out_dtype(self, arr_dt, out_dt, dtype): - a = numpy.arange(10, 20).reshape((2, 5)).astype(dtype=arr_dt) + a = numpy.arange(1, 7).reshape((2, 3)).astype(dtype=arr_dt) out = numpy.zeros_like(a, shape=(2,), dtype=out_dt) ia = dpnp.array(a) @@ -659,9 +660,9 @@ class TestNanStdVar: ) def test_basic(self, array, dtype): try: - a = numpy.array(array, dtype=dtype) + a = get_abs_array(array, dtype=dtype) except: - pytest.skip("floating datat type is needed to store NaN") + pytest.skip("floating data type is needed to store NaN") ia = dpnp.array(a) for ddof in range(a.ndim): diff --git a/dpnp/tests/test_ndarray.py b/dpnp/tests/test_ndarray.py index dd790c8e56a..e834f56749f 100644 --- a/dpnp/tests/test_ndarray.py +++ b/dpnp/tests/test_ndarray.py @@ -11,6 +11,7 @@ import dpnp from .helper import ( + get_abs_array, get_all_dtypes, get_complex_dtypes, get_float_dtypes, @@ -28,7 +29,7 @@ ids=["[-2, -1, 0, 1, 2]", "[[-2, -1], [1, 2]]", "[]"], ) def test_astype(arr, arr_dtype, res_dtype): - numpy_array = numpy.array(arr, dtype=arr_dtype) + numpy_array = get_abs_array(arr, arr_dtype) dpnp_array = dpnp.array(numpy_array) expected = numpy_array.astype(res_dtype) result = dpnp_array.astype(res_dtype) @@ -93,8 +94,8 @@ def test_create_from_usm_ndarray_error(arr): ids=["[-2, -1, 0, 1, 2]", "[[-2, -1], [1, 2]]", "[]"], ) def test_flatten(arr, arr_dtype): - numpy_array = numpy.array(arr, dtype=arr_dtype) - dpnp_array = dpnp.array(arr, dtype=arr_dtype) + numpy_array = get_abs_array(arr, arr_dtype) + dpnp_array = dpnp.array(numpy_array) expected = numpy_array.flatten() result = dpnp_array.flatten() assert_array_equal(expected, result) diff --git a/dpnp/tests/test_outer.py b/dpnp/tests/test_outer.py index 77f57ebf7dd..bcdc8091ed0 100644 --- a/dpnp/tests/test_outer.py +++ b/dpnp/tests/test_outer.py @@ -59,14 +59,14 @@ class TestScalarOuter(unittest.TestCase): @testing.numpy_cupy_allclose(type_check=False) def test_first_is_scalar(self, xp, dtype): scalar = 4 - a = xp.arange(5**3, dtype=dtype).reshape(5, 5, 5) + a = xp.arange(24, dtype=dtype).reshape(2, 3, 4) return xp.outer(scalar, a) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(type_check=False) def test_second_is_scalar(self, xp, dtype): - scalar = 7 - a = xp.arange(5**3, dtype=dtype).reshape(5, 5, 5) + scalar = 5 + a = xp.arange(24, dtype=dtype).reshape(2, 3, 4) return xp.outer(a, scalar) diff --git a/dpnp/tests/test_product.py b/dpnp/tests/test_product.py index ba305540632..b7cbfcf61e6 100644 --- a/dpnp/tests/test_product.py +++ b/dpnp/tests/test_product.py @@ -6,12 +6,15 @@ from numpy.testing import assert_allclose, assert_array_equal, assert_raises import dpnp +from dpnp.dpnp_utils import map_dtype_to_device from .helper import ( assert_dtype_allclose, generate_random_numpy_array, get_all_dtypes, get_complex_dtypes, + is_win_platform, + numpy_version, ) from .third_party.cupy import testing @@ -20,18 +23,6 @@ _selected_dtypes = [numpy.int64, numpy.float32] -def _assert_selective_dtype_allclose(result, expected, dtype): - # For numpy.dot, numpy.vdot, numpy.kron, numpy.inner, and numpy.tensordot, - # when inputs are an scalar (which has the default dtype of platform) and - # an array, the scalar dtype precision determines the output dtype - # precision. In dpnp, we rely on dpnp.multiply for scalar-array product - # and array (not scalar) determines output dtype precision of dpnp.multiply - if dtype in [numpy.int32, numpy.float32, numpy.complex64]: - assert_dtype_allclose(result, expected, check_only_type_kind=True) - else: - assert_dtype_allclose(result, expected) - - class TestCross: def setup_method(self): numpy.random.seed(42) @@ -226,11 +217,11 @@ def test_scalar(self, dtype): result = dpnp.dot(a, ib) expected = numpy.dot(a, b) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) result = dpnp.dot(ib, a) expected = numpy.dot(b, a) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( @@ -261,8 +252,8 @@ def test_scalar(self, dtype): ], ) def test_basic(self, dtype, shape1, shape2): - a = generate_random_numpy_array(shape1, dtype) - b = generate_random_numpy_array(shape2, dtype) + a = generate_random_numpy_array(shape1, dtype, low=-5, high=5) + b = generate_random_numpy_array(shape2, dtype, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -293,12 +284,15 @@ def test_out_scalar(self, dtype): b = generate_random_numpy_array(10, dtype) ib = dpnp.array(b) - dp_out = dpnp.empty(10, dtype=dtype) + np_res_dtype = numpy.result_type(type(a), b) + out = numpy.empty(10, dtype=np_res_dtype) + dp_res_dtype = map_dtype_to_device(np_res_dtype, ib.sycl_device) + dp_out = dpnp.array(out, dtype=dp_res_dtype) result = dpnp.dot(a, ib, out=dp_out) - expected = numpy.dot(a, b) + expected = numpy.dot(a, b, out=out) assert result is dp_out - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes()) @pytest.mark.parametrize( @@ -329,8 +323,8 @@ def test_out_scalar(self, dtype): ], ) def test_out(self, dtype, shape1, shape2, out_shape): - a = generate_random_numpy_array(shape1, dtype) - b = generate_random_numpy_array(shape2, dtype) + a = generate_random_numpy_array(shape1, dtype, low=-5, high=5) + b = generate_random_numpy_array(shape2, dtype, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -381,7 +375,9 @@ def test_out_error_scalar(self, ia): # output data type is incorrect dp_out = dpnp.empty((10,), dtype=dpnp.complex64) out = numpy.empty((10,), dtype=numpy.complex64) - assert_raises(ValueError, dpnp.dot, ia, ib, out=dp_out) + # For scalar dpnp raises TypeError, and for empty array raises ValueError + # NumPy raises ValueError for both cases + assert_raises((TypeError, ValueError), dpnp.dot, ia, ib, out=dp_out) assert_raises(ValueError, numpy.dot, a, b, out=out) # output shape is incorrect @@ -447,11 +443,11 @@ def test_scalar(self, dtype): result = dpnp.inner(a, ib) expected = numpy.inner(a, b) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) result = dpnp.inner(ib, a) expected = numpy.inner(b, a) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( @@ -465,8 +461,8 @@ def test_scalar(self, dtype): ], ) def test_basic(self, dtype, shape1, shape2): - a = generate_random_numpy_array(shape1, dtype) - b = generate_random_numpy_array(shape2, dtype) + a = generate_random_numpy_array(shape1, dtype, low=-5, high=5) + b = generate_random_numpy_array(shape2, dtype, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -515,11 +511,14 @@ def test_scalar(self, dtype): result = dpnp.kron(a, ib) expected = numpy.kron(a, b) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) result = dpnp.kron(ib, a) expected = numpy.kron(b, a) - _assert_selective_dtype_allclose(result, expected, dtype) + # NumPy returns incorrect dtype for numpy_version() < "2.0.0" + flag = dtype in [numpy.int64, numpy.float64, numpy.complex128] + flag = flag or numpy_version() >= "2.0.0" + assert_dtype_allclose(result, expected, check_type=flag) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( @@ -699,8 +698,8 @@ def test_basic(self, dtype, order1, order2, shape1, shape2): ], ) def test_axes_ND_ND(self, axes): - a = generate_random_numpy_array((2, 5, 3, 4)) - b = generate_random_numpy_array((4, 2, 5, 3)) + a = generate_random_numpy_array((2, 5, 3, 4), low=-5, high=5) + b = generate_random_numpy_array((4, 2, 5, 3), low=-5, high=5) ia, ib = dpnp.array(a), dpnp.array(b) result = dpnp.matmul(ia, ib, axes=axes) @@ -769,8 +768,8 @@ def test_axes_1D_1D(self): ], ) def test_axes_out(self, dtype, axes, out_shape): - a = generate_random_numpy_array((2, 5, 3, 4), dtype) - b = generate_random_numpy_array((4, 2, 5, 3), dtype) + a = generate_random_numpy_array((2, 5, 3, 4), dtype, low=-5, high=5) + b = generate_random_numpy_array((4, 2, 5, 3), dtype, low=-5, high=5) ia, ib = dpnp.array(a), dpnp.array(b) iout = dpnp.empty(out_shape, dtype=dtype) @@ -814,8 +813,8 @@ def test_axes_out_1D(self, axes, b_shape, out_shape): ids=["gemv", "gemm", "gemm_batch"], ) def test_dtype_matrix(self, dt_in1, dt_in2, dt_out, shape1, shape2): - a = generate_random_numpy_array(shape1, dt_in1) - b = generate_random_numpy_array(shape2, dt_in2) + a = generate_random_numpy_array(shape1, dt_in1, low=-5, high=5) + b = generate_random_numpy_array(shape2, dt_in2, low=-5, high=5) ia, ib = dpnp.array(a), dpnp.array(b) out_shape = shape1[:-2] + (shape1[-2], shape2[-1]) @@ -837,7 +836,11 @@ def test_dtype_matrix(self, dt_in1, dt_in2, dt_out, shape1, shape2): assert_allclose(result, expected, rtol=1e-5, atol=1e-5) else: assert_raises(TypeError, dpnp.matmul, ia, ib, dtype=dt_out) - assert_raises(TypeError, numpy.matmul, a, b, dtype=dt_out) + # If one of the inputs is `uint64`, and dt_out is not unsigned int + # NumPy raises TypeError when `out` is provide but not when `dtype` + # is provided. dpnp raises TypeError in both cases as expected + if a.dtype != numpy.uint64 and b.dtype != numpy.uint64: + assert_raises(TypeError, numpy.matmul, a, b, dtype=dt_out) assert_raises(TypeError, dpnp.matmul, ia, ib, out=iout) assert_raises(TypeError, numpy.matmul, a, b, out=out) @@ -1053,8 +1056,8 @@ def test_strided_vec_mat(self, dtype, func, incx, incy, transpose): @pytest.mark.parametrize("dtype", _selected_dtypes) def test_out_order1(self, order1, order2, out_order, dtype): # test gemm with out keyword - a = generate_random_numpy_array((5, 4), dtype) - b = generate_random_numpy_array((4, 7), dtype) + a = generate_random_numpy_array((5, 4), dtype, low=-5, high=5) + b = generate_random_numpy_array((4, 7), dtype, low=-5, high=5) a = numpy.array(a, order=order1) b = numpy.array(b, order=order2) ia, ib = dpnp.array(a), dpnp.array(b) @@ -1075,6 +1078,10 @@ def test_out_order1(self, order1, order2, out_order, dtype): def test_out_order2(self, trans_in, trans_out, dtype): # test gemm_batch with out keyword # the base of output array is c-contiguous or f-contiguous + a = generate_random_numpy_array((2, 4, 3), dtype, low=-5, high=5) + b = generate_random_numpy_array((2, 5, 4), dtype, low=-5, high=5) + ia, ib = dpnp.array(a), dpnp.array(b) + if trans_in: # the base of input arrays is f-contiguous a = generate_random_numpy_array((2, 4, 3), dtype) @@ -1441,8 +1448,8 @@ def setup_method(self): ], ) def test_basic(self, dtype, shape1, shape2): - a = generate_random_numpy_array(shape1, dtype) - b = generate_random_numpy_array(shape2, dtype) + a = generate_random_numpy_array(shape1, dtype, low=-5, high=5) + b = generate_random_numpy_array(shape2, dtype, low=-5, high=5) ia, ib = dpnp.array(a), dpnp.array(b) result = dpnp.matvec(ia, ib) @@ -1505,7 +1512,7 @@ def setup_method(self): ((6,), (6, 10), (10, 7), (7, 8)), ((4, 6), (6, 10), (10, 7), (7,)), ((6,), (6, 10), (10, 7), (7,)), - ((4, 6), (6, 9), (9, 7), (7, 8), (8, 3)), + ((4, 6), (6, 2), (2, 7), (7, 5), (5, 3)), ], ids=[ "two_arrays", @@ -1525,7 +1532,7 @@ def test_basic(self, shapes, dtype): numpy_array_list = [] dpnp_array_list = [] for shape in shapes: - a = generate_random_numpy_array(shape, dtype) + a = generate_random_numpy_array(shape, dtype, low=-2, high=2) ia = dpnp.array(a) numpy_array_list.append(a) @@ -1549,7 +1556,7 @@ def test_basic(self, shapes, dtype): ((6,), (6, 10), (10, 7), (7, 8), (8,)), ((4, 6), (6, 10), (10, 7), (7,), (4,)), ((6,), (6, 10), (10, 7), (7,), ()), - ((4, 6), (6, 9), (9, 7), (7, 8), (8, 3), (4, 3)), + ((4, 6), (6, 2), (2, 7), (7, 5), (5, 3), (4, 3)), ], ids=[ "two_arrays", @@ -1569,7 +1576,7 @@ def test_out(self, shapes, dtype): numpy_array_list = [] dpnp_array_list = [] for shape in shapes[:-1]: - a = generate_random_numpy_array(shape, dtype) + a = generate_random_numpy_array(shape, dtype, low=-2, high=2) ia = dpnp.array(a) numpy_array_list.append(a) @@ -1656,17 +1663,17 @@ def test_scalar(self, dtype): result = dpnp.tensordot(a, ib, axes=0) expected = numpy.tensordot(a, b, axes=0) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) result = dpnp.tensordot(ib, a, axes=0) expected = numpy.tensordot(b, a, axes=0) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("axes", [0, 1, 2]) def test_basic(self, dtype, axes): - a = generate_random_numpy_array((4, 4, 4), dtype) - b = generate_random_numpy_array((4, 4, 4), dtype) + a = generate_random_numpy_array((4, 4, 4), dtype, low=-5, high=5) + b = generate_random_numpy_array((4, 4, 4), dtype, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -1686,8 +1693,8 @@ def test_basic(self, dtype, axes): ], ) def test_axes(self, dtype, axes): - a = generate_random_numpy_array((2, 5, 3, 4), dtype) - b = generate_random_numpy_array((4, 2, 5, 3), dtype) + a = generate_random_numpy_array((2, 5, 3, 4), dtype, low=-5, high=5) + b = generate_random_numpy_array((4, 2, 5, 3), dtype, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -1698,8 +1705,8 @@ def test_axes(self, dtype, axes): @pytest.mark.parametrize("dtype1", get_all_dtypes()) @pytest.mark.parametrize("dtype2", get_all_dtypes()) def test_input_dtype_matrix(self, dtype1, dtype2): - a = generate_random_numpy_array((3, 4, 5), dtype1) - b = generate_random_numpy_array((4, 5, 2), dtype2) + a = generate_random_numpy_array((3, 4, 5), dtype1, low=-5, high=5) + b = generate_random_numpy_array((4, 5, 2), dtype2, low=-5, high=5) ia = dpnp.array(a) ib = dpnp.array(b) @@ -1790,11 +1797,11 @@ def test_scalar(self, dtype): result = dpnp.vdot(ia, b) expected = numpy.vdot(a, b) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) result = dpnp.vdot(b, ia) expected = numpy.vdot(b, a) - _assert_selective_dtype_allclose(result, expected, dtype) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( @@ -2167,8 +2174,8 @@ def setup_method(self): ], ) def test_basic(self, dtype, shape1, shape2): - a = generate_random_numpy_array(shape1, dtype) - b = generate_random_numpy_array(shape2, dtype) + a = generate_random_numpy_array(shape1, dtype, low=-5, high=5) + b = generate_random_numpy_array(shape2, dtype, low=-5, high=5) ia, ib = dpnp.array(a), dpnp.array(b) result = dpnp.vecmat(ia, ib) diff --git a/dpnp/tests/test_random_state.py b/dpnp/tests/test_random_state.py index 72afd5fcb24..2ed67259e0e 100644 --- a/dpnp/tests/test_random_state.py +++ b/dpnp/tests/test_random_state.py @@ -241,7 +241,7 @@ def test_fallback(self, loc, scale): float, dpnp.int64, dpnp.int32, - dpnp.int, + dpnp.int_, int, numpy.clongdouble, dpnp.complex128, @@ -254,7 +254,7 @@ def test_fallback(self, loc, scale): "float", "dpnp.int64", "dpnp.int32", - "dpnp.int", + "dpnp.int_", "int", "numpy.clongdouble", "dpnp.complex128", @@ -364,8 +364,8 @@ def test_wrong_dims(self): class TestRandInt: @pytest.mark.parametrize( "dtype", - [int, dpnp.int32, dpnp.int], - ids=["int", "dpnp.int32", "dpnp.int"], + [int, dpnp.int32, dpnp.int_], + ids=["int", "dpnp.int32", "dpnp.int_"], ) @pytest.mark.parametrize( "usm_type", @@ -377,7 +377,7 @@ def test_distr(self, dtype, usm_type): low = 1 high = 10 - if dtype == dpnp.int and dtype != dpnp.dtype("int32"): + if dtype == dpnp.int_ and dtype != dpnp.dtype("int32"): pytest.skip( "dtype isn't alias on dpnp.int32 on the target OS, so there will be a fallback" ) @@ -564,10 +564,10 @@ def test_bounds_fallback(self, low, high): @pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize( "dtype", - [dpnp.int64, dpnp.int, dpnp.bool, dpnp.bool_, bool], + [dpnp.int64, dpnp.int_, dpnp.bool, dpnp.bool_, bool], ids=[ "dpnp.int64", - "dpnp.int", + "dpnp.int_", "dpnp.bool", "dpnp.bool_", "bool", @@ -579,7 +579,7 @@ def test_dtype_fallback(self, dtype): high = 37 if not dtype in {dpnp.bool_, bool} else 2 size = (3, 2, 5) - if dtype == dpnp.int and dtype == dpnp.dtype("int32"): + if dtype == dpnp.int_ and dtype == dpnp.dtype("int32"): pytest.skip( "dtype is alias on dpnp.int32 on the target OS, so no fallback here" ) @@ -1155,7 +1155,7 @@ def test_fallback(self, low, high): dpnp.float16, float, dpnp.int64, - dpnp.int, + dpnp.int_, int, numpy.clongdouble, dpnp.complex128, @@ -1167,7 +1167,7 @@ def test_fallback(self, low, high): "dpnp.float16", "float", "dpnp.int64", - "dpnp.int", + "dpnp.int_", "int", "numpy.clongdouble", "dpnp.complex128", @@ -1177,7 +1177,7 @@ def test_fallback(self, low, high): ], ) def test_invalid_dtype(self, dtype): - if dtype == dpnp.int and dtype == dpnp.dtype("int32"): + if dtype == dpnp.int_ and dtype == dpnp.dtype("int32"): pytest.skip( "dtype is alias on dpnp.int32 on the target OS, so no error here" ) diff --git a/dpnp/tests/test_sort.py b/dpnp/tests/test_sort.py index 170583ac31c..636014ada2c 100644 --- a/dpnp/tests/test_sort.py +++ b/dpnp/tests/test_sort.py @@ -410,8 +410,13 @@ def test_complex(self, dtype): assert result.dtype == expected.dtype -@pytest.mark.parametrize("kth", [0, 1], ids=["0", "1"]) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) +@pytest.mark.parametrize("kth", [0, 1]) +@pytest.mark.parametrize( + "dtype", + get_all_dtypes( + no_none=True, no_unsigned=True, xfail_dtypes=[dpnp.int8, dpnp.int16] + ), +) @pytest.mark.parametrize( "array", [ diff --git a/dpnp/tests/test_statistics.py b/dpnp/tests/test_statistics.py index 93d7d7ea927..bbf5cbf3ee4 100644 --- a/dpnp/tests/test_statistics.py +++ b/dpnp/tests/test_statistics.py @@ -223,8 +223,14 @@ def test_correlate(self, a, v, mode, dtype, method): @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("method", ["auto", "direct", "fft"]) def test_correlate_random(self, a_size, v_size, mode, dtype, method): - an = generate_random_numpy_array(a_size, dtype, probability=0.9) - vn = generate_random_numpy_array(v_size, dtype, probability=0.9) + if dtype in [numpy.int8, numpy.uint8]: + pytest.skip("avoid overflow.") + an = generate_random_numpy_array( + a_size, dtype, low=-3, high=3, probability=0.9 + ) + vn = generate_random_numpy_array( + v_size, dtype, low=-3, high=3, probability=0.9 + ) ad = dpnp.array(an) vd = dpnp.array(vn) diff --git a/dpnp/tests/test_strides.py b/dpnp/tests/test_strides.py index 0f6732ab9a4..beacf6109fa 100644 --- a/dpnp/tests/test_strides.py +++ b/dpnp/tests/test_strides.py @@ -161,7 +161,10 @@ def test_logsumexp(dtype): result = dpnp.logsumexp(dpa) expected = numpy.logaddexp.reduce(a) - assert_allclose(result, expected) + # for int8, uint8, NumPy returns float16 but dpnp returns float64 + # for int16, uint16, NumPy returns float32 but dpnp returns float64 + flag = dtype in [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True)) @@ -171,7 +174,10 @@ def test_cumlogsumexp(dtype): result = dpnp.cumlogsumexp(dpa) expected = numpy.logaddexp.accumulate(a) - assert_allclose(result, expected) + # for int8, uint8, NumPy returns float16 but dpnp returns float64 + # for int16, uint16, NumPy returns float32 but dpnp returns float64 + flag = dtype in [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True)) @@ -181,15 +187,24 @@ def test_reduce_hypot(dtype): result = dpnp.reduce_hypot(dpa) expected = numpy.hypot.reduce(a) - assert_allclose(result, expected) + # for int8, uint8, NumPy returns float16 but dpnp returns float64 + # for int16, uint16, NumPy returns float32 but dpnp returns float64 + flag = dtype in [dpnp.int8, dpnp.uint8, dpnp.int16, dpnp.uint16] + assert_dtype_allclose(result, expected, check_only_type_kind=flag) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True)) -@pytest.mark.parametrize("shape", [(10,)], ids=["(10,)"]) -def test_strides_erf(dtype, shape): - a = dpnp.reshape( - dpnp.linspace(-1, 1, num=numpy.prod(shape), dtype=dtype), shape - ) +@pytest.mark.parametrize( + "dtype", + get_all_dtypes( + no_none=True, + no_bool=True, + no_complex=True, + no_unsigned=True, + xfail_dtypes=[dpnp.int8, dpnp.int16], + ), +) +def test_strides_erf(dtype): + a = dpnp.linspace(-1, 1, num=10, dtype=dtype) b = a[::2] result = dpnp.erf(b) diff --git a/dpnp/tests/test_sum.py b/dpnp/tests/test_sum.py index 21ecab42a6a..54a998bfa3a 100644 --- a/dpnp/tests/test_sum.py +++ b/dpnp/tests/test_sum.py @@ -2,14 +2,13 @@ import numpy import pytest -from numpy.testing import ( - assert_array_equal, -) +from numpy.testing import assert_array_equal import dpnp from .helper import ( assert_dtype_allclose, + generate_random_numpy_array, get_all_dtypes, get_float_dtypes, ) @@ -32,14 +31,13 @@ (40, 35), ], ) -@pytest.mark.parametrize("dtype_in", get_all_dtypes()) +@pytest.mark.parametrize("dtype_in", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("dtype_out", get_all_dtypes()) @pytest.mark.parametrize("transpose", [True, False]) @pytest.mark.parametrize("keepdims", [True, False]) @pytest.mark.parametrize("order", ["C", "F"]) def test_sum(shape, dtype_in, dtype_out, transpose, keepdims, order): - size = numpy.prod(shape) - a_np = numpy.arange(size).astype(dtype_in).reshape(shape, order=order) + a_np = generate_random_numpy_array(shape, dtype_in, order) a = dpnp.asarray(a_np) if transpose: @@ -53,9 +51,18 @@ def test_sum(shape, dtype_in, dtype_out, transpose, keepdims, order): axes.append(tuple(axes_range)) for axis in axes: + if ( + numpy.issubdtype(dtype_out, numpy.bool_) + and numpy.issubdtype(dtype_in, numpy.signedinteger) + and not a_np.sum(axis=axis).all() + ): + # TODO: remove workaround when dpctl-issue#1944 is resolved + a = a.astype(dpnp.bool) + dpnp_res = a.sum(axis=axis, dtype=dtype_out, keepdims=keepdims) + else: + dpnp_res = a.sum(axis=axis, dtype=dtype_out, keepdims=keepdims) numpy_res = a_np.sum(axis=axis, dtype=dtype_out, keepdims=keepdims) - dpnp_res = a.sum(axis=axis, dtype=dtype_out, keepdims=keepdims) - assert_array_equal(numpy_res, dpnp_res.asnumpy()) + assert_dtype_allclose(dpnp_res, numpy_res, factor=16) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) diff --git a/dpnp/tests/test_sycl_queue.py b/dpnp/tests/test_sycl_queue.py index b82df205746..eb3d01c86cd 100644 --- a/dpnp/tests/test_sycl_queue.py +++ b/dpnp/tests/test_sycl_queue.py @@ -814,6 +814,7 @@ def test_reduce_hypot(device): [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0], ), + pytest.param("round", [1.234, 2.567], 2), pytest.param("searchsorted", [11, 12, 13, 14, 15], [-10, 20, 12, 13]), pytest.param( "subtract", diff --git a/dpnp/tests/test_umath.py b/dpnp/tests/test_umath.py index 5c74df6d5ed..199dbe3850a 100644 --- a/dpnp/tests/test_umath.py +++ b/dpnp/tests/test_umath.py @@ -12,6 +12,7 @@ from .helper import ( assert_dtype_allclose, + get_abs_array, get_all_dtypes, get_float_complex_dtypes, get_float_dtypes, @@ -178,8 +179,16 @@ def _get_numpy_arrays_2in_1out(func_name, dtype, range): def _get_output_data_type(dtype): """Return a data type specified by input `dtype` and device capabilities.""" - if dpnp.issubdtype(dtype, dpnp.bool): + dtype_float16 = any( + dpnp.issubdtype(dtype, t) for t in (dpnp.bool, dpnp.int8, dpnp.uint8) + ) + dtype_float32 = any( + dpnp.issubdtype(dtype, t) for t in (dpnp.int16, dpnp.uint16) + ) + if dtype_float16: out_dtype = dpnp.float16 if has_support_aspect16() else dpnp.float32 + elif dtype_float32: + out_dtype = dpnp.float32 elif dpnp.issubdtype(dtype, dpnp.complexfloating): out_dtype = dpnp.complex64 if has_support_aspect64() and dtype != dpnp.complex64: @@ -315,7 +324,7 @@ class TestDegrees: "dtype", get_all_dtypes(no_none=True, no_complex=True) ) def test_basic(self, dtype): - a = numpy.array([numpy.pi, -0.5 * numpy.pi], dtype=dtype) + a = get_abs_array([numpy.pi, -0.5 * numpy.pi], dtype) ia = dpnp.array(a) result = dpnp.degrees(ia) @@ -354,7 +363,9 @@ def test_type_conversion(self, dt1, dt2): assert_dtype_allclose(result, expected, check_only_type_kind=True) @pytest.mark.usefixtures("suppress_invalid_numpy_warnings") - @pytest.mark.parametrize("dt", get_all_dtypes(no_none=True)) + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_unsigned=True) + ) def test_negative_base_value(self, dt): a = numpy.array([-1, -4], dtype=dt) ia = dpnp.array(a) @@ -363,7 +374,9 @@ def test_negative_base_value(self, dt): expected = numpy.float_power(a, 1.5) assert_allclose(result, expected) - @pytest.mark.parametrize("dt", get_all_dtypes(no_none=True)) + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_unsigned=True) + ) def test_negative_base_value_complex_dtype(self, dt): a = numpy.array([-1, -4], dtype=dt) ia = dpnp.array(a) @@ -458,7 +471,8 @@ def test_values(self, dt): assert_dtype_allclose(result, expected) @pytest.mark.parametrize( - "dt", get_all_dtypes(no_none=True, no_complex=True) + "dt", + [numpy.bool_, numpy.int32, numpy.int64, numpy.float32, numpy.float64], ) def test_range(self, dt): a = numpy.array([1000000, -1000000, 1000200, -1000200], dtype=dt) @@ -506,7 +520,7 @@ class TestRadians: "dtype", get_all_dtypes(no_none=True, no_complex=True) ) def test_basic(self, dtype): - a = numpy.array([180.0, -90.0], dtype=dtype) + a = get_abs_array([120.0, -90.0], dtype) ia = dpnp.array(a) result = dpnp.radians(ia) @@ -710,6 +724,7 @@ class TestUmath: def func_params(self, request): return request.param + @pytest.mark.filterwarnings("ignore:overflow encountered:RuntimeWarning") @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") @pytest.mark.parametrize("dtype", get_all_dtypes()) def test_out(self, func_params, dtype): diff --git a/dpnp/tests/test_usm_type.py b/dpnp/tests/test_usm_type.py index c0024409166..74fdd28d127 100644 --- a/dpnp/tests/test_usm_type.py +++ b/dpnp/tests/test_usm_type.py @@ -782,6 +782,7 @@ def test_1in_1out(func, data, usm_type): pytest.param("maximum", [0.0, 1.0, 2.0], [3.0, 4.0, 5.0]), pytest.param("minimum", [0.0, 1.0, 2.0], [3.0, 4.0, 5.0]), pytest.param("nextafter", [1, 2], [2, 1]), + pytest.param("round", [1.234, 2.567], 2), pytest.param("searchsorted", [11, 12, 13, 14, 15], [-10, 20, 12, 13]), pytest.param( "tensordot", diff --git a/dpnp/tests/third_party/cupy/core_tests/test_elementwise.py b/dpnp/tests/third_party/cupy/core_tests/test_elementwise.py index 2d268e53b37..72946894820 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_elementwise.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_elementwise.py @@ -4,7 +4,11 @@ import pytest import dpnp as cupy -from dpnp.tests.helper import has_support_aspect64 +from dpnp.tests.helper import ( + has_support_aspect64, + is_win_platform, + numpy_version, +) from dpnp.tests.third_party.cupy import testing @@ -94,20 +98,22 @@ class TestElementwiseType(unittest.TestCase): @testing.for_int_dtypes(no_bool=True) @testing.numpy_cupy_array_equal(accept_error=OverflowError) def test_large_int_upper_1(self, xp, dtype): - a = xp.array([0], dtype=numpy.int8) + a = xp.array([0], dtype=xp.int8) b = xp.iinfo(dtype).max return a + b @testing.for_int_dtypes(no_bool=True) @testing.numpy_cupy_array_equal(accept_error=OverflowError) def test_large_int_upper_2(self, xp, dtype): - if ( - numpy.issubdtype(dtype, numpy.unsignedinteger) - and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" - ): - pytest.skip("numpy promotes dtype differently") + if numpy_version() < "2.0.0": + flag = dtype in [xp.int16, xp.int32, xp.int64, xp.longlong] + if xp.issubdtype(dtype, xp.unsignedinteger) or flag: + pytest.skip("numpy doesn't raise OverflowError") + + if dtype in [xp.int8, xp.intc] and is_win_platform(): + pytest.skip("numpy promotes dtype differently") - a = xp.array([1], dtype=numpy.int8) + a = xp.array([1], dtype=xp.int8) b = xp.iinfo(dtype).max - 1 return a + b @@ -116,7 +122,7 @@ def test_large_int_upper_2(self, xp, dtype): def test_large_int_upper_3(self, xp, dtype): if ( numpy.issubdtype(dtype, numpy.unsignedinteger) - and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" + and numpy_version() < "2.0.0" ): pytest.skip("numpy promotes dtype differently") elif ( @@ -134,7 +140,7 @@ def test_large_int_upper_3(self, xp, dtype): def test_large_int_upper_4(self, xp, dtype): if ( numpy.issubdtype(dtype, numpy.unsignedinteger) - and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" + and numpy_version() < "2.0.0" ): pytest.skip("numpy promotes dtype differently") elif ( @@ -150,14 +156,28 @@ def test_large_int_upper_4(self, xp, dtype): @testing.for_int_dtypes(no_bool=True) @testing.numpy_cupy_array_equal(accept_error=OverflowError) def test_large_int_lower_1(self, xp, dtype): - a = xp.array([0], dtype=numpy.int8) + if numpy_version() < "2.0.0": + if dtype in [xp.int16, xp.int32, xp.int64, xp.longlong]: + pytest.skip("numpy doesn't raise OverflowError") + + if dtype in [xp.int8, xp.intc] and is_win_platform(): + pytest.skip("numpy promotes dtype differently") + + a = xp.array([0], dtype=xp.int8) b = xp.iinfo(dtype).min return a + b @testing.for_int_dtypes(no_bool=True) @testing.numpy_cupy_array_equal(accept_error=OverflowError) def test_large_int_lower_2(self, xp, dtype): - a = xp.array([-1], dtype=numpy.int8) + if numpy_version() < "2.0.0": + if dtype in [xp.int16, xp.int32, xp.int64, xp.longlong]: + pytest.skip("numpy doesn't raise OverflowError") + + if dtype in [xp.int8, xp.intc] and is_win_platform(): + pytest.skip("numpy promotes dtype differently") + + a = xp.array([-1], dtype=xp.int8) b = xp.iinfo(dtype).min + 1 return a + b @@ -166,7 +186,7 @@ def test_large_int_lower_2(self, xp, dtype): def test_large_int_lower_3(self, xp, dtype): if ( numpy.issubdtype(dtype, numpy.unsignedinteger) - and numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0" + and numpy_version() < "2.0.0" ): pytest.skip("numpy promotes dtype differently") elif ( diff --git a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py index 282c38b72e6..3acebaaeb3a 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py @@ -4,7 +4,6 @@ import pytest import dpnp as cupy -from dpnp.tests.helper import has_support_aspect64 from dpnp.tests.third_party.cupy import testing @@ -41,8 +40,10 @@ def test_conjugate_pass(self, xp, dtype): class TestAngle(unittest.TestCase): + # For dtype=int8, uint8, NumPy returns float16, but dpnp returns float32 + # so type_check=False @testing.for_all_dtypes() - @testing.numpy_cupy_array_almost_equal(type_check=has_support_aspect64()) + @testing.numpy_cupy_array_almost_equal(type_check=False) def test_angle(self, xp, dtype): x = testing.shaped_arange((2, 3), xp, dtype) return xp.angle(x) diff --git a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py index 515243d89c5..eaf01d1b345 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py @@ -338,7 +338,7 @@ def test_astype_type(self, src_dtype, dst_dtype, order): b = astype_without_warning(a, dst_dtype, order=order) a_cpu = testing.shaped_arange((2, 3, 4), numpy, src_dtype) b_cpu = astype_without_warning(a_cpu, dst_dtype, order=order) - assert b.dtype.type == b_cpu.dtype.type + assert b.dtype == b_cpu.dtype @testing.for_orders("CAK") @testing.for_all_dtypes() diff --git a/dpnp/tests/third_party/cupy/creation_tests/test_ranges.py b/dpnp/tests/third_party/cupy/creation_tests/test_ranges.py index b0d209e2570..06b4ef8dc75 100644 --- a/dpnp/tests/third_party/cupy/creation_tests/test_ranges.py +++ b/dpnp/tests/third_party/cupy/creation_tests/test_ranges.py @@ -227,7 +227,13 @@ def test_linspace_mixed_start_stop2(self, xp, dtype_range, dtype_out): # TODO (ev-br): np 2.0: had to bump the default rtol on Windows # and numpy 1.26+weak promotion from 0 to 5e-6 if xp.dtype(dtype_range).kind in "u": - start = xp.array([160, 120], dtype=dtype_range) + # to avoid overflow, limit `val` to be smaller + # than xp.iinfo(dtype).max + if dtype_range == xp.uint8 or dtype_out == xp.uint8: + val = 125 + else: + val = 160 + start = xp.array([val, 120], dtype=dtype_range) else: start = xp.array([-120, 120], dtype=dtype_range) stop = 0 diff --git a/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py b/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py index bec8f4204b3..f28d7647f14 100644 --- a/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py +++ b/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py @@ -204,6 +204,10 @@ class TestChoose(unittest.TestCase): @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_choose(self, xp, dtype): + # TODO: include additional dtype when dpnp#2201 is merged + dtype_list = [xp.int8, xp.int16] + if dtype in dtype_list or xp.issubdtype(dtype, xp.unsignedinteger): + pytest.skip("dpnp.choose() does not support new integer dtypes.") a = xp.array([0, 2, 1, 2]) c = testing.shaped_arange((3, 4), xp, dtype) return a.choose(c) diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_einsum.py b/dpnp/tests/third_party/cupy/linalg_tests/test_einsum.py index 0714fbc05a7..bb44b791d41 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_einsum.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_einsum.py @@ -464,9 +464,8 @@ def test_scalar_float(self, xp, dtype): ) ) class TestEinSumBinaryOperation: - @testing.for_all_dtypes_combination( - ["dtype_a", "dtype_b"], no_bool=False, no_float16=False - ) + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes_combination(["dtype_a", "dtype_b"], no_int8=True) @testing.numpy_cupy_allclose( type_check=has_support_aspect64(), contiguous_check=False ) @@ -555,13 +554,18 @@ def test_scalar_2(self, xp, dtype): ) ) class TestEinSumTernaryOperation: - @testing.for_all_dtypes_combination( - ["dtype_a", "dtype_b", "dtype_c"], no_bool=False, no_float16=False - ) + + @testing.for_all_dtypes_combination(["dtype_a", "dtype_b", "dtype_c"]) @testing.numpy_cupy_allclose( type_check=has_support_aspect64(), contiguous_check=False ) def test_einsum_ternary(self, xp, dtype_a, dtype_b, dtype_c): + flag = all( + dtype in [xp.int8, xp.uint8] + for dtype in [dtype_a, dtype_b, dtype_c] + ) + if self.subscripts == "ij,jk,kl" and flag: + pytest.skip("avoid overflow") a = testing.shaped_arange(self.shape_a, xp, dtype_a) b = testing.shaped_arange(self.shape_b, xp, dtype_b) c = testing.shaped_arange(self.shape_c, xp, dtype_c) diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_product.py b/dpnp/tests/third_party/cupy/linalg_tests/test_product.py index d0e7a0f5f7e..e5d21441626 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_product.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_product.py @@ -39,8 +39,9 @@ ) ) class TestDot(unittest.TestCase): - - @testing.for_all_dtypes_combination(["dtype_a", "dtype_b"]) + # no_int8=True is added to avoid overflow for shape=((2, 3, 4), (3, 4, 2)) + # and ((2, 3), (3, 4)) cases on cpu + @testing.for_all_dtypes_combination(["dtype_a", "dtype_b"], no_int8=True) @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_dot(self, xp, dtype_a, dtype_b): shape_a, shape_b = self.shape @@ -238,14 +239,14 @@ def test_dot_vec3(self, xp, dtype): b = testing.shaped_arange((2,), xp, dtype) return xp.dot(a, b) - @testing.for_all_dtypes() + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_transposed_dot(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype).transpose(1, 0, 2) b = testing.shaped_arange((2, 3, 4), xp, dtype).transpose(0, 2, 1) return xp.dot(a, b) - @testing.for_all_dtypes() + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_transposed_dot_with_out(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype).transpose(1, 0, 2) @@ -320,14 +321,16 @@ def test_reversed_inner(self, xp, dtype): b = testing.shaped_reverse_arange((5,), xp, dtype)[::-1] return xp.inner(a, b) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_multidim_inner(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype) b = testing.shaped_arange((3, 2, 4), xp, dtype) return xp.inner(a, b) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_transposed_higher_order_inner(self, xp, dtype): a = testing.shaped_arange((2, 4, 3), xp, dtype).transpose(2, 0, 1) @@ -355,14 +358,16 @@ def test_multidim_outer(self, xp, dtype): b = testing.shaped_arange((4, 5), xp, dtype) return xp.outer(a, b) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_tensordot(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype) b = testing.shaped_arange((3, 4, 5), xp, dtype) return xp.tensordot(a, b) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_transposed_tensordot(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype).transpose(1, 0, 2) @@ -516,13 +521,15 @@ def test_matrix_power_1(self, xp, dtype): a = testing.shaped_arange((3, 3), xp, dtype) return xp.linalg.matrix_power(a, 1) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_matrix_power_2(self, xp, dtype): a = testing.shaped_arange((3, 3), xp, dtype) return xp.linalg.matrix_power(a, 2) - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose() def test_matrix_power_3(self, xp, dtype): a = testing.shaped_arange((3, 3), xp, dtype) diff --git a/dpnp/tests/third_party/cupy/logic_tests/test_comparison.py b/dpnp/tests/third_party/cupy/logic_tests/test_comparison.py index 7e56ed5b64b..5215191987b 100644 --- a/dpnp/tests/third_party/cupy/logic_tests/test_comparison.py +++ b/dpnp/tests/third_party/cupy/logic_tests/test_comparison.py @@ -242,7 +242,8 @@ def test_allclose_array_scalar(self, xp, dtype): class TestIsclose(unittest.TestCase): - @testing.for_all_dtypes(no_complex=True) + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_complex=True, no_int8=True) @testing.numpy_cupy_array_equal() def test_is_close_finite(self, xp, dtype): # In numpy<1.10 this test fails when dtype is bool diff --git a/dpnp/tests/third_party/cupy/math_tests/test_matmul.py b/dpnp/tests/third_party/cupy/math_tests/test_matmul.py index 35852d25dbe..fd15ba33110 100644 --- a/dpnp/tests/third_party/cupy/math_tests/test_matmul.py +++ b/dpnp/tests/third_party/cupy/math_tests/test_matmul.py @@ -60,8 +60,9 @@ ) class TestMatmul(unittest.TestCase): - @testing.for_all_dtypes(name="dtype1") - @testing.for_all_dtypes(name="dtype2") + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(name="dtype1", no_int8=True) + @testing.for_all_dtypes(name="dtype2", no_int8=True) @testing.numpy_cupy_allclose( rtol=1e-3, atol=1e-3, type_check=has_support_aspect64() ) # required for uint8 @@ -70,8 +71,9 @@ def test_operator_matmul(self, xp, dtype1, dtype2): x2 = testing.shaped_arange(self.shape_pair[1], xp, dtype2) return operator.matmul(x1, x2) - @testing.for_all_dtypes(name="dtype1") - @testing.for_all_dtypes(name="dtype2") + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(name="dtype1", no_int8=True) + @testing.for_all_dtypes(name="dtype2", no_int8=True) @testing.numpy_cupy_allclose( rtol=1e-3, atol=1e-3, type_check=has_support_aspect64() ) # required for uint8 @@ -97,8 +99,9 @@ def test_cupy_matmul(self, xp, dtype1, dtype2): ) class TestMatmulOut(unittest.TestCase): - @testing.for_all_dtypes(name="dtype1") - @testing.for_all_dtypes(name="dtype2") + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(name="dtype1", no_int8=True) + @testing.for_all_dtypes(name="dtype2", no_int8=True) @testing.numpy_cupy_allclose( rtol=1e-3, atol=1e-3, accept_error=TypeError # required for uint8 ) @@ -140,7 +143,8 @@ def test_overlap_both(self, xp, dtype, shape): class TestMatmulStrides: - @testing.for_all_dtypes() + # no_int8=True is added to avoid overflow + @testing.for_all_dtypes(no_int8=True) @testing.numpy_cupy_allclose(rtol=1e-3, atol=1e-3) # required for uint8 def test_relaxed_c_contiguous_input(self, xp, dtype): x1 = testing.shaped_arange((2, 2, 3), xp, dtype)[:, None, :, :] @@ -171,6 +175,7 @@ class TestMatmulLarge(unittest.TestCase): # Avoid overflow skip_dtypes = { + (numpy.int8, numpy.int8), (numpy.int8, numpy.uint8), (numpy.int8, numpy.int16), (numpy.int8, numpy.float16), diff --git a/dpnp/tests/third_party/cupy/math_tests/test_misc.py b/dpnp/tests/third_party/cupy/math_tests/test_misc.py index 0fb2ee8fd7f..3fd562798c3 100644 --- a/dpnp/tests/third_party/cupy/math_tests/test_misc.py +++ b/dpnp/tests/third_party/cupy/math_tests/test_misc.py @@ -176,7 +176,8 @@ def test_sqrt(self): self.check_unary("sqrt") @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64()) + # atol=1e-3 is needed for int8 + @testing.numpy_cupy_allclose(atol=1e-3, type_check=has_support_aspect64()) def test_cbrt(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype) return xp.cbrt(a) diff --git a/dpnp/tests/third_party/cupy/math_tests/test_trigonometric.py b/dpnp/tests/third_party/cupy/math_tests/test_trigonometric.py index e0d4f484082..3579ddb7fe3 100644 --- a/dpnp/tests/third_party/cupy/math_tests/test_trigonometric.py +++ b/dpnp/tests/third_party/cupy/math_tests/test_trigonometric.py @@ -7,7 +7,9 @@ class TestTrigonometric(unittest.TestCase): @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64()) + @testing.numpy_cupy_allclose( + atol=1e-4, rtol=0.001, type_check=has_support_aspect64() + ) def check_unary(self, name, xp, dtype): a = testing.shaped_arange((2, 3), xp, dtype) return getattr(xp, name)(a) diff --git a/dpnp/tests/third_party/cupy/random_tests/test_distributions.py b/dpnp/tests/third_party/cupy/random_tests/test_distributions.py index 16ad014645a..ebed860fd29 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_distributions.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_distributions.py @@ -22,7 +22,7 @@ def check_distribution(self, dist_name, params, dtype=None): np_out = numpy.asarray( getattr(numpy.random, dist_name)(size=self.shape, **params), dtype ) - dt_kward = {dtype: dtype} if dtype else {} + dt_kward = {"dtype": dtype} if dtype else {} cp_out = getattr(_distributions, dist_name)( size=self.shape, **dt_kward, **cp_params ) @@ -72,12 +72,14 @@ def test_beta(self, a_dtype, b_dtype): "shape": [(4, 3, 2), (3, 2)], "n_shape": [(), (3, 2)], "p_shape": [(), (3, 2)], - "dtype": _int_dtypes, # to escape timeout + # "dtype": _int_dtypes, # to escape timeout + "dtype": [None], # no dtype supported } ) ) class TestDistributionsBinomial(RandomDistributionsTestCase): + @pytest.mark.skip("n and p params as arrays are not supported") @testing.for_signed_dtypes("n_dtype") @testing.for_float_dtypes("p_dtype") def test_binomial(self, n_dtype, p_dtype): diff --git a/dpnp/tests/third_party/cupy/random_tests/test_permutations.py b/dpnp/tests/third_party/cupy/random_tests/test_permutations.py index e703856728a..9a2d3b19f90 100644 --- a/dpnp/tests/third_party/cupy/random_tests/test_permutations.py +++ b/dpnp/tests/third_party/cupy/random_tests/test_permutations.py @@ -38,6 +38,11 @@ def test_permutation_zero_dim(self): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_permutation_sort_1dim(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.permutation() does not support new integer dtypes." + ) cupy_random = self._xp_random(cupy) a = cupy.arange(10, dtype=dtype) b = cupy.copy(a) @@ -47,6 +52,11 @@ def test_permutation_sort_1dim(self, dtype): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_permutation_sort_ndim(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.permutation() does not support new integer dtypes." + ) cupy_random = self._xp_random(cupy) a = cupy.arange(15, dtype=dtype).reshape(5, 3) b = cupy.copy(a) @@ -58,6 +68,11 @@ def test_permutation_sort_ndim(self, dtype): @testing.for_all_dtypes() def test_permutation_seed1(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.permutation() does not support new integer dtypes." + ) a = testing.shaped_random((10,), cupy, dtype) b = cupy.copy(a) @@ -89,6 +104,11 @@ def test_shuffle_zero_dim(self): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_shuffle_sort_1dim(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.shuffle() does not support new integer dtypes." + ) a = cupy.arange(10, dtype=dtype) b = cupy.copy(a) cupy.random.shuffle(a) @@ -96,6 +116,11 @@ def test_shuffle_sort_1dim(self, dtype): @testing.for_all_dtypes(no_float16=True, no_bool=True, no_complex=True) def test_shuffle_sort_ndim(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.shuffle() does not support new integer dtypes." + ) a = cupy.arange(15, dtype=dtype).reshape(5, 3) b = cupy.copy(a) cupy.random.shuffle(a) @@ -105,6 +130,11 @@ def test_shuffle_sort_ndim(self, dtype): @testing.for_all_dtypes() def test_shuffle_seed1(self, dtype): + flag = cupy.issubdtype(dtype, cupy.unsignedinteger) + if flag or dtype in [cupy.int8, cupy.int16]: + pytest.skip( + "dpnp.random.shuffle() does not support new integer dtypes." + ) a = testing.shaped_random((10,), cupy, dtype) b = cupy.copy(a) cupy.random.seed(0) diff --git a/dpnp/tests/third_party/cupy/sorting_tests/test_sort.py b/dpnp/tests/third_party/cupy/sorting_tests/test_sort.py index dc619d77f78..7e791f6a7c0 100644 --- a/dpnp/tests/third_party/cupy/sorting_tests/test_sort.py +++ b/dpnp/tests/third_party/cupy/sorting_tests/test_sort.py @@ -478,6 +478,9 @@ def test_partition_zero_dim(self): @testing.for_all_dtypes() @testing.numpy_cupy_equal() def test_partition_one_dim(self, xp, dtype): + flag = xp.issubdtype(dtype, xp.unsignedinteger) + if flag or dtype in [xp.int8, xp.int16]: + pytest.skip("dpnp.partition() does not support new integer dtypes.") a = testing.shaped_random((self.length,), xp, dtype) kth = 2 x = self.partition(a, kth) diff --git a/dpnp/tests/third_party/cupy/testing/_loops.py b/dpnp/tests/third_party/cupy/testing/_loops.py index c6884a555d6..18b816ead98 100644 --- a/dpnp/tests/third_party/cupy/testing/_loops.py +++ b/dpnp/tests/third_party/cupy/testing/_loops.py @@ -8,10 +8,12 @@ from typing import Tuple, Type import numpy +import pytest from dpctl import select_default_device from dpctl.tensor._numpy_helper import AxisError import dpnp as cupy +from dpnp.tests import config from dpnp.tests.third_party.cupy.testing import _array, _parameterized from dpnp.tests.third_party.cupy.testing._pytest_impl import is_available @@ -249,7 +251,7 @@ def _make_positive_masks(impl, args, kw, name, sp_name, scipy_name): assert error is None if not isinstance(result, (tuple, list)): result = (result,) - return [cupy.asnumpy(r) >= 0 for r in result] + return [r >= 0 for r in result] def _contains_signed_and_unsigned(kw): @@ -409,8 +411,8 @@ def test_func(*args, **kw): if cupy_r.shape == (): skip = (mask == 0).all() else: - cupy_r = cupy_r[mask].get() - numpy_r = numpy_r[mask] + cupy_r = cupy_r[mask] + numpy_r = numpy_r[mask.asnumpy()] if not skip: check_func(cupy_r, numpy_r) @@ -978,7 +980,7 @@ def test_func(*args, **kw): return decorator -def for_dtypes(dtypes, name="dtype"): +def for_dtypes(dtypes, name="dtype", xfail_dtypes=None): """Decorator for parameterized dtype test. Args: @@ -1009,7 +1011,11 @@ def test_func(*args, **kw): try: kw[name] = numpy.dtype(dtype).type - impl(*args, **kw) + if xfail_dtypes is not None and dtype in xfail_dtypes: + impl_ = pytest.mark.xfail(impl) + else: + impl_ = impl + impl_(*args, **kw) except _skip_classes as e: print("skipped: {} = {} ({})".format(name, dtype, e)) except Exception: @@ -1039,23 +1045,80 @@ def _get_supported_complex_dtypes(): return (numpy.complex64,) +def _get_int_dtypes(): + if config.all_int_types: + return _signed_dtypes + _unsigned_dtypes + else: + return (numpy.int64, numpy.int32) + + +def _get_float_dtypes(): + if config.float16_types: + return _regular_float_dtypes + (numpy.float16,) + else: + return _regular_float_dtypes + + +def _get_signed_dtypes(): + if config.all_int_types: + return tuple(numpy.dtype(i).type for i in "bhilq") + else: + return (numpy.int32,) + + +def _get_unsigned_dtypes(): + if config.all_int_types: + return tuple(numpy.dtype(i).type for i in "BHILQ") + else: + return (numpy.uint32,) + + +def _get_int_bool_dtypes(): + if config.bool_types: + return _int_dtypes + (numpy.bool_,) + else: + return _int_dtypes + + _complex_dtypes = _get_supported_complex_dtypes() _regular_float_dtypes = _get_supported_float_dtypes() -_float_dtypes = _regular_float_dtypes -_signed_dtypes = () -_unsigned_dtypes = tuple(numpy.dtype(i).type for i in "BHILQ") -_int_dtypes = _signed_dtypes + _unsigned_dtypes -_int_bool_dtypes = _int_dtypes +_float_dtypes = _get_float_dtypes() +_signed_dtypes = _get_signed_dtypes() +_unsigned_dtypes = _get_unsigned_dtypes() +_int_dtypes = _get_int_dtypes() +_int_bool_dtypes = _get_int_bool_dtypes() _regular_dtypes = _regular_float_dtypes + _int_bool_dtypes _dtypes = _float_dtypes + _int_bool_dtypes -def _make_all_dtypes(no_float16, no_bool, no_complex): - return (numpy.int64, numpy.int32) + _get_supported_float_dtypes() +def _make_all_dtypes(no_float16, no_bool, no_complex, no_int8): + if no_float16: + dtypes = _regular_float_dtypes + else: + dtypes = _float_dtypes + + if no_bool: + dtypes += _int_dtypes + else: + dtypes += _int_bool_dtypes + + if no_int8: + dtypes = tuple( + filter(lambda dt: dt not in [numpy.int8, numpy.uint8], dtypes) + ) + + if config.complex_types and not no_complex: + dtypes += _complex_dtypes + + return dtypes def for_all_dtypes( - name="dtype", no_float16=False, no_bool=False, no_complex=False + name="dtype", + no_float16=False, + no_bool=False, + no_complex=False, + no_int8=False, ): """Decorator that checks the fixture with all dtypes. @@ -1067,6 +1130,9 @@ def for_all_dtypes( omitted from candidate dtypes. no_complex(bool): If ``True``, ``numpy.complex64`` and ``numpy.complex128`` are omitted from candidate dtypes. + no_int8(bool): If ``True``, ``numpy.int8`` and + ``numpy.uint8`` are omitted from candidate dtypes. + This option is generally used to avoid overflow. dtypes to be tested: ``numpy.complex64`` (optional), ``numpy.complex128`` (optional), @@ -1110,7 +1176,7 @@ def for_all_dtypes( .. seealso:: :func:`cupy.testing.for_dtypes` """ return for_dtypes( - _make_all_dtypes(no_float16, no_bool, no_complex), name=name + _make_all_dtypes(no_float16, no_bool, no_complex, no_int8), name=name ) @@ -1280,6 +1346,7 @@ def for_all_dtypes_combination( no_bool=False, full=None, no_complex=False, + no_int8=False, ): """Decorator that checks the fixture with a product set of all dtypes. @@ -1293,12 +1360,15 @@ def for_all_dtypes_combination( will be tested. Otherwise, the subset of combinations will be tested (see description in :func:`cupy.testing.for_dtypes_combination`). - no_complex(bool): If, True, ``numpy.complex64`` and + no_complex(bool): If, ``True``, ``numpy.complex64`` and ``numpy.complex128`` are omitted from candidate dtypes. + no_int8(bool): If, ``True``, ``numpy.int8`` and + ``numpy.uint8`` are omitted from candidate dtypes. + This option is generally used to avoid overflow. .. seealso:: :func:`cupy.testing.for_dtypes_combination` """ - types = _make_all_dtypes(no_float16, no_bool, no_complex) + types = _make_all_dtypes(no_float16, no_bool, no_complex, no_int8) return for_dtypes_combination(types, names, full)