Skip to content

Commit 506d7a7

Browse files
authored
Implement dpnp.nancumsum() through dpnp.cumsum call (#1781)
* Implement dpnp.nancumsum() through existing calls * Enabled strict dtype check due to recent changes in dpnp.sum() * FFT tests still require check_only_type_kind=True
1 parent 240b14f commit 506d7a7

File tree

13 files changed

+255
-212
lines changed

13 files changed

+255
-212
lines changed

doc/reference/math.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,17 @@ Sums, products, differences
6666

6767
dpnp.prod
6868
dpnp.sum
69+
dpnp.nanprod
70+
dpnp.nansum
6971
dpnp.cumprod
7072
dpnp.cumsum
7173
dpnp.nancumprod
7274
dpnp.nancumsum
73-
dpnp.nansum
74-
dpnp.nanprod
75-
dpnp.cross
7675
dpnp.diff
7776
dpnp.ediff1d
7877
dpnp.gradient
7978
dpnp.trapz
79+
dpnp.cross
8080

8181

8282
Exponents and logarithms

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ enum class DPNPFuncName : size_t
108108
DPNP_FN_CUMPROD_EXT, /**< Used in numpy.cumprod() impl, requires extra
109109
parameters */
110110
DPNP_FN_CUMSUM, /**< Used in numpy.cumsum() impl */
111-
DPNP_FN_CUMSUM_EXT, /**< Used in numpy.cumsum() impl, requires extra
112-
parameters */
113111
DPNP_FN_DEGREES, /**< Used in numpy.degrees() impl */
114112
DPNP_FN_DEGREES_EXT, /**< Used in numpy.degrees() impl, requires extra
115113
parameters */

dpnp/backend/kernels/dpnp_krnl_mathematical.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -425,14 +425,6 @@ template <typename _DataType_input, typename _DataType_output>
425425
void (*dpnp_cumsum_default_c)(void *, void *, size_t) =
426426
dpnp_cumsum_c<_DataType_input, _DataType_output>;
427427

428-
template <typename _DataType_input, typename _DataType_output>
429-
DPCTLSyclEventRef (*dpnp_cumsum_ext_c)(DPCTLSyclQueueRef,
430-
void *,
431-
void *,
432-
size_t,
433-
const DPCTLEventVectorRef) =
434-
dpnp_cumsum_c<_DataType_input, _DataType_output>;
435-
436428
template <typename _KernelNameSpecialization1,
437429
typename _KernelNameSpecialization2>
438430
class dpnp_ediff1d_c_kernel;
@@ -1179,15 +1171,6 @@ void func_map_init_mathematical(func_map_t &fmap)
11791171
fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_DBL][eft_DBL] = {
11801172
eft_DBL, (void *)dpnp_cumsum_default_c<double, double>};
11811173

1182-
fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_INT][eft_INT] = {
1183-
eft_LNG, (void *)dpnp_cumsum_ext_c<int32_t, int64_t>};
1184-
fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_LNG][eft_LNG] = {
1185-
eft_LNG, (void *)dpnp_cumsum_ext_c<int64_t, int64_t>};
1186-
fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_FLT][eft_FLT] = {
1187-
eft_FLT, (void *)dpnp_cumsum_ext_c<float, float>};
1188-
fmap[DPNPFuncName::DPNP_FN_CUMSUM_EXT][eft_DBL][eft_DBL] = {
1189-
eft_DBL, (void *)dpnp_cumsum_ext_c<double, double>};
1190-
11911174
fmap[DPNPFuncName::DPNP_FN_EDIFF1D][eft_INT][eft_INT] = {
11921175
eft_LNG, (void *)dpnp_ediff1d_default_c<int32_t, int64_t>};
11931176
fmap[DPNPFuncName::DPNP_FN_EDIFF1D][eft_LNG][eft_LNG] = {

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
3838
DPNP_FN_COPY_EXT
3939
DPNP_FN_CORRELATE_EXT
4040
DPNP_FN_CUMPROD_EXT
41-
DPNP_FN_CUMSUM_EXT
4241
DPNP_FN_DEGREES_EXT
4342
DPNP_FN_DIAG_INDICES_EXT
4443
DPNP_FN_DIAGONAL_EXT

dpnp/dpnp_algo/dpnp_algo_mathematical.pxi

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ __all__ += [
4545
"dpnp_fmin",
4646
"dpnp_modf",
4747
"dpnp_nancumprod",
48-
"dpnp_nancumsum",
4948
"dpnp_trapz",
5049
]
5150

@@ -70,18 +69,6 @@ cpdef utils.dpnp_descriptor dpnp_cumprod(utils.dpnp_descriptor x1):
7069
return call_fptr_1in_1out(DPNP_FN_CUMPROD_EXT, x1, (x1.size,))
7170

7271

73-
cpdef utils.dpnp_descriptor dpnp_cumsum(utils.dpnp_descriptor x1):
74-
# instead of x1.shape, (x1.size, ) is passed to the function
75-
# due to the following:
76-
# >>> import numpy
77-
# >>> a = numpy.array([[1, 2], [2, 3]])
78-
# >>> res = numpy.cumsum(a)
79-
# >>> res.shape
80-
# (4,)
81-
82-
return call_fptr_1in_1out(DPNP_FN_CUMSUM_EXT, x1, (x1.size,))
83-
84-
8572
cpdef utils.dpnp_descriptor dpnp_ediff1d(utils.dpnp_descriptor x1):
8673

8774
if x1.size <= 1:
@@ -253,19 +240,6 @@ cpdef utils.dpnp_descriptor dpnp_nancumprod(utils.dpnp_descriptor x1):
253240
return dpnp_cumprod(x1_desc)
254241

255242

256-
cpdef utils.dpnp_descriptor dpnp_nancumsum(utils.dpnp_descriptor x1):
257-
cur_x1 = x1.get_pyobj().copy()
258-
259-
cur_x1_flatiter = cur_x1.flat
260-
261-
for i in range(cur_x1.size):
262-
if dpnp.isnan(cur_x1_flatiter[i]):
263-
cur_x1_flatiter[i] = 0
264-
265-
x1_desc = dpnp.get_dpnp_descriptor(cur_x1, copy_when_nondefault_queue=False)
266-
return dpnp_cumsum(x1_desc)
267-
268-
269243
cpdef utils.dpnp_descriptor dpnp_trapz(utils.dpnp_descriptor y1, utils.dpnp_descriptor x1, double dx):
270244

271245
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(y1.dtype)

dpnp/dpnp_iface_nanfunctions.py

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
# pylint: disable=no-name-in-module
4747
from .dpnp_algo import (
4848
dpnp_nancumprod,
49-
dpnp_nancumsum,
5049
)
5150
from .dpnp_utils import (
5251
call_origin,
@@ -292,43 +291,68 @@ def nancumprod(x1, **kwargs):
292291
return call_origin(numpy.nancumprod, x1, **kwargs)
293292

294293

295-
def nancumsum(x1, **kwargs):
294+
def nancumsum(a, axis=None, dtype=None, out=None):
296295
"""
297-
Return the cumulative sum of the elements along a given axis.
296+
Return the cumulative sum of array elements over a given axis treating
297+
Not a Numbers (NaNs) as zero. The cumulative sum does not change when NaNs
298+
are encountered and leading NaNs are replaced by zeros.
298299
299300
For full documentation refer to :obj:`numpy.nancumsum`.
300301
301-
Limitations
302-
-----------
303-
Parameter `x` is supported as :class:`dpnp.ndarray`.
304-
Keyword argument `kwargs` is currently unsupported.
305-
Otherwise the function will be executed sequentially on CPU.
306-
Input array data types are limited by supported DPNP :ref:`Data types`.
302+
Parameters
303+
----------
304+
a : {dpnp.ndarray, usm_ndarray}
305+
Input array.
306+
axis : int, optional
307+
Axis along which the cumulative sum is computed. The default (``None``)
308+
is to compute the cumsum over the flattened array.
309+
dtype : dtype, optional
310+
Type of the returned array and of the accumulator in which the elements
311+
are summed. If `dtype` is not specified, it defaults to the dtype of
312+
`a`, unless `a` has an integer dtype with a precision less than that of
313+
the default platform integer. In that case, the default platform
314+
integer is used.
315+
out : {dpnp.ndarray, usm_ndarray}, optional
316+
Alternative output array in which to place the result. It must have the
317+
same shape and buffer length as the expected output but the type will
318+
be cast if necessary.
319+
320+
Returns
321+
-------
322+
out : dpnp.ndarray
323+
A new array holding the result is returned unless `out` is specified as
324+
:class:`dpnp.ndarray`, in which case a reference to `out` is returned.
325+
The result has the same size as `a`, and the same shape as `a` if `axis`
326+
is not ``None`` or `a` is a 1-d array.
307327
308328
See Also
309329
--------
310-
:obj:`dpnp.cumsum` : Return the cumulative sum of the elements
311-
along a given axis.
330+
:obj:`dpnp.cumsum` : Cumulative sum across array propagating NaNs.
331+
:obj:`dpnp.isnan` : Show which elements are NaN.
312332
313333
Examples
314334
--------
315335
>>> import dpnp as np
316-
>>> a = np.array([1., np.nan])
317-
>>> result = np.nancumsum(a)
318-
>>> [x for x in result]
319-
[1.0, 1.0]
320-
>>> b = np.array([[1., 2., np.nan], [4., np.nan, 6.]])
321-
>>> result = np.nancumprod(b)
322-
>>> [x for x in result]
323-
[1.0, 3.0, 3.0, 7.0, 7.0, 13.0]
336+
>>> np.nancumsum(np.array(1))
337+
array([1])
338+
>>> np.nancumsum(np.array([1]))
339+
array([1])
340+
>>> np.nancumsum(np.array([1, np.nan]))
341+
array([1., 1.])
342+
>>> a = np.array([[1, 2], [3, np.nan]])
343+
>>> np.nancumsum(a)
344+
array([1., 3., 6., 6.])
345+
>>> np.nancumsum(a, axis=0)
346+
array([[1., 2.],
347+
[4., 2.]])
348+
>>> np.nancumsum(a, axis=1)
349+
array([[1., 3.],
350+
[3., 3.]])
324351
325352
"""
326353

327-
x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
328-
if x1_desc and not kwargs:
329-
return dpnp_nancumsum(x1_desc).get_pyobj()
330-
331-
return call_origin(numpy.nancumsum, x1, **kwargs)
354+
a, _ = _replace_nan(a, 0)
355+
return dpnp.cumsum(a, axis=axis, dtype=dtype, out=out)
332356

333357

334358
def nanmax(a, axis=None, out=None, keepdims=False, initial=None, where=True):

tests/test_linalg.py

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -961,13 +961,10 @@ def test_norm_0D(self, ord, axis):
961961
def test_norm_1D(self, dtype, ord, axis, keepdims):
962962
a = numpy.array(numpy.random.uniform(-5, 5, 10), dtype=dtype)
963963
ia = inp.array(a)
964+
964965
result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims)
965966
expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims)
966-
# use only type kinds check when dpnp handles complex64 arrays
967-
# since `dpnp.sum()` and `numpy.sum()` return different dtypes
968-
assert_dtype_allclose(
969-
result, expected, check_only_type_kind=(dtype == inp.float32)
970-
)
967+
assert_dtype_allclose(result, expected)
971968

972969
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
973970
@pytest.mark.parametrize("dtype", get_complex_dtypes())
@@ -983,11 +980,10 @@ def test_norm_1D_complex(self, dtype, ord, axis, keepdims):
983980
x2 = numpy.random.uniform(-5, 5, 10)
984981
a = numpy.array(x1 + 1j * x2, dtype=dtype)
985982
ia = inp.array(a)
983+
986984
result = inp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims)
987985
expected = numpy.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims)
988-
assert_dtype_allclose(
989-
result, expected, check_only_type_kind=(dtype == inp.complex64)
990-
)
986+
assert_dtype_allclose(result, expected)
991987

992988
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
993989
@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True))
@@ -1027,9 +1023,7 @@ def test_norm_2D(self, dtype, ord, axis, keepdims):
10271023
expected = numpy.linalg.norm(
10281024
a, ord=ord, axis=axis, keepdims=keepdims
10291025
)
1030-
assert_dtype_allclose(
1031-
result, expected, check_only_type_kind=(dtype == inp.float32)
1032-
)
1026+
assert_dtype_allclose(result, expected)
10331027

10341028
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
10351029
@pytest.mark.parametrize("dtype", get_complex_dtypes())
@@ -1069,9 +1063,7 @@ def test_norm_2D_complex(self, dtype, ord, axis, keepdims):
10691063
expected = numpy.linalg.norm(
10701064
a, ord=ord, axis=axis, keepdims=keepdims
10711065
)
1072-
assert_dtype_allclose(
1073-
result, expected, check_only_type_kind=(dtype == inp.complex64)
1074-
)
1066+
assert_dtype_allclose(result, expected)
10751067

10761068
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
10771069
@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True))
@@ -1117,9 +1109,7 @@ def test_norm_ND(self, dtype, ord, axis, keepdims):
11171109
expected = numpy.linalg.norm(
11181110
a, ord=ord, axis=axis, keepdims=keepdims
11191111
)
1120-
assert_dtype_allclose(
1121-
result, expected, check_only_type_kind=(dtype == inp.float32)
1122-
)
1112+
assert_dtype_allclose(result, expected)
11231113

11241114
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
11251115
@pytest.mark.parametrize("dtype", get_complex_dtypes())
@@ -1165,9 +1155,7 @@ def test_norm_ND_complex(self, dtype, ord, axis, keepdims):
11651155
expected = numpy.linalg.norm(
11661156
a, ord=ord, axis=axis, keepdims=keepdims
11671157
)
1168-
assert_dtype_allclose(
1169-
result, expected, check_only_type_kind=(dtype == inp.complex64)
1170-
)
1158+
assert_dtype_allclose(result, expected)
11711159

11721160
@pytest.mark.usefixtures("suppress_divide_numpy_warnings")
11731161
@pytest.mark.parametrize("dtype", get_all_dtypes())
@@ -1213,11 +1201,7 @@ def test_norm_usm_ndarray(self, dtype, ord, axis, keepdims):
12131201
expected = numpy.linalg.norm(
12141202
a, ord=ord, axis=axis, keepdims=keepdims
12151203
)
1216-
assert_dtype_allclose(
1217-
result,
1218-
expected,
1219-
check_only_type_kind=(dtype in [inp.float32, inp.complex64]),
1220-
)
1204+
assert_dtype_allclose(result, expected)
12211205

12221206
@pytest.mark.parametrize("stride", [3, -1, -5], ids=["3", "-1", "-5"])
12231207
def test_norm_strided_1D(self, stride):

0 commit comments

Comments
 (0)