diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 7583fee5d918..2fda6913bc5c 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -18,6 +18,7 @@ env: test_fft.py test_linalg.py test_logic.py + test_manipulation.py test_mathematical.py test_random_state.py test_sort.py @@ -26,6 +27,7 @@ env: test_usm_type.py third_party/cupy/linalg_tests/test_product.py third_party/cupy/logic_tests/test_truth.py + third_party/cupy/manipulation_tests/test_basic.py third_party/cupy/manipulation_tests/test_join.py third_party/cupy/math_tests/test_explog.py third_party/cupy/math_tests/test_misc.py diff --git a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp index 900f7d95c57a..d99510fde917 100644 --- a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp @@ -414,59 +414,26 @@ static void func_map_init_elemwise_1arg_2type(func_map_t &fmap) (void *) dpnp_copyto_c_default, std::complex>}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_BLN] = { - eft_BLN, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_INT] = { - eft_INT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_LNG] = { - eft_LNG, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_FLT] = { - eft_FLT, (void *)dpnp_copyto_c_ext}; + // dpnp_copyto_c is required by dpnp_fft_fft_c and dpnp_fft_rfft_c fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_DBL] = { eft_DBL, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_BLN] = { - eft_BLN, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_LNG] = { - eft_LNG, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_FLT] = { - eft_FLT, (void *)dpnp_copyto_c_ext}; fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_DBL] = { eft_DBL, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_BLN] = { - eft_BLN, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_INT] = { - eft_INT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_FLT] = { - eft_FLT, (void *)dpnp_copyto_c_ext}; fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_DBL] = { eft_DBL, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_BLN] = { - eft_BLN, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_INT] = { - eft_INT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_LNG] = { - eft_LNG, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_copyto_c_ext}; fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_DBL] = { eft_DBL, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_DBL][eft_BLN] = { - eft_BLN, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_DBL][eft_INT] = { - eft_INT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_DBL][eft_LNG] = { - eft_LNG, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_DBL][eft_FLT] = { - eft_FLT, (void *)dpnp_copyto_c_ext}; fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_C128][eft_C128] = { - eft_C128, - (void *)dpnp_copyto_c_ext, std::complex>}; + + fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_BLN][eft_FLT] = { + eft_FLT, (void *)dpnp_copyto_c_ext}; + fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_INT][eft_FLT] = { + eft_FLT, (void *)dpnp_copyto_c_ext}; + fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_LNG][eft_FLT] = { + eft_FLT, (void *)dpnp_copyto_c_ext}; + fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_FLT] = { + eft_FLT, (void *)dpnp_copyto_c_ext}; fmap[DPNPFuncName::DPNP_FN_COS][eft_INT][eft_INT] = { eft_DBL, (void *)dpnp_cos_c_default}; diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index c59c7ced6368..089e45e7c71a 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -72,8 +72,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_COPY_EXT DPNP_FN_COPYSIGN DPNP_FN_COPYSIGN_EXT - DPNP_FN_COPYTO - DPNP_FN_COPYTO_EXT DPNP_FN_CORRELATE DPNP_FN_CORRELATE_EXT DPNP_FN_COSH diff --git a/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi b/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi index 94a58b057bff..43b8310578df 100644 --- a/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi @@ -38,7 +38,6 @@ and the rest of the library __all__ += [ "dpnp_atleast_2d", "dpnp_atleast_3d", - "dpnp_copyto", "dpnp_expand_dims", "dpnp_repeat", "dpnp_reshape", @@ -105,45 +104,6 @@ cpdef utils.dpnp_descriptor dpnp_atleast_3d(utils.dpnp_descriptor arr): return arr -cpdef dpnp_copyto(utils.dpnp_descriptor dst, utils.dpnp_descriptor src, where=True): - # Convert string type names (array.dtype) to C enum DPNPFuncType - cdef DPNPFuncType dst_type = dpnp_dtype_to_DPNPFuncType(dst.dtype) - cdef DPNPFuncType src_type = dpnp_dtype_to_DPNPFuncType(src.dtype) - - cdef shape_type_c dst_shape = dst.shape - cdef shape_type_c dst_strides = utils.strides_to_vector(dst.strides, dst_shape) - - cdef shape_type_c src_shape = src.shape - cdef shape_type_c src_strides = utils.strides_to_vector(src.strides, src_shape) - - # get the FPTR data structure - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_COPYTO_EXT, src_type, dst_type) - - _, _, result_sycl_queue = utils.get_common_usm_allocation(dst, src) - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - # Call FPTR function - cdef fptr_1in_1out_strides_t func = kernel_data.ptr - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - dst.get_data(), - dst.size, - dst.ndim, - dst_shape.data(), - dst_strides.data(), - src.get_data(), - src.size, - src.ndim, - src_shape.data(), - src_strides.data(), - NULL, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - cpdef utils.dpnp_descriptor dpnp_expand_dims(utils.dpnp_descriptor in_array, axis): axis_tuple = utils._object_to_tuple(axis) result_ndim = len(axis_tuple) + in_array.ndim diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 5f5dcb3617db..e29e6b0203ea 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -251,7 +251,7 @@ def concatenate(arrays, /, *, axis=0, out=None, dtype=None, **kwargs): Limitations ----------- Each array in `arrays` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exeption + or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exception will be raised. Parameters `out` and `dtype are supported with default value. Keyword argument ``kwargs`` is currently unsupported. @@ -313,64 +313,79 @@ def copyto(dst, src, casting="same_kind", where=True): """ Copies values from one array to another, broadcasting as necessary. + Raises a ``TypeError`` if the `casting` rule is violated, and if + `where` is provided, it selects which elements to copy. + For full documentation refer to :obj:`numpy.copyto`. Limitations ----------- - Input arrays are supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. - Parameter ``casting`` is supported only with default value ``"same_kind"``. - Parameter ``where`` is supported only with default value ``True``. - Shapes of input arrays are supported to be equal. + The `dst` parameter is supported as either :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. + The `where` parameter is supported as either :class:`dpnp.ndarray`, + :class:`dpctl.tensor.usm_ndarray` or scalar. + Otherwise ``TypeError`` exception will be raised. Input array data types are limited by supported DPNP :ref:`Data types`. + Examples + -------- + >>> import dpnp as np + >>> A = np.array([4, 5, 6]) + >>> B = [1, 2, 3] + >>> np.copyto(A, B) + >>> A + array([1, 2, 3]) + + >>> A = np.array([[1, 2, 3], [4, 5, 6]]) + >>> B = [[4, 5, 6], [7, 8, 9]] + >>> np.copyto(A, B) + >>> A + array([[4, 5, 6], + [7, 8, 9]]) + """ - dst_desc = dpnp.get_dpnp_descriptor( - dst, copy_when_strides=False, copy_when_nondefault_queue=False - ) - src_desc = dpnp.get_dpnp_descriptor(src, copy_when_nondefault_queue=False) - if dst_desc and src_desc: - if casting != "same_kind": - pass - elif ( - dst_desc.dtype == dpnp.bool - and src_desc.dtype # due to 'same_kind' casting - in [ - dpnp.int32, - dpnp.int64, - dpnp.float32, - dpnp.float64, - dpnp.complex128, - ] - ): - pass - elif dst_desc.dtype in [ - dpnp.int32, - dpnp.int64, - ] and src_desc.dtype in [ # due to 'same_kind' casting - dpnp.float32, - dpnp.float64, - dpnp.complex128, - ]: - pass - elif ( - dst_desc.dtype in [dpnp.float32, dpnp.float64] - and src_desc.dtype == dpnp.complex128 - ): # due to 'same_kind' casting - pass - elif where is not True: - pass - elif dst_desc.shape != src_desc.shape: - pass - elif dst_desc.strides != src_desc.strides: - pass - else: - return dpnp_copyto(dst_desc, src_desc, where=where) + if not dpnp.is_supported_array_type(dst): + raise TypeError( + "Destination array must be any of supported type, " + f"but got {type(dst)}" + ) + elif not dpnp.is_supported_array_type(src): + src = dpnp.array(src, sycl_queue=dst.sycl_queue) - return call_origin( - numpy.copyto, dst, src, casting, where, dpnp_inplace=True - ) + if not dpt.can_cast(src.dtype, dst.dtype, casting=casting): + raise TypeError( + f"Cannot cast from {src.dtype} to {dst.dtype} " + f"according to the rule {casting}." + ) + + if where is True: + dst[...] = src + elif where is False: + # nothing to copy + pass + else: + if dpnp.isscalar(where): + where = dpnp.array( + where, dtype=dpnp.bool, sycl_queue=dst.sycl_queue + ) + elif not dpnp.is_supported_array_type(where): + raise TypeError( + "`where` array must be any of supported type, " + f"but got {type(where)}" + ) + elif where.dtype != dpnp.bool: + raise TypeError( + "`where` keyword argument must be of boolean type, " + f"but got {where.dtype}" + ) + + dst_usm, src_usm, mask_usm = dpt.broadcast_arrays( + dpnp.get_usm_ndarray(dst), + dpnp.get_usm_ndarray(src), + dpnp.get_usm_ndarray(where), + ) + dst_usm[mask_usm] = src_usm[mask_usm] def expand_dims(x1, axis): @@ -847,7 +862,7 @@ def stack(arrays, /, *, axis=0, out=None, dtype=None, **kwargs): Limitations ----------- Each array in `arrays` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exeption + or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exception will be raised. Parameters `out` and `dtype are supported with default value. Keyword argument ``kwargs`` is currently unsupported. diff --git a/tests/__init__.py b/tests/__init__.py index 8650a7c357ac..161e4a1a994a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,38 +1,7 @@ import numpy -import dpnp from tests import testing -from tests.third_party.cupy import testing as cupy_testing - -from .helper import has_support_aspect64 numpy.testing.assert_allclose = testing.assert_allclose numpy.testing.assert_array_equal = testing.assert_array_equal numpy.testing.assert_equal = testing.assert_equal - -# patch for shaped_arange func to exclude calls of astype and reshape -# necessary because new data container does not support these functions yet - -orig_shaped_arange = cupy_testing.shaped_arange -orig_shaped_reverse_arange = cupy_testing.shaped_reverse_arange - - -def _shaped_arange(shape, xp=dpnp, dtype=dpnp.float64, order="C"): - if dtype is dpnp.float64: - dtype = dpnp.float32 if not has_support_aspect64() else dtype - res = xp.array( - orig_shaped_arange(shape, xp=numpy, dtype=dtype, order=order), - dtype=dtype, - ) - return res - - -def _shaped_reverse_arange(shape, xp=dpnp, dtype=dpnp.float32): - res = xp.array( - orig_shaped_reverse_arange(shape, xp=numpy, dtype=dtype), dtype=dtype - ) - return res - - -cupy_testing.shaped_arange = _shaped_arange -cupy_testing.shaped_reverse_arange = _shaped_reverse_arange diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index f5f0f62c28e3..a78de781e3b0 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -265,6 +265,8 @@ tests/third_party/cupy/creation_tests/test_basic.py::TestBasic::test_ones_like_s tests/third_party/cupy/creation_tests/test_basic.py::TestBasic::test_zeros_like_subok tests/third_party/cupy/creation_tests/test_basic.py::TestBasic::test_zeros_strides +tests/third_party/cupy/creation_tests/test_from_data.py::TestFromData::test_copy_order + tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_construction_from_list tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_construction_from_tuple tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_extraction_from_nested_list diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 35092f3b07b8..79ca0610e32d 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -212,34 +212,6 @@ tests/third_party/cupy/linalg_tests/test_einsum.py::TestListArgEinSumError::test tests/third_party/cupy/linalg_tests/test_einsum.py::TestListArgEinSumError::test_too_many_dims3 tests/third_party/cupy/linalg_tests/test_product.py::TestProduct::test_reversed_vdot -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_7_{dst_shape=(0,), src=3.2}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_8_{dst_shape=(0,), src=0}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_9_{dst_shape=(0,), src=4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_10_{dst_shape=(0,), src=-4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_11_{dst_shape=(0,), src=True}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_12_{dst_shape=(0,), src=False}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_13_{dst_shape=(0,), src=(1+1j)}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_14_{dst_shape=(1,), src=3.2}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_15_{dst_shape=(1,), src=0}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_16_{dst_shape=(1,), src=4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_17_{dst_shape=(1,), src=-4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_18_{dst_shape=(1,), src=True}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_19_{dst_shape=(1,), src=False}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_20_{dst_shape=(1,), src=(1+1j)}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_21_{dst_shape=(1, 1), src=3.2}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_22_{dst_shape=(1, 1), src=0}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_23_{dst_shape=(1, 1), src=4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_24_{dst_shape=(1, 1), src=-4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_25_{dst_shape=(1, 1), src=True}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_26_{dst_shape=(1, 1), src=False}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_27_{dst_shape=(1, 1), src=(1+1j)}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_28_{dst_shape=(2, 2), src=3.2}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_29_{dst_shape=(2, 2), src=0}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_30_{dst_shape=(2, 2), src=4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_31_{dst_shape=(2, 2), src=-4}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_32_{dst_shape=(2, 2), src=True}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_33_{dst_shape=(2, 2), src=False}::test_copyto_where -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_34_{dst_shape=(2, 2), src=(1+1j)}::test_copyto_where tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_out_noncontiguous tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_axis_out_noncontiguous @@ -459,6 +431,9 @@ tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_ tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_linspace_zero_num_no_endopoint_with_retstep tests/third_party/cupy/creation_tests/test_ranges.py::TestRanges::test_logspace_zero_num + +tests/third_party/cupy/creation_tests/test_from_data.py::TestFromData::test_copy_order + tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_1_{axes=None, norm=None, s=(1, None), shape=(3, 4)}::test_fft2 tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_7_{axes=(), norm=None, s=None, shape=(3, 4)}::test_fft2 tests/third_party/cupy/fft_tests/test_fft.py::TestFft2_param_7_{axes=(), norm=None, s=None, shape=(3, 4)}::test_ifft2 diff --git a/tests/skipped_tests_gpu_no_fp64.tbl b/tests/skipped_tests_gpu_no_fp64.tbl index 2aca406319dd..5fc5b57352c9 100644 --- a/tests/skipped_tests_gpu_no_fp64.tbl +++ b/tests/skipped_tests_gpu_no_fp64.tbl @@ -885,28 +885,42 @@ tests/third_party/cupy/logic_tests/test_content.py::TestContent::test_isfinite tests/third_party/cupy/logic_tests/test_content.py::TestContent::test_isinf tests/third_party/cupy/logic_tests/test_content.py::TestContent::test_isnan -tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_6_{dst_shape=(), src=(1+1j)}::test_copyto - tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticUnary_param_29_{arg1=2.0, name='reciprocal'}::test_unary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_6_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_10_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_10_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_10_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_10_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_14_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_14_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_14_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_14_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_38_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_42_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_42_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_42_{arg1=array([[1., 2., 3.], [4., 5., 6.]]), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_42_{arg1=array([[1., 2., 3.], [4., 5., 6.]]), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_46_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_46_{arg1=array([[1., 2., 3.], [4., 5., 6.]], dtype=float32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_46_{arg1=array([[1., 2., 3.], [4., 5., 6.]]), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_46_{arg1=array([[1., 2., 3.], [4., 5., 6.]]), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_66_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0., 1., 2.], [3., 4., 5.]], dtype=float32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_66_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0., 1., 2.], [3., 4., 5.]], dtype=float32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_66_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[6., 5., 4.], [3., 2., 1.]], dtype=float32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_66_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6., 5., 4.], [3., 2., 1.]], dtype=float32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_70_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_70_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_70_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[6., 5., 4.], [3., 2., 1.]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_70_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6., 5., 4.], [3., 2., 1.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_74_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_74_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_74_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_74_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_78_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_78_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_78_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_78_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_82_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=0, name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_82_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=0, name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_86_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=0.0, name='power'}::test_binary @@ -915,12 +929,20 @@ tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_94_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=2.0, name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_98_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0., 1., 2.], [3., 4., 5.]], dtype=float32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_98_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[0., 1., 2.], [3., 4., 5.]], dtype=float32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_98_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6., 5., 4.], [3., 2., 1.]], dtype=float32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_98_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[6., 5., 4.], [3., 2., 1.]], dtype=float32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_102_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_102_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_102_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6., 5., 4.], [3., 2., 1.]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_102_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[6., 5., 4.], [3., 2., 1.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_106_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_106_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_106_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_106_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_110_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_110_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_110_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_110_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_114_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=0, name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_114_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int64), arg2=0, name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_118_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=0.0, name='power'}::test_binary @@ -930,16 +952,24 @@ tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_134_{arg1=0, arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_138_{arg1=0, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_138_{arg1=0, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_138_{arg1=0, arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_138_{arg1=0, arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_142_{arg1=0, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_142_{arg1=0, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_142_{arg1=0, arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_142_{arg1=0, arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_166_{arg1=0.0, arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_170_{arg1=0.0, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_174_{arg1=0.0, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_198_{arg1=2, arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_202_{arg1=2, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_202_{arg1=2, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_202_{arg1=2, arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int32), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_202_{arg1=2, arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_206_{arg1=2, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_206_{arg1=2, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int64), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_206_{arg1=2, arg2=array([[6, 5, 4], [3, 2, 1]]), name='power'}::test_binary +tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_206_{arg1=2, arg2=array([[6, 5, 4], [3, 2, 1]], dtype=int64), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_230_{arg1=2.0, arg2=array([[0., 1., 2.], [3., 4., 5.]]), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_234_{arg1=2.0, arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), name='power'}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary_param_238_{arg1=2.0, arg2=array([[0, 1, 2], [3, 4, 5]]), name='power'}::test_binary diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index c40ec0786ff4..576229b1d562 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -25,8 +25,6 @@ @pytest.mark.parametrize("in_obj, out_dtype", testdata) def test_copyto_dtype(in_obj, out_dtype): - if out_dtype == dpnp.complex64: - pytest.skip("SAT-6016: dpnp.copyto() do not work with complex64 dtype") ndarr = numpy.array(in_obj) expected = numpy.empty(ndarr.size, dtype=out_dtype) numpy.copyto(expected, ndarr) @@ -38,6 +36,27 @@ def test_copyto_dtype(in_obj, out_dtype): assert_array_equal(result, expected) +@pytest.mark.parametrize("dst", [7, numpy.ones(10), (2, 7), [5], range(3)]) +def test_copyto_dst_raises(dst): + a = dpnp.array(4) + with pytest.raises( + TypeError, + match="Destination array must be any of supported type, but got", + ): + dpnp.copyto(dst, a) + + +@pytest.mark.parametrize("where", [numpy.ones(10), (2, 7), [5], range(3)]) +def test_copyto_where_raises(where): + a = dpnp.empty((2, 3)) + b = dpnp.arange(6).reshape((2, 3)) + + with pytest.raises( + TypeError, match="`where` array must be any of supported type, but got" + ): + dpnp.copyto(a, b, where=where) + + @pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize( "arr", diff --git a/tests/third_party/cupy/fft_tests/test_fft.py b/tests/third_party/cupy/fft_tests/test_fft.py index 0cc49200a245..4650fda557ab 100644 --- a/tests/third_party/cupy/fft_tests/test_fft.py +++ b/tests/third_party/cupy/fft_tests/test_fft.py @@ -28,6 +28,7 @@ class TestFft(unittest.TestCase): atol=1e-7, accept_error=ValueError, type_check=has_support_aspect64(), + contiguous_check=False, ) def test_fft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -41,6 +42,7 @@ def test_fft(self, xp, dtype): atol=1e-7, accept_error=ValueError, type_check=has_support_aspect64(), + contiguous_check=False, ) def test_ifft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) diff --git a/tests/third_party/cupy/linalg_tests/test_product.py b/tests/third_party/cupy/linalg_tests/test_product.py index 2dc68b648b7a..974ea0af3773 100644 --- a/tests/third_party/cupy/linalg_tests/test_product.py +++ b/tests/third_party/cupy/linalg_tests/test_product.py @@ -100,7 +100,8 @@ def test_dot_with_out(self, xp, dtype_a, dtype_b, dtype_c): @testing.gpu class TestCrossProduct(unittest.TestCase): @testing.for_all_dtypes_combination(["dtype_a", "dtype_b"]) - @testing.numpy_cupy_allclose() + # TODO: remove 'contiguous_check=False' once fixed in dpnp.cross() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_cross(self, xp, dtype_a, dtype_b): if dtype_a == dtype_b == numpy.bool_: # cross does not support bool-bool inputs. diff --git a/tests/third_party/cupy/manipulation_tests/test_basic.py b/tests/third_party/cupy/manipulation_tests/test_basic.py index 0e5bb07fd398..0712f88a736e 100644 --- a/tests/third_party/cupy/manipulation_tests/test_basic.py +++ b/tests/third_party/cupy/manipulation_tests/test_basic.py @@ -1,17 +1,14 @@ -import itertools -import unittest +import warnings +import dpctl import numpy import pytest import dpnp as cupy - -# from cupy import cuda from tests.third_party.cupy import testing -@testing.gpu -class TestBasic(unittest.TestCase): +class TestBasic: @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_copyto(self, xp, dtype): @@ -20,6 +17,14 @@ def test_copyto(self, xp, dtype): xp.copyto(b, a) return b + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_copyto_different_contiguity(self, xp, dtype): + a = testing.shaped_arange((2, 3, 2), xp, dtype).T + b = xp.empty((2, 3, 2), dtype=dtype) + xp.copyto(b, a) + return b + @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_copyto_dtype(self, xp, dtype): @@ -28,7 +33,6 @@ def test_copyto_dtype(self, xp, dtype): xp.copyto(b, a) return b - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_copyto_broadcast(self, xp, dtype): @@ -37,7 +41,46 @@ def test_copyto_broadcast(self, xp, dtype): xp.copyto(b, a) return b - @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @pytest.mark.parametrize( + ("dst_shape", "src_shape"), + [ + ((), (2,)), + ((2, 0, 5, 4), (2, 0, 3, 4)), + ((6,), (2, 3)), + ((2, 3), (6,)), + ], + ) + def test_copyto_raises_shape(self, dst_shape, src_shape): + for xp in (numpy, cupy): + dst = xp.zeros(dst_shape, dtype=xp.int64) + src = xp.zeros(src_shape, dtype=xp.int64) + with pytest.raises(ValueError): + xp.copyto(dst, src) + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_copyto_squeeze(self, xp, dtype): + a = testing.shaped_arange((1, 1, 3, 4), xp, dtype) + b = xp.empty((3, 4), dtype=dtype) + xp.copyto(b, a) + return b + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_copyto_squeeze_different_contiguity(self, xp, dtype): + a = testing.shaped_arange((1, 1, 3, 4), xp, dtype) + b = xp.empty((4, 3), dtype=dtype).T + xp.copyto(b, a) + return b + + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_copyto_squeeze_broadcast(self, xp, dtype): + a = testing.shaped_arange((1, 2, 1, 4), xp, dtype) + b = xp.empty((2, 3, 4), dtype=dtype) + xp.copyto(b, a) + return b + @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_copyto_where(self, xp, dtype): @@ -47,63 +90,49 @@ def test_copyto_where(self, xp, dtype): xp.copyto(a, b, where=c) return a - # def _check_copyto_where_multigpu_raises(self, dtype, ngpus): - # def get_numpy(): - # a = testing.shaped_arange((2, 3, 4), numpy, dtype) - # b = testing.shaped_reverse_arange((2, 3, 4), numpy, dtype) - # c = testing.shaped_arange((2, 3, 4), numpy, '?') - # numpy.copyto(a, b, where=c) - # return a - # - # for dev1, dev2, dev3, dev4 in itertools.product(*[range(ngpus)] * 4): - # if dev1 == dev2 == dev3 == dev4: - # continue - # if not dev1 <= dev2 <= dev3 <= dev4: - # continue - # - # with cuda.Device(dev1): - # a = testing.shaped_arange((2, 3, 4), cupy, dtype) - # with cuda.Device(dev2): - # b = testing.shaped_reverse_arange((2, 3, 4), cupy, dtype) - # with cuda.Device(dev3): - # c = testing.shaped_arange((2, 3, 4), cupy, '?') - # with cuda.Device(dev4): - # with self.assertRaisesRegex( - # ValueError, - # '^Array device must be same as the current device'): - # cupy.copyto(a, b, where=c) - # - # @testing.multi_gpu(2) - # @testing.for_all_dtypes() - # def test_copyto_where_multigpu_raises(self, dtype): - # self._check_copyto_where_multigpu_raises(dtype, 2) - # - # @testing.multi_gpu(2) - # @testing.for_all_dtypes() - # @testing.numpy_cupy_array_equal() - # def test_copyto_multigpu(self, xp, dtype): - # with cuda.Device(0): - # a = testing.shaped_arange((2, 3, 4), xp, dtype) - # with cuda.Device(1): - # b = xp.empty((2, 3, 4), dtype=dtype) - # xp.copyto(b, a) - # return b - # - # @testing.multi_gpu(2) - # @testing.for_all_dtypes() - # def test_copyto_multigpu_noncontinguous(self, dtype): - # with cuda.Device(0): - # src = testing.shaped_arange((2, 3, 4), cupy, dtype) - # src = src.swapaxes(0, 1) - # with cuda.Device(1): - # dst = cupy.empty_like(src) - # cupy.copyto(dst, src) - # - # expected = testing.shaped_arange((2, 3, 4), numpy, dtype) - # expected = expected.swapaxes(0, 1) - # - # testing.assert_array_equal(expected, src.get()) - # testing.assert_array_equal(expected, dst.get()) + @pytest.mark.parametrize("shape", [(2, 3, 4), (0,)]) + @testing.for_all_dtypes(no_bool=True) + def test_copyto_where_raises(self, dtype, shape): + for xp in (numpy, cupy): + a = testing.shaped_arange(shape, xp, "i") + b = testing.shaped_reverse_arange(shape, xp, "i") + c = testing.shaped_arange(shape, xp, dtype) + with pytest.raises(TypeError): + xp.copyto(a, b, where=c) + + @testing.for_all_dtypes() + def test_copyto_where_multidevice_raises(self, dtype): + a = testing.shaped_arange( + (2, 3, 4), cupy, dtype, device=dpctl.SyclQueue() + ) + b = testing.shaped_reverse_arange( + (2, 3, 4), cupy, dtype, device=dpctl.SyclQueue() + ) + c = testing.shaped_arange( + (2, 3, 4), cupy, "?", device=dpctl.SyclQueue() + ) + with pytest.raises( + dpctl.utils.ExecutionPlacementError, + match="arrays have different associated queues", + ): + cupy.copyto(a, b, where=c) + + @testing.for_all_dtypes() + def test_copyto_noncontinguous(self, dtype): + src = testing.shaped_arange((2, 3, 4), cupy, dtype) + # TODO: replace with + # src = src.swapaxes(0, 1) + # once dpnp.ndarray.swapaxes() is fully implemented + src = cupy.swapaxes(src, 0, 1) + + dst = cupy.empty_like(src) + cupy.copyto(dst, src) + + expected = testing.shaped_arange((2, 3, 4), numpy, dtype) + expected = expected.swapaxes(0, 1) + + testing.assert_array_equal(expected, src) + testing.assert_array_equal(expected, dst) @testing.parameterize( @@ -114,9 +143,7 @@ def test_copyto_where(self, xp, dtype): } ) ) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@testing.gpu -class TestCopytoFromScalar(unittest.TestCase): +class TestCopytoFromScalar: @testing.for_all_dtypes() @testing.numpy_cupy_allclose(accept_error=TypeError) def test_copyto(self, xp, dtype): @@ -133,3 +160,68 @@ def test_copyto_where(self, xp, dtype): ) xp.copyto(dst, self.src, where=mask) return dst + + +@pytest.mark.parametrize( + "casting", ["no", "equiv", "safe", "same_kind", "unsafe"] +) +class TestCopytoFromNumpyScalar: + @testing.for_all_dtypes_combination(("dtype1", "dtype2")) + @testing.numpy_cupy_allclose(accept_error=TypeError) + def test_copyto(self, xp, dtype1, dtype2, casting): + if casting == "safe": + pytest.skip( + "NEP50 doesn't work properly in numpy with casting='safe'" + ) + + dst = xp.zeros((2, 3, 4), dtype=dtype1) + src = numpy.array(1, dtype=dtype2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", numpy.ComplexWarning) + xp.copyto(dst, src, casting) + return dst + + @testing.for_all_dtypes() + @pytest.mark.parametrize( + "make_src", + [lambda dtype: numpy.array([1], dtype=dtype), lambda dtype: dtype(1)], + ) + @testing.numpy_cupy_allclose(accept_error=TypeError) + def test_copyto2(self, xp, make_src, dtype, casting): + dst = xp.zeros((2, 3, 4), dtype=dtype) + src = make_src(dtype) + + with warnings.catch_warnings(): + warnings.simplefilter("ignore", numpy.ComplexWarning) + xp.copyto(dst, src, casting) + return dst + + @testing.for_all_dtypes_combination(("dtype1", "dtype2")) + @testing.numpy_cupy_allclose(accept_error=TypeError) + def test_copyto_where(self, xp, dtype1, dtype2, casting): + if casting == "safe": + pytest.skip( + "NEP50 doesn't work properly in numpy with casting='safe'" + ) + + shape = (2, 3, 4) + dst = xp.ones(shape, dtype=dtype1) + src = numpy.array(1, dtype=dtype2) + mask = (testing.shaped_arange(shape, xp, dtype1) % 2).astype(xp.bool_) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", numpy.ComplexWarning) + xp.copyto(dst, src, casting=casting, where=mask) + return dst + + +@pytest.mark.parametrize("shape", [(3, 2), (0,)]) +@pytest.mark.parametrize( + "where", [float(3.2), int(0), int(4), int(-4), True, False, 1 + 1j] +) +@testing.for_all_dtypes() +@testing.numpy_cupy_allclose() +def test_copyto_scalarwhere(xp, dtype, where, shape): + dst = xp.zeros(shape, dtype=dtype) + src = xp.ones(shape, dtype=dtype) + xp.copyto(dst, src, where=where) + return dst diff --git a/tests/third_party/cupy/math_tests/test_arithmetic.py b/tests/third_party/cupy/math_tests/test_arithmetic.py index 7a8cf0ffc086..f15682b9a675 100644 --- a/tests/third_party/cupy/math_tests/test_arithmetic.py +++ b/tests/third_party/cupy/math_tests/test_arithmetic.py @@ -100,7 +100,7 @@ def test_raises_with_numpy_input(self): ) @pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestArithmeticUnary(unittest.TestCase): - @testing.numpy_cupy_allclose(atol=1e-5) + @testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64()) def test_unary(self, xp): arg1 = self.arg1 if isinstance(arg1, numpy.ndarray): diff --git a/tests/third_party/cupy/testing/helper.py b/tests/third_party/cupy/testing/helper.py index c78dc07d9997..f9f419e91c37 100644 --- a/tests/third_party/cupy/testing/helper.py +++ b/tests/third_party/cupy/testing/helper.py @@ -49,12 +49,16 @@ def _format_exception(exc): return "".join(traceback.TracebackException.from_exception(exc).format()) -def _call_func(self, impl, args, kw): +def _call_func(impl, args, kw): + # Note that `_pytest.outcomes.Skipped` is derived from BaseException. + exceptions = (Exception,) + if _is_pytest_available: + exceptions += (_pytest.outcomes.Skipped,) + try: - result = impl(self, *args, **kw) + result = impl(*args, **kw) error = None - tb = None - except Exception as e: + except exceptions as e: tb = e.__traceback__ if tb.tb_next is None: # failed before impl is called, e.g. invalid kw @@ -62,10 +66,10 @@ def _call_func(self, impl, args, kw): result = None error = e - return result, error, tb + return result, error -def _call_func_cupy(self, impl, args, kw, name, sp_name, scipy_name): +def _call_func_cupy(impl, args, kw, name, sp_name, scipy_name): assert isinstance(name, str) assert sp_name is None or isinstance(sp_name, str) assert scipy_name is None or isinstance(scipy_name, str) @@ -76,12 +80,12 @@ def _call_func_cupy(self, impl, args, kw, name, sp_name, scipy_name): kw[sp_name] = cupyx.scipy.sparse if scipy_name: kw[scipy_name] = cupyx.scipy - kw[name] = dpnp - result, error, tb = _call_func(self, impl, args, kw) - return result, error, tb + kw[name] = cupy + result, error = _call_func(impl, args, kw) + return result, error -def _call_func_numpy(self, impl, args, kw, name, sp_name, scipy_name): +def _call_func_numpy(impl, args, kw, name, sp_name, scipy_name): assert isinstance(name, str) assert sp_name is None or isinstance(sp_name, str) assert scipy_name is None or isinstance(scipy_name, str) @@ -97,29 +101,22 @@ def _call_func_numpy(self, impl, args, kw, name, sp_name, scipy_name): import scipy kw[scipy_name] = scipy - result, error, tb = _call_func(self, impl, args, kw) - return result, error, tb + result, error = _call_func(impl, args, kw) + return result, error -def _call_func_numpy_cupy(self, impl, args, kw, name, sp_name, scipy_name): +def _call_func_numpy_cupy(impl, args, kw, name, sp_name, scipy_name): # Run cupy - cupy_result, cupy_error, cupy_tb = _call_func_cupy( - self, impl, args, kw, name, sp_name, scipy_name + cupy_result, cupy_error = _call_func_cupy( + impl, args, kw, name, sp_name, scipy_name ) # Run numpy - numpy_result, numpy_error, numpy_tb = _call_func_numpy( - self, impl, args, kw, name, sp_name, scipy_name + numpy_result, numpy_error = _call_func_numpy( + impl, args, kw, name, sp_name, scipy_name ) - return ( - cupy_result, - cupy_error, - cupy_tb, - numpy_result, - numpy_error, - numpy_tb, - ) + return (cupy_result, cupy_error, numpy_result, numpy_error) _numpy_errors = [ @@ -139,10 +136,8 @@ def _check_numpy_cupy_error_compatible(cupy_error, numpy_error): """Checks if try/except blocks are equivalent up to public error classes""" return all( - [ - isinstance(cupy_error, err) == isinstance(numpy_error, err) - for err in _numpy_errors - ] + isinstance(cupy_error, err) == isinstance(numpy_error, err) + for err in _numpy_errors ) @@ -250,21 +245,35 @@ def _check_cupy_numpy_error(cupy_error, numpy_error, accept_error=False): ) -def _make_positive_mask(self, impl, args, kw, name, sp_name, scipy_name): +def _signed_counterpart(dtype): + return numpy.dtype(numpy.dtype(dtype).char.lower()).type + + +def _make_positive_masks(impl, args, kw, name, sp_name, scipy_name): # Returns a mask of output arrays that indicates valid elements for # comparison. See the comment at the caller. ks = [k for k, v in kw.items() if v in _unsigned_dtypes] for k in ks: - kw[k] = numpy.intp - result, error, tb = _call_func_cupy( - self, impl, args, kw, name, sp_name, scipy_name - ) + kw[k] = _signed_counterpart(kw[k]) + result, error = _call_func_cupy(impl, args, kw, name, sp_name, scipy_name) assert error is None - return dpnp.asnumpy(result) >= 0 + if not isinstance(result, (tuple, list)): + result = (result,) + return [cupy.asnumpy(r) >= 0 for r in result] def _contains_signed_and_unsigned(kw): - vs = set(kw.values()) + def isdtype(v): + if isinstance(v, numpy.dtype): + return True + elif isinstance(v, str): # expecting dtype character codes + return True + elif isinstance(v, type) and issubclass(v, numpy.number): + return True + else: + return False + + vs = set(v for v in kw.values() if isdtype(v)) return any(d in vs for d in _unsigned_dtypes) and any( d in vs for d in _float_dtypes + _signed_dtypes ) @@ -282,27 +291,36 @@ def decorator(impl): return decorator +def _wraps_partial_xp(wrapped, name, sp_name, scipy_name): + names = [name, sp_name, scipy_name] + names = [n for n in names if n is not None] + return _wraps_partial(wrapped, *names) + + def _make_decorator( - check_func, name, type_check, accept_error, sp_name=None, scipy_name=None + check_func, + name, + type_check, + contiguous_check, + accept_error, + sp_name=None, + scipy_name=None, + check_sparse_format=True, ): assert isinstance(name, str) assert sp_name is None or isinstance(sp_name, str) assert scipy_name is None or isinstance(scipy_name, str) def decorator(impl): - @functools.wraps(impl) - def test_func(self, *args, **kw): + @_wraps_partial_xp(impl, name, sp_name, scipy_name) + def test_func(*args, **kw): # Run cupy and numpy ( cupy_result, cupy_error, - cupy_tb, numpy_result, numpy_error, - numpy_tb, - ) = _call_func_numpy_cupy( - self, impl, args, kw, name, sp_name, scipy_name - ) + ) = _call_func_numpy_cupy(impl, args, kw, name, sp_name, scipy_name) assert cupy_result is not None or cupy_error is not None assert numpy_result is not None or numpy_error is not None @@ -322,39 +340,87 @@ def test_func(self, *args, **kw): assert len(cupy_result) == len(numpy_result) + # Check types + cupy_numpy_result_ndarrays = [ + _convert_output_to_ndarray( + cupy_r, numpy_r, sp_name, check_sparse_format + ) + for cupy_r, numpy_r in zip(cupy_result, numpy_result) + ] + + # Check dtypes if type_check: - for cupy_r, numpy_r in zip(cupy_result, numpy_result): + for cupy_r, numpy_r in cupy_numpy_result_ndarrays: if cupy_r.dtype != numpy_r.dtype: - print( - f"\nERROR:\n\tcupy_r.dtype={cupy_r.dtype},\n\tnumpy_r.dtype={numpy_r.dtype}" + raise AssertionError( + """ndarrays of different dtypes are returned. +cupy: {} +numpy: {}""".format( + cupy_r.dtype, numpy_r.dtype + ) ) - assert cupy_r.dtype == numpy_r.dtype - for cupy_r, numpy_r in zip(cupy_result, numpy_result): - if cupy_r.shape != numpy_r.shape: - print( - f"\nERROR:\n\tcupy_r.shape={cupy_r.shape},\n\tnumpy_r.shape={numpy_r.shape}" - ) + # Check contiguities + if contiguous_check: + for cupy_r, numpy_r in zip(cupy_result, numpy_result): + if isinstance(numpy_r, numpy.ndarray): + if ( + numpy_r.flags.c_contiguous + and not cupy_r.flags.c_contiguous + ): + raise AssertionError( + "The state of c_contiguous flag is false. " + "(cupy_result:{} numpy_result:{})".format( + cupy_r.flags.c_contiguous, + numpy_r.flags.c_contiguous, + ) + ) + if ( + numpy_r.flags.f_contiguous + and not cupy_r.flags.f_contiguous + ): + raise AssertionError( + "The state of f_contiguous flag is false. " + "(cupy_result:{} numpy_result:{})".format( + cupy_r.flags.f_contiguous, + numpy_r.flags.f_contiguous, + ) + ) + + # Check shapes + for cupy_r, numpy_r in cupy_numpy_result_ndarrays: assert cupy_r.shape == numpy_r.shape + masks = [None] * len(cupy_result) + if _contains_signed_and_unsigned(kw): + needs_mask = [ + cupy_r.dtype in _unsigned_dtypes for cupy_r in cupy_result + ] + if any(needs_mask): + masks = _make_positive_masks( + impl, args, kw, name, sp_name, scipy_name + ) + for i, flag in enumerate(needs_mask): + if not flag: + masks[i] = None + + # Check item values + for (cupy_r, numpy_r), mask in zip( + cupy_numpy_result_ndarrays, masks + ): # Behavior of assigning a negative value to an unsigned integer # variable is undefined. # nVidia GPUs and Intel CPUs behave differently. # To avoid this difference, we need to ignore dimensions whose # values are negative. + skip = False - if ( - _contains_signed_and_unsigned(kw) - and cupy_r.dtype in _unsigned_dtypes - ): - mask = _make_positive_mask( - self, impl, args, kw, name, sp_name, scipy_name - ) + if mask is not None: if cupy_r.shape == (): skip = (mask == 0).all() else: - cupy_r = dpnp.asnumpy(cupy_r[mask]) - numpy_r = dpnp.asnumpy(numpy_r[mask]) + cupy_r = cupy_r[mask].get() + numpy_r = numpy_r[mask] if not skip: check_func(cupy_r, numpy_r) @@ -364,6 +430,99 @@ def test_func(self, *args, **kw): return decorator +def _convert_output_to_ndarray(c_out, n_out, sp_name, check_sparse_format): + """Checks type of cupy/numpy results and returns cupy/numpy ndarrays. + + Args: + c_out (cupy.ndarray, cupyx.scipy.sparse matrix, cupy.poly1d or scalar): + cupy result + n_out (numpy.ndarray, scipy.sparse matrix, numpy.poly1d or scalar): + numpy result + sp_name(str or None): Argument name whose value is either + ``scipy.sparse`` or ``cupyx.scipy.sparse`` module. If ``None``, no + argument is given for the modules. + check_sparse_format (bool): If ``True``, consistency of format of + sparse matrix is also checked. Default is ``True``. + + Returns: + The tuple of cupy.ndarray and numpy.ndarray. + """ + if sp_name is not None and cupyx.scipy.sparse.issparse(c_out): + # Sparse output case. + import scipy.sparse + + assert scipy.sparse.issparse(n_out) + if check_sparse_format: + assert c_out.format == n_out.format + return c_out.A, n_out.A + if isinstance(c_out, cupy.ndarray) and isinstance( + n_out, (numpy.ndarray, numpy.generic) + ): + # ndarray output case. + return c_out, n_out + if ( + hasattr(cupy, "poly1d") + and isinstance(c_out, cupy.poly1d) + and hasattr(numpy, "poly1d") + and isinstance(n_out, numpy.poly1d) + ): + # poly1d output case. + assert c_out.variable == n_out.variable + return c_out.coeffs, n_out.coeffs + if isinstance(c_out, numpy.generic) and isinstance(n_out, numpy.generic): + # numpy scalar output case. + return c_out, n_out + if isinstance(c_out, numpy.ndarray) and isinstance(n_out, numpy.ndarray): + # fallback on numpy output case. + return c_out, n_out + if numpy.isscalar(c_out) and numpy.isscalar(n_out): + # python scalar output case. + return cupy.array(c_out), numpy.array(n_out) + raise AssertionError( + "numpy and cupy returns different type of return value:\n" + "cupy: {}\nnumpy: {}".format(type(c_out), type(n_out)) + ) + + +def _check_tolerance_keys(rtol, atol): + def _check(tol): + if isinstance(tol, dict): + for k in tol.keys(): + if type(k) is type: + continue + if type(k) is str and k == "default": + continue + msg = ( + "Keys of the tolerance dictionary need to be type " + "objects as `numpy.float32` and `cupy.float32` or " + "`'default'` string." + ) + raise TypeError(msg) + + _check(rtol) + _check(atol) + + +def _resolve_tolerance(type_check, result, rtol, atol): + def _resolve(dtype, tol): + if isinstance(tol, dict): + tol1 = tol.get(dtype.type) + if tol1 is None: + tol1 = tol.get("default") + if tol1 is None: + raise TypeError( + "Can not find tolerance for {}".format(dtype.type) + ) + return tol1 + else: + return tol + + dtype = result.dtype + rtol1 = _resolve(dtype, rtol) + atol1 = _resolve(dtype, atol) + return rtol1, atol1 + + def numpy_cupy_allclose( rtol=1e-7, atol=0, @@ -375,12 +534,19 @@ def numpy_cupy_allclose( sp_name=None, scipy_name=None, contiguous_check=True, + *, + _check_sparse_format=True, ): """Decorator that checks NumPy results and CuPy ones are close. Args: - rtol(float): Relative tolerance. - atol(float): Absolute tolerance. + rtol(float or dict): Relative tolerance. Besides a float value, a + dictionary that maps a dtypes to a float value can be supplied to + adjust tolerance per dtype. If the dictionary has ``'default'`` + string as its key, its value is used as the default tolerance in + case any dtype keys do not match. + atol(float or dict): Absolute tolerance. Besides a float value, a + dictionary can be supplied as ``rtol``. err_msg(str): The error message to be printed in case of failure. verbose(bool): If ``True``, the conflicting values are appended to the error message. @@ -408,9 +574,8 @@ def numpy_cupy_allclose( should return same value. >>> import unittest - >>> from dpnp import testing - >>> @testing.gpu - ... class TestFoo(unittest.TestCase): + >>> from cupy import testing + >>> class TestFoo(unittest.TestCase): ... ... @testing.numpy_cupy_allclose() ... def test_foo(self, xp): @@ -423,21 +588,31 @@ def numpy_cupy_allclose( .. seealso:: :func:`cupy.testing.assert_allclose` """ + _check_tolerance_keys(rtol, atol) + + # When `type_check` is `False`, cupy result and numpy result may have + # different dtypes so we can not determine the dtype to use from the + # tolerance associations. + if not type_check: + if isinstance(rtol, dict) or isinstance(atol, dict): + raise TypeError( + "When `type_check` is `False`, `rtol` and `atol` " + "must be supplied as float." + ) def check_func(c, n): - c_array = c - n_array = n - if sp_name is not None: - import scipy.sparse - - if cupyx.scipy.sparse.issparse(c): - c_array = c.A - if scipy.sparse.issparse(n): - n_array = n.A - array.assert_allclose(c_array, n_array, rtol, atol, err_msg, verbose) + rtol1, atol1 = _resolve_tolerance(type_check, c, rtol, atol) + array.assert_allclose(c, n, rtol1, atol1, err_msg, verbose) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name + check_func, + name, + type_check, + contiguous_check, + accept_error, + sp_name, + scipy_name, + _check_sparse_format, ) @@ -485,7 +660,7 @@ def check_func(x, y): array.assert_array_almost_equal(x, y, decimal, err_msg, verbose) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name + check_func, name, type_check, False, accept_error, sp_name, scipy_name ) @@ -522,14 +697,19 @@ def numpy_cupy_array_almost_equal_nulp( (except the type of array module) even if ``xp`` is ``numpy`` or ``cupy``. .. seealso:: :func:`cupy.testing.assert_array_almost_equal_nulp` - """ def check_func(x, y): array.assert_array_almost_equal_nulp(x, y, nulp) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name=None + check_func, + name, + type_check, + False, + accept_error, + sp_name, + scipy_name=None, ) @@ -577,7 +757,7 @@ def check_func(x, y): array.assert_array_max_ulp(x, y, maxulp, dtype) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name + check_func, name, type_check, False, accept_error, sp_name, scipy_name ) @@ -623,18 +803,10 @@ def numpy_cupy_array_equal( """ def check_func(x, y): - if sp_name is not None: - import scipy.sparse - - if cupyx.scipy.sparse.issparse(x): - x = x.A - if scipy.sparse.issparse(y): - y = y.A - array.assert_array_equal(x, y, err_msg, verbose, strides_check) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name + check_func, name, type_check, False, accept_error, sp_name, scipy_name ) @@ -660,13 +832,19 @@ def numpy_cupy_array_list_equal( (except the type of array module) even if ``xp`` is ``numpy`` or ``cupy``. .. seealso:: :func:`cupy.testing.assert_array_list_equal` - """ + warnings.warn( + "numpy_cupy_array_list_equal is deprecated." + " Use numpy_cupy_array_equal instead.", + DeprecationWarning, + ) def check_func(x, y): array.assert_array_equal(x, y, err_msg, verbose) - return _make_decorator(check_func, name, False, False, sp_name, scipy_name) + return _make_decorator( + check_func, name, False, False, False, sp_name, scipy_name + ) def numpy_cupy_array_less( @@ -710,7 +888,7 @@ def check_func(x, y): array.assert_array_less(x, y, err_msg, verbose) return _make_decorator( - check_func, name, type_check, accept_error, sp_name, scipy_name + check_func, name, type_check, False, accept_error, sp_name, scipy_name ) @@ -721,7 +899,7 @@ def numpy_cupy_equal(name="xp", sp_name=None, scipy_name=None): name(str): Argument name whose value is either ``numpy`` or ``cupy`` module. sp_name(str or None): Argument name whose value is either - ``scipy.sparse`` or ``cupyx.sciyp.sparse`` module. If ``None``, no + ``scipy.sparse`` or ``cupyx.scipy.sparse`` module. If ``None``, no argument is given for the modules. scipy_name(str or None): Argument name whose value is either ``scipy`` or ``cupyx.scipy`` module. If ``None``, no argument is given for @@ -732,19 +910,21 @@ def numpy_cupy_equal(name="xp", sp_name=None, scipy_name=None): """ def decorator(impl): - @functools.wraps(impl) - def test_func(self, *args, **kw): + @_wraps_partial_xp(impl, name, sp_name, scipy_name) + def test_func(*args, **kw): # Run cupy and numpy ( cupy_result, cupy_error, - cupy_tb, numpy_result, numpy_error, - numpy_tb, - ) = _call_func_numpy_cupy( - self, impl, args, kw, name, sp_name, scipy_name - ) + ) = _call_func_numpy_cupy(impl, args, kw, name, sp_name, scipy_name) + + if cupy_error or numpy_error: + _check_cupy_numpy_error( + cupy_error, numpy_error, accept_error=False + ) + return if cupy_result != numpy_result: message = """Results are not equal: @@ -784,21 +964,20 @@ def numpy_cupy_raises( Decorated test fixture is required throw same errors even if ``xp`` is ``numpy`` or ``cupy``. """ + warnings.warn( + "cupy.testing.numpy_cupy_raises is deprecated.", DeprecationWarning + ) def decorator(impl): - @functools.wraps(impl) - def test_func(self, *args, **kw): + @_wraps_partial_xp(impl, name, sp_name, scipy_name) + def test_func(*args, **kw): # Run cupy and numpy ( cupy_result, cupy_error, - cupy_tb, numpy_result, numpy_error, - numpy_tb, - ) = _call_func_numpy_cupy( - self, impl, args, kw, name, sp_name, scipy_name - ) + ) = _call_func_numpy_cupy(impl, args, kw, name, sp_name, scipy_name) _check_cupy_numpy_error( cupy_error, numpy_error, accept_error=accept_error @@ -829,7 +1008,7 @@ def test_func(*args, **kw): try: kw[name] = numpy.dtype(dtype).type impl(*args, **kw) - except unittest.SkipTest as e: + except _skip_classes as e: print("skipped: {} = {} ({})".format(name, dtype, e)) except Exception: print(name, "is", dtype) @@ -913,9 +1092,8 @@ def for_all_dtypes( ``dtype`` is an argument inserted by the decorator. >>> import unittest - >>> from dpnp import testing - >>> @testing.gpu - ... class TestNpz(unittest.TestCase): + >>> from cupy import testing + >>> class TestNpz(unittest.TestCase): ... ... @testing.for_all_dtypes() ... def test_pickle(self, dtype): @@ -930,9 +1108,8 @@ def for_all_dtypes( The following is such an example. >>> import unittest - >>> from dpnp import testing - >>> @testing.gpu - ... class TestMean(unittest.TestCase): + >>> from cupy import testing + >>> class TestMean(unittest.TestCase): ... ... @testing.for_all_dtypes() ... @testing.numpy_cupy_allclose() @@ -1013,9 +1190,7 @@ def for_int_dtypes(name="dtype", no_bool=False): .. seealso:: :func:`cupy.testing.for_dtypes`, :func:`cupy.testing.for_all_dtypes` - """ - if no_bool: return for_dtypes(_int_dtypes, name=name) else: @@ -1062,7 +1237,6 @@ def for_dtypes_combination(types, names=("dtype",), full=None): If the value is set to ``'1'``, it behaves as if ``full=True``, and otherwise ``full=False``. """ - types = list(types) if len(types) == 1: @@ -1087,14 +1261,20 @@ def for_dtypes_combination(types, names=("dtype",), full=None): combination = [dict(assoc_list) for assoc_list in set(combination)] def decorator(impl): - @functools.wraps(impl) - def test_func(self, *args, **kw): + @_wraps_partial(impl, *names) + def test_func(*args, **kw): for dtypes in combination: kw_copy = kw.copy() kw_copy.update(dtypes) try: - impl(self, *args, **kw_copy) + impl(*args, **kw_copy) + except _skip_classes as e: + msg = ", ".join( + "{} = {}".format(name, dtype) + for name, dtype in dtypes.items() + ) + print("skipped: {} ({})".format(msg, e)) except Exception: print(dtypes) raise @@ -1143,9 +1323,7 @@ def for_signed_dtypes_combination(names=("dtype",), full=None): (see description in :func:`cupy.testing.for_dtypes_combination`). .. seealso:: :func:`cupy.testing.for_dtypes_combination` - """ - return for_dtypes_combination(_signed_dtypes, names=names, full=full) @@ -1160,9 +1338,7 @@ def for_unsigned_dtypes_combination(names=("dtype",), full=None): (see description in :func:`cupy.testing.for_dtypes_combination`). .. seealso:: :func:`cupy.testing.for_dtypes_combination` - """ - return for_dtypes_combination(_unsigned_dtypes, names=names, full=full) @@ -1179,9 +1355,7 @@ def for_int_dtypes_combination(names=("dtype",), no_bool=False, full=None): (see description in :func:`cupy.testing.for_dtypes_combination`). .. seealso:: :func:`cupy.testing.for_dtypes_combination` - """ - if no_bool: types = _int_dtypes else: @@ -1227,7 +1401,7 @@ def for_CF_orders(name="order"): .. seealso:: :func:`cupy.testing.for_all_dtypes` """ - return for_orders([None, "C", "c"], name) + return for_orders([None, "C", "F", "c", "f"], name) def for_castings(castings=None, name="casting"): @@ -1262,6 +1436,56 @@ def test_func(*args, **kw): return decorator +def for_contiguous_axes(name="axis"): + """Decorator for parametrizing tests with possible contiguous axes. + + Args: + name(str): Argument name to which specified axis are passed. + + .. note:: + 1. Adapted from tests/cupy_tests/fft_tests/test_fft.py. + 2. Example: for ``shape = (1, 2, 3)``, the tested axes are + ``[(2,), (1, 2), (0, 1, 2)]`` for the C order, and + ``[(0,), (0, 1), (0, 1, 2)]`` for the F order. + """ + + def decorator(impl): + @_wraps_partial(impl, name) + def test_func(self, *args, **kw): + ndim = len(self.shape) + order = self.order + for i in range(ndim): + a = () + if order in ("c", "C"): + for j in range(ndim - 1, i - 1, -1): + a = (j,) + a + elif order in ("f", "F"): + for j in range(0, i + 1): + a = a + (j,) + else: + raise ValueError("Please specify the array order.") + try: + kw[name] = a + impl(self, *args, **kw) + except Exception: + print( + name, + "is", + a, + ", ndim is", + ndim, + ", shape is", + self.shape, + ", order is", + order, + ) + raise + + return test_func + + return decorator + + def with_requires(*requirements): """Run a test case only when given requirements are satisfied. @@ -1313,7 +1537,7 @@ def numpy_satisfies(version_range): return True -def shaped_arange(shape, xp=dpnp, dtype=numpy.float64, order="C"): +def shaped_arange(shape, xp=cupy, dtype=numpy.float32, order="C", device=None): """Returns an array with given shape, array module, and dtype. Args: @@ -1321,6 +1545,7 @@ def shaped_arange(shape, xp=dpnp, dtype=numpy.float64, order="C"): xp(numpy or cupy): Array module to use. dtype(dtype): Dtype of returned ndarray. order({'C', 'F'}): Order of returned ndarray. + device(None or device): A device where the output array is created. Returns: numpy.ndarray or cupy.ndarray: @@ -1332,21 +1557,23 @@ def shaped_arange(shape, xp=dpnp, dtype=numpy.float64, order="C"): """ dtype = numpy.dtype(dtype) - a = xp.arange(1, prod(shape) + 1, 1) + kw = {} if xp is numpy else {"device": device} + a = numpy.arange(1, prod(shape) + 1, 1) if dtype == "?": a = a % 2 == 0 elif dtype.kind == "c": a = a + a * 1j - return xp.array(a.astype(dtype).reshape(shape), order=order, dtype=dtype) + return xp.array(a.astype(dtype).reshape(shape), order=order, **kw) -def shaped_reverse_arange(shape, xp=dpnp, dtype=numpy.float32): +def shaped_reverse_arange(shape, xp=cupy, dtype=numpy.float32, device=None): """Returns an array filled with decreasing numbers. Args: shape(tuple of int): Shape of returned ndarray. xp(numpy or cupy): Array module to use. dtype(dtype): Dtype of returned ndarray. + device(None or device): A device where the output array is created. Returns: numpy.ndarray or cupy.ndarray: @@ -1357,17 +1584,19 @@ def shaped_reverse_arange(shape, xp=dpnp, dtype=numpy.float32): ``True`` (resp. ``False``). """ dtype = numpy.dtype(dtype) + kw = {} if xp is numpy else {"device": device} size = prod(shape) - # a = xp.arange(size, 0, -1) - a = xp.arange(0, size) + a = numpy.arange(size, 0, -1) if dtype == "?": a = a % 2 == 0 elif dtype.kind == "c": a = a + a * 1j - return xp.array(a.astype(dtype).reshape(shape)) + return xp.array(a.astype(dtype).reshape(shape), **kw) -def shaped_random(shape, xp=dpnp, dtype=numpy.float64, scale=10, seed=0): +def shaped_random( + shape, xp=cupy, dtype=numpy.float32, scale=10, seed=0, order="C" +): """Returns an array filled with random values. Args: @@ -1379,7 +1608,7 @@ def shaped_random(shape, xp=dpnp, dtype=numpy.float64, scale=10, seed=0): Returns: numpy.ndarray or cupy.ndarray: The array with - given shape, array module, + given shape, array module, If ``dtype`` is ``numpy.bool_``, the elements are independently drawn from ``True`` and ``False`` @@ -1391,14 +1620,14 @@ def shaped_random(shape, xp=dpnp, dtype=numpy.float64, scale=10, seed=0): """ numpy.random.seed(seed) dtype = numpy.dtype(dtype) - if dtype == "?": - return xp.asarray(numpy.random.randint(2, size=shape), dtype=dtype) + a = numpy.random.randint(2, size=shape) elif dtype.kind == "c": - a = dpnp.random.rand(*shape) + 1j * numpy.random.rand(*shape) - return xp.asarray(a * scale, dtype=dtype) + a = numpy.random.rand(*shape) + 1j * numpy.random.rand(*shape) + a *= scale else: - return xp.asarray(numpy.random.rand(*shape) * scale, dtype=dtype) + a = numpy.random.rand(*shape) * scale + return xp.asarray(a, dtype=dtype, order=order) def empty(xp=dpnp, dtype=numpy.float64):