diff --git a/sdc/datatypes/hpat_pandas_series_functions.py b/sdc/datatypes/hpat_pandas_series_functions.py index 6b5e9ec6c..36f629a20 100644 --- a/sdc/datatypes/hpat_pandas_series_functions.py +++ b/sdc/datatypes/hpat_pandas_series_functions.py @@ -3422,7 +3422,7 @@ def hpat_pandas_series_prod_impl(self, axis=None, skipna=None, level=None, numer _skipna = skipna if _skipna: - return numpy.nanprod(self._data) + return numpy_like.nanprod(self._data) else: return numpy.prod(self._data) diff --git a/sdc/functions/numpy_like.py b/sdc/functions/numpy_like.py index 406bc0e37..9e74a76bd 100644 --- a/sdc/functions/numpy_like.py +++ b/sdc/functions/numpy_like.py @@ -364,3 +364,32 @@ def impl(a): sdc_overload(nanmin)(nan_min_max_overload_factory(min)) sdc_overload(nanmax)(nan_min_max_overload_factory(max)) + + +def nanprod(a): + pass + + +@sdc_overload(nanprod) +def np_nanprod(a): + """ + Reimplemented with parfor from numba.targets.arraymath. + """ + if not isinstance(a, types.Array): + return + if isinstance(a.dtype, types.Integer): + retty = types.intp + else: + retty = a.dtype + one = retty(1) + isnan = get_isnan(a.dtype) + + def nanprod_impl(a): + c = one + for i in prange(len(a)): + v = a[i] + if not isnan(v): + c *= v + return c + + return nanprod_impl diff --git a/sdc/tests/test_sdc_numpy.py b/sdc/tests/test_sdc_numpy.py index e7435e1d4..ece86bf6b 100644 --- a/sdc/tests/test_sdc_numpy.py +++ b/sdc/tests/test_sdc_numpy.py @@ -240,6 +240,7 @@ def sdc_impl(): sdc_func = self.jit(sdc_impl) np.testing.assert_array_equal(sdc_func(), ref_impl()) + class TestArrayReductions(TestCase): def check_reduction_basic(self, pyfunc, alt_pyfunc, all_nans=True): @@ -281,6 +282,15 @@ def sdc_impl(a): self.check_reduction_basic(ref_impl, sdc_impl) + def test_nanprod(self): + def ref_impl(a): + return np.nanprod(a) + + def sdc_impl(a): + return numpy_like.nanprod(a) + + self.check_reduction_basic(ref_impl, sdc_impl) + def test_nansum(self): def ref_impl(a): return np.nansum(a) diff --git a/sdc/tests/tests_perf/test_perf_numpy.py b/sdc/tests/tests_perf/test_perf_numpy.py index 110903d53..3a4d9288f 100644 --- a/sdc/tests/tests_perf/test_perf_numpy.py +++ b/sdc/tests/tests_perf/test_perf_numpy.py @@ -113,6 +113,11 @@ def _test_case(self, cases, name, total_data_length, data_num=1, input_data=test CE(type_='Python', code='np.nansum(data)', jitted=False), CE(type_='SDC', code='sdc.functions.numpy_like.nansum(data)', jitted=True), ], usecase_params='data'), + TC(name='nanprod', size=[10 ** 7], call_expr=[ + CE(type_='Python', code='np.nanprod(data)', jitted=False), + CE(type_='Numba', code='np.nanprod(data)', jitted=True), + CE(type_='SDC', code='sdc.functions.numpy_like.nanprod(data)', jitted=True), + ], usecase_params='data'), TC(name='sum', size=[10 ** 7], call_expr=[ CE(type_='Python', code='np.sum(data)', jitted=False), CE(type_='Numba', code='np.sum(data)', jitted=True), diff --git a/sdc/tests/tests_perf/test_perf_series.py b/sdc/tests/tests_perf/test_perf_series.py index dd4eabdc8..286c8f67c 100644 --- a/sdc/tests/tests_perf/test_perf_series.py +++ b/sdc/tests/tests_perf/test_perf_series.py @@ -115,7 +115,8 @@ def _test_case(self, pyfunc, name, total_data_length, data_num=1, input_data=tes TC(name='notna', size=[10 ** 7]), TC(name='nsmallest', size=[10 ** 6]), TC(name='nunique', size=[10 ** 7]), - TC(name='prod', size=[10 ** 8]), + TC(name='prod', size=[10 ** 8], params='skipna=True'), + TC(name='prod', size=[10 ** 8], params='skipna=False'), TC(name='pct_change', size=[10 ** 7], params='periods=1, limit=None, freq=None'), TC(name='pow', size=[10 ** 7], params='other', data_num=2), TC(name='quantile', size=[10 ** 8]),