Skip to content

Commit b6d0c4a

Browse files
authored
add kernel for cumsum and cumprod functions (#557)
1 parent 275b7be commit b6d0c4a

7 files changed

Lines changed: 134 additions & 48 deletions

File tree

dpnp/backend/include/dpnp_iface.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,30 @@ INP_DLLEXPORT void dpnp_dot_c(void* array1, void* array2, void* result1, size_t
169169
template <typename _DataType_input1, typename _DataType_input2, typename _DataType_output>
170170
INP_DLLEXPORT void dpnp_cross_c(void* array1_in, void* array2_in, void* result1, size_t size);
171171

172+
/**
173+
* @ingroup BACKEND_API
174+
* @brief Custom implementation of cumprod function
175+
*
176+
* @param [in] array1_in Input array.
177+
* @param [out] result1 Output array.
178+
* @param [in] size Number of elements in input arrays.
179+
*
180+
*/
181+
template <typename _DataType_input, typename _DataType_output>
182+
INP_DLLEXPORT void dpnp_cumprod_c(void* array1_in, void* result1, size_t size);
183+
184+
/**
185+
* @ingroup BACKEND_API
186+
* @brief Custom implementation of cumsum function
187+
*
188+
* @param [in] array1_in Input array.
189+
* @param [out] result1 Output array.
190+
* @param [in] size Number of elements in input arrays.
191+
*
192+
*/
193+
template <typename _DataType_input, typename _DataType_output>
194+
INP_DLLEXPORT void dpnp_cumsum_c(void* array1_in, void* result1, size_t size);
195+
172196
/**
173197
* @ingroup BACKEND_API
174198
* @brief Sum of array elements

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ enum class DPNPFuncName : size_t
8484
DPNP_FN_COSH, /**< Used in numpy.cosh() implementation */
8585
DPNP_FN_COV, /**< Used in numpy.cov() implementation */
8686
DPNP_FN_CROSS, /**< Used in numpy.cross() implementation */
87+
DPNP_FN_CUMPROD, /**< Used in numpy.cumprod() implementation */
88+
DPNP_FN_CUMSUM, /**< Used in numpy.cumsum() implementation */
8789
DPNP_FN_DEGREES, /**< Used in numpy.degrees() implementation */
8890
DPNP_FN_DET, /**< Used in numpy.linalg.det() implementation */
8991
DPNP_FN_DIVIDE, /**< Used in numpy.divide() implementation */

dpnp/backend/kernels/dpnp_krnl_mathematical.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,56 @@ void dpnp_cross_c(void* array1_in, void* array2_in, void* result1, size_t size)
103103
return;
104104
}
105105

106+
template <typename _KernelNameSpecialization1, typename _KernelNameSpecialization2>
107+
class dpnp_cumprod_c_kernel;
108+
109+
template <typename _DataType_input, typename _DataType_output>
110+
void dpnp_cumprod_c(void* array1_in, void* result1, size_t size)
111+
{
112+
if (!size)
113+
{
114+
return;
115+
}
116+
117+
_DataType_input* array1 = reinterpret_cast<_DataType_input*>(array1_in);
118+
_DataType_output* result = reinterpret_cast<_DataType_output*>(result1);
119+
120+
_DataType_output cur_res = 1;
121+
122+
for (size_t i = 0; i < size; ++i)
123+
{
124+
cur_res *= array1[i];
125+
result[i] = cur_res;
126+
}
127+
128+
return;
129+
}
130+
131+
template <typename _KernelNameSpecialization1, typename _KernelNameSpecialization2>
132+
class dpnp_cumsum_c_kernel;
133+
134+
template <typename _DataType_input, typename _DataType_output>
135+
void dpnp_cumsum_c(void* array1_in, void* result1, size_t size)
136+
{
137+
if (!size)
138+
{
139+
return;
140+
}
141+
142+
_DataType_input* array1 = reinterpret_cast<_DataType_input*>(array1_in);
143+
_DataType_output* result = reinterpret_cast<_DataType_output*>(result1);
144+
145+
_DataType_output cur_res = 0;
146+
147+
for (size_t i = 0; i < size; ++i)
148+
{
149+
cur_res += array1[i];
150+
result[i] = cur_res;
151+
}
152+
153+
return;
154+
}
155+
106156
template <typename _KernelNameSpecialization1, typename _KernelNameSpecialization2, typename _KernelNameSpecialization3>
107157
class dpnp_floor_divide_c_kernel;
108158

@@ -251,6 +301,16 @@ void func_map_init_mathematical(func_map_t& fmap)
251301
fmap[DPNPFuncName::DPNP_FN_CROSS][eft_DBL][eft_FLT] = {eft_DBL, (void*)dpnp_cross_c<double, float, double>};
252302
fmap[DPNPFuncName::DPNP_FN_CROSS][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_cross_c<double, double, double>};
253303

304+
fmap[DPNPFuncName::DPNP_FN_CUMPROD][eft_INT][eft_INT] = {eft_LNG, (void*)dpnp_cumprod_c<int, long>};
305+
fmap[DPNPFuncName::DPNP_FN_CUMPROD][eft_LNG][eft_LNG] = {eft_LNG, (void*)dpnp_cumprod_c<long, long>};
306+
fmap[DPNPFuncName::DPNP_FN_CUMPROD][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_cumprod_c<float, float>};
307+
fmap[DPNPFuncName::DPNP_FN_CUMPROD][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_cumprod_c<double, double>};
308+
309+
fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_INT][eft_INT] = {eft_LNG, (void*)dpnp_cumsum_c<int, long>};
310+
fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_LNG][eft_LNG] = {eft_LNG, (void*)dpnp_cumsum_c<long, long>};
311+
fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_cumsum_c<float, float>};
312+
fmap[DPNPFuncName::DPNP_FN_CUMSUM][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_cumsum_c<double, double>};
313+
254314
fmap[DPNPFuncName::DPNP_FN_FLOOR_DIVIDE][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_floor_divide_c<int, int, int>};
255315
fmap[DPNPFuncName::DPNP_FN_FLOOR_DIVIDE][eft_INT][eft_LNG] = {eft_LNG, (void*)dpnp_floor_divide_c<int, long, long>};
256316
fmap[DPNPFuncName::DPNP_FN_FLOOR_DIVIDE][eft_INT][eft_FLT] = {eft_DBL,

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
5757
DPNP_FN_COSH
5858
DPNP_FN_COV
5959
DPNP_FN_CROSS
60+
DPNP_FN_CUMPROD
61+
DPNP_FN_CUMSUM
6062
DPNP_FN_DEGREES
6163
DPNP_FN_DET
6264
DPNP_FN_DIVIDE

dpnp/dpnp_algo/dpnp_algo_mathematical.pyx

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ __all__ += [
6363
"dpnp_minimum",
6464
"dpnp_modf",
6565
"dpnp_multiply",
66+
"dpnp_nancumprod",
67+
"dpnp_nancumsum",
6668
"dpnp_nanprod",
6769
"dpnp_nansum",
6870
"dpnp_negative",
@@ -139,54 +141,28 @@ cpdef dparray dpnp_cross(dparray x1, dparray x2):
139141
return call_fptr_2in_1out(DPNP_FN_CROSS, x1, x2, x1.shape)
140142

141143

142-
cpdef dparray dpnp_cumprod(dparray x1, bint usenan=False):
144+
cpdef dparray dpnp_cumprod(dparray x1):
145+
#instead of x1.shape, (x1.size, ) is passed to the function
146+
# due to the following:
147+
# >>> import numpy
148+
# >>> a = numpy.array([[1, 2], [2, 3]])
149+
# >>> res = numpy.cumprod(a)
150+
# >>> res.shape
151+
# (4,)
143152

144-
types_map = {
145-
dpnp.int32: dpnp.int64,
146-
dpnp.int64: dpnp.int64,
147-
dpnp.float32: dpnp.float32,
148-
dpnp.float64: dpnp.float64
149-
}
150-
151-
res_type = types_map[x1.dtype.type]
152-
153-
cdef dparray result = dparray(x1.size, dtype=res_type)
154-
155-
cur_res = 1
156-
157-
for i in range(result.size):
158-
159-
if not usenan or not dpnp.isnan(x1[i]):
160-
cur_res *= x1[i]
161-
162-
result._setitem_scalar(i, cur_res)
163-
164-
return result
165-
166-
167-
cpdef dparray dpnp_cumsum(dparray x1, bint usenan=False):
168-
169-
types_map = {
170-
dpnp.int32: dpnp.int64,
171-
dpnp.int64: dpnp.int64,
172-
dpnp.float32: dpnp.float32,
173-
dpnp.float64: dpnp.float64
174-
}
175-
176-
res_type = types_map[x1.dtype.type]
153+
return call_fptr_1in_1out(DPNP_FN_CUMPROD, x1, (x1.size,))
177154

178-
cdef dparray result = dparray(x1.size, dtype=res_type)
179155

180-
cur_res = 0
156+
cpdef dparray dpnp_cumsum(dparray x1):
157+
#instead of x1.shape, (x1.size, ) is passed to the function
158+
# due to the following:
159+
# >>> import numpy
160+
# >>> a = numpy.array([[1, 2], [2, 3]])
161+
# >>> res = numpy.cumsum(a)
162+
# >>> res.shape
163+
# (4,)
181164

182-
for i in range(result.size):
183-
184-
if not usenan or not dpnp.isnan(x1[i]):
185-
cur_res += x1[i]
186-
187-
result._setitem_scalar(i, cur_res)
188-
189-
return result
165+
return call_fptr_1in_1out(DPNP_FN_CUMSUM, x1, (x1.size,))
190166

191167

192168
cpdef dparray dpnp_diff(dparray input, int n):
@@ -344,6 +320,28 @@ cpdef dparray dpnp_multiply(dparray x1, x2):
344320
return call_fptr_2in_1out(DPNP_FN_MULTIPLY, x1, x2, x1.shape)
345321

346322

323+
cpdef dparray dpnp_nancumprod(dparray x1):
324+
325+
cur_x1 = dpnp.copy(x1)
326+
327+
for i in range(cur_x1.size):
328+
if dpnp.isnan(cur_x1[i]):
329+
cur_x1._setitem_scalar(i, 1)
330+
331+
return dpnp_cumprod(cur_x1)
332+
333+
334+
cpdef dparray dpnp_nancumsum(dparray x1):
335+
336+
cur_x1 = dpnp.copy(x1)
337+
338+
for i in range(cur_x1.size):
339+
if dpnp.isnan(cur_x1[i]):
340+
cur_x1._setitem_scalar(i, 0)
341+
342+
return dpnp_cumsum(cur_x1)
343+
344+
347345
cpdef dpnp_nanprod(dparray x1):
348346
cdef dparray result = dparray(x1.shape, dtype=x1.dtype)
349347

dpnp/dpnp_iface_mathematical.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ def nancumprod(x1, **kwargs):
10651065
if not isinstance(x1, dparray):
10661066
pass
10671067
else:
1068-
return dpnp_cumprod(x1, usenan=True)
1068+
return dpnp_nancumprod(x1)
10691069

10701070
return call_origin(numpy.nancumprod, x1, **kwargs)
10711071

@@ -1103,7 +1103,7 @@ def nancumsum(x1, **kwargs):
11031103
if not isinstance(x1, dparray):
11041104
pass
11051105
else:
1106-
return dpnp_cumsum(x1, usenan=True)
1106+
return dpnp_nancumsum(x1)
11071107

11081108
return call_origin(numpy.nancumsum, x1, **kwargs)
11091109

tests/test_mathematical.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ def test_nancumprod(array):
6262
a = numpy.array(array)
6363
ia = inp.array(a)
6464

65-
result = inp.nancumsum(ia)
66-
expected = numpy.nancumsum(a)
65+
result = inp.nancumprod(ia)
66+
expected = numpy.nancumprod(a)
6767
numpy.testing.assert_array_equal(expected, result)
6868

6969

0 commit comments

Comments
 (0)