Skip to content

Redesign dpnp.diff thorough existing calls #1637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions .github/workflows/conda-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,7 @@ env:
third_party/cupy/manipulation_tests/test_join.py
third_party/cupy/manipulation_tests/test_rearrange.py
third_party/cupy/manipulation_tests/test_transpose.py
third_party/cupy/math_tests/test_arithmetic.py
third_party/cupy/math_tests/test_explog.py
third_party/cupy/math_tests/test_floating.py
third_party/cupy/math_tests/test_hyperbolic.py
third_party/cupy/math_tests/test_matmul.py
third_party/cupy/math_tests/test_misc.py
third_party/cupy/math_tests/test_rounding.py
third_party/cupy/math_tests/test_trigonometric.py
third_party/cupy/math_tests
third_party/cupy/sorting_tests/test_sort.py
third_party/cupy/sorting_tests/test_count.py
third_party/cupy/statistics_tests/test_meanvar.py
Expand Down
30 changes: 0 additions & 30 deletions dpnp/dpnp_algo/dpnp_algo_mathematical.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ __all__ += [
"dpnp_cross",
"dpnp_cumprod",
"dpnp_cumsum",
"dpnp_diff",
"dpnp_ediff1d",
"dpnp_fabs",
"dpnp_fmod",
Expand Down Expand Up @@ -95,35 +94,6 @@ cpdef utils.dpnp_descriptor dpnp_cumsum(utils.dpnp_descriptor x1):
return call_fptr_1in_1out(DPNP_FN_CUMSUM_EXT, x1, (x1.size,))


cpdef utils.dpnp_descriptor dpnp_diff(utils.dpnp_descriptor x1, int n):
cdef utils.dpnp_descriptor res

x1_obj = x1.get_array()

if x1.size - n < 1:
res_obj = dpnp_container.empty(0,
dtype=x1.dtype,
device=x1_obj.sycl_device,
usm_type=x1_obj.usm_type,
sycl_queue=x1_obj.sycl_queue)
res = utils.dpnp_descriptor(res_obj)
return res

res_obj = dpnp_container.empty(x1.size - 1,
dtype=x1.dtype,
device=x1_obj.sycl_device,
usm_type=x1_obj.usm_type,
sycl_queue=x1_obj.sycl_queue)
res = utils.dpnp_descriptor(res_obj)
for i in range(res.size):
res.get_pyobj()[i] = x1.get_pyobj()[i + 1] - x1.get_pyobj()[i]

if n == 1:
return res

return dpnp_diff(res, n - 1)


cpdef utils.dpnp_descriptor dpnp_ediff1d(utils.dpnp_descriptor x1):

if x1.size <= 1:
Expand Down
42 changes: 28 additions & 14 deletions dpnp/dpnp_iface_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,17 +550,24 @@ def put_along_axis(a, indices, values, axis):

For full documentation refer to :obj:`numpy.put_along_axis`.

Limitations
-----------
Parameters `a` and `indices` are supported either as :class:`dpnp.ndarray`
or :class:`dpctl.tensor.usm_ndarray`.
Parameter `values` is supported either as scalar, :class:`dpnp.ndarray`
or :class:`dpctl.tensor.usm_ndarray`.
Otherwise ``TypeError`` exception will be raised.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}, (Ni..., M, Nk...)
Destination array.
indices : {dpnp.ndarray, usm_ndarray}, (Ni..., J, Nk...)
Indices to change along each 1d slice of `a`. This must match the
dimension of input array, but dimensions in ``Ni`` and ``Nj``
may be 1 to broadcast against `a`.
values : {scalar, array_like}, (Ni..., J, Nk...)
Values to insert at those indices. Its shape and dimension are
broadcast to match that of `indices`.
axis : int
The axis to take 1d slices along. If axis is ``None``, the destination
array is treated as if a flattened 1d view had been created of it.

See Also
--------
:obj:`dpnp.put` : Put values along an axis, using the same indices for every 1d slice.
:obj:`dpnp.put` : Put values along an axis, using the same indices for every 1d slice.
:obj:`dpnp.take_along_axis` : Take values from the input array by matching 1d index and data slices.

Examples
Expand Down Expand Up @@ -736,17 +743,24 @@ def take_along_axis(a, indices, axis):

For full documentation refer to :obj:`numpy.take_along_axis`.

Parameters
----------
a : {dpnp.ndarray, usm_ndarray}, (Ni..., M, Nk...)
Source array
indices : {dpnp.ndarray, usm_ndarray}, (Ni..., J, Nk...)
Indices to take along each 1d slice of `a`. This must match the
dimension of the input array, but dimensions ``Ni`` and ``Nj``
only need to broadcast against `a`.
axis : int
The axis to take 1d slices along. If axis is ``None``, the input
array is treated as if it had first been flattened to 1d,
for consistency with `sort` and `argsort`.

Returns
-------
out : dpnp.ndarray
The indexed result.

Limitations
-----------
Parameters `a` and `indices` are supported either as :class:`dpnp.ndarray`
or :class:`dpctl.tensor.usm_ndarray`.
Otherwise ``TypeError`` exception will be raised.

See Also
--------
:obj:`dpnp.take` : Take along an axis, using the same indices for every 1d slice.
Expand Down
144 changes: 118 additions & 26 deletions dpnp/dpnp_iface_mathematical.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@
import dpctl.tensor as dpt
import dpctl.utils as du
import numpy
from numpy.core.numeric import normalize_axis_tuple
from numpy.core.numeric import (
normalize_axis_index,
normalize_axis_tuple,
)

import dpnp
from dpnp.dpnp_array import dpnp_array
Expand Down Expand Up @@ -129,6 +132,31 @@
]


def _append_to_diff_array(a, axis, combined, values):
"""
Append `values` to `combined` list based on data of array `a`.

Scalar value (including case with 0d array) is expanded to an array
with length=1 in the direction of axis and the shape of the input array `a`
in along all other axes.
Note, if `values` is a scalar. then it is converted to 0d array allocating
on the same SYCL queue as the input array `a` and with the same USM type.

"""

dpnp.check_supported_arrays_type(values, scalar_type=True)
if dpnp.isscalar(values):
values = dpnp.asarray(
values, sycl_queue=a.sycl_queue, usm_type=a.usm_type
)

if values.ndim == 0:
shape = list(a.shape)
shape[axis] = 1
values = dpnp.broadcast_to(values, tuple(shape))
combined.append(values)


def absolute(
x,
/,
Expand Down Expand Up @@ -609,6 +637,10 @@ def cumsum(x1, **kwargs):
Otherwise the function will be executed sequentially on CPU.
Input array data types are limited by supported DPNP :ref:`Data types`.

See Also
--------
:obj:`dpnp.diff` : Calculate the n-th discrete difference along the given axis.

Examples
--------
>>> import dpnp as np
Expand All @@ -630,39 +662,95 @@ def cumsum(x1, **kwargs):
return call_origin(numpy.cumsum, x1, **kwargs)


def diff(x1, n=1, axis=-1, prepend=numpy._NoValue, append=numpy._NoValue):
def diff(a, n=1, axis=-1, prepend=None, append=None):
"""
Calculate the n-th discrete difference along the given axis.

For full documentation refer to :obj:`numpy.diff`.

Limitations
-----------
Input array is supported as :obj:`dpnp.ndarray`.
Parameters `axis`, `prepend` and `append` are supported only with default values.
Otherwise the function will be executed sequentially on CPU.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array
n : int, optional
The number of times values are differenced. If zero, the input
is returned as-is.
axis : int, optional
The axis along which the difference is taken, default is the
last axis.
prepend, append : {scalar, dpnp.ndarray, usm_ndarray}, optional
Values to prepend or append to `a` along axis prior to
performing the difference. Scalar values are expanded to
arrays with length 1 in the direction of axis and the shape
of the input array in along all other axes. Otherwise the
dimension and shape must match `a` except along axis.

Returns
-------
out : dpnp.ndarray
The n-th differences. The shape of the output is the same as `a`
except along `axis` where the dimension is smaller by `n`. The
type of the output is the same as the type of the difference
between any two elements of `a`. This is the same as the type of
`a` in most cases.

See Also
--------
:obj:`dpnp.gradient` : Return the gradient of an N-dimensional array.
:obj:`dpnp.ediff1d` : Compute the differences between consecutive elements of an array.
:obj:`dpnp.cumsum` : Return the cumulative sum of the elements along a given axis.

Examples
--------
>>> import dpnp as np
>>> x = np.array([1, 2, 4, 7, 0])
>>> np.diff(x)
array([ 1, 2, 3, -7])
>>> np.diff(x, n=2)
array([ 1, 1, -10])

>>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]])
>>> np.diff(x)
array([[2, 3, 4],
[5, 1, 2]])
>>> np.diff(x, axis=0)
array([[-1, 2, 0, -2]])

"""

x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
if x1_desc:
if not isinstance(n, int):
pass
elif n < 1:
pass
elif x1_desc.ndim != 1:
pass
elif axis != -1:
pass
elif prepend is not numpy._NoValue:
pass
elif append is not numpy._NoValue:
pass
else:
return dpnp_diff(x1_desc, n).get_pyobj()
dpnp.check_supported_arrays_type(a)
if n == 0:
return a
if n < 0:
raise ValueError(f"order must be non-negative but got {n}")

return call_origin(
numpy.diff, x1, n=n, axis=axis, prepend=prepend, append=append
)
nd = a.ndim
if nd == 0:
raise ValueError("diff requires input that is at least one dimensional")
axis = normalize_axis_index(axis, nd)

combined = []
if prepend is not None:
_append_to_diff_array(a, axis, combined, prepend)

combined.append(a)
if append is not None:
_append_to_diff_array(a, axis, combined, append)

if len(combined) > 1:
a = dpnp.concatenate(combined, axis=axis)

slice1 = [slice(None)] * nd
slice2 = [slice(None)] * nd
slice1[axis] = slice(1, None)
slice2[axis] = slice(None, -1)
slice1 = tuple(slice1)
slice2 = tuple(slice2)

op = dpnp.not_equal if a.dtype == numpy.bool_ else dpnp.subtract
for _ in range(n):
a = op(a[slice1], a[slice2])
return a


def divide(
Expand Down Expand Up @@ -1276,6 +1364,10 @@ def gradient(x1, *varargs, **kwargs):
Otherwise the function will be executed sequentially on CPU.
Input array data types are limited by supported DPNP :ref:`Data types`.

See Also
--------
:obj:`dpnp.diff` : Calculate the n-th discrete difference along the given axis.

Examples
--------
>>> import dpnp as np
Expand Down
8 changes: 8 additions & 0 deletions tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ def get_integer_dtypes():
return [dpnp.int32, dpnp.int64]


def get_integer_dtypes():
"""
Build a list of integer types supported by DPNP.
"""

return [dpnp.int32, dpnp.int64]


def get_complex_dtypes(device=None):
"""
Build a list of complex types supported by DPNP based on device capabilities.
Expand Down
12 changes: 5 additions & 7 deletions tests/skipped_tests.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -557,24 +557,22 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolve::test_convolve_diff
tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out_wrong_shape

tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_ndarray_cumprod_2dim_with_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim_with_n
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_without_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_huge_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_out_noncontiguous
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_1dim
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_2dim_without_axis

tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_append
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_n_and_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_prepend

tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_0_{axis=(1, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_1_{axis=(1, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2_{axis=(0, 2, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
Expand Down
10 changes: 3 additions & 7 deletions tests/skipped_tests_gpu.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -654,16 +654,15 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolve::test_convolve_diff
tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_out_wrong_shape

tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_ndarray_cumprod_2dim_with_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_1dim_with_n
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_without_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_huge_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_out_noncontiguous
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_1dim
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumprod::test_cumprod_2dim_without_axis

tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_0_{axis=0}::test_cumsum_2dim
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum
Expand All @@ -676,10 +675,7 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_1_{axis=1}::test_cumsum_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_arraylike
tests/third_party/cupy/math_tests/test_sumprod.py::TestCumsum_param_2_{axis=2}::test_cumsum_numpy_array
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_append
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_n_and_axis
tests/third_party/cupy/math_tests/test_sumprod.py::TestDiff::test_diff_2dim_with_prepend

tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_0_{axis=(1, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_1_{axis=(1, 3), shape=(20, 30, 40, 50)}::test_nansum_axes
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodAxes_param_2_{axis=(0, 2, 3), shape=(2, 3, 4, 5)}::test_nansum_axes
Expand Down
Loading