From 2a3819260f391b8072c4fac7ddd639d1e34c7532 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 29 Sep 2023 10:05:16 -0500 Subject: [PATCH 01/15] rework implementation of diag, diagflat, vander, and ptp --- dpnp/backend/include/dpnp_iface_fptr.hpp | 31 +-- .../kernels/dpnp_krnl_arraycreation.cpp | 74 ----- dpnp/dpnp_algo/dpnp_algo.pxd | 6 - dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi | 168 ----------- dpnp/dpnp_array.py | 25 +- dpnp/dpnp_iface_arraycreation.py | 263 +++++++++++++++--- tests/skipped_tests.tbl | 12 - tests/skipped_tests_gpu.tbl | 9 - tests/test_arraycreation.py | 38 ++- tests/test_sycl_queue.py | 82 +++++- tests/test_usm_type.py | 31 ++- 11 files changed, 405 insertions(+), 334 deletions(-) diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 7d8b195935c6..5794e2db6189 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -132,8 +132,6 @@ enum class DPNPFuncName : size_t DPNP_FN_DET_EXT, /**< Used in numpy.linalg.det() impl, requires extra parameters */ DPNP_FN_DIAG, /**< Used in numpy.diag() impl */ - DPNP_FN_DIAG_EXT, /**< Used in numpy.diag() impl, requires extra parameters - */ DPNP_FN_DIAG_INDICES, /**< Used in numpy.diag_indices() impl */ DPNP_FN_DIAG_INDICES_EXT, /**< Used in numpy.diag_indices() impl, requires extra parameters */ @@ -243,7 +241,6 @@ enum class DPNPFuncName : size_t DPNP_FN_POWER, /**< Used in numpy.power() impl */ DPNP_FN_PROD, /**< Used in numpy.prod() impl */ DPNP_FN_PTP, /**< Used in numpy.ptp() impl */ - DPNP_FN_PTP_EXT, /**< Used in numpy.ptp() impl, requires extra parameters */ DPNP_FN_PUT, /**< Used in numpy.put() impl */ DPNP_FN_PUT_ALONG_AXIS, /**< Used in numpy.put_along_axis() impl */ DPNP_FN_PUT_ALONG_AXIS_EXT, /**< Used in numpy.put_along_axis() impl, @@ -405,21 +402,19 @@ enum class DPNPFuncName : size_t DPNP_FN_TAKE, /**< Used in numpy.take() impl */ DPNP_FN_TAN, /**< Used in numpy.tan() impl */ DPNP_FN_TANH, /**< Used in numpy.tanh() impl */ - DPNP_FN_TRANSPOSE, /**< Used in numpy.transpose() impl */ - DPNP_FN_TRACE, /**< Used in numpy.trace() impl */ - DPNP_FN_TRACE_EXT, /**< Used in numpy.trace() impl, requires extra - parameters */ - DPNP_FN_TRAPZ, /**< Used in numpy.trapz() impl */ - DPNP_FN_TRAPZ_EXT, /**< Used in numpy.trapz() impl, requires extra - parameters */ - DPNP_FN_TRI, /**< Used in numpy.tri() impl */ - DPNP_FN_TRIL, /**< Used in numpy.tril() impl */ - DPNP_FN_TRIU, /**< Used in numpy.triu() impl */ - DPNP_FN_TRUNC, /**< Used in numpy.trunc() impl */ - DPNP_FN_VANDER, /**< Used in numpy.vander() impl */ - DPNP_FN_VANDER_EXT, /**< Used in numpy.vander() impl, requires extra - parameters */ - DPNP_FN_VAR, /**< Used in numpy.var() impl */ + DPNP_FN_TRANSPOSE, /**< Used in numpy.transpose() impl */ + DPNP_FN_TRACE, /**< Used in numpy.trace() impl */ + DPNP_FN_TRACE_EXT, /**< Used in numpy.trace() impl, requires extra + parameters */ + DPNP_FN_TRAPZ, /**< Used in numpy.trapz() impl */ + DPNP_FN_TRAPZ_EXT, /**< Used in numpy.trapz() impl, requires extra + parameters */ + DPNP_FN_TRI, /**< Used in numpy.tri() impl */ + DPNP_FN_TRIL, /**< Used in numpy.tril() impl */ + DPNP_FN_TRIU, /**< Used in numpy.triu() impl */ + DPNP_FN_TRUNC, /**< Used in numpy.trunc() impl */ + DPNP_FN_VANDER, /**< Used in numpy.vander() impl */ + DPNP_FN_VAR, /**< Used in numpy.var() impl */ DPNP_FN_VAR_EXT, /**< Used in numpy.var() impl, requires extra parameters */ DPNP_FN_ZEROS, /**< Used in numpy.zeros() impl */ DPNP_FN_ZEROS_LIKE, /**< Used in numpy.zeros_like() impl */ diff --git a/dpnp/backend/kernels/dpnp_krnl_arraycreation.cpp b/dpnp/backend/kernels/dpnp_krnl_arraycreation.cpp index a655c03100fb..b1af79e019d0 100644 --- a/dpnp/backend/kernels/dpnp_krnl_arraycreation.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_arraycreation.cpp @@ -200,18 +200,6 @@ void (*dpnp_diag_default_c)(void *, const size_t, const size_t) = dpnp_diag_c<_DataType>; -template -DPCTLSyclEventRef (*dpnp_diag_ext_c)(DPCTLSyclQueueRef, - void *, - void *, - const int, - shape_elem_type *, - shape_elem_type *, - const size_t, - const size_t, - const DPCTLEventVectorRef) = - dpnp_diag_c<_DataType>; - template DPCTLSyclEventRef dpnp_eye_c(DPCTLSyclQueueRef q_ref, void *result1, @@ -569,23 +557,6 @@ void (*dpnp_ptp_default_c)(void *, const shape_elem_type *, const size_t) = dpnp_ptp_c<_DataType>; -template -DPCTLSyclEventRef (*dpnp_ptp_ext_c)(DPCTLSyclQueueRef, - void *, - const size_t, - const size_t, - const shape_elem_type *, - const shape_elem_type *, - const void *, - const size_t, - const size_t, - const shape_elem_type *, - const shape_elem_type *, - const shape_elem_type *, - const size_t, - const DPCTLEventVectorRef) = - dpnp_ptp_c<_DataType>; - template DPCTLSyclEventRef dpnp_vander_c(DPCTLSyclQueueRef q_ref, const void *array1_in, @@ -673,16 +644,6 @@ void (*dpnp_vander_default_c)(const void *, const int) = dpnp_vander_c<_DataType_input, _DataType_output>; -template -DPCTLSyclEventRef (*dpnp_vander_ext_c)(DPCTLSyclQueueRef, - const void *, - void *, - const size_t, - const size_t, - const int, - const DPCTLEventVectorRef) = - dpnp_vander_c<_DataType_input, _DataType_output>; - template class dpnp_trace_c_kernel; @@ -1192,15 +1153,6 @@ void func_map_init_arraycreation(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_DIAG][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_diag_default_c}; - fmap[DPNPFuncName::DPNP_FN_DIAG_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_diag_ext_c}; - fmap[DPNPFuncName::DPNP_FN_DIAG_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_diag_ext_c}; - fmap[DPNPFuncName::DPNP_FN_DIAG_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_diag_ext_c}; - fmap[DPNPFuncName::DPNP_FN_DIAG_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_diag_ext_c}; - fmap[DPNPFuncName::DPNP_FN_EYE][eft_INT][eft_INT] = { eft_INT, (void *)dpnp_eye_default_c}; fmap[DPNPFuncName::DPNP_FN_EYE][eft_LNG][eft_LNG] = { @@ -1284,15 +1236,6 @@ void func_map_init_arraycreation(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_PTP][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_ptp_default_c}; - fmap[DPNPFuncName::DPNP_FN_PTP_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_ptp_ext_c}; - fmap[DPNPFuncName::DPNP_FN_PTP_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_ptp_ext_c}; - fmap[DPNPFuncName::DPNP_FN_PTP_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_ptp_ext_c}; - fmap[DPNPFuncName::DPNP_FN_PTP_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_ptp_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER][eft_INT][eft_INT] = { eft_LNG, (void *)dpnp_vander_default_c}; fmap[DPNPFuncName::DPNP_FN_VANDER][eft_LNG][eft_LNG] = { @@ -1308,23 +1251,6 @@ void func_map_init_arraycreation(func_map_t &fmap) (void *) dpnp_vander_default_c, std::complex>}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_INT][eft_INT] = { - eft_LNG, (void *)dpnp_vander_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_vander_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_vander_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_vander_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_BLN][eft_BLN] = { - eft_LNG, (void *)dpnp_vander_ext_c}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_C64][eft_C64] = { - eft_C64, - (void *)dpnp_vander_ext_c, std::complex>}; - fmap[DPNPFuncName::DPNP_FN_VANDER_EXT][eft_C128][eft_C128] = { - eft_C128, - (void *)dpnp_vander_ext_c, std::complex>}; - fmap[DPNPFuncName::DPNP_FN_TRACE][eft_INT][eft_INT] = { eft_INT, (void *)dpnp_trace_default_c}; fmap[DPNPFuncName::DPNP_FN_TRACE][eft_LNG][eft_INT] = { diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index c2e4747fbdb7..7a38c99b9896 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -64,8 +64,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_DEGREES_EXT DPNP_FN_DET DPNP_FN_DET_EXT - DPNP_FN_DIAG - DPNP_FN_DIAG_EXT DPNP_FN_DIAG_INDICES DPNP_FN_DIAG_INDICES_EXT DPNP_FN_DIAGONAL @@ -122,8 +120,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_PARTITION DPNP_FN_PARTITION_EXT DPNP_FN_PLACE - DPNP_FN_PTP - DPNP_FN_PTP_EXT DPNP_FN_QR DPNP_FN_QR_EXT DPNP_FN_RADIANS @@ -222,8 +218,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_TRIL_EXT DPNP_FN_TRIU DPNP_FN_TRIU_EXT - DPNP_FN_VANDER - DPNP_FN_VANDER_EXT DPNP_FN_VAR DPNP_FN_VAR_EXT DPNP_FN_ZEROS diff --git a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi index 7b90ff1285fa..1322b1ccea5b 100644 --- a/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_arraycreation.pxi @@ -37,10 +37,7 @@ and the rest of the library __all__ += [ "dpnp_copy", - "dpnp_diag", - "dpnp_ptp", "dpnp_trace", - "dpnp_vander", ] @@ -88,136 +85,6 @@ cpdef utils.dpnp_descriptor dpnp_copy(utils.dpnp_descriptor x1): return call_fptr_1in_1out_strides(DPNP_FN_COPY_EXT, x1) -cpdef utils.dpnp_descriptor dpnp_diag(utils.dpnp_descriptor v, int k): - cdef shape_type_c input_shape = v.shape - cdef shape_type_c result_shape - - if v.ndim == 1: - n = v.shape[0] + abs(k) - - result_shape = (n, n) - else: - n = min(v.shape[0], v.shape[0] + k, v.shape[1], v.shape[1] - k) - if n < 0: - n = 0 - - result_shape = (n, ) - - v_obj = v.get_array() - - result_obj = dpnp_container.zeros(result_shape, dtype=v.dtype, device=v_obj.sycl_device) - cdef utils.dpnp_descriptor result = dpnp_descriptor(result_obj) - - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(v.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_DIAG_EXT, param1_type, param1_type) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef custom_1in_1out_func_ptr_t func = kernel_data.ptr - - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - v.get_data(), - result.get_data(), - k, - input_shape.data(), - result_shape.data(), - v.ndim, - result.ndim, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - -cpdef dpnp_ptp(utils.dpnp_descriptor arr, axis=None): - cdef shape_type_c shape_arr = arr.shape - cdef shape_type_c output_shape - if axis is None: - axis_ = axis - output_shape = (1,) - else: - if isinstance(axis, int): - if axis < 0: - axis_ = tuple([arr.ndim - axis]) - else: - axis_ = tuple([axis]) - else: - _axis_ = [] - for i in range(len(axis)): - if axis[i] < 0: - _axis_.append(arr.ndim - axis[i]) - else: - _axis_.append(axis[i]) - axis_ = tuple(_axis_) - - out_shape = [] - ind = 0 - for id, shape_axis in enumerate(shape_arr): - if id not in axis_: - out_shape.append(shape_axis) - output_shape = tuple(out_shape) - - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(arr.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_PTP_EXT, param1_type, param1_type) - - arr_obj = arr.get_array() - - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(output_shape, - kernel_data.return_type, - None, - device=arr_obj.sycl_device, - usm_type=arr_obj.usm_type, - sycl_queue=arr_obj.sycl_queue) - - cdef shape_type_c axis1 - cdef Py_ssize_t axis_size = 0 - cdef shape_type_c axis2 = axis1 - if axis_ is not None: - axis1 = axis_ - axis2.reserve(len(axis1)) - for shape_it in axis1: - if shape_it < 0: - raise ValueError("DPNP dparray::__init__(): Negative values in 'shape' are not allowed") - axis2.push_back(shape_it) - axis_size = len(axis1) - - cdef shape_type_c result_strides = utils.strides_to_vector(result.strides, result.shape) - cdef shape_type_c arr_strides = utils.strides_to_vector(arr.strides, arr.shape) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef custom_arraycreation_1in_1out_func_ptr_t func = kernel_data.ptr - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - result.get_data(), - result.size, - result.ndim, - output_shape.data(), - result_strides.data(), - arr.get_data(), - arr.size, - arr.ndim, - shape_arr.data(), - arr_strides.data(), - axis2.data(), - axis_size, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - cpdef utils.dpnp_descriptor dpnp_trace(utils.dpnp_descriptor arr, offset=0, axis1=0, axis2=1, dtype=None, out=None): if dtype is None: dtype_ = arr.dtype @@ -262,38 +129,3 @@ cpdef utils.dpnp_descriptor dpnp_trace(utils.dpnp_descriptor arr, offset=0, axis c_dpctl.DPCTLEvent_Delete(event_ref) return result - - -cpdef utils.dpnp_descriptor dpnp_vander(utils.dpnp_descriptor x1, int N, int increasing): - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(x1.dtype) - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_VANDER_EXT, param1_type, DPNP_FT_NONE) - - x1_obj = x1.get_array() - - # create result array with type given by FPTR data - cdef shape_type_c result_shape = (x1.size, N) - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape, - kernel_data.return_type, - None, - device=x1_obj.sycl_device, - usm_type=x1_obj.usm_type, - sycl_queue=x1_obj.sycl_queue) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef ftpr_custom_vander_1in_1out_t func = kernel_data.ptr - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - x1.get_data(), - result.get_data(), - x1.size, - N, - increasing, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index fb454a786424..a906ed41fe09 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -1039,7 +1039,30 @@ def prod( return dpnp.prod(self, axis, dtype, out, keepdims, initial, where) - # 'ptp' + def ptp( + self, + axis=None, + out=None, + keepdims=numpy._NoValue, + device=None, + usm_type=None, + sycl_queue=None, + ): + """ + Range of values (maximum - minimum) along an axis. + + For full documentation refer to :obj:`numpy.ptp`. + """ + + return dpnp.ptp( + self, + axis=axis, + out=out, + keepdims=keepdims, + device=device, + usm_type=usm_type, + sycl_queue=sycl_queue, + ) def put(self, indices, vals, /, *, axis=None, mode="wrap"): """ diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 0ed1187cb1d8..1dca52b4c11f 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -582,12 +582,31 @@ def copy(a, order="K", subok=False): return array(a, order=order, subok=subok, copy=True) -def diag(x1, k=0): +def diag(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): """ Extract a diagonal or construct a diagonal array. For full documentation refer to :obj:`numpy.diag`. + Returns + ------- + out : dpnp.ndarray + The extracted diagonal or constructed diagonal array. + + Limitations + ----------- + Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. + Parameter `k` is only supported as integer data type. + Otherwise the function will be executed sequentially on CPU. + + See Also + -------- + :obj:`diagonal` : Return specified diagonals. + :obj:`diagflat` : Create a 2-D array with the flattened input as a diagonal. + :obj:`trace` : Return sum along diagonals. + :obj:`triu` : Return upper triangle of an array. + :obj:`tril` : Return lower triangle of an array. + Examples -------- >>> import dpnp as np @@ -611,48 +630,107 @@ def diag(x1, k=0): """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - if not isinstance(k, int): - pass - elif x1_desc.ndim != 1 and x1_desc.ndim != 2: - pass + if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): + pass + elif not isinstance(k, int): + pass + else: + _usm_type = x1.usm_type if usm_type is None else usm_type + _sycl_queue = dpnp.get_normalized_queue_device( + x1, sycl_queue=sycl_queue, device=device + ) + x1 = ( + x1.to_device(_sycl_queue.sycl_device) + if x1.sycl_queue != _sycl_queue + else x1 + ) + + init0 = max(0, -k) + init1 = max(0, k) + if x1.ndim == 1: + size = x1.shape[0] + abs(k) + m = dpnp.zeros( + (size, size), + dtype=x1.dtype, + usm_type=_usm_type, + sycl_queue=_sycl_queue, + ) + for i in range(x1.shape[0]): + m[(init0 + i), init1 + i] = x1[i] + return m + elif x1.ndim == 2: + size = min( + x1.shape[0], x1.shape[0] + k, x1.shape[1], x1.shape[1] - k + ) + if size < 0: + size = 0 + m = dpnp.zeros( + (size,), + dtype=x1.dtype, + usm_type=_usm_type, + sycl_queue=_sycl_queue, + ) + for i in range(size): + m[i] = x1[(init0 + i), init1 + i] + return m else: - return dpnp_diag(x1_desc, k).get_pyobj() + raise ValueError("Input must be a 1-D or 2-D array.") return call_origin(numpy.diag, x1, k) -def diagflat(x1, k=0): +def diagflat(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): """ Create a two-dimensional array with the flattened input as a diagonal. For full documentation refer to :obj:`numpy.diagflat`. + Returns + ------- + out : dpnp.ndarray + The 2-D output array. + + See Also + -------- + :obj:`diag` : Return the extracted diagonal or constructed diagonal array. + :obj:`diagonal` : Return specified diagonals. + :obj:`trace` : Return sum along diagonals. + + Limitations + ----------- + Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. + Parameter `k` is only supported as integer data type. + Otherwise the function will be executed sequentially on CPU. + Examples -------- >>> import dpnp as np - >>> np.diagflat([[1,2], [3,4]]) + >>> x = np.array([[1,2], [3,4]]) + >>> np.diagflat(x) array([[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]) - >>> np.diagflat([1,2], 1) - array([[0, 1, 0], - [0, 0, 2], - [0, 0, 0]]) + >>> np.diagflat(x, 1) + array([[0, 1, 0, 0, 0], + [0, 0, 2, 0, 0], + [0, 0, 0, 3, 0], + [0, 0, 0, 0, 4], + [0, 0, 0, 0, 0]]) """ - - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - input_ravel = dpnp.ravel(x1) - input_ravel_desc = dpnp.get_dpnp_descriptor( - input_ravel, copy_when_nondefault_queue=False + if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): + pass + elif not isinstance(k, int): + pass + else: + _usm_type = x1.usm_type if usm_type is None else usm_type + _sycl_queue = dpnp.get_normalized_queue_device( + x1, sycl_queue=sycl_queue, device=device ) - - return dpnp_diag(input_ravel_desc, k).get_pyobj() + v = dpnp.ravel(x1) + return dpnp.diag(v, k, usm_type=_usm_type, sycl_queue=_sycl_queue) return call_origin(numpy.diagflat, x1, k) @@ -778,12 +856,12 @@ def empty_like( def eye( N, - M=None, /, - *, + M=None, k=0, dtype=None, order="C", + *, like=None, device=None, usm_type="device", @@ -800,6 +878,18 @@ def eye( Parameter `like` is supported only with default value ``None``. Otherwise the function will be executed sequentially on CPU. + Examples + -------- + >>> import dpnp as np + >>> np.eye(2, dtype=int) + array([[1, 0], + [0, 1]]) + + >>> np.eye(3, k=1) + array([[0., 1., 0.], + [0., 0., 1.], + [0., 0., 0.]]) + """ if order not in ("C", "c", "F", "f", None): pass @@ -1095,7 +1185,14 @@ def geomspace( def identity( - n, dtype=None, *, device=None, usm_type="device", sycl_queue=None, like=None + n, + /, + dtype=None, + *, + like=None, + device=None, + usm_type="device", + sycl_queue=None, ): """ Return the identity array. @@ -1552,20 +1649,47 @@ def ones_like( return call_origin(numpy.ones_like, x1, dtype, order, subok, shape) -def ptp(arr, axis=None, out=None, keepdims=numpy._NoValue): +def ptp( + arr, + /, + axis=None, + out=None, + keepdims=numpy._NoValue, + *, + device=None, + usm_type=None, + sycl_queue=None, +): """ Range of values (maximum - minimum) along an axis. For full documentation refer to :obj:`numpy.ptp`. + Returns + ------- + ptp : dpnp.ndarray + The range of a given array. + Limitations ----------- - Input array is supported as :obj:`dpnp.ndarray`. + Input array is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. Parameters `out` and `keepdims` are supported only with default values. + Otherwise the function will be executed sequentially on CPU. + Examples + -------- + >>> import dpnp as np + >>> x = np.array([[4, 9, 2, 10],[6, 9, 7, 12]]) + >>> np.ptp(x, axis=1) + array([8, 6]) + + >>> np.ptp(x, axis=0) + array([2, 0, 5, 2]) + + >>> np.ptp(x) + array(10) """ - arr_desc = dpnp.get_dpnp_descriptor(arr, copy_when_nondefault_queue=False) - if not arr_desc: + if not isinstance(arr, (dpnp.ndarray, dpt.usm_ndarray)): pass elif axis is not None and not isinstance(axis, int): pass @@ -1574,10 +1698,16 @@ def ptp(arr, axis=None, out=None, keepdims=numpy._NoValue): elif keepdims is not numpy._NoValue: pass else: - result_obj = dpnp_ptp(arr_desc, axis=axis).get_pyobj() - result = dpnp.convert_single_elem_array_to_scalar(result_obj) + max_array = dpnp.max(arr, axis=axis) + min_array = dpnp.min(arr, axis=axis) - return result + _usm_type = arr.usm_type if usm_type is None else usm_type + _sycl_queue = dpnp.get_normalized_queue_device( + arr, sycl_queue=sycl_queue, device=device + ) + return dpnp.array( + max_array - min_array, usm_type=_usm_type, sycl_queue=_sycl_queue + ) return call_origin(numpy.ptp, arr, axis, out, keepdims) @@ -1616,9 +1746,11 @@ def trace(x1, offset=0, axis1=0, axis2=1, dtype=None, out=None): def tri( N, + /, M=None, k=0, dtype=dpnp.float, + *, device=None, usm_type="device", sycl_queue=None, @@ -1636,7 +1768,7 @@ def tri( Limitations ----------- - Parameter `M`, `N`, and `k` are only supported as integer data type. + Parameter `M`, `N`, and `k` are only supported as integer data type and when they are positive. Keyword argument `kwargs` is currently unsupported. Otherwise the function will be executed sequentially on CPU. @@ -1781,12 +1913,31 @@ def triu(x1, /, *, k=0): return call_origin(numpy.triu, x1, k) -def vander(x1, N=None, increasing=False): +def vander( + x1, + /, + N=None, + increasing=False, + *, + device=None, + usm_type=None, + sycl_queue=None, +): """ Generate a Vandermonde matrix. For full documentation refer to :obj:`numpy.vander`. + Returns + ------- + out : dpnp.ndarray + Vandermonde matrix. + + Limitations + ----------- + Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. + Otherwise the function will be executed sequentially on CPU. + Examples -------- >>> import dpnp as np @@ -1797,12 +1948,14 @@ def vander(x1, N=None, increasing=False): [ 4, 2, 1], [ 9, 3, 1], [25, 5, 1]]) + >>> x = np.array([1, 2, 3, 5]) >>> np.vander(x) array([[ 1, 1, 1, 1], [ 8, 4, 2, 1], [ 27, 9, 3, 1], [125, 25, 5, 1]]) + >>> np.vander(x, increasing=True) array([[ 1, 1, 1, 1], [ 1, 2, 4, 8], @@ -1810,15 +1963,41 @@ def vander(x1, N=None, increasing=False): [ 1, 5, 25, 125]]) """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - if x1.ndim != 1: - pass - else: - if N is None: - N = x1.size + if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): + pass + elif N is not None and not isinstance(N, int): + pass + elif x1.ndim != 1: + raise ValueError("x1 must be a one-dimensional array or sequence.") + else: + if N is None: + N = x1.size + + _dtype = int if x1.dtype == bool else x1.dtype + _usm_type = x1.usm_type if usm_type is None else usm_type + _sycl_queue = dpnp.get_normalized_queue_device( + x1, sycl_queue=sycl_queue, device=device + ) + x1 = ( + x1.to_device(_sycl_queue.sycl_device) + if x1.sycl_queue != _sycl_queue + else x1 + ) + + m = empty( + (x1.size, N), + dtype=_dtype, + usm_type=_usm_type, + sycl_queue=_sycl_queue, + ) + tmp = m[:, ::-1] if not increasing else m + dpnp.power( + x1.reshape(-1, 1), + dpnp.arange(N, dtype=_dtype, sycl_queue=_sycl_queue), + out=tmp, + ) - return dpnp_vander(x1_desc, N, increasing).get_pyobj() + return m return call_origin(numpy.vander, x1, N=N, increasing=increasing) diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index e61f7497d97d..352e023d531b 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -118,18 +118,6 @@ tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatte tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_copied tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_transposed -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_all -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_all_keepdims -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis0 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis1 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis2 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis_large -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_multiple_axes -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_multiple_axes_keepdims -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_imag -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_real - tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestCubReduction_param_0_{order='C', shape=(10,)}::test_cub_max tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestCubReduction_param_0_{order='C', shape=(10,)}::test_cub_min tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestCubReduction_param_1_{order='C', shape=(10, 20)}::test_cub_max diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index a8d198b77334..5ce79ace941b 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -109,7 +109,6 @@ tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes_param_3_{order='C', shape=(2, 3)}::test_item tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes_param_4_{order='F', shape=(2, 3)}::test_item -tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_construction 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 @@ -200,14 +199,6 @@ tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatte tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_copied tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_transposed -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_all -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_all_keepdims -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis0 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis1 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis2 -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_axis_large -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_multiple_axes -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_multiple_axes_keepdims tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_imag tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_real diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 7c674d265dad..d89dd1a634c4 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -125,6 +125,36 @@ def test_diag(v, k): assert_array_equal(expected, result) +@pytest.mark.parametrize( + "axis", + [None, 0, 1], + ids=["None", "0", "1"], +) +@pytest.mark.parametrize( + "v", + [ + [[0, 0], [0, 0]], + [[1, 2], [1, 2]], + [[1, 2], [3, 4]], + [[0, 1, 2], [3, 4, 5], [6, 7, 8]], + [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], + ], + ids=[ + "[[0, 0], [0, 0]]", + "[[1, 2], [1, 2]]", + "[[1, 2], [3, 4]]", + "[[0, 1, 2], [3, 4, 5], [6, 7, 8]]", + "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", + ], +) +def test_ptp(v, axis): + a = numpy.array(v) + ia = dpnp.array(a) + expected = numpy.ptp(a, axis) + result = dpnp.ptp(ia, axis) + assert_array_equal(expected, result) + + @pytest.mark.parametrize("N", [0, 1, 2, 3], ids=["0", "1", "2", "3"]) @pytest.mark.parametrize( "M", [None, 0, 1, 2, 3], ids=["None", "0", "1", "2", "3"] @@ -426,12 +456,16 @@ def test_triu_size_null(k): @pytest.mark.parametrize("n", [0, 1, 4, None], ids=["0", "1", "4", "None"]) @pytest.mark.parametrize("increase", [True, False], ids=["True", "False"]) def test_vander(array, dtype, n, increase): - create_array = lambda xp: xp.array(array, dtype=dtype) + if dtype in [dpnp.complex64, dpnp.complex128] and array == [0, 3, 5]: + pytest.skip( + "dpnp.power(dpnp.array(complex(0,0)), dpnp.array(0)) returns nan+nanj while it should be 1+0j" + ) vander_func = lambda xp, x: xp.vander(x, N=n, increasing=increase) a_np = numpy.array(array, dtype=dtype) a_dpnp = dpnp.array(array, dtype=dtype) - assert_array_equal(vander_func(numpy, a_np), vander_func(dpnp, a_dpnp)) + + assert_allclose(vander_func(numpy, a_np), vander_func(dpnp, a_dpnp)) @pytest.mark.parametrize( diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 2a4a814b6f74..f41d56c166c9 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -141,6 +141,7 @@ def test_empty_like(device_x, device_y): @pytest.mark.parametrize( "func, args, kwargs", [ + pytest.param("diag", ["x0"], {}), pytest.param("full_like", ["x0"], {"fill_value": 5}), pytest.param("geomspace", ["x0[0:3]", "8", "4"], {}), pytest.param("geomspace", ["1", "x0[2:4]", "4"], {}), @@ -151,7 +152,13 @@ def test_empty_like(device_x, device_y): pytest.param("ones_like", ["x0"], {}), pytest.param("tril", ["x0.reshape((2,2))"], {}), pytest.param("triu", ["x0.reshape((2,2))"], {}), +<<<<<<< HEAD pytest.param("zeros_like", ["x0"], {}), +======= + pytest.param("linspace", ["x0", "4", "4"], {}), + pytest.param("linspace", ["1", "x0", "4"], {}), + pytest.param("vander", ["x0"], {}), +>>>>>>> rework implementation of diag, diagflat, vander, and ptp ], ) @pytest.mark.parametrize( @@ -196,11 +203,40 @@ def test_array_creation_follow_device_logspace_base(device): @pytest.mark.parametrize( "func, args, kwargs", [ + pytest.param("diag", ["x0"], {}), + pytest.param("diagflat", ["x0"], {}), + pytest.param("ptp", ["x0"], {"axis": 0}), + ], +) +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_array_creation_follow_device_2d_array(func, args, kwargs, device): + x_orig = numpy.arange(9).reshape(3, 3) + numpy_args = [eval(val, {"x0": x_orig}) for val in args] + y_orig = getattr(numpy, func)(*numpy_args, **kwargs) + + x = dpnp.arange(9, device=device).reshape(3, 3) + dpnp_args = [eval(val, {"x0": x}) for val in args] + + y = getattr(dpnp, func)(*dpnp_args, **kwargs) + assert_allclose(y_orig, y) + assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) + + +@pytest.mark.parametrize( + "func, args, kwargs", + [ + pytest.param("diag", ["x0"], {}), + pytest.param("full", ["10", "x0[3]"], {}), pytest.param("full_like", ["x0"], {"fill_value": 5}), pytest.param("ones_like", ["x0"], {}), pytest.param("zeros_like", ["x0"], {}), pytest.param("linspace", ["x0", "4", "4"], {}), pytest.param("linspace", ["1", "x0", "4"], {}), + pytest.param("vander", ["x0"], {}), ], ) @pytest.mark.parametrize( @@ -214,7 +250,7 @@ def test_array_creation_follow_device_logspace_base(device): ids=[device.filter_string for device in valid_devices], ) def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): - if func is "linspace" and is_win_platform(): + if func == "linspace" and is_win_platform(): pytest.skip("CPU driver experiences an instability on Windows.") x_orig = numpy.array([1, 2, 3, 4]) @@ -225,8 +261,52 @@ def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): dpnp_args = [eval(val, {"x0": x}) for val in args] dpnp_kwargs = dict(kwargs) + y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) + assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) + dpnp_kwargs["device"] = device_y + y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) + assert_allclose(y_orig, y) + + assert_sycl_queue_equal(y.sycl_queue, x.to_device(device_y).sycl_queue) + +@pytest.mark.parametrize( + "func, args, kwargs", + [ + pytest.param("diag", ["x0"], {}), + pytest.param("diagflat", ["x0"], {}), + pytest.param("ptp", ["x0"], {"axis": 0}), + ], +) +@pytest.mark.parametrize( + "device_x", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +@pytest.mark.parametrize( + "device_y", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_array_creation_cross_device_2d_array( + func, args, kwargs, device_x, device_y +): + if func == "linspace" and is_win_platform(): + pytest.skip("CPU driver experiences an instability on Windows.") + + x_orig = numpy.arange(9).reshape(3, 3) + numpy_args = [eval(val, {"x0": x_orig}) for val in args] + y_orig = getattr(numpy, func)(*numpy_args, **kwargs) + + x = dpnp.arange(9, device=device_x).reshape(3, 3) + dpnp_args = [eval(val, {"x0": x}) for val in args] + + dpnp_kwargs = dict(kwargs) + y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) + assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) + + dpnp_kwargs["device"] = device_y y = getattr(dpnp, func)(*dpnp_args, **dpnp_kwargs) assert_allclose(y_orig, y) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 99a39acae887..6839f012f02e 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -140,22 +140,30 @@ def test_coerced_usm_types_power(usm_type_x, usm_type_y): @pytest.mark.parametrize( "func, args", [ +<<<<<<< HEAD pytest.param("empty_like", ["x0"]), +======= + pytest.param("diag", ["x0"]), +>>>>>>> rework implementation of diag, diagflat, vander, and ptp pytest.param("full", ["10", "x0[3]"]), pytest.param("full_like", ["x0", "4"]), pytest.param("geomspace", ["x0[0:3]", "8", "4"]), pytest.param("geomspace", ["1", "x0[3:5]", "4"]), pytest.param("linspace", ["x0[0:2]", "8", "4"]), pytest.param("linspace", ["0", "x0[3:5]", "4"]), +<<<<<<< HEAD pytest.param("logspace", ["x0[0:2]", "8", "4"]), pytest.param("logspace", ["0", "x0[3:5]", "4"]), pytest.param("ones_like", ["x0"]), pytest.param("zeros_like", ["x0"]), +======= + pytest.param("vander", ["x0"]), +>>>>>>> rework implementation of diag, diagflat, vander, and ptp ], ) @pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) @pytest.mark.parametrize("usm_type_y", list_of_usm_types, ids=list_of_usm_types) -def test_array_creation_from_an_array(func, args, usm_type_x, usm_type_y): +def test_array_creation_from_1d_array(func, args, usm_type_x, usm_type_y): x0 = dp.full(10, 3, usm_type=usm_type_x) new_args = [eval(val, {"x0": x0}) for val in args] @@ -166,6 +174,27 @@ def test_array_creation_from_an_array(func, args, usm_type_x, usm_type_y): assert y.usm_type == usm_type_y +@pytest.mark.parametrize( + "func, args", + [ + pytest.param("diag", ["x0"]), + pytest.param("diagflat", ["x0"]), + pytest.param("ptp", ["x0", "0"]), + ], +) +@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) +@pytest.mark.parametrize("usm_type_y", list_of_usm_types, ids=list_of_usm_types) +def test_array_creation_from_2d_array(func, args, usm_type_x, usm_type_y): + x0 = dp.arange(25, usm_type=usm_type_x).reshape(5, 5) + new_args = [eval(val, {"x0": x0}) for val in args] + + x = getattr(dp, func)(*new_args) + y = getattr(dp, func)(*new_args, usm_type=usm_type_y) + + assert x.usm_type == usm_type_x + assert y.usm_type == usm_type_y + + @pytest.mark.parametrize( "func, arg, kwargs", [ From 6d3f8171751b46e7ee4fb9bbc4c5b1ce6b41b90c Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Sun, 22 Oct 2023 11:41:58 -0500 Subject: [PATCH 02/15] address comments - first round cherry-pick --- dpnp/dpnp_array.py | 25 -------- dpnp/dpnp_iface_arraycreation.py | 64 ------------------- dpnp/dpnp_iface_statistics.py | 50 +++++++++++++++ tests/skipped_tests_gpu.tbl | 4 +- tests/test_sycl_queue.py | 5 +- tests/test_usm_type.py | 2 +- .../cupy/core_tests/test_ndarray_reduction.py | 23 ++++--- 7 files changed, 65 insertions(+), 108 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index a906ed41fe09..57207e6801cf 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -1039,31 +1039,6 @@ def prod( return dpnp.prod(self, axis, dtype, out, keepdims, initial, where) - def ptp( - self, - axis=None, - out=None, - keepdims=numpy._NoValue, - device=None, - usm_type=None, - sycl_queue=None, - ): - """ - Range of values (maximum - minimum) along an axis. - - For full documentation refer to :obj:`numpy.ptp`. - """ - - return dpnp.ptp( - self, - axis=axis, - out=out, - keepdims=keepdims, - device=device, - usm_type=usm_type, - sycl_queue=sycl_queue, - ) - def put(self, indices, vals, /, *, axis=None, mode="wrap"): """ Puts values of an array into another array along a given axis. diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 1dca52b4c11f..4c2677f66029 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -86,7 +86,6 @@ "ogrid", "ones", "ones_like", - "ptp", "trace", "tri", "tril", @@ -1649,69 +1648,6 @@ def ones_like( return call_origin(numpy.ones_like, x1, dtype, order, subok, shape) -def ptp( - arr, - /, - axis=None, - out=None, - keepdims=numpy._NoValue, - *, - device=None, - usm_type=None, - sycl_queue=None, -): - """ - Range of values (maximum - minimum) along an axis. - - For full documentation refer to :obj:`numpy.ptp`. - - Returns - ------- - ptp : dpnp.ndarray - The range of a given array. - - Limitations - ----------- - Input array is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. - Parameters `out` and `keepdims` are supported only with default values. - Otherwise the function will be executed sequentially on CPU. - - Examples - -------- - >>> import dpnp as np - >>> x = np.array([[4, 9, 2, 10],[6, 9, 7, 12]]) - >>> np.ptp(x, axis=1) - array([8, 6]) - - >>> np.ptp(x, axis=0) - array([2, 0, 5, 2]) - - >>> np.ptp(x) - array(10) - """ - if not isinstance(arr, (dpnp.ndarray, dpt.usm_ndarray)): - pass - elif axis is not None and not isinstance(axis, int): - pass - elif out is not None: - pass - elif keepdims is not numpy._NoValue: - pass - else: - max_array = dpnp.max(arr, axis=axis) - min_array = dpnp.min(arr, axis=axis) - - _usm_type = arr.usm_type if usm_type is None else usm_type - _sycl_queue = dpnp.get_normalized_queue_device( - arr, sycl_queue=sycl_queue, device=device - ) - return dpnp.array( - max_array - min_array, usm_type=_usm_type, sycl_queue=_sycl_queue - ) - - return call_origin(numpy.ptp, arr, axis, out, keepdims) - - def trace(x1, offset=0, axis1=0, axis2=1, dtype=None, out=None): """ Return the sum along diagonals of the array. diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index 653b323c9e1d..215e98b85bc4 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -60,6 +60,7 @@ "mean", "median", "min", + "ptp", "nanvar", "std", "var", @@ -692,6 +693,55 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): return out +def ptp( + a, + /, + axis=None, + out=None, + keepdims=False, +): + """ + Range of values (maximum - minimum) along an axis. + + For full documentation refer to :obj:`numpy.ptp`. + + Returns + ------- + ptp : dpnp.ndarray + The range of a given array. + + Limitations + ----------- + Input array is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. + Otherwise the function will be executed sequentially on CPU. + + Examples + -------- + >>> import dpnp as np + >>> x = np.array([[4, 9, 2, 10],[6, 9, 7, 12]]) + >>> np.ptp(x, axis=1) + array([8, 6]) + + >>> np.ptp(x, axis=0) + array([2, 0, 5, 2]) + + >>> np.ptp(x) + array(10) + + """ + + if not isinstance(a, (dpnp.ndarray, dpt.usm_ndarray)): + pass + else: + return dpnp.subtract( + dpnp.max(a, axis=axis, keepdims=keepdims), + dpnp.min(a, axis=axis, keepdims=keepdims), + out=out, + ) + + return call_origin(numpy.ptp, a, axis, out, keepdims) + + def nanvar(x1, axis=None, dtype=None, out=None, ddof=0, keepdims=False): """ Compute the variance along the specified axis, while ignoring NaNs. diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 5ce79ace941b..5fa13fd72201 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -199,9 +199,7 @@ tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatte tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_copied tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayFlatten::test_flatten_order_transposed -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_imag -tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestArrayReduction::test_ptp_nan_real + tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestCubReduction_param_0_{order='C', shape=(10,)}::test_cub_max tests/third_party/cupy/core_tests/test_ndarray_reduction.py::TestCubReduction_param_0_{order='C', shape=(10,)}::test_cub_min diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index f41d56c166c9..df877152b62e 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -199,13 +199,11 @@ def test_array_creation_follow_device_logspace_base(device): assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) -@pytest.mark.skip("muted until the issue reported by SAT-5969 is resolved") @pytest.mark.parametrize( "func, args, kwargs", [ pytest.param("diag", ["x0"], {}), pytest.param("diagflat", ["x0"], {}), - pytest.param("ptp", ["x0"], {"axis": 0}), ], ) @pytest.mark.parametrize( @@ -226,6 +224,7 @@ def test_array_creation_follow_device_2d_array(func, args, kwargs, device): assert_sycl_queue_equal(y.sycl_queue, x.sycl_queue) +@pytest.mark.skip("muted until the issue reported by SAT-5969 is resolved") @pytest.mark.parametrize( "func, args, kwargs", [ @@ -276,7 +275,6 @@ def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): [ pytest.param("diag", ["x0"], {}), pytest.param("diagflat", ["x0"], {}), - pytest.param("ptp", ["x0"], {"axis": 0}), ], ) @pytest.mark.parametrize( @@ -375,6 +373,7 @@ def test_meshgrid(device_x, device_y): pytest.param("negative", [1.0, 0.0, -1.0]), pytest.param("positive", [1.0, 0.0, -1.0]), pytest.param("prod", [1.0, 2.0]), + pytest.param("ptp", [1.0, 2.0, 4.0, 7.0]), pytest.param( "real", [complex(1.0, 2.0), complex(3.0, 4.0), complex(5.0, 6.0)] ), diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 6839f012f02e..7e3fe1e0f988 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -179,7 +179,6 @@ def test_array_creation_from_1d_array(func, args, usm_type_x, usm_type_y): [ pytest.param("diag", ["x0"]), pytest.param("diagflat", ["x0"]), - pytest.param("ptp", ["x0", "0"]), ], ) @pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) @@ -403,6 +402,7 @@ def test_meshgrid(usm_type_x, usm_type_y): pytest.param("positive", [1.0, 0.0, -1.0]), pytest.param("prod", [1.0, 2.0]), pytest.param("proj", [complex(1.0, 2.0), complex(dp.inf, -1.0)]), + pytest.param("ptp", [1.0, 2.0, 4.0, 7.0]), pytest.param( "real", [complex(1.0, 2.0), complex(3.0, 4.0), complex(5.0, 6.0)] ), diff --git a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py index 952398575f1d..7d6c508eb2f1 100644 --- a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py +++ b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py @@ -9,7 +9,6 @@ from tests.third_party.cupy import testing -@pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.gpu class TestArrayReduction(unittest.TestCase): @testing.for_all_dtypes() @@ -149,70 +148,70 @@ def test_min_nan_imag(self, xp, dtype): @testing.numpy_cupy_allclose() def test_ptp_all(self, xp, dtype): a = testing.shaped_random((2, 3), xp, dtype) - return a.ptp() + return xp.ptp(a) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_all_keepdims(self, xp, dtype): a = testing.shaped_random((2, 3), xp, dtype) - return a.ptp(keepdims=True) + return xp.ptp(a, keepdims=True) @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_axis_large(self, xp, dtype): a = testing.shaped_random((3, 1000), xp, dtype) - return a.ptp(axis=0) + return xp.ptp(a, axis=0) @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_axis0(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) - return a.ptp(axis=0) + return xp.ptp(a, axis=0) @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_axis1(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) - return a.ptp(axis=1) + return xp.ptp(a, axis=1) @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_axis2(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) - return a.ptp(axis=2) + return xp.ptp(a, axis=2) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_multiple_axes(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) - return a.ptp(axis=(1, 2)) + return xp.ptp(a, axis=(1, 2)) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) @testing.numpy_cupy_allclose() def test_ptp_multiple_axes_keepdims(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) - return a.ptp(axis=(1, 2), keepdims=True) + return xp.ptp(a, axis=(1, 2), keepdims=True) @testing.for_float_dtypes() @testing.numpy_cupy_allclose() def test_ptp_nan(self, xp, dtype): a = xp.array([float("nan"), 1, -1], dtype) - return a.ptp() + return xp.ptp(a) @testing.for_complex_dtypes() @testing.numpy_cupy_allclose() def test_ptp_nan_real(self, xp, dtype): a = xp.array([float("nan"), 1, -1], dtype) - return a.ptp() + return xp.ptp(a) @testing.for_complex_dtypes() @testing.numpy_cupy_allclose() def test_ptp_nan_imag(self, xp, dtype): a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) - return a.ptp() + return xp.ptp(a) @testing.parameterize( From 0b8669128b68cdb59062a258936afa334cb0c7fd Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Thu, 26 Oct 2023 18:10:22 -0500 Subject: [PATCH 03/15] address comments - second round --- dpnp/dpnp_container.py | 1 + dpnp/dpnp_iface_arraycreation.py | 109 +++++-------- dpnp/dpnp_iface_statistics.py | 16 +- tests/skipped_tests.tbl | 5 - tests/skipped_tests_gpu.tbl | 5 - tests/test_arraycreation.py | 47 +++--- tests/test_statistics.py | 66 +++++++- tests/test_sycl_queue.py | 1 + .../cupy/core_tests/test_ndarray_reduction.py | 145 ++++++++++-------- .../cupy/creation_tests/test_matrix.py | 44 +++++- 10 files changed, 257 insertions(+), 182 deletions(-) diff --git a/dpnp/dpnp_container.py b/dpnp/dpnp_container.py index b36b64a5113f..fac883a775b5 100644 --- a/dpnp/dpnp_container.py +++ b/dpnp/dpnp_container.py @@ -218,6 +218,7 @@ def full( ): """Validate input parameters before passing them into `dpctl.tensor` module""" dpu.validate_usm_type(usm_type, allow_none=True) + sycl_queue_normalized = dpnp.get_normalized_queue_device( fill_value, sycl_queue=sycl_queue, device=device ) diff --git a/dpnp/dpnp_iface_arraycreation.py b/dpnp/dpnp_iface_arraycreation.py index 4c2677f66029..edcfe7ab3fc7 100644 --- a/dpnp/dpnp_iface_arraycreation.py +++ b/dpnp/dpnp_iface_arraycreation.py @@ -1,5 +1,3 @@ -# cython: language_level=3 -# distutils: language = c++ # -*- coding: utf-8 -*- # ***************************************************************************** # Copyright (c) 2016-2023, Intel Corporation @@ -581,7 +579,7 @@ def copy(a, order="K", subok=False): return array(a, order=order, subok=subok, copy=True) -def diag(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): +def diag(v, /, k=0, *, device=None, usm_type=None, sycl_queue=None): """ Extract a diagonal or construct a diagonal array. @@ -594,9 +592,8 @@ def diag(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): Limitations ----------- - Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. Parameter `k` is only supported as integer data type. - Otherwise the function will be executed sequentially on CPU. + Otherwise ``TypeError`` exception will be raised. See Also -------- @@ -629,56 +626,44 @@ def diag(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): """ - if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): - pass - elif not isinstance(k, int): - pass + if not isinstance(k, int): + raise TypeError("An integer is required, but got {}".format(type(k))) else: - _usm_type = x1.usm_type if usm_type is None else usm_type - _sycl_queue = dpnp.get_normalized_queue_device( - x1, sycl_queue=sycl_queue, device=device - ) - x1 = ( - x1.to_device(_sycl_queue.sycl_device) - if x1.sycl_queue != _sycl_queue - else x1 + v = dpnp.asarray( + v, device=device, usm_type=usm_type, sycl_queue=sycl_queue ) init0 = max(0, -k) init1 = max(0, k) - if x1.ndim == 1: - size = x1.shape[0] + abs(k) + if v.ndim == 1: + size = v.shape[0] + abs(k) m = dpnp.zeros( (size, size), - dtype=x1.dtype, - usm_type=_usm_type, - sycl_queue=_sycl_queue, + dtype=v.dtype, + usm_type=v.usm_type, + sycl_queue=v.sycl_queue, ) - for i in range(x1.shape[0]): - m[(init0 + i), init1 + i] = x1[i] + for i in range(v.shape[0]): + m[(init0 + i), init1 + i] = v[i] return m - elif x1.ndim == 2: - size = min( - x1.shape[0], x1.shape[0] + k, x1.shape[1], x1.shape[1] - k - ) + elif v.ndim == 2: + size = min(v.shape[0], v.shape[0] + k, v.shape[1], v.shape[1] - k) if size < 0: size = 0 m = dpnp.zeros( (size,), - dtype=x1.dtype, - usm_type=_usm_type, - sycl_queue=_sycl_queue, + dtype=v.dtype, + usm_type=v.usm_type, + sycl_queue=v.sycl_queue, ) for i in range(size): - m[i] = x1[(init0 + i), init1 + i] + m[i] = v[(init0 + i), init1 + i] return m else: raise ValueError("Input must be a 1-D or 2-D array.") - return call_origin(numpy.diag, x1, k) - -def diagflat(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): +def diagflat(v, /, k=0, *, device=None, usm_type=None, sycl_queue=None): """ Create a two-dimensional array with the flattened input as a diagonal. @@ -697,9 +682,8 @@ def diagflat(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): Limitations ----------- - Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. Parameter `k` is only supported as integer data type. - Otherwise the function will be executed sequentially on CPU. + Otherwise ``TypeError`` exception will be raised. Examples -------- @@ -719,19 +703,15 @@ def diagflat(x1, /, k=0, *, device=None, usm_type=None, sycl_queue=None): [0, 0, 0, 0, 0]]) """ - if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): - pass - elif not isinstance(k, int): - pass + + if not isinstance(k, int): + raise TypeError("An integer is required, but got {}".format(type(k))) else: - _usm_type = x1.usm_type if usm_type is None else usm_type - _sycl_queue = dpnp.get_normalized_queue_device( - x1, sycl_queue=sycl_queue, device=device + v = dpnp.asarray( + v, device=device, usm_type=usm_type, sycl_queue=sycl_queue ) - v = dpnp.ravel(x1) - return dpnp.diag(v, k, usm_type=_usm_type, sycl_queue=_sycl_queue) - - return call_origin(numpy.diagflat, x1, k) + v = dpnp.ravel(v) + return dpnp.diag(v, k, usm_type=v.usm_type, sycl_queue=v.sycl_queue) def empty( @@ -1030,6 +1010,7 @@ def full( [10, 10, 10, 10] """ + if like is not None: pass elif order not in ("C", "c", "F", "f", None): @@ -1871,8 +1852,8 @@ def vander( Limitations ----------- - Parameter `x1` is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. - Otherwise the function will be executed sequentially on CPU. + Parameter `N`, if it is not ``None``, is only supported as integer data type. + Otherwise ``TypeError`` exception will be raised. Examples -------- @@ -1899,10 +1880,12 @@ def vander( [ 1, 5, 25, 125]]) """ - if not isinstance(x1, (dpnp.ndarray, dpt.usm_ndarray)): - pass - elif N is not None and not isinstance(N, int): - pass + x1 = dpnp.asarray( + x1, device=device, usm_type=usm_type, sycl_queue=sycl_queue + ) + + if N is not None and not isinstance(N, int): + raise TypeError("An integer is required, but got {}".format(type(N))) elif x1.ndim != 1: raise ValueError("x1 must be a one-dimensional array or sequence.") else: @@ -1910,33 +1893,21 @@ def vander( N = x1.size _dtype = int if x1.dtype == bool else x1.dtype - _usm_type = x1.usm_type if usm_type is None else usm_type - _sycl_queue = dpnp.get_normalized_queue_device( - x1, sycl_queue=sycl_queue, device=device - ) - x1 = ( - x1.to_device(_sycl_queue.sycl_device) - if x1.sycl_queue != _sycl_queue - else x1 - ) - m = empty( (x1.size, N), dtype=_dtype, - usm_type=_usm_type, - sycl_queue=_sycl_queue, + usm_type=x1.usm_type, + sycl_queue=x1.sycl_queue, ) tmp = m[:, ::-1] if not increasing else m dpnp.power( x1.reshape(-1, 1), - dpnp.arange(N, dtype=_dtype, sycl_queue=_sycl_queue), + dpnp.arange(N, dtype=_dtype, sycl_queue=x1.sycl_queue), out=tmp, ) return m - return call_origin(numpy.vander, x1, N=N, increasing=increasing) - def zeros( shape, diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index 215e98b85bc4..cc6f848ae9f5 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -713,7 +713,6 @@ def ptp( Limitations ----------- Input array is supported as :class:`dpnp.dpnp_array` or :class:`dpctl.tensor.usm_ndarray`. - Otherwise the function will be executed sequentially on CPU. Examples -------- @@ -730,16 +729,11 @@ def ptp( """ - if not isinstance(a, (dpnp.ndarray, dpt.usm_ndarray)): - pass - else: - return dpnp.subtract( - dpnp.max(a, axis=axis, keepdims=keepdims), - dpnp.min(a, axis=axis, keepdims=keepdims), - out=out, - ) - - return call_origin(numpy.ptp, a, axis, out, keepdims) + return dpnp.subtract( + dpnp.max(a, axis=axis, keepdims=keepdims, out=out), + dpnp.min(a, axis=axis, keepdims=keepdims), + out=out, + ) def nanvar(x1, axis=None, dtype=None, out=None, ddof=0, keepdims=False): diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 352e023d531b..e078d104ca1b 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -155,11 +155,6 @@ 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_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 -tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_extraction_from_nested_tuple - tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_0_{copy=False, indexing='xy', sparse=False}::test_meshgrid0 tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_0_{copy=False, indexing='xy', sparse=False}::test_meshgrid1 tests/third_party/cupy/creation_tests/test_ranges.py::TestMeshgrid_param_0_{copy=False, indexing='xy', sparse=False}::test_meshgrid2 diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 5fa13fd72201..564d4b19b674 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -109,11 +109,6 @@ tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes_param_3_{order='C', shape=(2, 3)}::test_item tests/third_party/cupy/core_tests/test_ndarray_conversion.py::TestNdarrayToBytes_param_4_{order='F', shape=(2, 3)}::test_item -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 -tests/third_party/cupy/creation_tests/test_matrix.py::TestMatrix::test_diag_extraction_from_nested_tuple - tests/third_party/cupy/indexing_tests/test_insert.py::TestFillDiagonal_param_4_{shape=(3, 3), val=(2,), wrap=True}::test_1darray tests/third_party/cupy/indexing_tests/test_insert.py::TestFillDiagonal_param_4_{shape=(3, 3), val=(2,), wrap=True}::test_fill_diagonal tests/third_party/cupy/indexing_tests/test_insert.py::TestFillDiagonal_param_5_{shape=(3, 3), val=(2,), wrap=False}::test_1darray diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index d89dd1a634c4..7406af237b21 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -117,41 +117,40 @@ def test_arange(start, stop, step, dtype): "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", ], ) -def test_diag(v, k): +def test_diag_diagflat(v, k): a = numpy.array(v) ia = dpnp.array(a) expected = numpy.diag(a, k) result = dpnp.diag(ia, k) assert_array_equal(expected, result) + expected = numpy.diagflat(a, k) + result = dpnp.diagflat(ia, k) + assert_array_equal(expected, result) + @pytest.mark.parametrize( - "axis", - [None, 0, 1], - ids=["None", "0", "1"], -) -@pytest.mark.parametrize( - "v", + "seq", [ - [[0, 0], [0, 0]], - [[1, 2], [1, 2]], - [[1, 2], [3, 4]], + [0, 1, 2, 3, 4], + (0, 1, 2, 3, 4), [[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], ], ids=[ - "[[0, 0], [0, 0]]", - "[[1, 2], [1, 2]]", - "[[1, 2], [3, 4]]", + "[0, 1, 2, 3, 4]", + "(0, 1, 2, 3, 4)", "[[0, 1, 2], [3, 4, 5], [6, 7, 8]]", "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", ], ) -def test_ptp(v, axis): - a = numpy.array(v) - ia = dpnp.array(a) - expected = numpy.ptp(a, axis) - result = dpnp.ptp(ia, axis) +def test_diag_diagflat_seq(seq): + expected = numpy.diag(seq) + result = dpnp.diag(seq) + assert_array_equal(expected, result) + + expected = numpy.diagflat(seq) + result = dpnp.diagflat(seq) assert_array_equal(expected, result) @@ -458,7 +457,7 @@ def test_triu_size_null(k): def test_vander(array, dtype, n, increase): if dtype in [dpnp.complex64, dpnp.complex128] and array == [0, 3, 5]: pytest.skip( - "dpnp.power(dpnp.array(complex(0,0)), dpnp.array(0)) returns nan+nanj while it should be 1+0j" + "per array API dpnp.power(complex(0,0)), 0) returns nan+nanj while NumPy returns 1+0j" ) vander_func = lambda xp, x: xp.vander(x, N=n, increasing=increase) @@ -468,6 +467,16 @@ def test_vander(array, dtype, n, increase): assert_allclose(vander_func(numpy, a_np), vander_func(dpnp, a_dpnp)) +@pytest.mark.parametrize( + "sequence", + [[1, 2, 3, 4], (1, 2, 3, 4)], + ids=["[1, 2, 3, 4]", "(1, 2, 3, 4)"], +) +def test_vander_seq(sequence): + vander_func = lambda xp, x: xp.vander(x) + assert_allclose(vander_func(numpy, sequence), vander_func(dpnp, sequence)) + + @pytest.mark.parametrize( "shape", [(), 0, (0,), (2, 0, 3), (3, 2)], diff --git a/tests/test_statistics.py b/tests/test_statistics.py index 2894f24a37bb..fdfea361e6f5 100644 --- a/tests/test_statistics.py +++ b/tests/test_statistics.py @@ -1,7 +1,10 @@ import dpctl.tensor as dpt import numpy import pytest -from numpy.testing import assert_allclose +from numpy.testing import ( + assert_allclose, + assert_array_equal, +) import dpnp @@ -190,3 +193,64 @@ def test_cov_1D_rowvar(dtype): a = dpnp.array([[0, 1, 2]], dtype=dtype) b = numpy.array([[0, 1, 2]], dtype=dtype) assert_allclose(numpy.cov(b, rowvar=False), dpnp.cov(a, rowvar=False)) + + +@pytest.mark.parametrize( + "axis", + [None, 0, 1], + ids=["None", "0", "1"], +) +@pytest.mark.parametrize( + "v", + [ + [[0, 0], [0, 0]], + [[1, 2], [1, 2]], + [[1, 2], [3, 4]], + [[0, 1, 2], [3, 4, 5], [6, 7, 8]], + [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], + ], + ids=[ + "[[0, 0], [0, 0]]", + "[[1, 2], [1, 2]]", + "[[1, 2], [3, 4]]", + "[[0, 1, 2], [3, 4, 5], [6, 7, 8]]", + "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", + ], +) +def test_ptp(v, axis): + a = numpy.array(v) + ia = dpnp.array(a) + expected = numpy.ptp(a, axis) + result = dpnp.ptp(ia, axis) + assert_array_equal(expected, result) + + +@pytest.mark.parametrize( + "axis", + [None, 0, 1], + ids=["None", "0", "1"], +) +@pytest.mark.parametrize( + "v", + [ + [[0, 0], [0, 0]], + [[1, 2], [1, 2]], + [[1, 2], [3, 4]], + [[0, 1, 2], [3, 4, 5], [6, 7, 8]], + [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], + ], + ids=[ + "[[0, 0], [0, 0]]", + "[[1, 2], [1, 2]]", + "[[1, 2], [3, 4]]", + "[[0, 1, 2], [3, 4, 5], [6, 7, 8]]", + "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", + ], +) +def test_ptp_out(v, axis): + a = numpy.array(v) + ia = dpnp.array(a) + expected = numpy.ptp(a, axis) + result = dpnp.array(numpy.empty_like(expected)) + dpnp.ptp(ia, axis, out=result) + assert_array_equal(expected, result) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index df877152b62e..0e83acbd3341 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -270,6 +270,7 @@ def test_array_creation_cross_device(func, args, kwargs, device_x, device_y): assert_sycl_queue_equal(y.sycl_queue, x.to_device(device_y).sycl_queue) +@pytest.mark.skip("muted until the issue reported by SAT-5969 is resolved") @pytest.mark.parametrize( "func, args, kwargs", [ diff --git a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py index 7d6c508eb2f1..f22864bfef5b 100644 --- a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py +++ b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py @@ -10,207 +10,220 @@ @testing.gpu +@testing.parameterize( + *testing.product( + { + "order": ("C", "F"), + } + ) +) class TestArrayReduction(unittest.TestCase): @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_all(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.max() @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_all_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.max(keepdims=True) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_axis_large(self, xp, dtype): - a = testing.shaped_random((3, 1000), xp, dtype) + a = testing.shaped_random((3, 1000), xp, dtype, order=self.order) return a.max(axis=0) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_axis0(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.max(axis=0) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_axis1(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.max(axis=1) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_axis2(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.max(axis=2) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_multiple_axes(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.max(axis=(1, 2)) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_multiple_axes_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.max(axis=(1, 2), keepdims=True) @testing.for_float_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_nan(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.max() @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_nan_real(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.max() @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_max_nan_imag(self, xp, dtype): - a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + a = xp.array( + [float("nan") * 1.0j, 1.0j, -1.0j], dtype, order=self.order + ) return a.max() @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_all(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.min() @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_all_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.min(keepdims=True) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_axis_large(self, xp, dtype): - a = testing.shaped_random((3, 1000), xp, dtype) + a = testing.shaped_random((3, 1000), xp, dtype, order=self.order) return a.min(axis=0) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_axis0(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.min(axis=0) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_axis1(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.min(axis=1) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_axis2(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.min(axis=2) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_multiple_axes(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.min(axis=(1, 2)) @testing.for_all_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_multiple_axes_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.min(axis=(1, 2), keepdims=True) @testing.for_float_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_nan(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.min() @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_nan_real(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.min() @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_min_nan_imag(self, xp, dtype): - a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + a = xp.array( + [float("nan") * 1.0j, 1.0j, -1.0j], dtype, order=self.order + ) return a.min() # skip bool: numpy's ptp raises a TypeError on bool inputs @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_all(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return xp.ptp(a) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_all_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return xp.ptp(a, keepdims=True) @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_axis_large(self, xp, dtype): - a = testing.shaped_random((3, 1000), xp, dtype) + a = testing.shaped_random((3, 1000), xp, dtype, order=self.order) return xp.ptp(a, axis=0) @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_axis0(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return xp.ptp(a, axis=0) @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_axis1(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return xp.ptp(a, axis=1) @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_axis2(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return xp.ptp(a, axis=2) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_multiple_axes(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return xp.ptp(a, axis=(1, 2)) @testing.with_requires("numpy>=1.15") @testing.for_all_dtypes(no_bool=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_multiple_axes_keepdims(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return xp.ptp(a, axis=(1, 2), keepdims=True) @testing.for_float_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_nan(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return xp.ptp(a) @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_nan_real(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return xp.ptp(a) @testing.for_complex_dtypes() - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(contiguous_check=False) def test_ptp_nan_imag(self, xp, dtype): - a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + a = xp.array( + [float("nan") * 1.0j, 1.0j, -1.0j], dtype, order=self.order + ) return xp.ptp(a) diff --git a/tests/third_party/cupy/creation_tests/test_matrix.py b/tests/third_party/cupy/creation_tests/test_matrix.py index e51a33c8c039..2308ecee00cb 100644 --- a/tests/third_party/cupy/creation_tests/test_matrix.py +++ b/tests/third_party/cupy/creation_tests/test_matrix.py @@ -59,19 +59,16 @@ def test_diag_construction_from_tuple(self, xp): self.assertIsInstance(r, xp.ndarray) return r - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_diag_scaler(self): for xp in (numpy, cupy): with pytest.raises(ValueError): xp.diag(1) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_diag_0dim(self): for xp in (numpy, cupy): with pytest.raises(ValueError): xp.diag(xp.zeros(())) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_diag_3dim(self): for xp in (numpy, cupy): with pytest.raises(ValueError): @@ -92,17 +89,14 @@ def test_diagflat3(self, xp): a = testing.shaped_arange((3, 3), xp) return xp.diagflat(a, -2) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar(self, xp): return xp.diagflat(3) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar_with_k0(self, xp): return xp.diagflat(3, 0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar_with_k1(self, xp): return xp.diagflat(3, 1) @@ -183,3 +177,41 @@ def test_triu_nega(self, xp, dtype): def test_triu_posi(self, xp, dtype): m = testing.shaped_arange(self.shape, xp, dtype) return xp.triu(m, k=1) + + +@testing.parameterize( + *testing.product({"N": [None, 0, 1, 2, 3], "increasing": [False, True]}) +) +class TestVander(unittest.TestCase): + @testing.for_all_dtypes(no_bool=True) + @testing.numpy_cupy_allclose(type_check=False) + def test_vander(self, xp, dtype): + a = testing.shaped_arange((3,), xp, dtype=dtype) + return xp.vander(a, N=self.N, increasing=self.increasing) + + @testing.numpy_cupy_allclose() + def test_vander_array_like_list(self, xp): + a = [0, 1, 2, 3, 4, 5, 6] + return xp.vander(a, N=self.N, increasing=self.increasing) + + @testing.numpy_cupy_allclose() + def test_vander_array_like_tuple(self, xp): + a = (0, 1, 2, 3, 4, 5, 6) + return xp.vander(a, N=self.N, increasing=self.increasing) + + def test_vander_scalar(self): + for xp in (numpy, cupy): + with pytest.raises(ValueError): + xp.vander(1, N=self.N, increasing=self.increasing) + + def test_vander_0dim(self): + for xp in (numpy, cupy): + a = xp.zeros(()) + with pytest.raises(ValueError): + xp.vander(a, N=self.N, increasing=self.increasing) + + def test_vander_2dim(self): + for xp in (numpy, cupy): + m = xp.zeros((2, 2)) + with pytest.raises(ValueError): + xp.vander(m, N=self.N, increasing=self.increasing) From bd6fcb0d672a8ea3a77e3ee6a78362ae6cdf0706 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 30 Oct 2023 12:04:06 -0500 Subject: [PATCH 04/15] add tests for negative use cases to improve covergae --- tests/test_arraycreation.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/tests/test_arraycreation.py b/tests/test_arraycreation.py index 7406af237b21..779e62237a08 100644 --- a/tests/test_arraycreation.py +++ b/tests/test_arraycreation.py @@ -91,6 +91,7 @@ def test_arange(start, stop, step, dtype): assert_array_equal(exp_array, res_array) +@pytest.mark.parametrize("func", ["diag", "diagflat"]) @pytest.mark.parametrize( "k", [-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6], @@ -117,18 +118,22 @@ def test_arange(start, stop, step, dtype): "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", ], ) -def test_diag_diagflat(v, k): +def test_diag_diagflat(func, v, k): a = numpy.array(v) ia = dpnp.array(a) - expected = numpy.diag(a, k) - result = dpnp.diag(ia, k) + expected = getattr(numpy, func)(a, k) + result = getattr(dpnp, func)(ia, k) assert_array_equal(expected, result) - expected = numpy.diagflat(a, k) - result = dpnp.diagflat(ia, k) - assert_array_equal(expected, result) + +@pytest.mark.parametrize("func", ["diag", "diagflat"]) +def test_diag_diagflat_raise_error(func): + ia = dpnp.array([0, 1, 2, 3, 4]) + with pytest.raises(TypeError): + getattr(dpnp, func)(ia, k=2.0) +@pytest.mark.parametrize("func", ["diag", "diagflat"]) @pytest.mark.parametrize( "seq", [ @@ -144,13 +149,9 @@ def test_diag_diagflat(v, k): "[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]", ], ) -def test_diag_diagflat_seq(seq): - expected = numpy.diag(seq) - result = dpnp.diag(seq) - assert_array_equal(expected, result) - - expected = numpy.diagflat(seq) - result = dpnp.diagflat(seq) +def test_diag_diagflat_seq(func, seq): + expected = getattr(numpy, func)(seq) + result = getattr(dpnp, func)(seq) assert_array_equal(expected, result) @@ -467,6 +468,16 @@ def test_vander(array, dtype, n, increase): assert_allclose(vander_func(numpy, a_np), vander_func(dpnp, a_dpnp)) +def test_vander_raise_error(): + a = dpnp.array([1, 2, 3, 4]) + with pytest.raises(TypeError): + dpnp.vander(a, N=1.0) + + a = dpnp.array([[1, 2], [3, 4]]) + with pytest.raises(ValueError): + dpnp.vander(a) + + @pytest.mark.parametrize( "sequence", [[1, 2, 3, 4], (1, 2, 3, 4)], From 8e870e862d93b091fd2894818224a99ecfd29a97 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Wed, 8 Nov 2023 11:58:57 -0600 Subject: [PATCH 05/15] fixed missing merge conflicts --- tests/test_sycl_queue.py | 5 +---- tests/test_usm_type.py | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 0e83acbd3341..083616cbf85b 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -152,13 +152,10 @@ def test_empty_like(device_x, device_y): pytest.param("ones_like", ["x0"], {}), pytest.param("tril", ["x0.reshape((2,2))"], {}), pytest.param("triu", ["x0.reshape((2,2))"], {}), -<<<<<<< HEAD - pytest.param("zeros_like", ["x0"], {}), -======= pytest.param("linspace", ["x0", "4", "4"], {}), pytest.param("linspace", ["1", "x0", "4"], {}), pytest.param("vander", ["x0"], {}), ->>>>>>> rework implementation of diag, diagflat, vander, and ptp + pytest.param("zeros_like", ["x0"], {}), ], ) @pytest.mark.parametrize( diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 7e3fe1e0f988..fd26d3e1c054 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -140,25 +140,19 @@ def test_coerced_usm_types_power(usm_type_x, usm_type_y): @pytest.mark.parametrize( "func, args", [ -<<<<<<< HEAD - pytest.param("empty_like", ["x0"]), -======= pytest.param("diag", ["x0"]), ->>>>>>> rework implementation of diag, diagflat, vander, and ptp + pytest.param("empty_like", ["x0"]), pytest.param("full", ["10", "x0[3]"]), pytest.param("full_like", ["x0", "4"]), pytest.param("geomspace", ["x0[0:3]", "8", "4"]), pytest.param("geomspace", ["1", "x0[3:5]", "4"]), pytest.param("linspace", ["x0[0:2]", "8", "4"]), pytest.param("linspace", ["0", "x0[3:5]", "4"]), -<<<<<<< HEAD pytest.param("logspace", ["x0[0:2]", "8", "4"]), pytest.param("logspace", ["0", "x0[3:5]", "4"]), pytest.param("ones_like", ["x0"]), - pytest.param("zeros_like", ["x0"]), -======= pytest.param("vander", ["x0"]), ->>>>>>> rework implementation of diag, diagflat, vander, and ptp + pytest.param("zeros_like", ["x0"]), ], ) @pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) From 5b5439da659c617abb36efb4d3c09cbd002b0f61 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Wed, 8 Nov 2023 12:00:48 -0600 Subject: [PATCH 06/15] fix pre-commit --- dpnp/backend/include/dpnp_iface_fptr.hpp | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 5794e2db6189..9eb6b8384c0d 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -132,7 +132,7 @@ enum class DPNPFuncName : size_t DPNP_FN_DET_EXT, /**< Used in numpy.linalg.det() impl, requires extra parameters */ DPNP_FN_DIAG, /**< Used in numpy.diag() impl */ - DPNP_FN_DIAG_INDICES, /**< Used in numpy.diag_indices() impl */ + DPNP_FN_DIAG_INDICES, /**< Used in numpy.diag_indices() impl */ DPNP_FN_DIAG_INDICES_EXT, /**< Used in numpy.diag_indices() impl, requires extra parameters */ DPNP_FN_DIAGONAL, /**< Used in numpy.diagonal() impl */ @@ -225,24 +225,24 @@ enum class DPNPFuncName : size_t DPNP_FN_MODF_EXT, /**< Used in numpy.modf() impl, requires extra parameters */ DPNP_FN_MULTIPLY, /**< Used in numpy.multiply() impl */ - DPNP_FN_MULTIPLY_EXT, /**< Used in numpy.multiply() impl, requires extra - parameters */ - DPNP_FN_NANVAR, /**< Used in numpy.nanvar() impl */ - DPNP_FN_NANVAR_EXT, /**< Used in numpy.nanvar() impl, requires extra - parameters */ - DPNP_FN_NEGATIVE, /**< Used in numpy.negative() impl */ - DPNP_FN_NONZERO, /**< Used in numpy.nonzero() impl */ - DPNP_FN_ONES, /**< Used in numpy.ones() impl */ - DPNP_FN_ONES_LIKE, /**< Used in numpy.ones_like() impl */ - DPNP_FN_PARTITION, /**< Used in numpy.partition() impl */ - DPNP_FN_PARTITION_EXT, /**< Used in numpy.partition() impl, requires extra - parameters */ - DPNP_FN_PLACE, /**< Used in numpy.place() impl */ - DPNP_FN_POWER, /**< Used in numpy.power() impl */ - DPNP_FN_PROD, /**< Used in numpy.prod() impl */ - DPNP_FN_PTP, /**< Used in numpy.ptp() impl */ - DPNP_FN_PUT, /**< Used in numpy.put() impl */ - DPNP_FN_PUT_ALONG_AXIS, /**< Used in numpy.put_along_axis() impl */ + DPNP_FN_MULTIPLY_EXT, /**< Used in numpy.multiply() impl, requires extra + parameters */ + DPNP_FN_NANVAR, /**< Used in numpy.nanvar() impl */ + DPNP_FN_NANVAR_EXT, /**< Used in numpy.nanvar() impl, requires extra + parameters */ + DPNP_FN_NEGATIVE, /**< Used in numpy.negative() impl */ + DPNP_FN_NONZERO, /**< Used in numpy.nonzero() impl */ + DPNP_FN_ONES, /**< Used in numpy.ones() impl */ + DPNP_FN_ONES_LIKE, /**< Used in numpy.ones_like() impl */ + DPNP_FN_PARTITION, /**< Used in numpy.partition() impl */ + DPNP_FN_PARTITION_EXT, /**< Used in numpy.partition() impl, requires extra + parameters */ + DPNP_FN_PLACE, /**< Used in numpy.place() impl */ + DPNP_FN_POWER, /**< Used in numpy.power() impl */ + DPNP_FN_PROD, /**< Used in numpy.prod() impl */ + DPNP_FN_PTP, /**< Used in numpy.ptp() impl */ + DPNP_FN_PUT, /**< Used in numpy.put() impl */ + DPNP_FN_PUT_ALONG_AXIS, /**< Used in numpy.put_along_axis() impl */ DPNP_FN_PUT_ALONG_AXIS_EXT, /**< Used in numpy.put_along_axis() impl, requires extra parameters */ DPNP_FN_QR, /**< Used in numpy.linalg.qr() impl */ From fd38502725c1f895690467d40151e418f2efc204 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 16 Oct 2023 15:05:00 -0400 Subject: [PATCH 07/15] implement dpnp.argmin and dpnp.argmax using dpctl.tensor --- dpnp/backend/include/dpnp_iface_fptr.hpp | 4 - dpnp/backend/kernels/dpnp_krnl_searching.cpp | 50 ----- dpnp/dpnp_algo/dpnp_algo.pxd | 10 - dpnp/dpnp_algo/dpnp_algo_searching.pxi | 119 ------------ dpnp/dpnp_array.py | 32 +--- dpnp/dpnp_iface_searching.py | 172 +++++++++++++----- tests/skipped_tests.tbl | 2 - tests/skipped_tests_gpu.tbl | 2 - tests/test_search.py | 69 +++++++ tests/test_sycl_queue.py | 2 + tests/test_usm_type.py | 2 + .../cupy/core_tests/test_ndarray_reduction.py | 98 +++++++++- .../cupy/sorting_tests/test_search.py | 14 -- 13 files changed, 302 insertions(+), 274 deletions(-) delete mode 100644 dpnp/dpnp_algo/dpnp_algo_searching.pxi create mode 100644 tests/test_search.py diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 9eb6b8384c0d..2489cbe1281e 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -76,11 +76,7 @@ enum class DPNPFuncName : size_t DPNP_FN_ARCTAN2, /**< Used in numpy.arctan2() impl */ DPNP_FN_ARCTANH, /**< Used in numpy.arctanh() impl */ DPNP_FN_ARGMAX, /**< Used in numpy.argmax() impl */ - DPNP_FN_ARGMAX_EXT, /**< Used in numpy.argmax() impl, requires extra - parameters */ DPNP_FN_ARGMIN, /**< Used in numpy.argmin() impl */ - DPNP_FN_ARGMIN_EXT, /**< Used in numpy.argmin() impl, requires extra - parameters */ DPNP_FN_ARGSORT, /**< Used in numpy.argsort() impl */ DPNP_FN_ARGSORT_EXT, /**< Used in numpy.argsort() impl, requires extra parameters */ diff --git a/dpnp/backend/kernels/dpnp_krnl_searching.cpp b/dpnp/backend/kernels/dpnp_krnl_searching.cpp index ae08e9c4bf53..045d405056c5 100644 --- a/dpnp/backend/kernels/dpnp_krnl_searching.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_searching.cpp @@ -78,14 +78,6 @@ void (*dpnp_argmax_default_c)(void *, void *, size_t) = dpnp_argmax_c<_DataType, _idx_DataType>; -template -DPCTLSyclEventRef (*dpnp_argmax_ext_c)(DPCTLSyclQueueRef, - void *, - void *, - size_t, - const DPCTLEventVectorRef) = - dpnp_argmax_c<_DataType, _idx_DataType>; - template class dpnp_argmin_c_kernel; @@ -133,14 +125,6 @@ void (*dpnp_argmin_default_c)(void *, void *, size_t) = dpnp_argmin_c<_DataType, _idx_DataType>; -template -DPCTLSyclEventRef (*dpnp_argmin_ext_c)(DPCTLSyclQueueRef, - void *, - void *, - size_t, - const DPCTLEventVectorRef) = - dpnp_argmin_c<_DataType, _idx_DataType>; - void func_map_init_searching(func_map_t &fmap) { fmap[DPNPFuncName::DPNP_FN_ARGMAX][eft_INT][eft_INT] = { @@ -160,23 +144,6 @@ void func_map_init_searching(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_ARGMAX][eft_DBL][eft_LNG] = { eft_LNG, (void *)dpnp_argmax_default_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_INT][eft_LNG] = { - eft_LNG, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_LNG][eft_INT] = { - eft_INT, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_FLT][eft_INT] = { - eft_INT, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_FLT][eft_LNG] = { - eft_LNG, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_DBL][eft_INT] = { - eft_INT, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMAX_EXT][eft_DBL][eft_LNG] = { - eft_LNG, (void *)dpnp_argmax_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN][eft_INT][eft_INT] = { eft_INT, (void *)dpnp_argmin_default_c}; fmap[DPNPFuncName::DPNP_FN_ARGMIN][eft_INT][eft_LNG] = { @@ -194,22 +161,5 @@ void func_map_init_searching(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_ARGMIN][eft_DBL][eft_LNG] = { eft_LNG, (void *)dpnp_argmin_default_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_INT][eft_LNG] = { - eft_LNG, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_LNG][eft_INT] = { - eft_INT, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_FLT][eft_INT] = { - eft_INT, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_FLT][eft_LNG] = { - eft_LNG, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_DBL][eft_INT] = { - eft_INT, (void *)dpnp_argmin_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ARGMIN_EXT][eft_DBL][eft_LNG] = { - eft_LNG, (void *)dpnp_argmin_ext_c}; - return; } diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index 7a38c99b9896..5f423ecb1af0 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -36,10 +36,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_ALLCLOSE DPNP_FN_ALLCLOSE_EXT DPNP_FN_ARANGE - DPNP_FN_ARGMAX - DPNP_FN_ARGMAX_EXT - DPNP_FN_ARGMIN - DPNP_FN_ARGMIN_EXT DPNP_FN_ARGSORT DPNP_FN_ARGSORT_EXT DPNP_FN_CBRT @@ -365,12 +361,6 @@ Sorting functions cpdef dpnp_descriptor dpnp_argsort(dpnp_descriptor array1) cpdef dpnp_descriptor dpnp_sort(dpnp_descriptor array1) -""" -Searching functions -""" -cpdef dpnp_descriptor dpnp_argmax(dpnp_descriptor array1) -cpdef dpnp_descriptor dpnp_argmin(dpnp_descriptor array1) - """ Trigonometric functions """ diff --git a/dpnp/dpnp_algo/dpnp_algo_searching.pxi b/dpnp/dpnp_algo/dpnp_algo_searching.pxi deleted file mode 100644 index a84c918f3c23..000000000000 --- a/dpnp/dpnp_algo/dpnp_algo_searching.pxi +++ /dev/null @@ -1,119 +0,0 @@ -# cython: language_level=3 -# cython: linetrace=True -# -*- coding: utf-8 -*- -# ***************************************************************************** -# Copyright (c) 2016-2023, Intel Corporation -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# - Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# - Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -# THE POSSIBILITY OF SUCH DAMAGE. -# ***************************************************************************** - -"""Module Backend (Searching part) - -This module contains interface functions between C backend layer -and the rest of the library - -""" - -# NO IMPORTs here. All imports must be placed into main "dpnp_algo.pyx" file - -__all__ += [ - "dpnp_argmax", - "dpnp_argmin" -] - - -# C function pointer to the C library template functions -ctypedef c_dpctl.DPCTLSyclEventRef(*custom_search_1in_1out_func_ptr_t)(c_dpctl.DPCTLSyclQueueRef, - void * , void * , size_t, - const c_dpctl.DPCTLEventVectorRef) - - -cpdef utils.dpnp_descriptor dpnp_argmax(utils.dpnp_descriptor in_array1): - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(in_array1.dtype) - cdef DPNPFuncType output_type = dpnp_dtype_to_DPNPFuncType(dpnp.int64) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_ARGMAX_EXT, param1_type, output_type) - - in_array1_obj = in_array1.get_array() - - # create result array with type given by FPTR data - cdef shape_type_c result_shape = (1,) - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape, - kernel_data.return_type, - None, - device=in_array1_obj.sycl_device, - usm_type=in_array1_obj.usm_type, - sycl_queue=in_array1_obj.sycl_queue) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef custom_search_1in_1out_func_ptr_t func = kernel_data.ptr - - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - in_array1.get_data(), - result.get_data(), - in_array1.size, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - -cpdef utils.dpnp_descriptor dpnp_argmin(utils.dpnp_descriptor in_array1): - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(in_array1.dtype) - cdef DPNPFuncType output_type = dpnp_dtype_to_DPNPFuncType(dpnp.int64) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_ARGMIN_EXT, param1_type, output_type) - - in_array1_obj = in_array1.get_array() - - # create result array with type given by FPTR data - cdef shape_type_c result_shape = (1,) - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape, - kernel_data.return_type, - None, - device=in_array1_obj.sycl_device, - usm_type=in_array1_obj.usm_type, - sycl_queue=in_array1_obj.sycl_queue) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef custom_search_1in_1out_func_ptr_t func = kernel_data.ptr - - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - in_array1.get_data(), - result.get_data(), - in_array1.size, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index 57207e6801cf..bcbcedf376b7 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -490,24 +490,14 @@ def argmax(self, axis=None, out=None): """ Returns array of indices of the maximum values along the given axis. - Parameters - ---------- - axis : {None, integer} - If None, the index is into the flattened array, otherwise along - the specified axis - out : {None, array}, optional - Array into which the result can be placed. Its type is preserved - and it must be of the right shape to hold the output. - - Returns - ------- - index_array : {integer_array} + Refer to :obj:`dpnp.argmax` for full documentation. Examples -------- + >>> import dpnp as np >>> a = np.arange(6).reshape(2,3) >>> a.argmax() - 5 + array(5) >>> a.argmax(0) array([1, 1, 1]) >>> a.argmax(1) @@ -520,21 +510,7 @@ def argmin(self, axis=None, out=None): """ Return array of indices to the minimum values along the given axis. - Parameters - ---------- - axis : {None, integer} - If None, the index is into the flattened array, otherwise along - the specified axis - out : {None, array}, optional - Array into which the result can be placed. Its type is preserved - and it must be of the right shape to hold the output. - - Returns - ------- - ndarray or scalar - If multi-dimension input, returns a new ndarray of indices to the - minimum values along the given axis. Otherwise, returns a scalar - of index to the minimum values along the given axis. + Refer to :obj:`dpnp.argmin` for full documentation. """ return dpnp.argmin(self, axis, out) diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index 26fc1528a0fa..28f1565a02e6 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -1,5 +1,3 @@ -# cython: language_level=3 -# distutils: language = c++ # -*- coding: utf-8 -*- # ***************************************************************************** # Copyright (c) 2016-2023, Intel Corporation @@ -51,18 +49,20 @@ __all__ = ["argmax", "argmin", "searchsorted", "where"] -def argmax(x1, axis=None, out=None): +def argmax(a, axis=None, out=None, keepdims=False): """ Returns the indices of the maximum values along an axis. For full documentation refer to :obj:`numpy.argmax`. + Returns + ------- + out : dpnp.ndarray + Indices of maximum value of `a`. + Limitations ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. - Parameter `axis` is supported only with default value ``None``. - Parameter `out` is supported only with default value ``None``. + Input array is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`. Input array data types are limited by supported DPNP :ref:`Data types`. See Also @@ -82,42 +82,85 @@ def argmax(x1, axis=None, out=None): -------- >>> import dpnp as np >>> a = np.arange(6).reshape((2, 3)) + 10 - >>> a.shape - (2, 3) - >>> [i for i in a] - [10, 11, 12, 13, 14, 15] + >>> a + array([[10, 11, 12], + [13, 14, 15]]) >>> np.argmax(a) - 5 + array(5) + + >>> np.argmax(a, axis=0) + array([1, 1, 1]) + >>> np.argmax(a, axis=1) + array([2, 2]) + + >>> b = np.arange(6) + >>> b[1] = 5 + >>> b + array([0, 5, 2, 3, 4, 5]) + >>> np.argmax(b) # Only the first occurrence is returned. + array(1) + + >>> x = np.arange(24).reshape((2, 3, 4)) + >>> res = np.argmax(x, axis=1, keepdims=True) # Setting keepdims to True + >>> res.shape + (2, 1, 4) """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - if axis is not None: - pass - elif out is not None: - pass - else: - result_obj = dpnp_argmax(x1_desc).get_pyobj() - result = dpnp.convert_single_elem_array_to_scalar(result_obj) + dpt_array = dpnp.get_usm_ndarray(a) + if dpt_array.size == 0: + # TODO: get rid of this if condition when dpctl supports it + for i in range(a.ndim): + if a.shape[i] == 0: + if i == axis or axis is None: + raise ValueError( + "reduction does not support zero-size arrays" + ) + else: + indices = [i for i in range(a.ndim) if i != axis] + res_shape = tuple([a.shape[i] for i in indices]) + result = dpnp.empty(res_shape, dtype=int) + else: + result = dpnp_array._create_from_usm_ndarray( + dpt.argmax(dpt_array, axis=axis, keepdims=keepdims) + ) + + if out is None: + return result + else: + if out.shape != result.shape: + raise ValueError( + f"Output array of shape {result.shape} is needed, got {out.shape}." + ) + elif not isinstance(out, dpnp_array): + if isinstance(out, dpt.usm_ndarray): + out = dpnp_array._create_from_usm_ndarray(out) + else: + raise TypeError( + "Output array must be any of supported type, but got {}".format( + type(out) + ) + ) - return result + dpnp.copyto(out, result, casting="safe") - return call_origin(numpy.argmax, x1, axis, out) + return out -def argmin(x1, axis=None, out=None): +def argmin(a, axis=None, out=None, keepdims=False): """ Returns the indices of the minimum values along an axis. For full documentation refer to :obj:`numpy.argmin`. + Returns + ------- + out : dpnp.ndarray + Indices of minimum value of `a`. + Limitations ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. - Parameter `axis` is supported only with default value ``None``. - Parameter `out` is supported only with default value ``None``. + Input array is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`. Input array data types are limited by supported DPNP :ref:`Data types`. See Also @@ -137,28 +180,69 @@ def argmin(x1, axis=None, out=None): -------- >>> import dpnp as np >>> a = np.arange(6).reshape((2, 3)) + 10 - >>> a.shape - (2, 3) - >>> [i for i in a] - [10, 11, 12, 13, 14, 15] + >>> a + array([[10, 11, 12], + [13, 14, 15]]) >>> np.argmin(a) - 0 + array(0) + + >>> np.argmin(a, axis=0) + array([0, 0, 0]) + >>> np.argmin(a, axis=1) + array([0, 0]) + + >>> b = np.arange(6) + 10 + >>> b[4] = 10 + >>> b + array([10, 11, 12, 13, 10, 15]) + >>> np.argmin(b) # Only the first occurrence is returned. + array(0) + + >>> x = np.arange(24).reshape((2, 3, 4)) + >>> res = np.argmin(x, axis=1, keepdims=True) # Setting keepdims to True + >>> res.shape + (2, 1, 4) """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: - if axis is not None: - pass - elif out is not None: - pass - else: - result_obj = dpnp_argmin(x1_desc).get_pyobj() - result = dpnp.convert_single_elem_array_to_scalar(result_obj) + dpt_array = dpnp.get_usm_ndarray(a) + if dpt_array.size == 0: + # TODO: get rid of this if condition when dpctl supports it + for i in range(a.ndim): + if a.shape[i] == 0: + if i == axis or axis is None: + raise ValueError( + "reduction does not support zero-size arrays" + ) + else: + indices = [i for i in range(a.ndim) if i != axis] + res_shape = tuple([a.shape[i] for i in indices]) + result = dpnp.empty(res_shape, dtype=int) + else: + result = dpnp_array._create_from_usm_ndarray( + dpt.argmin(dpt_array, axis=axis, keepdims=keepdims) + ) + + if out is None: + return result + else: + if out.shape != result.shape: + raise ValueError( + f"Output array of shape {result.shape} is needed, got {out.shape}." + ) + elif not isinstance(out, dpnp_array): + if isinstance(out, dpt.usm_ndarray): + out = dpnp_array._create_from_usm_ndarray(out) + else: + raise TypeError( + "Output array must be any of supported type, but got {}".format( + type(out) + ) + ) - return result + dpnp.copyto(out, result, casting="safe") - return call_origin(numpy.argmin, x1, axis, out) + return out def searchsorted(a, v, side="left", sorter=None): diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index e078d104ca1b..01971ed53a75 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -825,8 +825,6 @@ tests/third_party/cupy/sorting_tests/test_search.py::TestNanArgMin::test_nanargm tests/third_party/cupy/sorting_tests/test_search.py::TestNanArgMin::test_nanargmin_zero_size_axis1 tests/third_party/cupy/sorting_tests/test_search.py::TestNonzeroZeroDimension_param_0_{array=array(0)}::test_nonzero tests/third_party/cupy/sorting_tests/test_search.py::TestNonzeroZeroDimension_param_1_{array=array(1)}::test_nonzero -tests/third_party/cupy/sorting_tests/test_search.py::TestSearch::test_argmax_zero_size -tests/third_party/cupy/sorting_tests/test_search.py::TestSearch::test_argmin_zero_size tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_axis tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_invalid_axis1 tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_invalid_axis2 diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 564d4b19b674..b4d16cd7d846 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -887,8 +887,6 @@ tests/third_party/cupy/sorting_tests/test_search.py::TestNanArgMin::test_nanargm tests/third_party/cupy/sorting_tests/test_search.py::TestNanArgMin::test_nanargmin_zero_size_axis1 tests/third_party/cupy/sorting_tests/test_search.py::TestNonzeroZeroDimension_param_0_{array=array(0)}::test_nonzero tests/third_party/cupy/sorting_tests/test_search.py::TestNonzeroZeroDimension_param_1_{array=array(1)}::test_nonzero -tests/third_party/cupy/sorting_tests/test_search.py::TestSearch::test_argmax_zero_size -tests/third_party/cupy/sorting_tests/test_search.py::TestSearch::test_argmin_zero_size tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_axis tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_invalid_axis1 tests/third_party/cupy/sorting_tests/test_sort.py::TestArgpartition_param_0_{external=False}::test_argpartition_invalid_axis2 diff --git a/tests/test_search.py b/tests/test_search.py new file mode 100644 index 000000000000..8485c4561f24 --- /dev/null +++ b/tests/test_search.py @@ -0,0 +1,69 @@ +import numpy +import pytest +from numpy.testing import assert_allclose + +import dpnp + +from .helper import get_all_dtypes + + +@pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2]) +@pytest.mark.parametrize("keepdims", [False, True]) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) +def test_argmax_argmin(axis, keepdims, dtype): + a = numpy.arange(768, dtype=dtype).reshape((4, 4, 6, 8)) + ia = dpnp.array(a) + + np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.argmax(ia, axis=axis, keepdims=keepdims) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) + + np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.argmin(ia, axis=axis, keepdims=keepdims) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) + + +@pytest.mark.parametrize("axis", [None, 0, 1, -1]) +@pytest.mark.parametrize("keepdims", [False, True]) +def test_argmax_argmin_bool(axis, keepdims): + a = numpy.arange(2, dtype=dpnp.bool) + a = numpy.tile(a, (2, 2)) + ia = dpnp.array(a) + + np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.argmax(ia, axis=axis, keepdims=keepdims) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) + + np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.argmin(ia, axis=axis, keepdims=keepdims) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) + + +@pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2]) +@pytest.mark.parametrize("keepdims", [False, True]) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) +def test_argmax_argmin_out(axis, keepdims, dtype): + a = numpy.arange(768, dtype=dtype).reshape((4, 4, 6, 8)) + ia = dpnp.array(a) + + np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.array(numpy.empty_like(np_res)) + dpnp.argmax(ia, axis=axis, keepdims=keepdims, out=dpnp_res) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) + + np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) + dpnp_res = dpnp.array(numpy.empty_like(np_res)) + dpnp.argmin(ia, axis=axis, keepdims=keepdims, out=dpnp_res) + + assert dpnp_res.shape == np_res.shape + assert_allclose(dpnp_res, np_res) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 083616cbf85b..43d89a27cb8e 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -338,6 +338,8 @@ def test_meshgrid(device_x, device_y): pytest.param("arcsinh", [-5.0, -3.5, 0.0, 3.5, 5.0]), pytest.param("arctan", [-1.0, 0.0, 1.0]), pytest.param("arctanh", [-0.5, 0.0, 0.5]), + pytest.param("argmax", [1.0, 2.0, 4.0, 7.0]), + pytest.param("argmin", [1.0, 2.0, 4.0, 7.0]), pytest.param("ceil", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]), pytest.param("conjugate", [[1.0 + 1.0j, 0.0], [0.0, 1.0 + 1.0j]]), pytest.param("copy", [1.0, 2.0, 3.0]), diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index fd26d3e1c054..7d31cb7f25aa 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -372,6 +372,8 @@ def test_meshgrid(usm_type_x, usm_type_y): pytest.param("arcsinh", [-5.0, -3.5, 0.0, 3.5, 5.0]), pytest.param("arctan", [-1.0, 0.0, 1.0]), pytest.param("arctanh", [-0.5, 0.0, 0.5]), + pytest.param("argmax", [1.0, 2.0, 4.0, 7.0]), + pytest.param("argmin", [1.0, 2.0, 4.0, 7.0]), pytest.param("ceil", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]), pytest.param("conjugate", [[1.0 + 1.0j, 0.0], [0.0, 1.0 + 1.0j]]), pytest.param( diff --git a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py index f22864bfef5b..ecc5655e6b4c 100644 --- a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py +++ b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py @@ -226,6 +226,102 @@ def test_ptp_nan_imag(self, xp, dtype): ) return xp.ptp(a) + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_all(self, xp, dtype): + a = testing.shaped_random((2, 3), xp, dtype) + return a.argmax() + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_axis_large(self, xp, dtype): + a = testing.shaped_random((3, 1000), xp, dtype) + return a.argmax(axis=0) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_axis0(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmax(axis=0) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_axis1(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmax(axis=1) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_axis2(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmax(axis=2) + + @testing.for_float_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_nan(self, xp, dtype): + a = xp.array([float("nan"), 1, -1], dtype) + return a.argmax() + + @testing.for_complex_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_nan_real(self, xp, dtype): + a = xp.array([float("nan"), 1, -1], dtype) + return a.argmax() + + @testing.for_complex_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmax_nan_imag(self, xp, dtype): + a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + return a.argmax() + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_all(self, xp, dtype): + a = testing.shaped_random((2, 3), xp, dtype) + return a.argmin() + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_axis_large(self, xp, dtype): + a = testing.shaped_random((3, 1000), xp, dtype) + return a.argmin(axis=0) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_axis0(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmin(axis=0) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_axis1(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmin(axis=1) + + @testing.for_all_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_axis2(self, xp, dtype): + a = testing.shaped_random((2, 3, 4), xp, dtype) + return a.argmin(axis=2) + + @testing.for_float_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_nan(self, xp, dtype): + a = xp.array([float("nan"), 1, -1], dtype) + return a.argmin() + + @testing.for_complex_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_nan_real(self, xp, dtype): + a = xp.array([float("nan"), 1, -1], dtype) + return a.argmin() + + @testing.for_complex_dtypes() + @testing.numpy_cupy_allclose(contiguous_check=False) + def test_argmin_nan_imag(self, xp, dtype): + a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + return a.argmin() + @testing.parameterize( *testing.product( @@ -263,7 +359,7 @@ def test_ptp_nan_imag(self, xp, dtype): ((2, 3, 0), (0, 1, 2)), ], "order": ("C", "F"), - "func": ("min", "max"), + "func": ("min", "max", "argmin", "argmax"), } ) ) diff --git a/tests/third_party/cupy/sorting_tests/test_search.py b/tests/third_party/cupy/sorting_tests/test_search.py index 1a917367266d..32eee58b7924 100644 --- a/tests/third_party/cupy/sorting_tests/test_search.py +++ b/tests/third_party/cupy/sorting_tests/test_search.py @@ -29,35 +29,30 @@ def test_argmax_nan(self, xp, dtype): a = xp.array([float("nan"), -1, 1], dtype) return a.argmax() - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmax_axis_large(self, xp, dtype): a = testing.shaped_random((3, 1000), xp, dtype) return a.argmax(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_external_argmax_axis_large(self, xp, dtype): a = testing.shaped_random((3, 1000), xp, dtype) return xp.argmax(a, axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmax_axis0(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) return a.argmax(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmax_axis1(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) return a.argmax(axis=1) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmax_axis2(self, xp, dtype): @@ -77,7 +72,6 @@ def test_argmax_zero_size(self, dtype): with pytest.raises(ValueError): a.argmax() - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) def test_argmax_zero_size_axis0(self, dtype): for xp in (numpy, cupy): @@ -85,7 +79,6 @@ def test_argmax_zero_size_axis0(self, dtype): with pytest.raises(ValueError): a.argmax(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmax_zero_size_axis1(self, xp, dtype): @@ -110,35 +103,30 @@ def test_external_argmin_all(self, xp, dtype): a = testing.shaped_random((2, 3), xp, dtype) return xp.argmin(a) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmin_axis_large(self, xp, dtype): a = testing.shaped_random((3, 1000), xp, dtype) return a.argmin(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_external_argmin_axis_large(self, xp, dtype): a = testing.shaped_random((3, 1000), xp, dtype) return xp.argmin(a, axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmin_axis0(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) return a.argmin(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmin_axis1(self, xp, dtype): a = testing.shaped_random((2, 3, 4), xp, dtype) return a.argmin(axis=1) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmin_axis2(self, xp, dtype): @@ -158,7 +146,6 @@ def test_argmin_zero_size(self, dtype): with pytest.raises(ValueError): return a.argmin() - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) def test_argmin_zero_size_axis0(self, dtype): for xp in (numpy, cupy): @@ -166,7 +153,6 @@ def test_argmin_zero_size_axis0(self, dtype): with pytest.raises(ValueError): a.argmin(axis=0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose() def test_argmin_zero_size_axis1(self, xp, dtype): From 14f043f6dda2f5b861cbbf1968e04ba057729558 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 27 Oct 2023 03:45:40 -0500 Subject: [PATCH 08/15] address comments --- dpnp/dpnp_algo/CMakeLists.txt | 1 - dpnp/dpnp_algo/dpnp_algo.pyx | 1 - dpnp/dpnp_array.py | 11 ------ dpnp/dpnp_iface_searching.py | 12 ++++--- .../cupy/core_tests/test_ndarray_reduction.py | 36 ++++++++++--------- .../cupy/sorting_tests/test_search.py | 4 +-- 6 files changed, 30 insertions(+), 35 deletions(-) diff --git a/dpnp/dpnp_algo/CMakeLists.txt b/dpnp/dpnp_algo/CMakeLists.txt index f39615f145a6..68badc8019b9 100644 --- a/dpnp/dpnp_algo/CMakeLists.txt +++ b/dpnp/dpnp_algo/CMakeLists.txt @@ -7,7 +7,6 @@ set(dpnp_algo_pyx_deps ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_sorting.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_arraycreation.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_mathematical.pxi - ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_searching.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_indexing.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_logic.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_special.pxi diff --git a/dpnp/dpnp_algo/dpnp_algo.pyx b/dpnp/dpnp_algo/dpnp_algo.pyx index 0892c9f05e4b..4f0e8e6588d6 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pyx +++ b/dpnp/dpnp_algo/dpnp_algo.pyx @@ -65,7 +65,6 @@ include "dpnp_algo_linearalgebra.pxi" include "dpnp_algo_logic.pxi" include "dpnp_algo_manipulation.pxi" include "dpnp_algo_mathematical.pxi" -include "dpnp_algo_searching.pxi" include "dpnp_algo_sorting.pxi" include "dpnp_algo_special.pxi" include "dpnp_algo_statistics.pxi" diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index bcbcedf376b7..0b863f9e8f64 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -492,17 +492,6 @@ def argmax(self, axis=None, out=None): Refer to :obj:`dpnp.argmax` for full documentation. - Examples - -------- - >>> import dpnp as np - >>> a = np.arange(6).reshape(2,3) - >>> a.argmax() - array(5) - >>> a.argmax(0) - array([1, 1, 1]) - >>> a.argmax(1) - array([2, 2]) - """ return dpnp.argmax(self, axis, out) diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index 28f1565a02e6..53025c358061 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -49,7 +49,7 @@ __all__ = ["argmax", "argmin", "searchsorted", "where"] -def argmax(a, axis=None, out=None, keepdims=False): +def argmax(a, axis=None, out=None, *, keepdims=False): """ Returns the indices of the maximum values along an axis. @@ -62,11 +62,13 @@ def argmax(a, axis=None, out=None, keepdims=False): Limitations ----------- - Input array is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`. + Input and output arrays are only supported as either :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. Input array data types are limited by supported DPNP :ref:`Data types`. See Also -------- + :obj:`dpnp.ndarray.argmax` : Equivalent function. :obj:`dpnp.argmin` : Returns the indices of the minimum values along an axis. :obj:`dpnp.amax` : The maximum value along a given axis. :obj:`dpnp.unravel_index` : Convert a flat index into an index tuple. @@ -147,7 +149,7 @@ def argmax(a, axis=None, out=None, keepdims=False): return out -def argmin(a, axis=None, out=None, keepdims=False): +def argmin(a, axis=None, out=None, *, keepdims=False): """ Returns the indices of the minimum values along an axis. @@ -160,11 +162,13 @@ def argmin(a, axis=None, out=None, keepdims=False): Limitations ----------- - Input array is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`. + Input and output arrays are only supported as either :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. Input array data types are limited by supported DPNP :ref:`Data types`. See Also -------- + :obj:`dpnp.ndarray.argmin` : Equivalent function. :obj:`dpnp.argmax` : Returns the indices of the maximum values along an axis. :obj:`dpnp.amin` : The minimum value along a given axis. :obj:`dpnp.unravel_index` : Convert a flat index into an index tuple. diff --git a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py index ecc5655e6b4c..70d654d6a694 100644 --- a/tests/third_party/cupy/core_tests/test_ndarray_reduction.py +++ b/tests/third_party/cupy/core_tests/test_ndarray_reduction.py @@ -229,97 +229,101 @@ def test_ptp_nan_imag(self, xp, dtype): @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_all(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.argmax() @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_axis_large(self, xp, dtype): - a = testing.shaped_random((3, 1000), xp, dtype) + a = testing.shaped_random((3, 1000), xp, dtype, order=self.order) return a.argmax(axis=0) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_axis0(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmax(axis=0) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_axis1(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmax(axis=1) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_axis2(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmax(axis=2) @testing.for_float_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_nan(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.argmax() @testing.for_complex_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_nan_real(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.argmax() @testing.for_complex_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmax_nan_imag(self, xp, dtype): - a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + a = xp.array( + [float("nan") * 1.0j, 1.0j, -1.0j], dtype, order=self.order + ) return a.argmax() @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_all(self, xp, dtype): - a = testing.shaped_random((2, 3), xp, dtype) + a = testing.shaped_random((2, 3), xp, dtype, order=self.order) return a.argmin() @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_axis_large(self, xp, dtype): - a = testing.shaped_random((3, 1000), xp, dtype) + a = testing.shaped_random((3, 1000), xp, dtype, order=self.order) return a.argmin(axis=0) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_axis0(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmin(axis=0) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_axis1(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmin(axis=1) @testing.for_all_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_axis2(self, xp, dtype): - a = testing.shaped_random((2, 3, 4), xp, dtype) + a = testing.shaped_random((2, 3, 4), xp, dtype, order=self.order) return a.argmin(axis=2) @testing.for_float_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_nan(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.argmin() @testing.for_complex_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_nan_real(self, xp, dtype): - a = xp.array([float("nan"), 1, -1], dtype) + a = xp.array([float("nan"), 1, -1], dtype, order=self.order) return a.argmin() @testing.for_complex_dtypes() @testing.numpy_cupy_allclose(contiguous_check=False) def test_argmin_nan_imag(self, xp, dtype): - a = xp.array([float("nan") * 1.0j, 1.0j, -1.0j], dtype) + a = xp.array( + [float("nan") * 1.0j, 1.0j, -1.0j], dtype, order=self.order + ) return a.argmin() diff --git a/tests/third_party/cupy/sorting_tests/test_search.py b/tests/third_party/cupy/sorting_tests/test_search.py index 32eee58b7924..edfe4ea02ed1 100644 --- a/tests/third_party/cupy/sorting_tests/test_search.py +++ b/tests/third_party/cupy/sorting_tests/test_search.py @@ -91,8 +91,8 @@ def test_argmin_all(self, xp, dtype): a = testing.shaped_random((2, 3), xp, dtype) return a.argmin() - @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose(accept_error=ValueError) + @testing.for_float_dtypes() + @testing.numpy_cupy_allclose() def test_argmin_nan(self, xp, dtype): a = xp.array([float("nan"), -1, 1], dtype) return a.argmin() From e026c373e80432a33692ae5727fa6ec79dbf763d Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 30 Oct 2023 12:14:29 -0500 Subject: [PATCH 09/15] add tests for negative use cases to improve coverage --- tests/test_search.py | 54 +++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/tests/test_search.py b/tests/test_search.py index 8485c4561f24..9179867efc37 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -1,3 +1,4 @@ +import dpctl.tensor as dpt import numpy import pytest from numpy.testing import assert_allclose @@ -7,63 +8,54 @@ from .helper import get_all_dtypes +@pytest.mark.parametrize("func", ["argmax", "argmin"]) @pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2]) @pytest.mark.parametrize("keepdims", [False, True]) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) -def test_argmax_argmin(axis, keepdims, dtype): +def test_argmax_argmin(func, axis, keepdims, dtype): a = numpy.arange(768, dtype=dtype).reshape((4, 4, 6, 8)) ia = dpnp.array(a) - np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) - dpnp_res = dpnp.argmax(ia, axis=axis, keepdims=keepdims) - - assert dpnp_res.shape == np_res.shape - assert_allclose(dpnp_res, np_res) - - np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) - dpnp_res = dpnp.argmin(ia, axis=axis, keepdims=keepdims) + np_res = getattr(numpy, func)(a, axis=axis, keepdims=keepdims) + dpnp_res = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims) assert dpnp_res.shape == np_res.shape assert_allclose(dpnp_res, np_res) +@pytest.mark.parametrize("func", ["argmax", "argmin"]) @pytest.mark.parametrize("axis", [None, 0, 1, -1]) @pytest.mark.parametrize("keepdims", [False, True]) -def test_argmax_argmin_bool(axis, keepdims): +def test_argmax_argmin_bool(func, axis, keepdims): a = numpy.arange(2, dtype=dpnp.bool) a = numpy.tile(a, (2, 2)) ia = dpnp.array(a) - np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) - dpnp_res = dpnp.argmax(ia, axis=axis, keepdims=keepdims) + np_res = getattr(numpy, func)(a, axis=axis, keepdims=keepdims) + dpnp_res = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims) assert dpnp_res.shape == np_res.shape assert_allclose(dpnp_res, np_res) - np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) - dpnp_res = dpnp.argmin(ia, axis=axis, keepdims=keepdims) - assert dpnp_res.shape == np_res.shape - assert_allclose(dpnp_res, np_res) - - -@pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2]) -@pytest.mark.parametrize("keepdims", [False, True]) -@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) -def test_argmax_argmin_out(axis, keepdims, dtype): - a = numpy.arange(768, dtype=dtype).reshape((4, 4, 6, 8)) +@pytest.mark.parametrize("func", ["argmax", "argmin"]) +def test_argmax_argmin_out(func): + a = numpy.arange(6).reshape((2, 3)) ia = dpnp.array(a) - np_res = numpy.argmax(a, axis=axis, keepdims=keepdims) + np_res = getattr(numpy, func)(a, axis=0) dpnp_res = dpnp.array(numpy.empty_like(np_res)) - dpnp.argmax(ia, axis=axis, keepdims=keepdims, out=dpnp_res) + getattr(dpnp, func)(ia, axis=0, out=dpnp_res) + assert_allclose(dpnp_res, np_res) - assert dpnp_res.shape == np_res.shape + dpnp_res = dpt.asarray(numpy.empty_like(np_res)) + getattr(dpnp, func)(ia, axis=0, out=dpnp_res) assert_allclose(dpnp_res, np_res) - np_res = numpy.argmin(a, axis=axis, keepdims=keepdims) - dpnp_res = dpnp.array(numpy.empty_like(np_res)) - dpnp.argmin(ia, axis=axis, keepdims=keepdims, out=dpnp_res) + dpnp_res = numpy.empty_like(np_res) + with pytest.raises(TypeError): + getattr(dpnp, func)(ia, axis=0, out=dpnp_res) - assert dpnp_res.shape == np_res.shape - assert_allclose(dpnp_res, np_res) + dpnp_res = dpnp.array(numpy.empty((2, 3))) + with pytest.raises(ValueError): + getattr(dpnp, func)(ia, axis=0, out=dpnp_res) From dec3e57b7a309806a5ec9fb32f6f0f6fd84dcc51 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Thu, 9 Nov 2023 09:25:16 -0600 Subject: [PATCH 10/15] remove unneccessary parts with updates in dpctl #1465 --- dpnp/dpnp_iface_searching.py | 38 +++++--------------------------- dpnp/dpnp_iface_statistics.py | 41 +++++++---------------------------- 2 files changed, 14 insertions(+), 65 deletions(-) diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index 53025c358061..49e063fb1a2e 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -110,22 +110,9 @@ def argmax(a, axis=None, out=None, *, keepdims=False): """ dpt_array = dpnp.get_usm_ndarray(a) - if dpt_array.size == 0: - # TODO: get rid of this if condition when dpctl supports it - for i in range(a.ndim): - if a.shape[i] == 0: - if i == axis or axis is None: - raise ValueError( - "reduction does not support zero-size arrays" - ) - else: - indices = [i for i in range(a.ndim) if i != axis] - res_shape = tuple([a.shape[i] for i in indices]) - result = dpnp.empty(res_shape, dtype=int) - else: - result = dpnp_array._create_from_usm_ndarray( - dpt.argmax(dpt_array, axis=axis, keepdims=keepdims) - ) + result = dpnp_array._create_from_usm_ndarray( + dpt.argmax(dpt_array, axis=axis, keepdims=keepdims) + ) if out is None: return result @@ -210,22 +197,9 @@ def argmin(a, axis=None, out=None, *, keepdims=False): """ dpt_array = dpnp.get_usm_ndarray(a) - if dpt_array.size == 0: - # TODO: get rid of this if condition when dpctl supports it - for i in range(a.ndim): - if a.shape[i] == 0: - if i == axis or axis is None: - raise ValueError( - "reduction does not support zero-size arrays" - ) - else: - indices = [i for i in range(a.ndim) if i != axis] - res_shape = tuple([a.shape[i] for i in indices]) - result = dpnp.empty(res_shape, dtype=int) - else: - result = dpnp_array._create_from_usm_ndarray( - dpt.argmin(dpt_array, axis=axis, keepdims=keepdims) - ) + result = dpnp_array._create_from_usm_ndarray( + dpt.argmin(dpt_array, axis=axis, keepdims=keepdims) + ) if out is None: return result diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index cc6f848ae9f5..902b10f3c274 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -410,23 +410,10 @@ def max(a, axis=None, out=None, keepdims=False, initial=None, where=True): ) else: dpt_array = dpnp.get_usm_ndarray(a) - if dpt_array.size == 0: - # TODO: get rid of this if condition when dpctl supports it - axis = (axis,) if isinstance(axis, int) else axis - for i in range(a.ndim): - if a.shape[i] == 0: - if axis is None or i in axis: - raise ValueError( - "reduction does not support zero-size arrays" - ) - else: - indices = [i for i in range(a.ndim) if i not in axis] - res_shape = tuple([a.shape[i] for i in indices]) - result = dpnp.empty(res_shape, dtype=a.dtype) - else: - result = dpnp_array._create_from_usm_ndarray( - dpt.max(dpt_array, axis=axis, keepdims=keepdims) - ) + result = dpnp_array._create_from_usm_ndarray( + dpt.max(dpt_array, axis=axis, keepdims=keepdims) + ) + if out is None: return result else: @@ -655,22 +642,10 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): ) else: dpt_array = dpnp.get_usm_ndarray(a) - if dpt_array.size == 0: - # TODO: get rid of this if condition when dpctl supports it - for i in range(a.ndim): - if a.shape[i] == 0: - if axis is None or i in axis: - raise ValueError( - "reduction does not support zero-size arrays" - ) - else: - indices = [i for i in range(a.ndim) if i not in axis] - res_shape = tuple([a.shape[i] for i in indices]) - result = dpnp.empty(res_shape, dtype=a.dtype) - else: - result = dpnp_array._create_from_usm_ndarray( - dpt.min(dpt_array, axis=axis, keepdims=keepdims) - ) + result = dpnp_array._create_from_usm_ndarray( + dpt.min(dpt_array, axis=axis, keepdims=keepdims) + ) + if out is None: return result else: From 3eb40d6367d2e8333f5295ba9c037c9f071c1799 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 20 Nov 2023 15:06:29 -0600 Subject: [PATCH 11/15] add paramater section in doc --- dpnp/dpnp_iface_searching.py | 52 ++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index 49e063fb1a2e..fa4ddf4e2dd9 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -55,16 +55,28 @@ def argmax(a, axis=None, out=None, *, keepdims=False): For full documentation refer to :obj:`numpy.argmax`. + Parameters + ---------- + a : {dpnp_array, usm_ndarray} + Input array. + axis : int, optional + By default, the index is into the flattened array, otherwise + along the specified axis. + out : {dpnp_array, usm_ndarray}, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and dtype. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the array. + Returns ------- out : dpnp.ndarray - Indices of maximum value of `a`. - - Limitations - ----------- - Input and output arrays are only supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. + Indices of maximum value of `a`. It has the same shape as `a.shape` + with the dimension along `axis` removed. If `keepdims` is set to True, + then the size of `axis` will be 1 with the resulting array having same + shape as `a.shape`. See Also -------- @@ -142,16 +154,28 @@ def argmin(a, axis=None, out=None, *, keepdims=False): For full documentation refer to :obj:`numpy.argmin`. + Parameters + ---------- + a : {dpnp_array, usm_ndarray} + Input array. + axis : int, optional + By default, the index is into the flattened array, otherwise + along the specified axis. + out : {dpnp_array, usm_ndarray}, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and dtype. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the array. + Returns ------- out : dpnp.ndarray - Indices of minimum value of `a`. - - Limitations - ----------- - Input and output arrays are only supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. + Indices of minimum value of `a`. It has the same shape as `a.shape` + with the dimension along `axis` removed. If `keepdims` is set to True, + then the size of `axis` will be 1 with the resulting array having same + shape as `a.shape`. See Also -------- From ccdf3c46000f7ff1878c3ca662b5f6576aa8b296 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 20 Nov 2023 17:41:09 -0600 Subject: [PATCH 12/15] update ndarray.argmin and ndarray.argmax function signature --- dpnp/dpnp_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index 26049a948968..450a5851f43e 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -486,7 +486,7 @@ def any(self, axis=None, out=None, keepdims=False, *, where=True): self, axis=axis, out=out, keepdims=keepdims, where=where ) - def argmax(self, axis=None, out=None): + def argmax(self, axis=None, out=None, *, keepdims=False): """ Returns array of indices of the maximum values along the given axis. @@ -495,7 +495,7 @@ def argmax(self, axis=None, out=None): """ return dpnp.argmax(self, axis, out) - def argmin(self, axis=None, out=None): + def argmin(self, axis=None, out=None, *, keepdims=False): """ Return array of indices to the minimum values along the given axis. From 655182a55fc56d7fac7526ac99b9b57ae34cca89 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 20 Nov 2023 17:43:20 -0600 Subject: [PATCH 13/15] use a utility func for returning output --- dpnp/dpnp_iface.py | 44 +++++++++++++++++++++++++++++++++ dpnp/dpnp_iface_mathematical.py | 21 +--------------- dpnp/dpnp_iface_searching.py | 42 ++----------------------------- dpnp/dpnp_iface_statistics.py | 44 +++------------------------------ 4 files changed, 50 insertions(+), 101 deletions(-) diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index d6d5b3a48615..03cd3abb1037 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -69,6 +69,7 @@ "get_usm_ndarray_or_scalar", "is_supported_array_or_scalar", "is_supported_array_type", + "_copyto", ] from dpnp import float64, isscalar @@ -516,3 +517,46 @@ def is_supported_array_type(a): """ return isinstance(a, (dpnp_array, dpt.usm_ndarray)) + + +def _copyto(a, out=None): + """ + If `out` is provided, `a` will be inserted into this array. + Otherwise, `a` is returned. + + Parameters + ---------- + a : {dpnp_array} + An input array. + + out : {dpnp_array, usm_ndarray} + If provided, the input will be inserted into this array. + It should be of the appropriate shape. + + Returns + ------- + out : {dpnp_array} + Return `out` if provided, otherwise return `a`. + + """ + + if out is None: + return a + else: + if out.shape != a.shape: + raise ValueError( + f"Output array of shape {a.shape} is needed, got {out.shape}." + ) + elif not isinstance(out, dpnp_array): + if isinstance(out, dpt.usm_ndarray): + out = dpnp_array._create_from_usm_ndarray(out) + else: + raise TypeError( + "Output array must be any of supported type, but got {}".format( + type(out) + ) + ) + + dpnp.copyto(out, a, casting="safe") + + return out diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 330179c2ca44..1344fdabd597 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -2158,26 +2158,7 @@ def prod( dpt.prod(dpt_array, axis=axis, dtype=dtype, keepdims=keepdims) ) - if out is None: - return result - else: - if out.shape != result.shape: - raise ValueError( - f"Output array of shape {result.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, result, casting="safe") - - return out + return dpnp._copyto(result, out) def proj( diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index fa4ddf4e2dd9..443076db95e9 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -126,26 +126,7 @@ def argmax(a, axis=None, out=None, *, keepdims=False): dpt.argmax(dpt_array, axis=axis, keepdims=keepdims) ) - if out is None: - return result - else: - if out.shape != result.shape: - raise ValueError( - f"Output array of shape {result.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, result, casting="safe") - - return out + return dpnp._copyto(result, out) def argmin(a, axis=None, out=None, *, keepdims=False): @@ -225,26 +206,7 @@ def argmin(a, axis=None, out=None, *, keepdims=False): dpt.argmin(dpt_array, axis=axis, keepdims=keepdims) ) - if out is None: - return result - else: - if out.shape != result.shape: - raise ValueError( - f"Output array of shape {result.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, result, casting="safe") - - return out + return dpnp._copyto(result, out) def searchsorted(a, v, side="left", sorter=None): diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index 902b10f3c274..291c1001eca2 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -414,26 +414,7 @@ def max(a, axis=None, out=None, keepdims=False, initial=None, where=True): dpt.max(dpt_array, axis=axis, keepdims=keepdims) ) - if out is None: - return result - else: - if out.shape != result.shape: - raise ValueError( - f"Output array of shape {result.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, result, casting="safe") - - return out + return dpnp._copyto(result, out) def mean(x, /, *, axis=None, dtype=None, keepdims=False, out=None, where=True): @@ -638,7 +619,7 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): ) elif where is not True: raise NotImplementedError( - "where keyword argument is only supported by its default values." + "where keyword argument is only supported by its default value." ) else: dpt_array = dpnp.get_usm_ndarray(a) @@ -646,26 +627,7 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): dpt.min(dpt_array, axis=axis, keepdims=keepdims) ) - if out is None: - return result - else: - if out.shape != result.shape: - raise ValueError( - f"Output array of shape {result.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, result, casting="safe") - - return out + return dpnp._copyto(result, out) def ptp( From 30f87ebd6ee3ca9d259574bd6b6387b813a9e95e Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Tue, 21 Nov 2023 09:29:36 -0600 Subject: [PATCH 14/15] add tests for ndarray implementation --- dpnp/dpnp_array.py | 4 ++-- dpnp/dpnp_iface.py | 14 ++++++++------ dpnp/dpnp_iface_mathematical.py | 2 +- dpnp/dpnp_iface_searching.py | 4 ++-- dpnp/dpnp_iface_statistics.py | 4 ++-- tests/test_search.py | 15 +++++++++++++++ 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index 450a5851f43e..88db5d695f9d 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -493,7 +493,7 @@ def argmax(self, axis=None, out=None, *, keepdims=False): Refer to :obj:`dpnp.argmax` for full documentation. """ - return dpnp.argmax(self, axis, out) + return dpnp.argmax(self, axis, out, keepdims=keepdims) def argmin(self, axis=None, out=None, *, keepdims=False): """ @@ -502,7 +502,7 @@ def argmin(self, axis=None, out=None, *, keepdims=False): Refer to :obj:`dpnp.argmin` for full documentation. """ - return dpnp.argmin(self, axis, out) + return dpnp.argmin(self, axis, out, keepdims=keepdims) # 'argpartition', diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index 03cd3abb1037..df0d2b53ac14 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -69,7 +69,7 @@ "get_usm_ndarray_or_scalar", "is_supported_array_or_scalar", "is_supported_array_type", - "_copyto", + "get_result_array", ] from dpnp import float64, isscalar @@ -519,18 +519,20 @@ def is_supported_array_type(a): return isinstance(a, (dpnp_array, dpt.usm_ndarray)) -def _copyto(a, out=None): +def get_result_array(a, out=None): """ - If `out` is provided, `a` will be inserted into this array. - Otherwise, `a` is returned. + If `out` is provided, value of `a` array will be copied into the + `out` array according to ``safe`` casting rule. + Otherwise, the input array `a` is returned. Parameters ---------- a : {dpnp_array} - An input array. + Input array. out : {dpnp_array, usm_ndarray} - If provided, the input will be inserted into this array. + If provided, value of `a` array will be copied into it + according to ``safe`` casting rule. It should be of the appropriate shape. Returns diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 1344fdabd597..d9e0155ca118 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -2158,7 +2158,7 @@ def prod( dpt.prod(dpt_array, axis=axis, dtype=dtype, keepdims=keepdims) ) - return dpnp._copyto(result, out) + return dpnp.get_result_array(result, out) def proj( diff --git a/dpnp/dpnp_iface_searching.py b/dpnp/dpnp_iface_searching.py index 443076db95e9..e74c0c1beccf 100644 --- a/dpnp/dpnp_iface_searching.py +++ b/dpnp/dpnp_iface_searching.py @@ -126,7 +126,7 @@ def argmax(a, axis=None, out=None, *, keepdims=False): dpt.argmax(dpt_array, axis=axis, keepdims=keepdims) ) - return dpnp._copyto(result, out) + return dpnp.get_result_array(result, out) def argmin(a, axis=None, out=None, *, keepdims=False): @@ -206,7 +206,7 @@ def argmin(a, axis=None, out=None, *, keepdims=False): dpt.argmin(dpt_array, axis=axis, keepdims=keepdims) ) - return dpnp._copyto(result, out) + return dpnp.get_result_array(result, out) def searchsorted(a, v, side="left", sorter=None): diff --git a/dpnp/dpnp_iface_statistics.py b/dpnp/dpnp_iface_statistics.py index 291c1001eca2..cc11aeede1a5 100644 --- a/dpnp/dpnp_iface_statistics.py +++ b/dpnp/dpnp_iface_statistics.py @@ -414,7 +414,7 @@ def max(a, axis=None, out=None, keepdims=False, initial=None, where=True): dpt.max(dpt_array, axis=axis, keepdims=keepdims) ) - return dpnp._copyto(result, out) + return dpnp.get_result_array(result, out) def mean(x, /, *, axis=None, dtype=None, keepdims=False, out=None, where=True): @@ -627,7 +627,7 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True): dpt.min(dpt_array, axis=axis, keepdims=keepdims) ) - return dpnp._copyto(result, out) + return dpnp.get_result_array(result, out) def ptp( diff --git a/tests/test_search.py b/tests/test_search.py index 9179867efc37..aa5a2c9915c4 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -59,3 +59,18 @@ def test_argmax_argmin_out(func): dpnp_res = dpnp.array(numpy.empty((2, 3))) with pytest.raises(ValueError): getattr(dpnp, func)(ia, axis=0, out=dpnp_res) + + +@pytest.mark.parametrize("axis", [None, 0, 1, -1]) +@pytest.mark.parametrize("keepdims", [False, True]) +def test_ndarray_argmax_argmin(axis, keepdims): + a = numpy.arange(192, dtype="f4").reshape((4, 6, 8)) + ia = dpnp.array(a) + + np_res = a.argmax(axis=axis, keepdims=keepdims) + dpnp_res = ia.argmax(axis=axis, keepdims=keepdims) + assert_allclose(dpnp_res, np_res) + + np_res = a.argmin(axis=axis, keepdims=keepdims) + dpnp_res = ia.argmin(axis=axis, keepdims=keepdims) + assert_allclose(dpnp_res, np_res) From df98a829fc1c5db607c64e2185aedb85824f18d3 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 22 Nov 2023 11:52:01 +0100 Subject: [PATCH 15/15] Place new function acc to lexicographical order --- dpnp/dpnp_iface.py | 92 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index df0d2b53ac14..e91a9b991f89 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -65,11 +65,11 @@ "get_dpnp_descriptor", "get_include", "get_normalized_queue_device", + "get_result_array", "get_usm_ndarray", "get_usm_ndarray_or_scalar", "is_supported_array_or_scalar", "is_supported_array_type", - "get_result_array", ] from dpnp import float64, isscalar @@ -419,6 +419,51 @@ def get_normalized_queue_device(obj=None, device=None, sycl_queue=None): ) +def get_result_array(a, out=None): + """ + If `out` is provided, value of `a` array will be copied into the + `out` array according to ``safe`` casting rule. + Otherwise, the input array `a` is returned. + + Parameters + ---------- + a : {dpnp_array} + Input array. + + out : {dpnp_array, usm_ndarray} + If provided, value of `a` array will be copied into it + according to ``safe`` casting rule. + It should be of the appropriate shape. + + Returns + ------- + out : {dpnp_array} + Return `out` if provided, otherwise return `a`. + + """ + + if out is None: + return a + else: + if out.shape != a.shape: + raise ValueError( + f"Output array of shape {a.shape} is needed, got {out.shape}." + ) + elif not isinstance(out, dpnp_array): + if isinstance(out, dpt.usm_ndarray): + out = dpnp_array._create_from_usm_ndarray(out) + else: + raise TypeError( + "Output array must be any of supported type, but got {}".format( + type(out) + ) + ) + + dpnp.copyto(out, a, casting="safe") + + return out + + def get_usm_ndarray(a): """ Return :class:`dpctl.tensor.usm_ndarray` from input array `a`. @@ -517,48 +562,3 @@ def is_supported_array_type(a): """ return isinstance(a, (dpnp_array, dpt.usm_ndarray)) - - -def get_result_array(a, out=None): - """ - If `out` is provided, value of `a` array will be copied into the - `out` array according to ``safe`` casting rule. - Otherwise, the input array `a` is returned. - - Parameters - ---------- - a : {dpnp_array} - Input array. - - out : {dpnp_array, usm_ndarray} - If provided, value of `a` array will be copied into it - according to ``safe`` casting rule. - It should be of the appropriate shape. - - Returns - ------- - out : {dpnp_array} - Return `out` if provided, otherwise return `a`. - - """ - - if out is None: - return a - else: - if out.shape != a.shape: - raise ValueError( - f"Output array of shape {a.shape} is needed, got {out.shape}." - ) - elif not isinstance(out, dpnp_array): - if isinstance(out, dpt.usm_ndarray): - out = dpnp_array._create_from_usm_ndarray(out) - else: - raise TypeError( - "Output array must be any of supported type, but got {}".format( - type(out) - ) - ) - - dpnp.copyto(out, a, casting="safe") - - return out