Skip to content

Commit c2a5fe4

Browse files
committed
address comments
1 parent 8a47e32 commit c2a5fe4

File tree

7 files changed

+74
-98
lines changed

7 files changed

+74
-98
lines changed

dpnp/dpnp_array.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1026,9 +1026,7 @@ def prod(
10261026
"""
10271027
Returns the prod along a given axis.
10281028
1029-
.. seealso::
1030-
:obj:`dpnp.prod` for full documentation,
1031-
:meth:`dpnp.dparray.sum`
1029+
For full documentation refer to :obj:`dpnp.prod`.
10321030
10331031
"""
10341032

dpnp/dpnp_iface_mathematical.py

+27-23
Original file line numberDiff line numberDiff line change
@@ -1761,16 +1761,19 @@ def nanprod(
17611761
where=True,
17621762
):
17631763
"""
1764-
Calculate prod() function treating 'Not a Numbers' (NaN) as ones.
1764+
Return the product of array elements over a given axis treating Not a Numbers (NaNs) as ones.
17651765
17661766
For full documentation refer to :obj:`numpy.nanprod`.
17671767
17681768
Returns
17691769
-------
17701770
out : dpnp.ndarray
1771-
Return the product of array elements over a given axis treating Not a Numbers (NaNs) as ones.
1771+
A new array holding the result is returned unless `out` is specified, in which case it is returned.
17721772
1773-
.. seealso:: :obj:`dpnp.prod` : Returns product across array propagating NaNs.
1773+
See Also
1774+
--------
1775+
:obj:`dpnp.prod` : Returns product across array propagating NaNs.
1776+
:obj:`dpnp.isnan` : Test element-wise for NaN and return result as a boolean array.
17741777
17751778
Limitations
17761779
-----------
@@ -1796,8 +1799,14 @@ def nanprod(
17961799
17971800
"""
17981801

1799-
mask = dpnp.isnan(a)
1800-
dpnp.copyto(a, 1, where=mask)
1802+
if issubclass(a.dtype.type, dpnp.inexact):
1803+
mask = dpnp.isnan(a)
1804+
else:
1805+
mask = None
1806+
1807+
if mask is not None:
1808+
a = dpnp.array(a, copy=True)
1809+
dpnp.copyto(a, 1, where=mask)
18011810

18021811
return dpnp.prod(
18031812
a,
@@ -2069,14 +2078,14 @@ def prod(
20692078
where=True,
20702079
):
20712080
"""
2072-
Calculate product of array elements over a given axis.
2081+
Return the product of array elements over a given axis.
20732082
20742083
For full documentation refer to :obj:`numpy.prod`.
20752084
20762085
Returns
20772086
-------
20782087
out : dpnp.ndarray
2079-
Return the product of array elements over a given axis.
2088+
A new array holding the result is returned unless `out` is specified, in which case it is returned.
20802089
20812090
Limitations
20822091
-----------
@@ -2085,7 +2094,9 @@ def prod(
20852094
Otherwise the function will be executed sequentially on CPU.
20862095
Input array data types are limited by DPNP :ref:`Data types`.
20872096
2088-
.. seealso:: :obj:`dpnp.nanprod` : Return the product of array elements over a given axis treating Not a Numbers (NaNs) as ones.
2097+
See Also
2098+
--------
2099+
:obj:`dpnp.nanprod` : Return the product of array elements over a given axis treating Not a Numbers (NaNs) as ones.
20892100
20902101
Examples
20912102
--------
@@ -2116,7 +2127,7 @@ def prod(
21162127
)
21172128
_dtypes = (a.dtype, dtype)
21182129
_any_complex = any(
2119-
dpt.isdtype(dpnp.dtype(dt), "complex floating") for dt in _dtypes
2130+
dpnp.issubdtype(dt, dpnp.complexfloating) for dt in _dtypes
21202131
)
21212132
device_mask = (
21222133
du.intel_device_info(a.sycl_device).get("device_id", 0) & 0xFF00
@@ -2132,10 +2143,14 @@ def prod(
21322143
initial=initial,
21332144
where=where,
21342145
)
2135-
if initial is not None:
2136-
pass
2146+
elif initial is not None:
2147+
raise NotImplementedError(
2148+
"initial keyword argument is only supported by its default value."
2149+
)
21372150
elif where is not True:
2138-
pass
2151+
raise NotImplementedError(
2152+
"where keyword argument is only supported by its default value."
2153+
)
21392154
else:
21402155
dpt_array = dpnp.get_usm_ndarray(a)
21412156
result = dpnp_array._create_from_usm_ndarray(
@@ -2163,17 +2178,6 @@ def prod(
21632178

21642179
return out
21652180

2166-
return call_origin(
2167-
numpy.prod,
2168-
a,
2169-
axis=axis,
2170-
dtype=dtype,
2171-
out=out,
2172-
keepdims=keepdims,
2173-
initial=initial,
2174-
where=where,
2175-
)
2176-
21772181

21782182
def proj(
21792183
x,

tests/skipped_tests.tbl

-4
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,6 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2
616616
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_3_{axis=(0, 2, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
617617
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodExtra_param_0_{shape=(2, 3, 4)}::test_nansum_out
618618
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodExtra_param_1_{shape=(20, 30, 40)}::test_nansum_out
619-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_11_{axis=0, func='nanprod', keepdims=True, shape=(20, 30, 40), transpose_axes=False}::test_nansum_all
620-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_11_{axis=0, func='nanprod', keepdims=True, shape=(20, 30, 40), transpose_axes=False}::test_nansum_axis_transposed
621-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_15_{axis=0, func='nanprod', keepdims=False, shape=(20, 30, 40), transpose_axes=False}::test_nansum_all
622-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_15_{axis=0, func='nanprod', keepdims=False, shape=(20, 30, 40), transpose_axes=False}::test_nansum_axis_transposed
623619

624620
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim
625621
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont

tests/skipped_tests_gpu.tbl

-4
Original file line numberDiff line numberDiff line change
@@ -711,10 +711,6 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2
711711
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_3_{axis=(0, 2, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
712712
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodExtra_param_0_{shape=(2, 3, 4)}::test_nansum_out
713713
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodExtra_param_1_{shape=(20, 30, 40)}::test_nansum_out
714-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_11_{axis=0, func='nanprod', keepdims=True, shape=(20, 30, 40), transpose_axes=False}::test_nansum_all
715-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_11_{axis=0, func='nanprod', keepdims=True, shape=(20, 30, 40), transpose_axes=False}::test_nansum_axis_transposed
716-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_15_{axis=0, func='nanprod', keepdims=False, shape=(20, 30, 40), transpose_axes=False}::test_nansum_all
717-
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_15_{axis=0, func='nanprod', keepdims=False, shape=(20, 30, 40), transpose_axes=False}::test_nansum_axis_transposed
718714

719715
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim
720716
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont

tests/test_mathematical.py

+34-64
Original file line numberDiff line numberDiff line change
@@ -461,15 +461,18 @@ def test_positive_boolean():
461461
dpnp.positive(dpnp_a)
462462

463463

464+
@pytest.mark.parametrize("func", ["prod", "nanprod"])
464465
@pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2, (1, 2), (0, -2)])
465466
@pytest.mark.parametrize("keepdims", [False, True])
466467
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
467-
def test_prod(axis, keepdims, dtype):
468+
def test_prod_nanprod(func, axis, keepdims, dtype):
468469
a = numpy.arange(1, 13, dtype=dtype).reshape((2, 2, 3))
470+
if func == "nanprod" and issubclass(a.dtype.type, dpnp.inexact):
471+
a[1:2:] = numpy.nan
469472
ia = dpnp.array(a)
470473

471-
np_res = numpy.prod(a, axis=axis, keepdims=keepdims)
472-
dpnp_res = dpnp.prod(ia, axis=axis, keepdims=keepdims)
474+
np_res = getattr(numpy, func)(a, axis=axis, keepdims=keepdims)
475+
dpnp_res = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims)
473476

474477
assert dpnp_res.shape == np_res.shape
475478
assert_allclose(dpnp_res, np_res)
@@ -487,107 +490,74 @@ def test_prod_zero_size(axis):
487490
assert_allclose(dpnp_res, np_res)
488491

489492

490-
@pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2, (1, 2), (0, -2)])
491-
@pytest.mark.parametrize("keepdims", [False, True])
492-
@pytest.mark.parametrize("dtype", get_float_complex_dtypes())
493-
def test_nanprod(axis, keepdims, dtype):
494-
a = numpy.arange(1, 13, dtype=dtype).reshape((2, 2, 3))
495-
a[1:2:] = numpy.nan
496-
ia = dpnp.array(a)
497-
498-
np_res = numpy.nanprod(a, axis=axis, keepdims=keepdims)
499-
dpnp_res = dpnp.nanprod(ia, axis=axis, keepdims=keepdims)
500-
501-
assert dpnp_res.shape == np_res.shape
502-
assert_allclose(dpnp_res, np_res)
503-
504-
493+
@pytest.mark.parametrize("func", ["prod", "nanprod"])
505494
@pytest.mark.parametrize("axis", [None, 0, 1, -1])
506495
@pytest.mark.parametrize("keepdims", [False, True])
507-
def test_prod_bool(axis, keepdims):
496+
def test_prod_nanprod_bool(func, axis, keepdims):
508497
a = numpy.arange(2, dtype=dpnp.bool)
509498
a = numpy.tile(a, (2, 2))
510499
ia = dpnp.array(a)
511500

512-
np_res = numpy.prod(a, axis=axis, keepdims=keepdims)
513-
dpnp_res = dpnp.prod(ia, axis=axis, keepdims=keepdims)
501+
np_res = getattr(numpy, func)(a, axis=axis, keepdims=keepdims)
502+
dpnp_res = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims)
514503

515504
assert dpnp_res.shape == np_res.shape
516505
assert_allclose(dpnp_res, np_res)
517506

518507

508+
@pytest.mark.usefixtures("suppress_complex_warning")
509+
@pytest.mark.usefixtures("suppress_invalid_numpy_warnings")
510+
@pytest.mark.parametrize("func", ["prod", "nanprod"])
519511
@pytest.mark.parametrize("in_dtype", get_all_dtypes(no_bool=True))
520512
@pytest.mark.parametrize("out_dtype", get_all_dtypes(no_bool=True))
521-
def test_prod_dtype(in_dtype, out_dtype):
513+
def test_prod_nanprod_dtype(func, in_dtype, out_dtype):
522514
a = numpy.arange(1, 13, dtype=in_dtype).reshape((2, 2, 3))
515+
if func == "nanprod" and issubclass(a.dtype.type, dpnp.inexact):
516+
a[1:2:] = numpy.nan
523517
ia = dpnp.array(a)
524518

525-
np_res = numpy.prod(a, dtype=out_dtype)
526-
dpnp_res = dpnp.prod(ia, dtype=out_dtype)
519+
np_res = getattr(numpy, func)(a, dtype=out_dtype)
520+
dpnp_res = getattr(dpnp, func)(ia, dtype=out_dtype)
527521

528522
if out_dtype is not None:
529523
assert dpnp_res.dtype == out_dtype
530524
assert_allclose(dpnp_res, np_res)
531525

532526

533-
@pytest.mark.parametrize("in_dtype", get_float_complex_dtypes())
534-
@pytest.mark.parametrize("out_dtype", get_float_complex_dtypes())
535-
def test_nanprod_dtype(in_dtype, out_dtype):
536-
a = numpy.arange(1, 13, dtype=in_dtype).reshape((2, 2, 3))
537-
a[1:2:] = numpy.nan
538-
ia = dpnp.array(a)
539-
540-
np_res = numpy.nanprod(a, dtype=out_dtype)
541-
dpnp_res = dpnp.nanprod(ia, dtype=out_dtype)
542-
543-
if out_dtype is not None:
544-
assert dpnp_res.dtype == out_dtype
545-
assert_allclose(dpnp_res, np_res)
546-
547-
548-
def test_prod_out():
527+
@pytest.mark.parametrize("func", ["prod", "nanprod"])
528+
def test_prod_nanprod_out(func):
549529
a = numpy.arange(1, 7).reshape((2, 3))
530+
if func == "nanprod" and issubclass(a.dtype.type, dpnp.inexact):
531+
a[1:2:] = numpy.nan
550532
ia = dpnp.array(a)
551533

552-
np_res = numpy.prod(a, axis=0)
534+
np_res = getattr(numpy, func)(a, axis=0)
553535
dpnp_res = dpnp.array(numpy.empty_like(np_res))
554-
dpnp.prod(ia, axis=0, out=dpnp_res)
536+
getattr(dpnp, func)(ia, axis=0, out=dpnp_res)
555537
assert_allclose(dpnp_res, np_res)
556538

557539
dpnp_res = dpt.asarray(numpy.empty_like(np_res))
558-
dpnp.prod(ia, axis=0, out=dpnp_res)
540+
getattr(dpnp, func)(ia, axis=0, out=dpnp_res)
559541
assert_allclose(dpnp_res, np_res)
560542

561543
dpnp_res = numpy.empty_like(np_res)
562544
with pytest.raises(TypeError):
563-
dpnp.prod(ia, axis=0, out=dpnp_res)
545+
getattr(dpnp, func)(ia, axis=0, out=dpnp_res)
564546

565547
dpnp_res = dpnp.array(numpy.empty((2, 3)))
566548
with pytest.raises(ValueError):
567-
dpnp.prod(ia, axis=0, out=dpnp_res)
549+
getattr(dpnp, func)(ia, axis=0, out=dpnp_res)
568550

569551

570-
def test_nanprod_out():
571-
a = numpy.arange(1, 7, dtype=float).reshape((2, 3))
572-
a[1:2:] = numpy.nan
573-
ia = dpnp.array(a)
574-
575-
np_res = numpy.prod(a, axis=0)
576-
dpnp_res = dpnp.array(numpy.empty_like(np_res))
577-
dpnp.prod(ia, axis=0, out=dpnp_res)
578-
assert_allclose(dpnp_res, np_res)
552+
def test_prod_Error():
553+
ia = dpnp.arange(5)
579554

580-
dpnp_res = dpt.asarray(numpy.empty_like(np_res))
581-
dpnp.prod(ia, axis=0, out=dpnp_res)
582-
assert_allclose(dpnp_res, np_res)
583-
584-
dpnp_res = numpy.empty_like(np_res)
585555
with pytest.raises(TypeError):
586-
dpnp.prod(ia, axis=0, out=dpnp_res)
587-
588-
dpnp_res = dpnp.array(numpy.empty((2, 3)))
589-
with pytest.raises(ValueError):
590-
dpnp.prod(ia, axis=0, out=dpnp_res)
556+
dpnp.prod(dpnp.asnumpy(ia))
557+
with pytest.raises(NotImplementedError):
558+
dpnp.prod(ia, where=False)
559+
with pytest.raises(NotImplementedError):
560+
dpnp.prod(ia, initial=6)
591561

592562

593563
@pytest.mark.parametrize(

tests/test_usm_type.py

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ def test_meshgrid(usm_type_x, usm_type_y):
349349
pytest.param("log10", [1.0, 2.0, 4.0, 7.0]),
350350
pytest.param("log1p", [1.0e-10, 1.0, 2.0, 4.0, 7.0]),
351351
pytest.param("log2", [1.0, 2.0, 4.0, 7.0]),
352+
pytest.param("nanprod", [1.0, 2.0, dp.nan]),
352353
pytest.param("negative", [1.0, 0.0, -1.0]),
353354
pytest.param("positive", [1.0, 0.0, -1.0]),
354355
pytest.param("prod", [1.0, 2.0]),

tests/third_party/cupy/math_tests/test_sumprod.py

+11
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,17 @@ def _numpy_nanprod_implemented(self):
267267
)
268268

269269
def _test(self, xp, dtype):
270+
if (
271+
self.func == "nanprod"
272+
and self.shape == (20, 30, 40)
273+
and has_support_aspect64()
274+
):
275+
# If input type is float, NumPy returns the same data type but
276+
# dpctl (and dpnp) returns default platform float following array api.
277+
# When input is `float32` and output is a very large number, dpnp returns
278+
# the number because it is `float64` but NumPy returns `inf` since it is `float32`.
279+
pytest.skip("Output is a very large number.")
280+
270281
a = testing.shaped_arange(self.shape, xp, dtype)
271282
if self.transpose_axes:
272283
a = a.transpose(2, 0, 1)

0 commit comments

Comments
 (0)