diff --git a/doc/reference/math.rst b/doc/reference/math.rst index 2b8b2befd79..bc4747429f9 100644 --- a/doc/reference/math.rst +++ b/doc/reference/math.rst @@ -66,17 +66,17 @@ Sums, products, differences dpnp.prod dpnp.sum + dpnp.nanprod + dpnp.nansum dpnp.cumprod dpnp.cumsum dpnp.nancumprod dpnp.nancumsum - dpnp.nansum - dpnp.nanprod - dpnp.cross dpnp.diff dpnp.ediff1d dpnp.gradient dpnp.trapz + dpnp.cross Exponents and logarithms diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 4b8c4e86c0d..4825ef4cd17 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -108,8 +108,6 @@ enum class DPNPFuncName : size_t DPNP_FN_CUMPROD_EXT, /**< Used in numpy.cumprod() impl, requires extra parameters */ DPNP_FN_CUMSUM, /**< Used in numpy.cumsum() impl */ - DPNP_FN_CUMSUM_EXT, /**< Used in numpy.cumsum() impl, requires extra - parameters */ DPNP_FN_DEGREES, /**< Used in numpy.degrees() impl */ DPNP_FN_DEGREES_EXT, /**< Used in numpy.degrees() impl, requires extra parameters */ diff --git a/dpnp/backend/kernels/dpnp_krnl_mathematical.cpp b/dpnp/backend/kernels/dpnp_krnl_mathematical.cpp index b3552763c82..df73e0b0aa5 100644 --- a/dpnp/backend/kernels/dpnp_krnl_mathematical.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_mathematical.cpp @@ -425,14 +425,6 @@ template void (*dpnp_cumsum_default_c)(void *, void *, size_t) = dpnp_cumsum_c<_DataType_input, _DataType_output>; -template -DPCTLSyclEventRef (*dpnp_cumsum_ext_c)(DPCTLSyclQueueRef, - void *, - void *, - size_t, - const DPCTLEventVectorRef) = - dpnp_cumsum_c<_DataType_input, _DataType_output>; - template class dpnp_ediff1d_c_kernel; @@ -1179,15 +1171,6 @@ void func_map_init_mathematical(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_cumsum_default_c}; - fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_INT][eft_INT] = { - eft_LNG, (void *)dpnp_cumsum_ext_c}; - fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_cumsum_ext_c}; - fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_cumsum_ext_c}; - fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_cumsum_ext_c}; - fmap[DPNPFuncName::DPNP_FN_EDIFF1D][eft_INT][eft_INT] = { eft_LNG, (void *)dpnp_ediff1d_default_c}; fmap[DPNPFuncName::DPNP_FN_EDIFF1D][eft_LNG][eft_LNG] = { diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index cc87448fc5a..ee12ffa4947 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -38,7 +38,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_COPY_EXT DPNP_FN_CORRELATE_EXT DPNP_FN_CUMPROD_EXT - DPNP_FN_CUMSUM_EXT DPNP_FN_DEGREES_EXT DPNP_FN_DIAG_INDICES_EXT DPNP_FN_DIAGONAL_EXT diff --git a/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi b/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi index 3f7c129cbbd..9a3017b2a92 100644 --- a/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi @@ -45,7 +45,6 @@ __all__ += [ "dpnp_fmin", "dpnp_modf", "dpnp_nancumprod", - "dpnp_nancumsum", "dpnp_trapz", ] @@ -70,18 +69,6 @@ cpdef utils.dpnp_descriptor dpnp_cumprod(utils.dpnp_descriptor x1): return call_fptr_1in_1out(DPNP_FN_CUMPROD_EXT, x1, (x1.size,)) -cpdef utils.dpnp_descriptor dpnp_cumsum(utils.dpnp_descriptor x1): - # instead of x1.shape, (x1.size, ) is passed to the function - # due to the following: - # >>> import numpy - # >>> a = numpy.array([[1, 2], [2, 3]]) - # >>> res = numpy.cumsum(a) - # >>> res.shape - # (4,) - - return call_fptr_1in_1out(DPNP_FN_CUMSUM_EXT, x1, (x1.size,)) - - cpdef utils.dpnp_descriptor dpnp_ediff1d(utils.dpnp_descriptor x1): if x1.size <= 1: @@ -253,19 +240,6 @@ cpdef utils.dpnp_descriptor dpnp_nancumprod(utils.dpnp_descriptor x1): return dpnp_cumprod(x1_desc) -cpdef utils.dpnp_descriptor dpnp_nancumsum(utils.dpnp_descriptor x1): - cur_x1 = x1.get_pyobj().copy() - - cur_x1_flatiter = cur_x1.flat - - for i in range(cur_x1.size): - if dpnp.isnan(cur_x1_flatiter[i]): - cur_x1_flatiter[i] = 0 - - x1_desc = dpnp.get_dpnp_descriptor(cur_x1, copy_when_nondefault_queue=False) - return dpnp_cumsum(x1_desc) - - cpdef utils.dpnp_descriptor dpnp_trapz(utils.dpnp_descriptor y1, utils.dpnp_descriptor x1, double dx): cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(y1.dtype) diff --git a/dpnp/dpnp_iface_nanfunctions.py b/dpnp/dpnp_iface_nanfunctions.py index f9386be7608..07c74671a00 100644 --- a/dpnp/dpnp_iface_nanfunctions.py +++ b/dpnp/dpnp_iface_nanfunctions.py @@ -46,7 +46,6 @@ # pylint: disable=no-name-in-module from .dpnp_algo import ( dpnp_nancumprod, - dpnp_nancumsum, ) from .dpnp_utils import ( call_origin, @@ -292,43 +291,68 @@ def nancumprod(x1, **kwargs): return call_origin(numpy.nancumprod, x1, **kwargs) -def nancumsum(x1, **kwargs): +def nancumsum(a, axis=None, dtype=None, out=None): """ - Return the cumulative sum of the elements along a given axis. + Return the cumulative sum of array elements over a given axis treating + Not a Numbers (NaNs) as zero. The cumulative sum does not change when NaNs + are encountered and leading NaNs are replaced by zeros. For full documentation refer to :obj:`numpy.nancumsum`. - Limitations - ----------- - Parameter `x` is supported as :class:`dpnp.ndarray`. - Keyword argument `kwargs` is currently unsupported. - Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axis : int, optional + Axis along which the cumulative sum is computed. The default (``None``) + is to compute the cumsum over the flattened array. + dtype : dtype, optional + Type of the returned array and of the accumulator in which the elements + are summed. If `dtype` is not specified, it defaults to the dtype of + `a`, unless `a` has an integer dtype with a precision less than that of + the default platform integer. In that case, the default platform + integer is used. + out : {dpnp.ndarray, usm_ndarray}, optional + Alternative output array in which to place the result. It must have the + same shape and buffer length as the expected output but the type will + be cast if necessary. + + Returns + ------- + out : dpnp.ndarray + A new array holding the result is returned unless `out` is specified as + :class:`dpnp.ndarray`, in which case a reference to `out` is returned. + The result has the same size as `a`, and the same shape as `a` if `axis` + is not ``None`` or `a` is a 1-d array. See Also -------- - :obj:`dpnp.cumsum` : Return the cumulative sum of the elements - along a given axis. + :obj:`dpnp.cumsum` : Cumulative sum across array propagating NaNs. + :obj:`dpnp.isnan` : Show which elements are NaN. Examples -------- >>> import dpnp as np - >>> a = np.array([1., np.nan]) - >>> result = np.nancumsum(a) - >>> [x for x in result] - [1.0, 1.0] - >>> b = np.array([[1., 2., np.nan], [4., np.nan, 6.]]) - >>> result = np.nancumprod(b) - >>> [x for x in result] - [1.0, 3.0, 3.0, 7.0, 7.0, 13.0] + >>> np.nancumsum(np.array(1)) + array([1]) + >>> np.nancumsum(np.array([1])) + array([1]) + >>> np.nancumsum(np.array([1, np.nan])) + array([1., 1.]) + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nancumsum(a) + array([1., 3., 6., 6.]) + >>> np.nancumsum(a, axis=0) + array([[1., 2.], + [4., 2.]]) + >>> np.nancumsum(a, axis=1) + array([[1., 3.], + [3., 3.]]) """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and not kwargs: - return dpnp_nancumsum(x1_desc).get_pyobj() - - return call_origin(numpy.nancumsum, x1, **kwargs) + a, _ = _replace_nan(a, 0) + return dpnp.cumsum(a, axis=axis, dtype=dtype, out=out) def nanmax(a, axis=None, out=None, keepdims=False, initial=None, where=True): diff --git a/tests/test_linalg.py b/tests/test_linalg.py index b5b0d8f3897..e2ade89d9ea 100644 --- a/tests/test_linalg.py +++ b/tests/test_linalg.py @@ -961,13 +961,10 @@ def test_norm_0D(self, ord, axis): def test_norm_1D(self, dtype, ord, axis, keepdims): a = numpy.array(numpy.random.uniform(-5, 5, 10), dtype=dtype) ia = inp.array(a) + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims) - # use only type kinds check when dpnp handles complex64 arrays - # since `dpnp.sum()` and `numpy.sum()` return different dtypes - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.float32) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_complex_dtypes()) @@ -983,11 +980,10 @@ def test_norm_1D_complex(self, dtype, ord, axis, keepdims): x2 = numpy.random.uniform(-5, 5, 10) a = numpy.array(x1 + 1j * x2, dtype=dtype) ia = inp.array(a) + result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims) - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.complex64) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) @@ -1027,9 +1023,7 @@ def test_norm_2D(self, dtype, ord, axis, keepdims): expected = numpy.linalg.norm( a, ord=ord, axis=axis, keepdims=keepdims ) - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.float32) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_complex_dtypes()) @@ -1069,9 +1063,7 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims): expected = numpy.linalg.norm( a, ord=ord, axis=axis, keepdims=keepdims ) - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.complex64) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) @@ -1117,9 +1109,7 @@ def test_norm_ND(self, dtype, ord, axis, keepdims): expected = numpy.linalg.norm( a, ord=ord, axis=axis, keepdims=keepdims ) - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.float32) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_complex_dtypes()) @@ -1165,9 +1155,7 @@ def test_norm_ND_complex(self, dtype, ord, axis, keepdims): expected = numpy.linalg.norm( a, ord=ord, axis=axis, keepdims=keepdims ) - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == inp.complex64) - ) + assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize("dtype", get_all_dtypes()) @@ -1213,11 +1201,7 @@ def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims): expected = numpy.linalg.norm( a, ord=ord, axis=axis, keepdims=keepdims ) - assert_dtype_allclose( - result, - expected, - check_only_type_kind=(dtype in [inp.float32, inp.complex64]), - ) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("stride", [3, -1, -5], ids=["3", "-1", "-5"]) def test_norm_strided_1D(self, stride): diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 0968f0fe280..acd69452975 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -720,42 +720,6 @@ def test_power_scalar(shape, dtype): assert_allclose(result, expected, rtol=1e-6) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@pytest.mark.parametrize( - "array", - [ - [1, 2, 3, 4, 5], - [1, 2, numpy.nan, 4, 5], - [[1, 2, numpy.nan], [3, -4, -5]], - ], -) -def test_nancumprod(array): - np_a = numpy.array(array) - dpnp_a = dpnp.array(np_a) - - result = dpnp.nancumprod(dpnp_a) - expected = numpy.nancumprod(np_a) - assert_array_equal(expected, result) - - -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -@pytest.mark.parametrize( - "array", - [ - [1, 2, 3, 4, 5], - [1, 2, numpy.nan, 4, 5], - [[1, 2, numpy.nan], [3, -4, -5]], - ], -) -def test_nancumsum(array): - np_a = numpy.array(array) - dpnp_a = dpnp.array(np_a) - - result = dpnp.nancumsum(dpnp_a) - expected = numpy.nancumsum(np_a) - assert_array_equal(expected, result) - - @pytest.mark.parametrize( "data", [[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]], @@ -2519,71 +2483,6 @@ def test_sum(shape, dtype_in, dtype_out, transpose, keepdims, order): assert_array_equal(numpy_res, dpnp_res.asnumpy()) -class TestNanSum: - @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) - @pytest.mark.parametrize("axis", [None, 0, 1, (0, 1)]) - @pytest.mark.parametrize("keepdims", [True, False]) - def test_nansum(self, dtype, axis, keepdims): - dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - expected = numpy.nansum(np_array, axis=axis, keepdims=keepdims) - result = dpnp.nansum(dp_array, axis=axis, keepdims=keepdims) - assert_allclose(result, expected) - - @pytest.mark.parametrize("dtype", get_complex_dtypes()) - def test_nansum_complex(self, dtype): - x1 = numpy.random.rand(10) - x2 = numpy.random.rand(10) - a = numpy.array(x1 + 1j * x2, dtype=dtype) - a[::3] = numpy.nan - ia = dpnp.array(a) - - expected = numpy.nansum(a) - result = dpnp.nansum(ia) - - # use only type kinds check when dpnp handles complex64 arrays - # since `dpnp.sum()` and `numpy.sum()` return different dtypes - assert_dtype_allclose( - result, expected, check_only_type_kind=(dtype == dpnp.complex64) - ) - - @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) - @pytest.mark.parametrize("axis", [0, 1]) - def test_nansum_out(self, dtype, axis): - dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - expected = numpy.nansum(np_array, axis=axis) - out = dpnp.empty_like(dpnp.asarray(expected)) - result = dpnp.nansum(dp_array, axis=axis, out=out) - assert out is result - assert_dtype_allclose(result, expected) - - @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) - def test_nansum_dtype(self, dtype): - dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]]) - np_array = dpnp.asnumpy(dp_array) - - expected = numpy.nansum(np_array, dtype=dtype) - result = dpnp.nansum(dp_array, dtype=dtype) - assert_dtype_allclose(result, expected) - - @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) - def test_nansum_strided(self, dtype): - dp_array = dpnp.arange(20, dtype=dtype) - dp_array[::3] = dpnp.nan - np_array = dpnp.asnumpy(dp_array) - - result = dpnp.nansum(dp_array[::-1]) - expected = numpy.nansum(np_array[::-1]) - assert_allclose(result, expected) - - result = dpnp.nansum(dp_array[::2]) - expected = numpy.nansum(np_array[::2]) - assert_allclose(result, expected) - - @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) ) diff --git a/tests/test_nanfunctions.py b/tests/test_nanfunctions.py new file mode 100644 index 00000000000..8e58cd4cf65 --- /dev/null +++ b/tests/test_nanfunctions.py @@ -0,0 +1,186 @@ +import numpy +import pytest +from numpy.testing import ( + assert_allclose, + assert_almost_equal, + assert_equal, +) + +import dpnp +from tests.third_party.cupy import testing + +from .helper import ( + assert_dtype_allclose, + get_complex_dtypes, + get_float_complex_dtypes, + get_float_dtypes, +) + + +@testing.parameterize( + *testing.product( + { + "func": ("nancumsum", "nancumprod"), + } + ) +) +class TestNanCumSumProd: + @pytest.fixture(autouse=True) + def setUp(self): + if self.func == "nancumprod": + pytest.skip("nancumprod() is not implemented yet") + pass + + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + @pytest.mark.parametrize( + "array", + [numpy.array(numpy.nan), numpy.full((3, 3), numpy.nan)], + ids=["0d", "2d"], + ) + def test_allnans(self, dtype, array): + a = numpy.array(array, dtype=dtype) + ia = dpnp.array(a, dtype=dtype) + + result = getattr(dpnp, self.func)(ia) + expected = getattr(numpy, self.func)(a) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("axis", [None, 0, 1]) + def test_empty(self, axis): + a = numpy.zeros((0, 3)) + ia = dpnp.array(a) + + result = getattr(dpnp, self.func)(ia, axis=axis) + expected = getattr(numpy, self.func)(a, axis=axis) + assert_equal(result, expected) + + @pytest.mark.parametrize("axis", [None, 0, 1]) + def test_keepdims(self, axis): + a = numpy.eye(3) + ia = dpnp.array(a) + + result = getattr(dpnp, self.func)(ia, axis=axis, out=None) + expected = getattr(numpy, self.func)(a, axis=axis, out=None) + assert_equal(result, expected) + assert result.ndim == expected.ndim + + @pytest.mark.parametrize("axis", [None] + list(range(4))) + def test_keepdims_random(self, axis): + a = numpy.ones((3, 5, 7, 11)) + # Randomly set some elements to NaN: + rs = numpy.random.RandomState(0) + a[rs.rand(*a.shape) < 0.5] = numpy.nan + ia = dpnp.array(a) + + result = getattr(dpnp, self.func)(ia, axis=axis) + expected = getattr(numpy, self.func)(a, axis=axis) + assert_equal(result, expected) + + @pytest.mark.parametrize("axis", [-2, -1, 0, 1, None]) + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_ndat_ones(self, axis, dtype): + a = numpy.array( + [ + [0.6244, 1.0, 0.2692, 0.0116, 1.0, 0.1170], + [0.5351, -0.9403, 1.0, 0.2100, 0.4759, 0.2833], + [1.0, 1.0, 1.0, 0.1042, 1.0, -0.5954], + [0.1610, 1.0, 1.0, 0.1859, 0.3146, 1.0], + ] + ) + a = a.astype(dtype=dtype) + ia = dpnp.array(a) + + result = getattr(dpnp, self.func)(ia, axis=axis) + expected = getattr(numpy, self.func)(a, axis=axis) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("axis", [-2, -1, 0, 1, None]) + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_ndat_zeros(self, axis, dtype): + a = numpy.array( + [ + [0.6244, 0.0, 0.2692, 0.0116, 0.0, 0.1170], + [0.5351, -0.9403, 0.0, 0.2100, 0.4759, 0.2833], + [0.0, 0.0, 0.0, 0.1042, 0.0, -0.5954], + [0.1610, 0.0, 0.0, 0.1859, 0.3146, 0.0], + ] + ) + a = a.astype(dtype=dtype) + ia = dpnp.array(a) + + result = getattr(dpnp, self.func)(ia, axis=axis) + expected = getattr(numpy, self.func)(a, axis=axis) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("axis", [-2, -1, 0, 1]) + def test_out(self, axis): + a = numpy.eye(3) + out = numpy.eye(3) + + ia = dpnp.array(a) + iout = dpnp.array(out) + + result = getattr(dpnp, self.func)(ia, axis=axis, out=iout) + expected = getattr(numpy, self.func)(a, axis=axis, out=out) + assert_almost_equal(result, expected) + assert result is iout + + +class TestNanSum: + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + @pytest.mark.parametrize("axis", [None, 0, 1, (0, 1)]) + @pytest.mark.parametrize("keepdims", [True, False]) + def test_nansum(self, dtype, axis, keepdims): + dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + expected = numpy.nansum(np_array, axis=axis, keepdims=keepdims) + result = dpnp.nansum(dp_array, axis=axis, keepdims=keepdims) + assert_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_complex_dtypes()) + def test_nansum_complex(self, dtype): + x1 = numpy.random.rand(10) + x2 = numpy.random.rand(10) + a = numpy.array(x1 + 1j * x2, dtype=dtype) + a[::3] = numpy.nan + ia = dpnp.array(a) + + expected = numpy.nansum(a) + result = dpnp.nansum(ia) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + @pytest.mark.parametrize("axis", [0, 1]) + def test_nansum_out(self, dtype, axis): + dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + expected = numpy.nansum(np_array, axis=axis) + out = dpnp.empty_like(dpnp.asarray(expected)) + result = dpnp.nansum(dp_array, axis=axis, out=out) + assert out is result + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + def test_nansum_dtype(self, dtype): + dp_array = dpnp.array([[dpnp.nan, 1, 2], [3, dpnp.nan, 0]]) + np_array = dpnp.asnumpy(dp_array) + + expected = numpy.nansum(np_array, dtype=dtype) + result = dpnp.nansum(dp_array, dtype=dtype) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + def test_nansum_strided(self, dtype): + dp_array = dpnp.arange(20, dtype=dtype) + dp_array[::3] = dpnp.nan + np_array = dpnp.asnumpy(dp_array) + + result = dpnp.nansum(dp_array[::-1]) + expected = numpy.nansum(np_array[::-1]) + assert_allclose(result, expected) + + result = dpnp.nansum(dp_array[::2]) + expected = numpy.nansum(np_array[::2]) + assert_allclose(result, expected) diff --git a/tests/test_sum.py b/tests/test_sum.py index c58acb86e62..d028ef18a8e 100644 --- a/tests/test_sum.py +++ b/tests/test_sum.py @@ -9,13 +9,9 @@ assert_dtype_allclose, get_all_dtypes, get_float_dtypes, - has_support_aspect64, ) -# Note: dpnp.sum() always upcast integers to (u)int64 and float32 to -# float64 for dtype=None. `numpy.sum()` does that too for integers, but not for -# float32, so we need to special-case it for these tests @pytest.mark.parametrize("dtype", get_float_dtypes()) def test_sum_float(dtype): a = numpy.array( @@ -28,16 +24,10 @@ def test_sum_float(dtype): ) ia = dpnp.array(a) - # Flag for type check in special cases - # Use only type kinds checks when dpnp handles float32 arrays - # as `dpnp.sum()` and `numpy.sum()` return different dtypes - check_type_kind = dtype == dpnp.float32 for axis in range(len(a)): result = dpnp.sum(ia, axis=axis) expected = numpy.sum(a, axis=axis) - assert_dtype_allclose( - result, expected, check_only_type_kind=check_type_kind - ) + assert_dtype_allclose(result, expected) def test_sum_int(): diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 5ab3484c075..2b14bbb330f 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1479,7 +1479,7 @@ def test_norm(device, ord, axis): else: result = dpnp.linalg.norm(ia, ord=ord, axis=axis) expected = numpy.linalg.norm(a, ord=ord, axis=axis) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) expected_queue = ia.get_array().sycl_queue result_queue = result.get_array().sycl_queue diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 124cf5c7c1f..3b2aad98ea2 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -541,6 +541,7 @@ def test_norm(usm_type, ord, axis): pytest.param("min", [1.0, 2.0, 4.0, 7.0]), pytest.param("nanargmax", [1.0, 2.0, 4.0, dp.nan]), pytest.param("nanargmin", [1.0, 2.0, 4.0, dp.nan]), + pytest.param("nancumsum", [3.0, dp.nan]), pytest.param("nanmax", [1.0, 2.0, 4.0, dp.nan]), pytest.param("nanmean", [1.0, 2.0, 4.0, dp.nan]), pytest.param("nanmin", [1.0, 2.0, 4.0, dp.nan]), diff --git a/tests/third_party/cupy/math_tests/test_sumprod.py b/tests/third_party/cupy/math_tests/test_sumprod.py index 2a8d0cbd991..d4f35559118 100644 --- a/tests/third_party/cupy/math_tests/test_sumprod.py +++ b/tests/third_party/cupy/math_tests/test_sumprod.py @@ -606,10 +606,15 @@ def test_cumproduct_alias(self, xp): } ) ) -@pytest.mark.skip("nancumsum() and nancumprod() are not implemented yet") class TestNanCumSumProd: zero_density = 0.25 + @pytest.fixture(autouse=True) + def setUp(self): + if self.func == "nancumprod": + pytest.skip("nancumprod() is not implemented yet") + pass + def _make_array(self, dtype): dtype = numpy.dtype(dtype) if dtype.char in "efdFD":