Skip to content

Commit 83d28d7

Browse files
authored
Add support of missing arguments in dpnp.count_nonzero (#1615)
* Added support of missing arguments in dpnp.count_nonzero * Assert correct result dtype in test_count.py * Addressed review comments * Update test_count_nonzero to properly handle bool dtype
1 parent d389bd4 commit 83d28d7

File tree

16 files changed

+81
-141
lines changed

16 files changed

+81
-141
lines changed

.github/workflows/conda-package.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ env:
4545
third_party/cupy/math_tests/test_rounding.py
4646
third_party/cupy/math_tests/test_trigonometric.py
4747
third_party/cupy/sorting_tests/test_sort.py
48+
third_party/cupy/sorting_tests/test_count.py
4849
VER_JSON_NAME: 'version.json'
4950
VER_SCRIPT1: "import json; f = open('version.json', 'r'); j = json.load(f); f.close(); "
5051
VER_SCRIPT2: "d = j['dpnp'][0]; print('='.join((d[s] for s in ('version', 'build'))))"

dpnp/backend/cmake/Modules/IntelSYCLConfig.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
IntelSYCLConfig
1919
-------
2020
21-
Library to verify SYCL compatability of CMAKE_CXX_COMPILER
21+
Library to verify SYCL compatibility of CMAKE_CXX_COMPILER
2222
and passes relevant compiler flags.
2323
2424
Result Variables
@@ -290,7 +290,7 @@ if(nosycllang)
290290
set(IntelSYCL_NOT_FOUND_MESSAGE "${SYCL_REASON_FAILURE}")
291291
endif()
292292

293-
# Placeholder for identifying various implemenations of SYCL compilers.
293+
# Placeholder for identifying various implementations of SYCL compilers.
294294
# for now, set to the CMAKE_CXX_COMPILER_ID
295295
set(SYCL_IMPLEMENTATION_ID "${CMAKE_CXX_COMPILER_ID}")
296296

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,25 +115,23 @@ enum class DPNPFuncName : size_t
115115
DPNP_FN_COS, /**< Used in numpy.cos() impl */
116116
DPNP_FN_COSH, /**< Used in numpy.cosh() impl */
117117
DPNP_FN_COUNT_NONZERO, /**< Used in numpy.count_nonzero() impl */
118-
DPNP_FN_COUNT_NONZERO_EXT, /**< Used in numpy.count_nonzero() impl, requires
119-
extra parameters */
120-
DPNP_FN_COV, /**< Used in numpy.cov() impl */
121-
DPNP_FN_CROSS, /**< Used in numpy.cross() impl */
122-
DPNP_FN_CROSS_EXT, /**< Used in numpy.cross() impl, requires extra
123-
parameters */
124-
DPNP_FN_CUMPROD, /**< Used in numpy.cumprod() impl */
125-
DPNP_FN_CUMPROD_EXT, /**< Used in numpy.cumprod() impl, requires extra
126-
parameters */
127-
DPNP_FN_CUMSUM, /**< Used in numpy.cumsum() impl */
128-
DPNP_FN_CUMSUM_EXT, /**< Used in numpy.cumsum() impl, requires extra
129-
parameters */
130-
DPNP_FN_DEGREES, /**< Used in numpy.degrees() impl */
131-
DPNP_FN_DEGREES_EXT, /**< Used in numpy.degrees() impl, requires extra
132-
parameters */
133-
DPNP_FN_DET, /**< Used in numpy.linalg.det() impl */
134-
DPNP_FN_DET_EXT, /**< Used in numpy.linalg.det() impl, requires extra
135-
parameters */
136-
DPNP_FN_DIAG, /**< Used in numpy.diag() impl */
118+
DPNP_FN_COV, /**< Used in numpy.cov() impl */
119+
DPNP_FN_CROSS, /**< Used in numpy.cross() impl */
120+
DPNP_FN_CROSS_EXT, /**< Used in numpy.cross() impl, requires extra
121+
parameters */
122+
DPNP_FN_CUMPROD, /**< Used in numpy.cumprod() impl */
123+
DPNP_FN_CUMPROD_EXT, /**< Used in numpy.cumprod() impl, requires extra
124+
parameters */
125+
DPNP_FN_CUMSUM, /**< Used in numpy.cumsum() impl */
126+
DPNP_FN_CUMSUM_EXT, /**< Used in numpy.cumsum() impl, requires extra
127+
parameters */
128+
DPNP_FN_DEGREES, /**< Used in numpy.degrees() impl */
129+
DPNP_FN_DEGREES_EXT, /**< Used in numpy.degrees() impl, requires extra
130+
parameters */
131+
DPNP_FN_DET, /**< Used in numpy.linalg.det() impl */
132+
DPNP_FN_DET_EXT, /**< Used in numpy.linalg.det() impl, requires extra
133+
parameters */
134+
DPNP_FN_DIAG, /**< Used in numpy.diag() impl */
137135
DPNP_FN_DIAG_EXT, /**< Used in numpy.diag() impl, requires extra parameters
138136
*/
139137
DPNP_FN_DIAG_INDICES, /**< Used in numpy.diag_indices() impl */

dpnp/backend/kernels/dpnp_krnl_statistics.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,6 @@ template <typename _DataType_input, typename _DataType_output>
292292
void (*dpnp_count_nonzero_default_c)(void *, void *, size_t) =
293293
dpnp_count_nonzero_c<_DataType_input, _DataType_output>;
294294

295-
template <typename _DataType_input, typename _DataType_output>
296-
DPCTLSyclEventRef (*dpnp_count_nonzero_ext_c)(DPCTLSyclQueueRef,
297-
void *,
298-
void *,
299-
size_t,
300-
const DPCTLEventVectorRef) =
301-
dpnp_count_nonzero_c<_DataType_input, _DataType_output>;
302-
303295
template <typename _DataType>
304296
class dpnp_max_c_kernel;
305297

@@ -1273,17 +1265,6 @@ void func_map_init_statistics(func_map_t &fmap)
12731265
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO][eft_DBL][eft_DBL] = {
12741266
eft_LNG, (void *)dpnp_count_nonzero_default_c<double, int64_t>};
12751267

1276-
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO_EXT][eft_BLN][eft_BLN] = {
1277-
eft_LNG, (void *)dpnp_count_nonzero_ext_c<bool, int64_t>};
1278-
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO_EXT][eft_INT][eft_INT] = {
1279-
eft_LNG, (void *)dpnp_count_nonzero_ext_c<int32_t, int64_t>};
1280-
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO_EXT][eft_LNG][eft_LNG] = {
1281-
eft_LNG, (void *)dpnp_count_nonzero_ext_c<int64_t, int64_t>};
1282-
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO_EXT][eft_FLT][eft_FLT] = {
1283-
eft_LNG, (void *)dpnp_count_nonzero_ext_c<float, int64_t>};
1284-
fmap[DPNPFuncName::DPNP_FN_COUNT_NONZERO_EXT][eft_DBL][eft_DBL] = {
1285-
eft_LNG, (void *)dpnp_count_nonzero_ext_c<double, int64_t>};
1286-
12871268
fmap[DPNPFuncName::DPNP_FN_COV][eft_INT][eft_INT] = {
12881269
eft_DBL, (void *)dpnp_cov_default_c<double>};
12891270
fmap[DPNPFuncName::DPNP_FN_COV][eft_LNG][eft_LNG] = {

dpnp/dpnp_algo/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
set(dpnp_algo_pyx_deps
33
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_linearalgebra.pxi
44
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_manipulation.pxi
5-
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_counting.pxi
65
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_statistics.pxi
76
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_trigonometric.pxi
87
${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_sorting.pxi

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
5454
DPNP_FN_COPYSIGN_EXT
5555
DPNP_FN_CORRELATE
5656
DPNP_FN_CORRELATE_EXT
57-
DPNP_FN_COUNT_NONZERO
58-
DPNP_FN_COUNT_NONZERO_EXT
5957
DPNP_FN_CROSS
6058
DPNP_FN_CROSS_EXT
6159
DPNP_FN_CUMPROD

dpnp/dpnp_algo/dpnp_algo.pyx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ __all__ = [
6060

6161

6262
include "dpnp_algo_arraycreation.pxi"
63-
include "dpnp_algo_counting.pxi"
6463
include "dpnp_algo_indexing.pxi"
6564
include "dpnp_algo_linearalgebra.pxi"
6665
include "dpnp_algo_logic.pxi"

dpnp/dpnp_algo/dpnp_algo_counting.pxi

Lines changed: 0 additions & 44 deletions
This file was deleted.

dpnp/dpnp_iface_counting.py

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,48 +39,54 @@
3939
4040
"""
4141

42-
43-
import numpy
44-
4542
import dpnp
46-
from dpnp.dpnp_algo.dpnp_algo import * # TODO need to investigate why dpnp.dpnp_algo can not be used
47-
from dpnp.dpnp_utils import *
4843

4944
__all__ = ["count_nonzero"]
5045

5146

52-
def count_nonzero(x1, axis=None, *, keepdims=False):
47+
def count_nonzero(a, axis=None, *, keepdims=False):
5348
"""
54-
Counts the number of non-zero values in the array ``in_array1``.
49+
Counts the number of non-zero values in the array `a`.
5550
5651
For full documentation refer to :obj:`numpy.count_nonzero`.
5752
53+
Returns
54+
-------
55+
out : dpnp.ndarray
56+
Number of non-zero values in the array along a given axis.
57+
Otherwise, a zero-dimensional array with the total number of
58+
non-zero values in the array is returned.
59+
5860
Limitations
5961
-----------
60-
Parameter `x1` is supported as :obj:`dpnp.ndarray`.
61-
Otherwise the function will be executed sequentially on CPU.
62-
Parameter `axis` is supported only with default value `None`.
63-
Parameter `keepdims` is supported only with default value `False`.
62+
Parameters `a` is supported as either :class:`dpnp.ndarray`
63+
or :class:`dpctl.tensor.usm_ndarray`.
64+
Otherwise ``TypeError`` exception will be raised.
65+
Input array data types are limited by supported DPNP :ref:`Data types`.
66+
67+
See Also
68+
--------
69+
:obj:`dpnp.nonzero` : Return the coordinates of all the non-zero values.
6470
6571
Examples
6672
--------
6773
>>> import dpnp as np
68-
>>> np.count_nonzero(np.array([1, 0, 3, 0, 5])
69-
3
70-
>>> np.count_nonzero(np.array([[1, 0, 3, 0, 5],[0, 9, 0, 7, 0]]))
71-
5
74+
>>> np.count_nonzero(np.eye(4))
75+
array(4)
76+
>>> a = np.array([[0, 1, 7, 0],
77+
[3, 0, 2, 19]])
78+
>>> np.count_nonzero(a)
79+
array(5)
80+
>>> np.count_nonzero(a, axis=0)
81+
array([1, 1, 2, 1])
82+
>>> np.count_nonzero(a, axis=1)
83+
array([2, 3])
84+
>>> np.count_nonzero(a, axis=1, keepdims=True)
85+
array([[2],
86+
[3]])
7287
7388
"""
74-
x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
75-
if x1_desc:
76-
if axis is not None:
77-
pass
78-
elif keepdims is not False:
79-
pass
80-
else:
81-
result_obj = dpnp_count_nonzero(x1_desc).get_pyobj()
82-
result = dpnp.convert_single_elem_array_to_scalar(result_obj)
83-
84-
return result
8589

86-
return call_origin(numpy.count_nonzero, x1, axis, keepdims=keepdims)
90+
# TODO: might be improved by implementing an extension with `count_nonzero` kernel
91+
a = dpnp.astype(a, dpnp.bool, copy=False)
92+
return a.sum(axis=axis, dtype=dpnp.intp, keepdims=keepdims)

dpnp/dpnp_iface_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"int64",
7373
"integer",
7474
"intc",
75+
"intp",
7576
"isscalar",
7677
"issubdtype",
7778
"issubsctype",
@@ -119,6 +120,7 @@
119120
int64 = numpy.int64
120121
integer = numpy.integer
121122
intc = numpy.intc
123+
intp = numpy.intp
122124
number = numpy.number
123125
signedinteger = numpy.signedinteger
124126
single = numpy.single

tests/skipped_tests.tbl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -815,10 +815,6 @@ tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers::test_hig
815815
tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers::test_normal
816816
tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers::test_size_is_not_none
817817

818-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero
819-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_int_axis
820-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_tuple_axis
821-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_zero_dim
822818
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_0_{func='argmin', is_module=True, shape=(3, 4)}::test_argminmax_dtype
823819
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_1_{func='argmin', is_module=True, shape=()}::test_argminmax_dtype
824820
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_2_{func='argmin', is_module=False, shape=(3, 4)}::test_argminmax_dtype

tests/skipped_tests_gpu.tbl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,10 +902,6 @@ tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_bo
902902
tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_goodness_of_fit
903903
tests/third_party/cupy/random_tests/test_sample.py::TestRandomIntegers2::test_goodness_of_fit_2
904904

905-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero
906-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_int_axis
907-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_tuple_axis
908-
tests/third_party/cupy/sorting_tests/test_count.py::TestCount::test_count_nonzero_zero_dim
909905
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_0_{func='argmin', is_module=True, shape=(3, 4)}::test_argminmax_dtype
910906
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_1_{func='argmin', is_module=True, shape=()}::test_argminmax_dtype
911907
tests/third_party/cupy/sorting_tests/test_search.py::TestArgMinMaxDtype_param_2_{func='argmin', is_module=False, shape=(3, 4)}::test_argminmax_dtype

tests/test_counting.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
import numpy
22
import pytest
3+
from numpy.testing import (
4+
assert_allclose,
5+
)
36

47
import dpnp
58

6-
7-
@pytest.mark.parametrize(
8-
"type",
9-
[numpy.float64, numpy.float32, numpy.int64, numpy.int32],
10-
ids=["float64", "float32", "int64", "int32"],
9+
from .helper import (
10+
get_all_dtypes,
1111
)
12+
13+
14+
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
1215
@pytest.mark.parametrize("size", [2, 4, 8, 16, 3, 9, 27, 81])
13-
def test_count_nonzero(type, size):
14-
a = numpy.arange(size, dtype=type)
16+
def test_count_nonzero(dtype, size):
17+
if dtype != dpnp.bool:
18+
a = numpy.arange(size, dtype=dtype)
19+
else:
20+
a = numpy.resize(numpy.arange(2, dtype=dtype), size)
21+
1522
for i in range(int(size / 2)):
1623
a[(i * (int(size / 3) - 1)) % size] = 0
1724

@@ -20,4 +27,4 @@ def test_count_nonzero(type, size):
2027
np_res = numpy.count_nonzero(a)
2128
dpnp_res = dpnp.count_nonzero(ia)
2229

23-
numpy.testing.assert_allclose(dpnp_res, np_res)
30+
assert_allclose(dpnp_res, np_res)

tests/test_sycl_queue.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ def test_meshgrid(device_x, device_y):
238238
pytest.param("arctanh", [-0.5, 0.0, 0.5]),
239239
pytest.param("ceil", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]),
240240
pytest.param("conjugate", [[1.0 + 1.0j, 0.0], [0.0, 1.0 + 1.0j]]),
241+
pytest.param("copy", [1.0, 2.0, 3.0]),
241242
pytest.param(
242243
"cos", [-dpnp.pi / 2, -dpnp.pi / 4, 0.0, dpnp.pi / 4, dpnp.pi / 2]
243244
),
244245
pytest.param("cosh", [-5.0, -3.5, 0.0, 3.5, 5.0]),
245-
pytest.param("copy", [1.0, 2.0, 3.0]),
246+
pytest.param("count_nonzero", [3, 0, 2, -1.2]),
246247
pytest.param("cumprod", [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]),
247248
pytest.param("cumsum", [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]),
248249
pytest.param("diff", [1.0, 2.0, 4.0, 7.0, 0.0]),

tests/test_usm_type.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ def test_meshgrid(usm_type_x, usm_type_y):
338338
"cos", [-dp.pi / 2, -dp.pi / 4, 0.0, dp.pi / 4, dp.pi / 2]
339339
),
340340
pytest.param("cosh", [-5.0, -3.5, 0.0, 3.5, 5.0]),
341+
pytest.param("count_nonzero", [0, 1, 7, 0]),
341342
pytest.param("exp", [1.0, 2.0, 4.0, 7.0]),
342343
pytest.param("expm1", [1.0e-10, 1.0, 2.0, 4.0, 7.0]),
343344
pytest.param("floor", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]),

tests/third_party/cupy/sorting_tests/test_count.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from tests.third_party.cupy import testing
77

88

9-
@testing.gpu
109
class TestCount(unittest.TestCase):
1110
@testing.for_all_dtypes()
1211
def test_count_nonzero(self, dtype):
@@ -17,12 +16,12 @@ def func(xp):
1716
if xp is cupy:
1817
# CuPy returns zero-dimensional array instead of
1918
# returning a scalar value
20-
self.assertIsInstance(c, xp.ndarray)
21-
self.assertEqual(c.dtype, "l")
22-
self.assertEqual(c.shape, ())
19+
assert isinstance(c, xp.ndarray)
20+
assert c.dtype == "p"
21+
assert c.shape == ()
2322
return int(c)
2423

25-
self.assertEqual(func(numpy), func(cupy))
24+
assert func(numpy) == func(cupy)
2625

2726
@testing.for_all_dtypes()
2827
def test_count_nonzero_zero_dim(self, dtype):
@@ -32,12 +31,12 @@ def func(xp):
3231
if xp is cupy:
3332
# CuPy returns zero-dimensional array instead of
3433
# returning a scalar value
35-
self.assertIsInstance(c, xp.ndarray)
36-
self.assertEqual(c.dtype, "l")
37-
self.assertEqual(c.shape, ())
34+
assert isinstance(c, xp.ndarray)
35+
assert c.dtype == "p"
36+
assert c.shape == ()
3837
return int(c)
3938

40-
self.assertEqual(func(numpy), func(cupy))
39+
assert func(numpy) == func(cupy)
4140

4241
@testing.for_all_dtypes()
4342
def test_count_nonzero_int_axis(self, dtype):

0 commit comments

Comments
 (0)