From 2376b7bd48c493b2b988dae557b6fb654428e15e Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Tue, 24 Jan 2023 15:00:59 -0600 Subject: [PATCH] Add support of comparison operations --- .../include/dpnp_gen_2arg_2type_tbl.hpp | 5 + dpnp/backend/include/dpnp_iface_fptr.hpp | 5 + dpnp/backend/kernels/dpnp_krnl_logic.cpp | 10 + dpnp/dpnp_algo/dpnp_algo.pxd | 5 + dpnp/dpnp_algo/dpnp_algo_logic.pyx | 90 ++---- dpnp/dpnp_iface_logic.py | 260 +++++++++++++----- tests/test_linalg.py | 1 - tests/test_logic.py | 23 +- tests/test_random.py | 1 - tests/test_random_state.py | 1 - tests/test_sycl_queue.py | 5 +- .../cupy/logic_tests/test_comparison.py | 6 - 12 files changed, 259 insertions(+), 153 deletions(-) diff --git a/dpnp/backend/include/dpnp_gen_2arg_2type_tbl.hpp b/dpnp/backend/include/dpnp_gen_2arg_2type_tbl.hpp index e76c92b47cd6..2fb4fe9d6fde 100644 --- a/dpnp/backend/include/dpnp_gen_2arg_2type_tbl.hpp +++ b/dpnp/backend/include/dpnp_gen_2arg_2type_tbl.hpp @@ -86,6 +86,11 @@ #endif +MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_equal_c, input1_elem == input2_elem) +MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_greater_c, input1_elem > input2_elem) +MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_greater_equal_c, input1_elem >= input2_elem) +MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_less_c, input1_elem < input2_elem) MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_less_equal_c, input1_elem <= input2_elem) +MACRO_2ARG_2TYPES_LOGIC_OP(dpnp_not_equal_c, input1_elem != input2_elem) #undef MACRO_2ARG_2TYPES_LOGIC_OP diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 18e3629366df..7a3564fa1d35 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -151,6 +151,7 @@ enum class DPNPFuncName : size_t DPNP_FN_EIG_EXT, /**< Used in numpy.linalg.eig() impl, requires extra parameters */ DPNP_FN_EIGVALS, /**< Used in numpy.linalg.eigvals() impl */ DPNP_FN_EIGVALS_EXT, /**< Used in numpy.linalg.eigvals() impl, requires extra parameters */ + DPNP_FN_EQUAL_EXT, /**< Used in numpy.equal() impl, requires extra parameters */ DPNP_FN_ERF, /**< Used in scipy.special.erf impl */ DPNP_FN_ERF_EXT, /**< Used in scipy.special.erf impl, requires extra parameters */ DPNP_FN_EYE, /**< Used in numpy.eye() impl */ @@ -179,6 +180,8 @@ enum class DPNPFuncName : size_t DPNP_FN_FMOD_EXT, /**< Used in numpy.fmod() impl, requires extra parameters */ DPNP_FN_FULL, /**< Used in numpy.full() impl */ DPNP_FN_FULL_LIKE, /**< Used in numpy.full_like() impl */ + DPNP_FN_GREATER_EXT, /**< Used in numpy.greater() impl, requires extra parameters */ + DPNP_FN_GREATER_EQUAL_EXT, /**< Used in numpy.greater_equal() impl, requires extra parameters */ DPNP_FN_HYPOT, /**< Used in numpy.hypot() impl */ DPNP_FN_HYPOT_EXT, /**< Used in numpy.hypot() impl, requires extra parameters */ DPNP_FN_IDENTITY, /**< Used in numpy.identity() impl */ @@ -193,6 +196,7 @@ enum class DPNPFuncName : size_t DPNP_FN_KRON_EXT, /**< Used in numpy.kron() impl, requires extra parameters */ DPNP_FN_LEFT_SHIFT, /**< Used in numpy.left_shift() impl */ DPNP_FN_LEFT_SHIFT_EXT, /**< Used in numpy.left_shift() impl, requires extra parameters */ + DPNP_FN_LESS_EXT, /**< Used in numpy.less() impl, requires extra parameters */ DPNP_FN_LESS_EQUAL_EXT, /**< Used in numpy.less_equal() impl, requires extra parameters */ DPNP_FN_LOG, /**< Used in numpy.log() impl */ DPNP_FN_LOG_EXT, /**< Used in numpy.log() impl, requires extra parameters */ @@ -228,6 +232,7 @@ enum class DPNPFuncName : size_t DPNP_FN_NEGATIVE_EXT, /**< Used in numpy.negative() impl, requires extra parameters */ DPNP_FN_NONZERO, /**< Used in numpy.nonzero() impl */ DPNP_FN_NONZERO_EXT, /**< Used in numpy.nonzero() impl, requires extra parameters */ + DPNP_FN_NOT_EQUAL_EXT, /**< Used in numpy.not_equal() impl, requires extra parameters */ 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 */ diff --git a/dpnp/backend/kernels/dpnp_krnl_logic.cpp b/dpnp/backend/kernels/dpnp_krnl_logic.cpp index 6be989a4ec85..19a6dd3646e3 100644 --- a/dpnp/backend/kernels/dpnp_krnl_logic.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_logic.cpp @@ -536,8 +536,18 @@ DPCTLSyclEventRef (*dpnp_any_ext_c)(DPCTLSyclQueueRef, template static void func_map_logic_2arg_2type_core(func_map_t& fmap) { + ((fmap[DPNPFuncName::DPNP_FN_EQUAL_EXT][FT1][FTs] = + {eft_BLN, (void*)dpnp_equal_c_ext, func_type_map_t::find_type>}), ...); + ((fmap[DPNPFuncName::DPNP_FN_GREATER_EXT][FT1][FTs] = + {eft_BLN, (void*)dpnp_greater_c_ext, func_type_map_t::find_type>}), ...); + ((fmap[DPNPFuncName::DPNP_FN_GREATER_EQUAL_EXT][FT1][FTs] = + {eft_BLN, (void*)dpnp_greater_equal_c_ext, func_type_map_t::find_type>}), ...); + ((fmap[DPNPFuncName::DPNP_FN_LESS_EXT][FT1][FTs] = + {eft_BLN, (void*)dpnp_less_c_ext, func_type_map_t::find_type>}), ...); ((fmap[DPNPFuncName::DPNP_FN_LESS_EQUAL_EXT][FT1][FTs] = {eft_BLN, (void*)dpnp_less_equal_c_ext, func_type_map_t::find_type>}), ...); + ((fmap[DPNPFuncName::DPNP_FN_NOT_EQUAL_EXT][FT1][FTs] = + {eft_BLN, (void*)dpnp_not_equal_c_ext, func_type_map_t::find_type>}), ...); } template diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index 0c30fa18b6f9..50387e1565a0 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -127,6 +127,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_EIG_EXT DPNP_FN_EIGVALS DPNP_FN_EIGVALS_EXT + DPNP_FN_EQUAL_EXT DPNP_FN_ERF DPNP_FN_ERF_EXT DPNP_FN_EYE @@ -155,6 +156,8 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_FMOD_EXT DPNP_FN_FULL DPNP_FN_FULL_LIKE + DPNP_FN_GREATER_EXT + DPNP_FN_GREATER_EQUAL_EXT DPNP_FN_HYPOT DPNP_FN_HYPOT_EXT DPNP_FN_IDENTITY @@ -169,6 +172,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_KRON_EXT DPNP_FN_LEFT_SHIFT DPNP_FN_LEFT_SHIFT_EXT + DPNP_FN_LESS_EXT DPNP_FN_LESS_EQUAL_EXT DPNP_FN_LOG DPNP_FN_LOG_EXT @@ -204,6 +208,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_NEGATIVE_EXT DPNP_FN_NONZERO DPNP_FN_NONZERO_EXT + DPNP_FN_NOT_EQUAL_EXT DPNP_FN_ONES DPNP_FN_ONES_LIKE DPNP_FN_PARTITION diff --git a/dpnp/dpnp_algo/dpnp_algo_logic.pyx b/dpnp/dpnp_algo/dpnp_algo_logic.pyx index 0aa8f949cfbd..ae0f711eb109 100644 --- a/dpnp/dpnp_algo/dpnp_algo_logic.pyx +++ b/dpnp/dpnp_algo/dpnp_algo_logic.pyx @@ -166,46 +166,28 @@ cpdef utils.dpnp_descriptor dpnp_any(utils.dpnp_descriptor array1): return result -cpdef utils.dpnp_descriptor dpnp_equal(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2): - result_sycl_device, result_usm_type, result_sycl_queue = utils.get_common_usm_allocation(input1, input2) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(input1.shape, - dpnp.bool, - None, - device=result_sycl_device, - usm_type=result_usm_type, - sycl_queue=result_sycl_queue) - for i in range(result.size): - result.get_pyobj()[i] = dpnp.bool(input1.get_pyobj()[i] == input2.get_pyobj()[i]) +cpdef utils.dpnp_descriptor dpnp_equal(utils.dpnp_descriptor x1_obj, + utils.dpnp_descriptor x2_obj, + object dtype=None, + utils.dpnp_descriptor out=None, + object where=True): + return call_fptr_2in_1out_strides(DPNP_FN_EQUAL_EXT, x1_obj, x2_obj, dtype, out, where, func_name="equal") - return result +cpdef utils.dpnp_descriptor dpnp_greater(utils.dpnp_descriptor x1_obj, + utils.dpnp_descriptor x2_obj, + object dtype=None, + utils.dpnp_descriptor out=None, + object where=True): + return call_fptr_2in_1out_strides(DPNP_FN_GREATER_EXT, x1_obj, x2_obj, dtype, out, where, func_name="greater") -cpdef utils.dpnp_descriptor dpnp_greater(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2): - result_sycl_device, result_usm_type, result_sycl_queue = utils.get_common_usm_allocation(input1, input2) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(input1.shape, - dpnp.bool, - None, - device=result_sycl_device, - usm_type=result_usm_type, - sycl_queue=result_sycl_queue) - for i in range(result.size): - result.get_pyobj()[i] = dpnp.bool(input1.get_pyobj()[i] > input2.get_pyobj()[i]) - - return result - - -cpdef utils.dpnp_descriptor dpnp_greater_equal(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2): - result_sycl_device, result_usm_type, result_sycl_queue = utils.get_common_usm_allocation(input1, input2) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(input1.shape, - dpnp.bool, - None, - device=result_sycl_device, - usm_type=result_usm_type, - sycl_queue=result_sycl_queue) - for i in range(result.size): - result.get_pyobj()[i] = dpnp.bool(input1.get_pyobj()[i] >= input2.get_pyobj()[i]) - return result +cpdef utils.dpnp_descriptor dpnp_greater_equal(utils.dpnp_descriptor x1_obj, + utils.dpnp_descriptor x2_obj, + object dtype=None, + utils.dpnp_descriptor out=None, + object where=True): + return call_fptr_2in_1out_strides(DPNP_FN_GREATER_EQUAL_EXT, x1_obj, x2_obj, dtype, out, where, func_name="greater_equal") cpdef utils.dpnp_descriptor dpnp_isclose(utils.dpnp_descriptor input1, @@ -272,18 +254,12 @@ cpdef utils.dpnp_descriptor dpnp_isnan(utils.dpnp_descriptor input1): return result -cpdef utils.dpnp_descriptor dpnp_less(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2): - result_sycl_device, result_usm_type, result_sycl_queue = utils.get_common_usm_allocation(input1, input2) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(input1.shape, - dpnp.bool, - None, - device=result_sycl_device, - usm_type=result_usm_type, - sycl_queue=result_sycl_queue) - for i in range(result.size): - result.get_pyobj()[i] = dpnp.bool(input1.get_pyobj()[i] < input2.get_pyobj()[i]) - - return result +cpdef utils.dpnp_descriptor dpnp_less(utils.dpnp_descriptor x1_obj, + utils.dpnp_descriptor x2_obj, + object dtype=None, + utils.dpnp_descriptor out=None, + object where=True): + return call_fptr_2in_1out_strides(DPNP_FN_LESS_EXT, x1_obj, x2_obj, dtype, out, where, func_name="less") cpdef utils.dpnp_descriptor dpnp_less_equal(utils.dpnp_descriptor x1_obj, @@ -355,15 +331,9 @@ cpdef utils.dpnp_descriptor dpnp_logical_xor(utils.dpnp_descriptor input1, utils return result -cpdef utils.dpnp_descriptor dpnp_not_equal(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2): - result_sycl_device, result_usm_type, result_sycl_queue = utils.get_common_usm_allocation(input1, input2) - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(input1.shape, - dpnp.bool, - None, - device=result_sycl_device, - usm_type=result_usm_type, - sycl_queue=result_sycl_queue) - for i in range(result.size): - result.get_pyobj()[i] = dpnp.bool(input1.get_pyobj()[i] != input2.get_pyobj()[i]) - - return result +cpdef utils.dpnp_descriptor dpnp_not_equal(utils.dpnp_descriptor x1_obj, + utils.dpnp_descriptor x2_obj, + object dtype=None, + utils.dpnp_descriptor out=None, + object where=True): + return call_fptr_2in_1out_strides(DPNP_FN_NOT_EQUAL_EXT, x1_obj, x2_obj, dtype, out, where, func_name="not_equal") diff --git a/dpnp/dpnp_iface_logic.py b/dpnp/dpnp_iface_logic.py index 96fa795d4d61..153bac1b24fa 100644 --- a/dpnp/dpnp_iface_logic.py +++ b/dpnp/dpnp_iface_logic.py @@ -219,18 +219,32 @@ def any(x1, axis=None, out=None, keepdims=False): return call_origin(numpy.any, x1, axis, out, keepdims) -def equal(x1, x2): +def equal(x1, + x2, + /, + out=None, + *, + where=True, + dtype=None, + subok=True): """ - Return (x1 == x2) element-wise. + Return the truth value of (x1 == x2) element-wise. For full documentation refer to :obj:`numpy.equal`. + Returns + ------- + out : dpnp.ndarray + Output array of bool type, element-wise comparison of `x1` and `x2`. + Limitations ----------- - Parameter ``x1`` is supported as :obj:`dpnp.ndarray`. - Parameter ``x2`` is supported as either :obj:`dpnp.ndarray` or int. - Input array data types are limited by supported DPNP :ref:`Data types`. - Sizes, shapes and data types of input arrays ``x1`` and ``x2`` are supported to be equal. + Parameters `x1` and `x2` are supported as either :class:`dpnp.ndarray` or scalar, + but not both (at least either `x1` or `x2` should be as :class:`dpnp.ndarray`). + Parameters `out`, `where`, `dtype` and `subok` are supported with their default values. + Otherwise the function will be executed sequentially on CPU. + Input array data types are limited by supported DPNP :ref:`Data types`, + excluding `dpnp.complex64` and `dpnp.complex128`. See Also -------- @@ -250,33 +264,55 @@ def equal(x1, x2): [True, True, False] """ + + if out is not None: + pass + elif where is not True: + pass + elif dtype is not None: + pass + elif subok is not True: + pass + elif dpnp.isscalar(x1) and dpnp.isscalar(x2): + # at least either x1 or x2 has to be an array + pass + else: + # get a common queue to copy data from the host into a device if any input is scalar + queue = get_common_allocation_queue([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else None - # x1_desc = dpnp.get_dpnp_descriptor(x1) - # x2_desc = dpnp.get_dpnp_descriptor(x2) - # if x1_desc and x2_desc: - # if x1_desc.size != x2_desc.size: - # pass - # elif x1_desc.dtype != x2_desc.dtype: - # pass - # elif x1_desc.shape != x2_desc.shape: - # pass - # else: - # return dpnp_equal(x1_desc, x2_desc).get_pyobj() - + x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + if x1_desc and x2_desc: + return dpnp_equal(x1_desc, x2_desc).get_pyobj() return call_origin(numpy.equal, x1, x2) -def greater(x1, x2): +def greater(x1, + x2, + /, + out=None, + *, + where=True, + dtype=None, + subok=True): """ - Return (x1 > x2) element-wise. + Return the truth value of (x1 > x2) element-wise. For full documentation refer to :obj:`numpy.greater`. + Returns + ------- + out : dpnp.ndarray + Output array of bool type, element-wise comparison of `x1` and `x2`. + Limitations ----------- - At least either ``x1`` or ``x2`` should be as :obj:`dpnp.ndarray`. + Parameters `x1` and `x2` are supported as either :class:`dpnp.ndarray` or scalar, + but not both (at least either `x1` or `x2` should be as :class:`dpnp.ndarray`). + Parameters `out`, `where`, `dtype` and `subok` are supported with their default values. Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Input array data types are limited by supported DPNP :ref:`Data types`, + excluding `dpnp.complex64` and `dpnp.complex128`. See Also -------- @@ -297,30 +333,54 @@ def greater(x1, x2): """ - # x1_desc = dpnp.get_dpnp_descriptor(x1) - # x2_desc = dpnp.get_dpnp_descriptor(x2) - # if x1_desc and x2_desc: - # if x1_desc.size < 2: - # pass - # elif x2_desc.size < 2: - # pass - # else: - # return dpnp_greater(x1_desc, x2_desc).get_pyobj() + if out is not None: + pass + elif where is not True: + pass + elif dtype is not None: + pass + elif subok is not True: + pass + elif dpnp.isscalar(x1) and dpnp.isscalar(x2): + # at least either x1 or x2 has to be an array + pass + else: + # get a common queue to copy data from the host into a device if any input is scalar + queue = get_common_allocation_queue([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else None + x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + if x1_desc and x2_desc: + return dpnp_greater(x1_desc, x2_desc).get_pyobj() return call_origin(numpy.greater, x1, x2) -def greater_equal(x1, x2): +def greater_equal(x1, + x2, + /, + out=None, + *, + where=True, + dtype=None, + subok=True): """ - Return (x1 >= x2) element-wise. + Return the truth value of (x1 >= x2) element-wise. For full documentation refer to :obj:`numpy.greater_equal`. + Returns + ------- + out : dpnp.ndarray + Output array of bool type, element-wise comparison of `x1` and `x2`. + Limitations ----------- - At least either ``x1`` or ``x2`` should be as :obj:`dpnp.ndarray`. + Parameters `x1` and `x2` are supported as either :class:`dpnp.ndarray` or scalar, + but not both (at least either `x1` or `x2` should be as :class:`dpnp.ndarray`). + Parameters `out`, `where`, `dtype` and `subok` are supported with their default values. Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Input array data types are limited by supported DPNP :ref:`Data types`, + excluding `dpnp.complex64` and `dpnp.complex128`. See Also -------- @@ -341,16 +401,25 @@ def greater_equal(x1, x2): """ - # x1_desc = dpnp.get_dpnp_descriptor(x1) - # x2_desc = dpnp.get_dpnp_descriptor(x2) - # if x1_desc and x2_desc: - # if x1_desc.size < 2: - # pass - # elif x2_desc.size < 2: - # pass - # else: - # return dpnp_greater_equal(x1_desc, x2_desc).get_pyobj() + if out is not None: + pass + elif where is not True: + pass + elif dtype is not None: + pass + elif subok is not True: + pass + elif dpnp.isscalar(x1) and dpnp.isscalar(x2): + # at least either x1 or x2 has to be an array + pass + else: + # get a common queue to copy data from the host into a device if any input is scalar + queue = get_common_allocation_queue([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else None + x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + if x1_desc and x2_desc: + return dpnp_greater_equal(x1_desc, x2_desc).get_pyobj() return call_origin(numpy.greater_equal, x1, x2) @@ -532,17 +601,32 @@ def isnan(x1, out=None, **kwargs): return call_origin(numpy.isnan, x1, out, **kwargs) -def less(x1, x2): +def less(x1, + x2, + /, + out=None, + *, + where=True, + dtype=None, + subok=True): """ - Return (x1 < x2) element-wise. + Return the truth value of (x1 < x2) element-wise. For full documentation refer to :obj:`numpy.less`. + Returns + ------- + out : dpnp.ndarray + Output array of bool type, element-wise comparison of `x1` and `x2`. + Limitations ----------- - At least either ``x1`` or ``x2`` should be as :obj:`dpnp.ndarray`. + Parameters `x1` and `x2` are supported as either :class:`dpnp.ndarray` or scalar, + but not both (at least either `x1` or `x2` should be as :class:`dpnp.ndarray`). + Parameters `out`, `where`, `dtype` and `subok` are supported with their default values. Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Input array data types are limited by supported DPNP :ref:`Data types`, + excluding `dpnp.complex64` and `dpnp.complex128`. See Also -------- @@ -563,16 +647,25 @@ def less(x1, x2): """ - # x1_desc = dpnp.get_dpnp_descriptor(x1) - # x2_desc = dpnp.get_dpnp_descriptor(x2) - # if x1_desc and x2_desc: - # if x1_desc.size < 2: - # pass - # elif x2_desc.size < 2: - # pass - # else: - # return dpnp_less(x1_desc, x2_desc).get_pyobj() + if out is not None: + pass + elif where is not True: + pass + elif dtype is not None: + pass + elif subok is not True: + pass + elif dpnp.isscalar(x1) and dpnp.isscalar(x2): + # at least either x1 or x2 has to be an array + pass + else: + # get a common queue to copy data from the host into a device if any input is scalar + queue = get_common_allocation_queue([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else None + x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + if x1_desc and x2_desc: + return dpnp_less(x1_desc, x2_desc).get_pyobj() return call_origin(numpy.less, x1, x2) @@ -813,18 +906,32 @@ def logical_xor(x1, x2, out=None, **kwargs): return call_origin(numpy.logical_xor, x1, x2, out, **kwargs) -def not_equal(x1, x2): +def not_equal(x1, + x2, + /, + out=None, + *, + where=True, + dtype=None, + subok=True): """ - Return (x1 != x2) element-wise. + Return the truth value of (x1 != x2) element-wise. For full documentation refer to :obj:`numpy.not_equal`. + Returns + ------- + out : dpnp.ndarray + Output array of bool type, element-wise comparison of `x1` and `x2`. + Limitations ----------- - At least either ``x1`` or ``x2`` should be as :obj:`dpnp.ndarray`. - If either ``x1`` or ``x2`` is scalar then other one should be :obj:`dpnp.ndarray`. + Parameters `x1` and `x2` are supported as either :class:`dpnp.ndarray` or scalar, + but not both (at least either `x1` or `x2` should be as :class:`dpnp.ndarray`). + Parameters `out`, `where`, `dtype` and `subok` are supported with their default values. Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Input array data types are limited by supported DPNP :ref:`Data types`, + excluding `dpnp.complex64` and `dpnp.complex128`. See Also -------- @@ -845,16 +952,23 @@ def not_equal(x1, x2): """ - # x1_desc = dpnp.get_dpnp_descriptor(x1) - # x2_desc = dpnp.get_dpnp_descriptor(x2) - # if x1_desc and x2_desc: - # if x1_desc.size < 2: - # pass - # elif x2_desc.size < 2: - # pass - # else: - # result = dpnp_not_equal(x1_desc, x2_desc).get_pyobj() - - # return result + if out is not None: + pass + elif where is not True: + pass + elif dtype is not None: + pass + elif subok is not True: + pass + elif dpnp.isscalar(x1) and dpnp.isscalar(x2): + # at least either x1 or x2 has to be an array + pass + else: + # get a common queue to copy data from the host into a device if any input is scalar + queue = get_common_allocation_queue([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else None + x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False, alloc_queue=queue) + if x1_desc and x2_desc: + return dpnp_not_equal(x1_desc, x2_desc).get_pyobj() return call_origin(numpy.not_equal, x1, x2) diff --git a/tests/test_linalg.py b/tests/test_linalg.py index dd89a18adbd6..ac8392d15384 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -278,7 +278,6 @@ def test_qr(type, shape, mode): numpy.testing.assert_allclose(dpnp_r, np_r, rtol=tol, atol=tol) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize("type", [numpy.float64, numpy.float32, numpy.int64, numpy.int32], ids=['float64', 'float32', 'int64', 'int32']) diff --git a/tests/test_logic.py b/tests/test_logic.py index d79ffaa744f4..062300bb8d3a 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -99,7 +99,15 @@ def test_any(type, shape): assert_allclose(dpnp_res, np_res) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") +def test_equal(): + a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8]) + ia = dpnp.array(a) + for i in range(len(a)): + np_res = (a == i) + dpnp_res = (ia == i) + assert_equal(dpnp_res, np_res) + + def test_greater(): a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8]) ia = dpnp.array(a) @@ -109,7 +117,6 @@ def test_greater(): assert_equal(dpnp_res, np_res) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_greater_equal(): a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8]) ia = dpnp.array(a) @@ -119,7 +126,6 @@ def test_greater_equal(): assert_equal(dpnp_res, np_res) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_less(): a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8]) ia = dpnp.array(a) @@ -138,7 +144,6 @@ def test_less_equal(): assert_equal(dpnp_res, np_res) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_not_equal(): a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8]) ia = dpnp.array(a) @@ -147,9 +152,10 @@ def test_not_equal(): dpnp_res = (ia != i) assert_equal(dpnp_res, np_res) + @pytest.mark.parametrize("op", - ['less_equal'], - ids=['less_equal']) + ['equal', 'greater', 'greater_equal', 'less', 'less_equal', 'not_equal'], + ids=['equal', 'greater', 'greater_equal', 'less', 'less_equal', 'not_equal']) @pytest.mark.parametrize("x1", [[3, 4, 5, 6], [[1, 2, 3, 4], [5, 6, 7, 8]], [[1, 2, 5, 6], [3, 4, 7, 8], [1, 2, 7, 8]]], ids=['[3, 4, 5, 6]', '[[1, 2, 3, 4], [5, 6, 7, 8]]', '[[1, 2, 5, 6], [3, 4, 7, 8], [1, 2, 7, 8]]']) @@ -177,9 +183,10 @@ def test_elemwise_comparison(op, x1, x2): dpnp_res = getattr(dpnp, op)(dp_x1[::-1], dp_x2) assert_equal(dpnp_res, np_res) + @pytest.mark.parametrize("op", - ['less_equal'], - ids=['less_equal']) + ['equal', 'greater', 'greater_equal', 'less', 'less_equal', 'not_equal'], + ids=['equal', 'greater', 'greater_equal', 'less', 'less_equal', 'not_equal']) @pytest.mark.parametrize("sh1", [[10], [8, 4], [4, 1, 2]], ids=['(10,)', '(8, 4)', '(4, 1, 2)']) diff --git a/tests/test_random.py b/tests/test_random.py index 54cb2fa3a4d7..bc3501f4d20b 100644 --- a/tests/test_random.py +++ b/tests/test_random.py @@ -75,7 +75,6 @@ def test_input_shape(func): assert shape == res.shape -@pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize("func", [dpnp.random.random, dpnp.random.random_sample, diff --git a/tests/test_random_state.py b/tests/test_random_state.py index 1a5d554e14d5..0d1752c744ee 100644 --- a/tests/test_random_state.py +++ b/tests/test_random_state.py @@ -322,7 +322,6 @@ def test_negative_bounds(self): assert_array_equal(actual, desired) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_negative_interval(self): rs = RandomState(3567) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 977f4561f5a0..a184ec51c253 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -655,7 +655,6 @@ def test_qr(device): assert_sycl_queue_equal(dpnp_r_queue, expected_queue) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize("device", valid_devices, ids=[device.filter_string for device in valid_devices]) @@ -663,7 +662,7 @@ def test_svd(device): tol = 1e-12 shape = (2,2) numpy_data = numpy.arange(shape[0] * shape[1]).reshape(shape) - dpnp_data = dpnp.arange(shape[0] * shape[1]).reshape(shape) + dpnp_data = dpnp.arange(shape[0] * shape[1], device=device).reshape(shape) np_u, np_s, np_vt = numpy.linalg.svd(numpy_data) dpnp_u, dpnp_s, dpnp_vt = dpnp.linalg.svd(dpnp_data) @@ -675,7 +674,7 @@ def test_svd(device): assert (dpnp_vt.shape == np_vt.shape) # check decomposition - dpnp_diag_s = dpnp.zeros(shape, dtype=dpnp_s.dtype) + dpnp_diag_s = dpnp.zeros(shape, dtype=dpnp_s.dtype, device=device) for i in range(dpnp_s.size): dpnp_diag_s[i, i] = dpnp_s[i] diff --git a/tests/third_party/cupy/logic_tests/test_comparison.py b/tests/third_party/cupy/logic_tests/test_comparison.py index 4afcea568ffc..461f00319bc7 100644 --- a/tests/third_party/cupy/logic_tests/test_comparison.py +++ b/tests/third_party/cupy/logic_tests/test_comparison.py @@ -11,7 +11,6 @@ @testing.gpu class TestComparison(unittest.TestCase): - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose(atol=1e-5) def check_binary(self, name, xp, dtype): @@ -19,26 +18,21 @@ def check_binary(self, name, xp, dtype): b = testing.shaped_reverse_arange((2, 3), xp, dtype) return getattr(xp, name)(a, b) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_greater(self): self.check_binary('greater') - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_greater_equal(self): self.check_binary('greater_equal') - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_less(self): self.check_binary('less') def test_less_equal(self): self.check_binary('less_equal') - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_not_equal(self): self.check_binary('not_equal') - @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_equal(self): self.check_binary('equal')