diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 9ad801cf5fd4..bc9f64aae4ae 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -17,6 +17,7 @@ env: test_dparray.py test_fft.py test_linalg.py + test_logic.py test_mathematical.py test_random_state.py test_sort.py @@ -24,6 +25,7 @@ env: test_umath.py test_usm_type.py third_party/cupy/linalg_tests/test_product.py + third_party/cupy/logic_tests/test_truth.py third_party/cupy/manipulation_tests/test_join.py third_party/cupy/math_tests/test_explog.py third_party/cupy/math_tests/test_misc.py diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 96b858854731..c7a9f9f701af 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -65,14 +65,12 @@ enum class DPNPFuncName : size_t DPNP_FN_ADD, /**< Used in numpy.add() impl */ DPNP_FN_ADD_EXT, /**< Used in numpy.add() impl, requires extra parameters */ DPNP_FN_ALL, /**< Used in numpy.all() impl */ - DPNP_FN_ALL_EXT, /**< Used in numpy.all() impl, requires extra parameters */ - DPNP_FN_ALLCLOSE, /**< Used in numpy.allclose() impl */ - DPNP_FN_ALLCLOSE_EXT, /**< Used in numpy.allclose() impl, requires extra - parameters */ - DPNP_FN_ANY, /**< Used in numpy.any() impl */ - DPNP_FN_ANY_EXT, /**< Used in numpy.any() impl, requires extra parameters */ - DPNP_FN_ARANGE, /**< Used in numpy.arange() impl */ - DPNP_FN_ARCCOS, /**< Used in numpy.arccos() impl */ + DPNP_FN_ALLCLOSE, /**< Used in numpy.allclose() impl */ + DPNP_FN_ALLCLOSE_EXT, /**< Used in numpy.allclose() impl, requires extra + parameters */ + DPNP_FN_ANY, /**< Used in numpy.any() impl */ + DPNP_FN_ARANGE, /**< Used in numpy.arange() impl */ + DPNP_FN_ARCCOS, /**< Used in numpy.arccos() impl */ DPNP_FN_ARCCOS_EXT, /**< Used in numpy.arccos() impl, requires extra parameters */ DPNP_FN_ARCCOSH, /**< Used in numpy.arccosh() impl */ diff --git a/dpnp/backend/kernels/dpnp_krnl_logic.cpp b/dpnp/backend/kernels/dpnp_krnl_logic.cpp index e2fe0d460cfc..1757d053416a 100644 --- a/dpnp/backend/kernels/dpnp_krnl_logic.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_logic.cpp @@ -640,21 +640,6 @@ void func_map_init_logic(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_ALL][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_all_default_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_BLN][eft_BLN] = { - eft_BLN, (void *)dpnp_all_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_all_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_all_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_all_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_all_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_C64][eft_C64] = { - eft_C64, (void *)dpnp_all_ext_c, bool>}; - fmap[DPNPFuncName::DPNP_FN_ALL_EXT][eft_C128][eft_C128] = { - eft_C128, (void *)dpnp_all_ext_c, bool>}; - fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_INT][eft_INT] = { eft_BLN, (void *)dpnp_allclose_default_c}; fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_LNG][eft_INT] = { @@ -732,21 +717,6 @@ void func_map_init_logic(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_ANY][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_any_default_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_BLN][eft_BLN] = { - eft_BLN, (void *)dpnp_any_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_any_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_any_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_any_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_any_ext_c}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_C64][eft_C64] = { - eft_C64, (void *)dpnp_any_ext_c, bool>}; - fmap[DPNPFuncName::DPNP_FN_ANY_EXT][eft_C128][eft_C128] = { - eft_C128, (void *)dpnp_any_ext_c, bool>}; - func_map_logic_2arg_2type_helper(fmap); diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index 37d4a7d3694a..f560545f5022 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -35,12 +35,8 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na cdef enum DPNPFuncName "DPNPFuncName": DPNP_FN_ABSOLUTE DPNP_FN_ABSOLUTE_EXT - DPNP_FN_ALL - DPNP_FN_ALL_EXT DPNP_FN_ALLCLOSE DPNP_FN_ALLCLOSE_EXT - DPNP_FN_ANY - DPNP_FN_ANY_EXT DPNP_FN_ARANGE DPNP_FN_ARCCOS DPNP_FN_ARCCOS_EXT diff --git a/dpnp/dpnp_algo/dpnp_algo_logic.pxi b/dpnp/dpnp_algo/dpnp_algo_logic.pxi index d5cf2aa740d1..cb97670f4777 100644 --- a/dpnp/dpnp_algo/dpnp_algo_logic.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_logic.pxi @@ -36,16 +36,11 @@ and the rest of the library # NO IMPORTs here. All imports must be placed into main "dpnp_algo.pyx" file __all__ += [ - "dpnp_all", "dpnp_allclose", - "dpnp_any", "dpnp_isclose", ] -ctypedef c_dpctl.DPCTLSyclEventRef(*custom_logic_1in_1out_func_ptr_t)(c_dpctl.DPCTLSyclQueueRef, - void *, void * , const size_t, - const c_dpctl.DPCTLEventVectorRef) ctypedef c_dpctl.DPCTLSyclEventRef(*custom_allclose_1in_1out_func_ptr_t)(c_dpctl.DPCTLSyclQueueRef, void * , void * , @@ -56,35 +51,6 @@ ctypedef c_dpctl.DPCTLSyclEventRef(*custom_allclose_1in_1out_func_ptr_t)(c_dpctl const c_dpctl.DPCTLEventVectorRef) -cpdef utils.dpnp_descriptor dpnp_all(utils.dpnp_descriptor array1): - array1_obj = array1.get_array() - - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py((1,), - dpnp.bool, - None, - device=array1_obj.sycl_device, - usm_type=array1_obj.usm_type, - sycl_queue=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 DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_ALL_EXT, param1_type, param1_type) - - cdef custom_logic_1in_1out_func_ptr_t func = kernel_data.ptr - - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, array1.get_data(), result.get_data(), array1.size, NULL) - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - cpdef utils.dpnp_descriptor dpnp_allclose(utils.dpnp_descriptor array1, utils.dpnp_descriptor array2, double rtol_val, @@ -125,35 +91,6 @@ cpdef utils.dpnp_descriptor dpnp_allclose(utils.dpnp_descriptor array1, return result -cpdef utils.dpnp_descriptor dpnp_any(utils.dpnp_descriptor array1): - array1_obj = array1.get_array() - - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py((1,), - dpnp.bool, - None, - device=array1_obj.sycl_device, - usm_type=array1_obj.usm_type, - sycl_queue=array1_obj.sycl_queue) - - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_ANY_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_logic_1in_1out_func_ptr_t func = kernel_data.ptr - - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, array1.get_data(), result.get_data(), array1.size, NULL) - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - cpdef utils.dpnp_descriptor dpnp_isclose(utils.dpnp_descriptor input1, utils.dpnp_descriptor input2, double rtol=1e-05, diff --git a/dpnp/dpnp_iface_logic.py b/dpnp/dpnp_iface_logic.py index f00b61f8ed23..a560b71a1a6f 100644 --- a/dpnp/dpnp_iface_logic.py +++ b/dpnp/dpnp_iface_logic.py @@ -40,10 +40,12 @@ """ +import dpctl.tensor as dpt import numpy import dpnp from dpnp.dpnp_algo import * +from dpnp.dpnp_array import dpnp_array from dpnp.dpnp_utils import * from .dpnp_algo.dpnp_elementwise_common import ( @@ -84,24 +86,29 @@ ] -def all(x1, /, axis=None, out=None, keepdims=False, *, where=True): +def all(x, /, axis=None, out=None, keepdims=False, *, where=True): """ Test whether all array elements along a given axis evaluate to True. For full documentation refer to :obj:`numpy.all`. + Returns + ------- + dpnp.ndarray + An array with a data type of `bool` + containing the results of the logical AND reduction. + Limitations ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. + Parameters `x` is supported either as :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. + Parameters `out` and `where` are supported with default value. Input array data types are limited by supported DPNP :ref:`Data types`. - Parameter `axis` is supported only with default value `None`. - Parameter `out` is supported only with default value `None`. - Parameter `keepdims` is supported only with default value `False`. - Parameter `where` is supported only with default value `True`. + Otherwise the function will be executed sequentially on CPU. See Also -------- + :obj:`dpnp.ndarray.all` : equivalent method :obj:`dpnp.any` : Test whether any element along a given axis evaluates to True. Notes @@ -111,35 +118,37 @@ def all(x1, /, axis=None, out=None, keepdims=False, *, where=True): Examples -------- - >>> import dpnp as dp - >>> x = dp.array([[True, False], [True, True]]) - >>> dp.all(x) - False - >>> x2 = dp.array([-1, 4, 5]) - >>> dp.all(x2) - True - >>> x3 = dp.array([1.0, dp.nan]) - >>> dp.all(x3) - True + >>> import dpnp as np + >>> x = np.array([[True, False], [True, True]]) + >>> np.all(x) + array(False) + + >>> np.all(x, axis=0) + array([ True, False]) + + >>> x2 = np.array([-1, 4, 5]) + >>> np.all(x2) + array(True) + + >>> x3 = np.array([1.0, np.nan]) + >>> np.all(x3) + array(True) """ - 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 - elif keepdims is not False: + if dpnp.is_supported_array_type(x): + if out is not None: pass elif where is not True: pass else: - result_obj = dpnp_all(x1_desc).get_pyobj() - return dpnp.convert_single_elem_array_to_scalar(result_obj) + dpt_array = dpnp.get_usm_ndarray(x) + return dpnp_array._create_from_usm_ndarray( + dpt.all(dpt_array, axis=axis, keepdims=keepdims) + ) return call_origin( - numpy.all, x1, axis=axis, out=out, keepdims=keepdims, where=where + numpy.all, x, axis=axis, out=out, keepdims=keepdims, where=where ) @@ -181,24 +190,29 @@ def allclose(x1, x2, rtol=1.0e-5, atol=1.0e-8, **kwargs): return call_origin(numpy.allclose, x1, x2, rtol=rtol, atol=atol, **kwargs) -def any(x1, /, axis=None, out=None, keepdims=False, *, where=True): +def any(x, /, axis=None, out=None, keepdims=False, *, where=True): """ Test whether any array element along a given axis evaluates to True. For full documentation refer to :obj:`numpy.any`. + Returns + ------- + dpnp.ndarray + An array with a data type of `bool` + containing the results of the logical OR reduction. + Limitations ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. + Parameters `x` is supported either as :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. + Parameters `out` and `where` are supported with default value. Input array data types are limited by supported DPNP :ref:`Data types`. - Parameter `axis` is supported only with default value `None`. - Parameter `out` is supported only with default value `None`. - Parameter `keepdims` is supported only with default value `False`. - Parameter `where` is supported only with default value `True`. + Otherwise the function will be executed sequentially on CPU. See Also -------- + :obj:`dpnp.ndarray.any` : equivalent method :obj:`dpnp.all` : Test whether all elements along a given axis evaluate to True. Notes @@ -208,35 +222,37 @@ def any(x1, /, axis=None, out=None, keepdims=False, *, where=True): Examples -------- - >>> import dpnp as dp - >>> x = dp.array([[True, False], [True, True]]) - >>> dp.any(x) - True - >>> x2 = dp.array([0, 0, 0]) - >>> dp.any(x2) - False - >>> x3 = dp.array([1.0, dp.nan]) - >>> dp.any(x3) - True + >>> import dpnp as np + >>> x = np.array([[True, False], [True, True]]) + >>> np.any(x) + array(True) + + >>> np.any(x, axis=0) + array([ True, True]) + + >>> x2 = np.array([0, 0, 0]) + >>> np.any(x2) + array(False) + + >>> x3 = np.array([1.0, np.nan]) + >>> np.any(x3) + array(True) """ - 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 - elif keepdims is not False: + if dpnp.is_supported_array_type(x): + if out is not None: pass elif where is not True: pass else: - result_obj = dpnp_any(x1_desc).get_pyobj() - return dpnp.convert_single_elem_array_to_scalar(result_obj) + dpt_array = dpnp.get_usm_ndarray(x) + return dpnp_array._create_from_usm_ndarray( + dpt.any(dpt_array, axis=axis, keepdims=keepdims) + ) return call_origin( - numpy.any, x1, axis=axis, out=out, keepdims=keepdims, where=where + numpy.any, x, axis=axis, out=out, keepdims=keepdims, where=where ) diff --git a/tests/third_party/cupy/logic_tests/test_truth.py b/tests/third_party/cupy/logic_tests/test_truth.py new file mode 100644 index 000000000000..aa0e563ec42a --- /dev/null +++ b/tests/third_party/cupy/logic_tests/test_truth.py @@ -0,0 +1,91 @@ +import unittest + +import numpy +import pytest + +from tests.third_party.cupy import testing + + +def _calc_out_shape(shape, axis, keepdims): + if axis is None: + axis = list(range(len(shape))) + elif isinstance(axis, int): + axis = [axis] + else: + axis = list(axis) + + shape = numpy.array(shape) + + if keepdims: + shape[axis] = 1 + else: + shape[axis] = -1 + shape = filter(lambda x: x != -1, shape) + return tuple(shape) + + +@testing.parameterize( + *testing.product( + { + "f": ["all", "any"], + "x": [ + numpy.arange(24).reshape(2, 3, 4) - 10, + numpy.zeros((2, 3, 4)), + numpy.ones((2, 3, 4)), + numpy.zeros((0, 3, 4)), + numpy.ones((0, 3, 4)), + ], + "axis": [None, (0, 1, 2), 0, 1, 2, (0, 1)], + "keepdims": [False, True], + } + ) +) +class TestAllAny(unittest.TestCase): + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_without_out(self, xp, dtype): + x = xp.asarray(self.x).astype(dtype) + return getattr(xp, self.f)(x, self.axis, None, self.keepdims) + + @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @testing.for_all_dtypes() + @testing.numpy_cupy_array_equal() + def test_with_out(self, xp, dtype): + x = xp.asarray(self.x).astype(dtype) + out_shape = _calc_out_shape(x.shape, self.axis, self.keepdims) + out = xp.empty(out_shape, dtype=x.dtype) + getattr(xp, self.f)(x, self.axis, out, self.keepdims) + return out + + +@testing.parameterize( + *testing.product( + { + "f": ["all", "any"], + "x": [ + numpy.array([[[numpy.nan]]]), + numpy.array([[[numpy.nan, 0]]]), + numpy.array([[[numpy.nan, 1]]]), + numpy.array([[[numpy.nan, 0, 1]]]), + ], + "axis": [None, (0, 1, 2), 0, 1, 2, (0, 1)], + "keepdims": [False, True], + } + ) +) +class TestAllAnyWithNaN(unittest.TestCase): + @testing.for_dtypes((*testing.helper._float_dtypes, numpy.bool_)) + @testing.numpy_cupy_array_equal() + def test_without_out(self, xp, dtype): + x = xp.asarray(self.x).astype(dtype) + return getattr(xp, self.f)(x, self.axis, None, self.keepdims) + + @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @testing.for_dtypes((*testing.helper._float_dtypes, numpy.bool_)) + @testing.numpy_cupy_array_equal() + def test_with_out(self, xp, dtype): + x = xp.asarray(self.x).astype(dtype) + out_shape = _calc_out_shape(x.shape, self.axis, self.keepdims) + out = xp.empty(out_shape, dtype=x.dtype) + getattr(xp, self.f)(x, self.axis, out, self.keepdims) + return out