Skip to content

Commit cceb7cf

Browse files
Rubtsowashssf
andauthored
add dpnp.nanvar() (#720)
Co-authored-by: Sergey Shalnov <[email protected]>
1 parent d02031a commit cceb7cf

File tree

7 files changed

+151
-0
lines changed

7 files changed

+151
-0
lines changed

dpnp/backend/include/dpnp_iface.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ template <typename _DataType>
189189
INP_DLLEXPORT void
190190
dpnp_matmul_c(void* array1, void* array2, void* result1, size_t size_m, size_t size_n, size_t size_k);
191191

192+
/**
193+
* @ingroup BACKEND_API
194+
* @brief Compute the variance along the specified axis, while ignoring NaNs.
195+
*
196+
* @param [in] array Input array.
197+
* @param [in] mask_arr Input mask array when elem is nan.
198+
* @param [out] result Output array.
199+
* @param [in] size Number of elements in input arrays.
200+
*/
201+
template <typename _DataType>
202+
INP_DLLEXPORT void dpnp_nanvar_c(void* array, void* mask_arr, void* result, size_t size);
203+
192204
/**
193205
* @ingroup BACKEND_API
194206
* @brief Return the indices of the elements that are non-zero.

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ enum class DPNPFuncName : size_t
135135
DPNP_FN_MINIMUM, /**< Used in numpy.minimum() implementation */
136136
DPNP_FN_MODF, /**< Used in numpy.modf() implementation */
137137
DPNP_FN_MULTIPLY, /**< Used in numpy.multiply() implementation */
138+
DPNP_FN_NANVAR, /**< Used in numpy.nanvar() implementation */
138139
DPNP_FN_NEGATIVE, /**< Used in numpy.negative() implementation */
139140
DPNP_FN_NONZERO, /**< Used in numpy.nonzero() implementation */
140141
DPNP_FN_ONES, /**< Used in numpy.ones() implementation */

dpnp/backend/kernels/dpnp_krnl_statistics.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,36 @@ void dpnp_min_c(void* array1_in, void* result1, const size_t* shape, size_t ndim
447447
return;
448448
}
449449

450+
template <typename _DataType>
451+
void dpnp_nanvar_c(void* array1_in, void* mask_arr1, void* result1, size_t arr_size)
452+
{
453+
_DataType* array1 = reinterpret_cast<_DataType*>(array1_in);
454+
bool* mask_arr = reinterpret_cast<bool*>(mask_arr1);
455+
_DataType* result = reinterpret_cast<_DataType*>(result1);
456+
457+
if ((array1 == nullptr) || (mask_arr == nullptr) || (result == nullptr))
458+
{
459+
return;
460+
}
461+
462+
if (arr_size == 0)
463+
{
464+
return;
465+
}
466+
467+
size_t ind = 0;
468+
for (size_t i = 0; i < arr_size; ++i)
469+
{
470+
if (!mask_arr[i])
471+
{
472+
result[ind] = array1[i];
473+
ind += 1;
474+
}
475+
}
476+
477+
return;
478+
}
479+
450480
template <typename _DataType, typename _ResultType>
451481
void dpnp_std_c(
452482
void* array1_in, void* result1, const size_t* shape, size_t ndim, const size_t* axis, size_t naxis, size_t ddof)
@@ -560,6 +590,11 @@ void func_map_init_statistics(func_map_t& fmap)
560590
fmap[DPNPFuncName::DPNP_FN_MIN][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_min_c<float>};
561591
fmap[DPNPFuncName::DPNP_FN_MIN][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_min_c<double>};
562592

593+
fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_nanvar_c<int>};
594+
fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_LNG][eft_LNG] = {eft_LNG, (void*)dpnp_nanvar_c<long>};
595+
fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_nanvar_c<float>};
596+
fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_nanvar_c<double>};
597+
563598
fmap[DPNPFuncName::DPNP_FN_STD][eft_INT][eft_INT] = {eft_DBL, (void*)dpnp_std_c<int, double>};
564599
fmap[DPNPFuncName::DPNP_FN_STD][eft_LNG][eft_LNG] = {eft_DBL, (void*)dpnp_std_c<long, double>};
565600
fmap[DPNPFuncName::DPNP_FN_STD][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_std_c<float, float>};

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
108108
DPNP_FN_MINIMUM
109109
DPNP_FN_MODF
110110
DPNP_FN_MULTIPLY
111+
DPNP_FN_NANVAR
111112
DPNP_FN_NEGATIVE
112113
DPNP_FN_NONZERO
113114
DPNP_FN_ONES

dpnp/dpnp_algo/dpnp_algo_statistics.pyx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ __all__ += [
4848
"dpnp_mean",
4949
"dpnp_median",
5050
"dpnp_min",
51+
"dpnp_nanvar",
5152
"dpnp_std",
5253
"dpnp_var",
5354
]
5455

5556

5657
# C function pointer to the C library template functions
5758
ctypedef void(*fptr_custom_cov_1in_1out_t)(void * , void * , size_t, size_t)
59+
ctypedef void(*fptr_custom_nanvar_t)(void * , void * , void * , size_t)
5860
ctypedef void(*fptr_custom_std_var_1in_1out_t)(void * , void * , size_t * , size_t, size_t * , size_t, size_t)
5961

6062
# C function pointer to the C library template functions
@@ -426,6 +428,25 @@ cpdef dparray dpnp_min(dparray input, axis):
426428
return _dpnp_min(input, axis_, output_shape)
427429

428430

431+
cpdef dparray dpnp_nanvar(dparray arr, ddof):
432+
cdef dparray mask_arr = dpnp.isnan(arr)
433+
n = sum(mask_arr)
434+
res_size = arr.size - n
435+
436+
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(arr.dtype)
437+
438+
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_NANVAR, param1_type, param1_type)
439+
440+
result_type = dpnp_DPNPFuncType_to_dtype( < size_t > kernel_data.return_type)
441+
cdef dparray without_nan_arr = dparray((res_size, ), dtype=result_type)
442+
443+
cdef fptr_custom_nanvar_t func = <fptr_custom_nanvar_t > kernel_data.ptr
444+
445+
func(arr.get_data(), mask_arr.get_data(), without_nan_arr.get_data(), arr.size)
446+
447+
return call_fptr_custom_std_var_1in_1out(DPNP_FN_VAR, without_nan_arr, ddof)
448+
449+
429450
cpdef dparray dpnp_std(dparray a, size_t ddof):
430451
return call_fptr_custom_std_var_1in_1out(DPNP_FN_STD, a, ddof)
431452

dpnp/dpnp_iface_statistics.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'mean',
5959
'median',
6060
'min',
61+
'nanvar',
6162
'std',
6263
'var',
6364
]
@@ -474,6 +475,44 @@ def min(input, axis=None, out=None, keepdims=numpy._NoValue, initial=numpy._NoVa
474475
return call_origin(numpy.min, input, axis, out, keepdims, initial, where)
475476

476477

478+
def nanvar(arr, axis=None, dtype=None, out=None, ddof=0, keepdims=numpy._NoValue):
479+
"""
480+
Compute the variance along the specified axis, while ignoring NaNs.
481+
482+
For full documentation refer to :obj:`numpy.nanvar`.
483+
484+
Limitations
485+
-----------
486+
Input array is supported as :obj:`dpnp.ndarray`.
487+
Prameters ``axis`` is supported only with default value ``None``.
488+
Prameters ``dtype`` is supported only with default value ``None``.
489+
Prameters ``out`` is supported only with default value ``None``.
490+
Prameters ``keepdims`` is supported only with default value ``numpy._NoValue``.
491+
Otherwise the function will be executed sequentially on CPU.
492+
"""
493+
if not use_origin_backend(arr):
494+
if not isinstance(arr, dparray):
495+
pass
496+
elif axis is not None:
497+
pass
498+
elif dtype is not None:
499+
pass
500+
elif out is not None:
501+
pass
502+
elif keepdims is not numpy._NoValue:
503+
pass
504+
else:
505+
result = dpnp_nanvar(arr, ddof)
506+
507+
# scalar returned
508+
if result.shape == (1,):
509+
return result.dtype.type(result[0])
510+
511+
return result
512+
513+
return call_origin(numpy.nanvar, arr, axis=axis, dtype=dtype, out=out, ddof=ddof, keepdims=keepdims)
514+
515+
477516
def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=numpy._NoValue):
478517
"""
479518
Compute the standard deviation along the specified axis.

tests/test_statistics.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,45 @@ def test_median(type, size):
1818
dpnp_res = dpnp.median(ia)
1919

2020
numpy.testing.assert_allclose(dpnp_res, np_res)
21+
22+
23+
@pytest.mark.parametrize("array",
24+
[[2, 0, 6, 2],
25+
[2, 0, 6, 2, 5, 6, 7, 8],
26+
[],
27+
[2, 1, numpy.nan, 5, 3],
28+
[-1, numpy.nan, 1, numpy.inf],
29+
[3, 6, 0, 1],
30+
[3, 6, 0, 1, 8],
31+
[3, 2, 9, 6, numpy.nan],
32+
[numpy.nan, numpy.nan, numpy.inf, numpy.nan],
33+
[[2, 0], [6, 2]],
34+
[[2, 0, 6, 2], [5, 6, 7, 8]],
35+
[[[2, 0], [6, 2]], [[5, 6], [7, 8]]],
36+
[[-1, numpy.nan], [1, numpy.inf]],
37+
[[numpy.nan, numpy.nan], [numpy.inf, numpy.nan]]],
38+
ids=['[2, 0, 6, 2]',
39+
'[2, 0, 6, 2, 5, 6, 7, 8]',
40+
'[]',
41+
'[2, 1, np.nan, 5, 3]',
42+
'[-1, np.nan, 1, np.inf]',
43+
'[3, 6, 0, 1]',
44+
'[3, 6, 0, 1, 8]',
45+
'[3, 2, 9, 6, np.nan]',
46+
'[np.nan, np.nan, np.inf, np.nan]',
47+
'[[2, 0], [6, 2]]',
48+
'[[2, 0, 6, 2], [5, 6, 7, 8]]',
49+
'[[[2, 0], [6, 2]], [[5, 6], [7, 8]]]',
50+
'[[-1, np.nan], [1, np.inf]]',
51+
'[[np.nan, np.nan], [np.inf, np.nan]]'])
52+
def test_nanvar(array):
53+
a = numpy.array(array)
54+
ia = dpnp.array(a)
55+
for ddof in range(a.ndim):
56+
expected = numpy.nanvar(a, ddof=ddof)
57+
result = dpnp.nanvar(ia, ddof=ddof)
58+
numpy.testing.assert_array_equal(expected, result)
59+
60+
expected = numpy.nanvar(a, axis=None, ddof=0)
61+
result = dpnp.nanvar(ia, axis=None, ddof=0)
62+
numpy.testing.assert_array_equal(expected, result)

0 commit comments

Comments
 (0)