Skip to content

Commit 9575363

Browse files
authored
Redesign dpnp.diff thorough existing calls (#1637)
* Redesigned `put_along_axis` and `take_along_axis` thorugh existing calls * Redesigned `dpnp.diff` thorugh existing calls * Proper resolving conflicts after rebase of master branch * Increased tests coverage * Fixed test_logspace_axis to be passed in wheels tests * Resolved pre-commit issue
1 parent a7add8e commit 9575363

File tree

12 files changed

+368
-134
lines changed

12 files changed

+368
-134
lines changed

.github/workflows/conda-package.yml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,7 @@ env:
3838
third_party/cupy/manipulation_tests/test_join.py
3939
third_party/cupy/manipulation_tests/test_rearrange.py
4040
third_party/cupy/manipulation_tests/test_transpose.py
41-
third_party/cupy/math_tests/test_arithmetic.py
42-
third_party/cupy/math_tests/test_explog.py
43-
third_party/cupy/math_tests/test_floating.py
44-
third_party/cupy/math_tests/test_hyperbolic.py
45-
third_party/cupy/math_tests/test_matmul.py
46-
third_party/cupy/math_tests/test_misc.py
47-
third_party/cupy/math_tests/test_rounding.py
48-
third_party/cupy/math_tests/test_trigonometric.py
41+
third_party/cupy/math_tests
4942
third_party/cupy/sorting_tests/test_sort.py
5043
third_party/cupy/sorting_tests/test_count.py
5144
third_party/cupy/statistics_tests/test_meanvar.py

dpnp/dpnp_algo/dpnp_algo_mathematical.pxi

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ __all__ += [
3939
"dpnp_cross",
4040
"dpnp_cumprod",
4141
"dpnp_cumsum",
42-
"dpnp_diff",
4342
"dpnp_ediff1d",
4443
"dpnp_fabs",
4544
"dpnp_fmod",
@@ -95,35 +94,6 @@ cpdef utils.dpnp_descriptor dpnp_cumsum(utils.dpnp_descriptor x1):
9594
return call_fptr_1in_1out(DPNP_FN_CUMSUM_EXT, x1, (x1.size,))
9695

9796

98-
cpdef utils.dpnp_descriptor dpnp_diff(utils.dpnp_descriptor x1, int n):
99-
cdef utils.dpnp_descriptor res
100-
101-
x1_obj = x1.get_array()
102-
103-
if x1.size - n < 1:
104-
res_obj = dpnp_container.empty(0,
105-
dtype=x1.dtype,
106-
device=x1_obj.sycl_device,
107-
usm_type=x1_obj.usm_type,
108-
sycl_queue=x1_obj.sycl_queue)
109-
res = utils.dpnp_descriptor(res_obj)
110-
return res
111-
112-
res_obj = dpnp_container.empty(x1.size - 1,
113-
dtype=x1.dtype,
114-
device=x1_obj.sycl_device,
115-
usm_type=x1_obj.usm_type,
116-
sycl_queue=x1_obj.sycl_queue)
117-
res = utils.dpnp_descriptor(res_obj)
118-
for i in range(res.size):
119-
res.get_pyobj()[i] = x1.get_pyobj()[i + 1] - x1.get_pyobj()[i]
120-
121-
if n == 1:
122-
return res
123-
124-
return dpnp_diff(res, n - 1)
125-
126-
12797
cpdef utils.dpnp_descriptor dpnp_ediff1d(utils.dpnp_descriptor x1):
12898

12999
if x1.size <= 1:

dpnp/dpnp_iface_indexing.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -550,17 +550,24 @@ def put_along_axis(a, indices, values, axis):
550550
551551
For full documentation refer to :obj:`numpy.put_along_axis`.
552552
553-
Limitations
554-
-----------
555-
Parameters `a` and `indices` are supported either as :class:`dpnp.ndarray`
556-
or :class:`dpctl.tensor.usm_ndarray`.
557-
Parameter `values` is supported either as scalar, :class:`dpnp.ndarray`
558-
or :class:`dpctl.tensor.usm_ndarray`.
559-
Otherwise ``TypeError`` exception will be raised.
553+
Parameters
554+
----------
555+
a : {dpnp.ndarray, usm_ndarray}, (Ni..., M, Nk...)
556+
Destination array.
557+
indices : {dpnp.ndarray, usm_ndarray}, (Ni..., J, Nk...)
558+
Indices to change along each 1d slice of `a`. This must match the
559+
dimension of input array, but dimensions in ``Ni`` and ``Nj``
560+
may be 1 to broadcast against `a`.
561+
values : {scalar, array_like}, (Ni..., J, Nk...)
562+
Values to insert at those indices. Its shape and dimension are
563+
broadcast to match that of `indices`.
564+
axis : int
565+
The axis to take 1d slices along. If axis is ``None``, the destination
566+
array is treated as if a flattened 1d view had been created of it.
560567
561568
See Also
562569
--------
563-
:obj:`dpnp.put` : Put values along an axis, using the same indices for every 1d slice.
570+
:obj:`dpnp.put` : Put values along an axis, using the same indices for every 1d slice.
564571
:obj:`dpnp.take_along_axis` : Take values from the input array by matching 1d index and data slices.
565572
566573
Examples
@@ -736,17 +743,24 @@ def take_along_axis(a, indices, axis):
736743
737744
For full documentation refer to :obj:`numpy.take_along_axis`.
738745
746+
Parameters
747+
----------
748+
a : {dpnp.ndarray, usm_ndarray}, (Ni..., M, Nk...)
749+
Source array
750+
indices : {dpnp.ndarray, usm_ndarray}, (Ni..., J, Nk...)
751+
Indices to take along each 1d slice of `a`. This must match the
752+
dimension of the input array, but dimensions ``Ni`` and ``Nj``
753+
only need to broadcast against `a`.
754+
axis : int
755+
The axis to take 1d slices along. If axis is ``None``, the input
756+
array is treated as if it had first been flattened to 1d,
757+
for consistency with `sort` and `argsort`.
758+
739759
Returns
740760
-------
741761
out : dpnp.ndarray
742762
The indexed result.
743763
744-
Limitations
745-
-----------
746-
Parameters `a` and `indices` are supported either as :class:`dpnp.ndarray`
747-
or :class:`dpctl.tensor.usm_ndarray`.
748-
Otherwise ``TypeError`` exception will be raised.
749-
750764
See Also
751765
--------
752766
:obj:`dpnp.take` : Take along an axis, using the same indices for every 1d slice.

dpnp/dpnp_iface_mathematical.py

Lines changed: 118 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@
4343
import dpctl.tensor as dpt
4444
import dpctl.utils as du
4545
import numpy
46-
from numpy.core.numeric import normalize_axis_tuple
46+
from numpy.core.numeric import (
47+
normalize_axis_index,
48+
normalize_axis_tuple,
49+
)
4750

4851
import dpnp
4952
from dpnp.dpnp_array import dpnp_array
@@ -129,6 +132,31 @@
129132
]
130133

131134

135+
def _append_to_diff_array(a, axis, combined, values):
136+
"""
137+
Append `values` to `combined` list based on data of array `a`.
138+
139+
Scalar value (including case with 0d array) is expanded to an array
140+
with length=1 in the direction of axis and the shape of the input array `a`
141+
in along all other axes.
142+
Note, if `values` is a scalar. then it is converted to 0d array allocating
143+
on the same SYCL queue as the input array `a` and with the same USM type.
144+
145+
"""
146+
147+
dpnp.check_supported_arrays_type(values, scalar_type=True)
148+
if dpnp.isscalar(values):
149+
values = dpnp.asarray(
150+
values, sycl_queue=a.sycl_queue, usm_type=a.usm_type
151+
)
152+
153+
if values.ndim == 0:
154+
shape = list(a.shape)
155+
shape[axis] = 1
156+
values = dpnp.broadcast_to(values, tuple(shape))
157+
combined.append(values)
158+
159+
132160
def absolute(
133161
x,
134162
/,
@@ -609,6 +637,10 @@ def cumsum(x1, **kwargs):
609637
Otherwise the function will be executed sequentially on CPU.
610638
Input array data types are limited by supported DPNP :ref:`Data types`.
611639
640+
See Also
641+
--------
642+
:obj:`dpnp.diff` : Calculate the n-th discrete difference along the given axis.
643+
612644
Examples
613645
--------
614646
>>> import dpnp as np
@@ -630,39 +662,95 @@ def cumsum(x1, **kwargs):
630662
return call_origin(numpy.cumsum, x1, **kwargs)
631663

632664

633-
def diff(x1, n=1, axis=-1, prepend=numpy._NoValue, append=numpy._NoValue):
665+
def diff(a, n=1, axis=-1, prepend=None, append=None):
634666
"""
635667
Calculate the n-th discrete difference along the given axis.
636668
637669
For full documentation refer to :obj:`numpy.diff`.
638670
639-
Limitations
640-
-----------
641-
Input array is supported as :obj:`dpnp.ndarray`.
642-
Parameters `axis`, `prepend` and `append` are supported only with default values.
643-
Otherwise the function will be executed sequentially on CPU.
671+
Parameters
672+
----------
673+
a : {dpnp.ndarray, usm_ndarray}
674+
Input array
675+
n : int, optional
676+
The number of times values are differenced. If zero, the input
677+
is returned as-is.
678+
axis : int, optional
679+
The axis along which the difference is taken, default is the
680+
last axis.
681+
prepend, append : {scalar, dpnp.ndarray, usm_ndarray}, optional
682+
Values to prepend or append to `a` along axis prior to
683+
performing the difference. Scalar values are expanded to
684+
arrays with length 1 in the direction of axis and the shape
685+
of the input array in along all other axes. Otherwise the
686+
dimension and shape must match `a` except along axis.
687+
688+
Returns
689+
-------
690+
out : dpnp.ndarray
691+
The n-th differences. The shape of the output is the same as `a`
692+
except along `axis` where the dimension is smaller by `n`. The
693+
type of the output is the same as the type of the difference
694+
between any two elements of `a`. This is the same as the type of
695+
`a` in most cases.
696+
697+
See Also
698+
--------
699+
:obj:`dpnp.gradient` : Return the gradient of an N-dimensional array.
700+
:obj:`dpnp.ediff1d` : Compute the differences between consecutive elements of an array.
701+
:obj:`dpnp.cumsum` : Return the cumulative sum of the elements along a given axis.
702+
703+
Examples
704+
--------
705+
>>> import dpnp as np
706+
>>> x = np.array([1, 2, 4, 7, 0])
707+
>>> np.diff(x)
708+
array([ 1, 2, 3, -7])
709+
>>> np.diff(x, n=2)
710+
array([ 1, 1, -10])
711+
712+
>>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]])
713+
>>> np.diff(x)
714+
array([[2, 3, 4],
715+
[5, 1, 2]])
716+
>>> np.diff(x, axis=0)
717+
array([[-1, 2, 0, -2]])
718+
644719
"""
645720

646-
x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
647-
if x1_desc:
648-
if not isinstance(n, int):
649-
pass
650-
elif n < 1:
651-
pass
652-
elif x1_desc.ndim != 1:
653-
pass
654-
elif axis != -1:
655-
pass
656-
elif prepend is not numpy._NoValue:
657-
pass
658-
elif append is not numpy._NoValue:
659-
pass
660-
else:
661-
return dpnp_diff(x1_desc, n).get_pyobj()
721+
dpnp.check_supported_arrays_type(a)
722+
if n == 0:
723+
return a
724+
if n < 0:
725+
raise ValueError(f"order must be non-negative but got {n}")
662726

663-
return call_origin(
664-
numpy.diff, x1, n=n, axis=axis, prepend=prepend, append=append
665-
)
727+
nd = a.ndim
728+
if nd == 0:
729+
raise ValueError("diff requires input that is at least one dimensional")
730+
axis = normalize_axis_index(axis, nd)
731+
732+
combined = []
733+
if prepend is not None:
734+
_append_to_diff_array(a, axis, combined, prepend)
735+
736+
combined.append(a)
737+
if append is not None:
738+
_append_to_diff_array(a, axis, combined, append)
739+
740+
if len(combined) > 1:
741+
a = dpnp.concatenate(combined, axis=axis)
742+
743+
slice1 = [slice(None)] * nd
744+
slice2 = [slice(None)] * nd
745+
slice1[axis] = slice(1, None)
746+
slice2[axis] = slice(None, -1)
747+
slice1 = tuple(slice1)
748+
slice2 = tuple(slice2)
749+
750+
op = dpnp.not_equal if a.dtype == numpy.bool_ else dpnp.subtract
751+
for _ in range(n):
752+
a = op(a[slice1], a[slice2])
753+
return a
666754

667755

668756
def divide(
@@ -1276,6 +1364,10 @@ def gradient(x1, *varargs, **kwargs):
12761364
Otherwise the function will be executed sequentially on CPU.
12771365
Input array data types are limited by supported DPNP :ref:`Data types`.
12781366
1367+
See Also
1368+
--------
1369+
:obj:`dpnp.diff` : Calculate the n-th discrete difference along the given axis.
1370+
12791371
Examples
12801372
--------
12811373
>>> import dpnp as np

tests/helper.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ def get_integer_dtypes():
7676
return [dpnp.int32, dpnp.int64]
7777

7878

79+
def get_integer_dtypes():
80+
"""
81+
Build a list of integer types supported by DPNP.
82+
"""
83+
84+
return [dpnp.int32, dpnp.int64]
85+
86+
7987
def get_complex_dtypes(device=None):
8088
"""
8189
Build a list of complex types supported by DPNP based on device capabilities.

tests/skipped_tests.tbl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -557,24 +557,22 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolve::test_convolve_diff
557557
tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix
558558
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out
559559
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out_wrong_shape
560+
560561
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_ndarray_cumprod_2dim_with_axis
561-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim
562-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim_with_n
563-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_without_axis
564562
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_arraylike
565563
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_huge_array
566564
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_numpy_array
567565
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_out_noncontiguous
566+
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_1dim
567+
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_2dim_without_axis
568+
568569
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_arraylike
569570
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_numpy_array
570571
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_arraylike
571572
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_numpy_array
572573
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_arraylike
573574
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_numpy_array
574-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_append
575-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_axis
576-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_n_and_axis
577-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_prepend
575+
578576
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_0_{axis=(1, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
579577
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_1_{axis=(1, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
580578
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2_{axis=(0, 2, 3), shape=(2, 3, 4, 5)}::test_nansum_axes

tests/skipped_tests_gpu.tbl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -654,16 +654,15 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolve::test_convolve_diff
654654
tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix
655655
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out
656656
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out_wrong_shape
657+
657658
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_ndarray_cumprod_2dim_with_axis
658-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim
659-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim_with_n
660-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_without_axis
661659
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_arraylike
662660
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_huge_array
663661
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_numpy_array
664662
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_out_noncontiguous
665663
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_1dim
666664
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_2dim_without_axis
665+
667666
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum
668667
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_2dim
669668
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum
@@ -676,10 +675,7 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::
676675
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_numpy_array
677676
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_arraylike
678677
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_numpy_array
679-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_append
680-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_axis
681-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_n_and_axis
682-
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_prepend
678+
683679
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_0_{axis=(1, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
684680
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_1_{axis=(1, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
685681
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2_{axis=(0, 2, 3), shape=(2, 3, 4, 5)}::test_nansum_axes

0 commit comments

Comments
 (0)