Skip to content
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

Implementation of dpnp.append and dpnp.asarray_chkfinite #2015

Merged
merged 6 commits into from
Aug 29, 2024
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
3 changes: 3 additions & 0 deletions doc/reference/manipulation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Basic operations
:nosignatures:

dpnp.copyto
dpnp.ndim
dpnp.shape
dpnp.size


Changing array shape
Expand Down Expand Up @@ -73,6 +75,7 @@ Changing kind of array
dpnp.asfarray
dpnp.asfortranarray
dpnp.ascontiguousarray
dpnp.asarray_chkfinite
dpnp.require


Expand Down
6 changes: 3 additions & 3 deletions dpnp/dpnp_iface.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def check_limitations(
"""
Checking limitation kwargs for their supported values.

Parameter `order` is only supported with values ``"C"``, ``"F"``
Parameter `order` is only supported with values ``"C"``, ``"F"``,
and ``None``.
Parameter `subok` is only supported with default value ``False``.
Parameter `like` is only supported with default value ``None``.
Expand All @@ -343,12 +343,12 @@ def check_limitations(
if order in ("A", "a", "K", "k"):
raise NotImplementedError(
"Keyword argument `order` is supported only with "
f"values ``'C'`` and ``'F'``, but got {order}"
f"values 'C' and 'F', but got '{order}'"
)
if order not in ("C", "c", "F", "f", None):
raise ValueError(
"Unrecognized `order` keyword value, expecting "
f"``'C'`` or ``'F'``, but got {order}"
f"'C' or 'F', but got '{order}'"
)
if like is not None:
raise NotImplementedError(
Expand Down
20 changes: 5 additions & 15 deletions dpnp/dpnp_iface_arraycreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,6 @@ def empty(

Limitations
-----------
Parameter `order` is supported only with values ``"C"``, ``"F"`` and
``None``.
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.

Expand Down Expand Up @@ -1186,7 +1184,7 @@ def empty(

"""

dpnp.check_limitations(order=order, like=like)
dpnp.check_limitations(like=like)

if usm_type is None:
usm_type = "device"
Expand Down Expand Up @@ -1373,8 +1371,6 @@ def eye(

Limitations
-----------
Parameter `order` is supported only with values ``"C"``, ``"F"`` and
``None``.
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.

Expand Down Expand Up @@ -1414,7 +1410,7 @@ def eye(

"""

dpnp.check_limitations(order=order, like=like)
dpnp.check_limitations(like=like)

if usm_type is None:
usm_type = "device"
Expand Down Expand Up @@ -2013,8 +2009,6 @@ def full(

Limitations
-----------
Parameter `order` is supported only with values ``"C"``, ``"F"`` and
``None``.
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.

Expand Down Expand Up @@ -2048,7 +2042,7 @@ def full(

"""

dpnp.check_limitations(order=order, like=like)
dpnp.check_limitations(like=like)

return dpnp_container.full(
shape,
Expand Down Expand Up @@ -3057,8 +3051,6 @@ def ones(

Limitations
-----------
Parameter `order` is supported only with values ``"C"``, ``"F"`` and
``None``.
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.

Expand Down Expand Up @@ -3098,7 +3090,7 @@ def ones(

"""

dpnp.check_limitations(order=order, like=like)
dpnp.check_limitations(like=like)

if usm_type is None:
usm_type = "device"
Expand Down Expand Up @@ -3706,8 +3698,6 @@ def zeros(

Limitations
-----------
Parameter `order` is supported only with values ``"C"``, ``"F"`` and
``None``.
Parameter `like` is supported only with default value ``None``.
Otherwise, the function raises `NotImplementedError` exception.

Expand Down Expand Up @@ -3747,7 +3737,7 @@ def zeros(

"""

dpnp.check_limitations(order=order, like=like)
dpnp.check_limitations(like=like)

if usm_type is None:
usm_type = "device"
Expand Down
185 changes: 185 additions & 0 deletions dpnp/dpnp_iface_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
from .dpnp_array import dpnp_array

__all__ = [
"append",
"asarray_chkfinite",
"asfarray",
"atleast_1d",
"atleast_2d",
Expand Down Expand Up @@ -260,6 +262,189 @@ def _unpack_tuple(a):
return a


def append(arr, values, axis=None):
"""
Append values to the end of an array.

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

Parameters
----------
arr : {dpnp.ndarray, usm_ndarray}
Values are appended to a copy of this array.
values : {scalar, array_like}
These values are appended to a copy of `arr`. It must be of the
correct shape (the same shape as `arr`, excluding `axis`). If
`axis` is not specified, `values` can be any shape and will be
flattened before use.
These values can be in any form that can be converted to an array.
This includes scalars, lists, lists of tuples, tuples,
tuples of tuples, tuples of lists, and ndarrays.
axis : {None, int}, optional
The axis along which `values` are appended. If `axis` is not
given, both `arr` and `values` are flattened before use.
Default: ``None``.

Returns
-------
out : dpnp.ndarray
A copy of `arr` with `values` appended to `axis`. Note that
`append` does not occur in-place: a new array is allocated and
filled. If `axis` is None, `out` is a flattened array.

See Also
--------
:obj:`dpnp.insert` : Insert elements into an array.
:obj:`dpnp.delete` : Delete elements from an array.

Examples
--------
>>> import dpnp as np
>>> a = np.array([1, 2, 3])
>>> np.append(a, [[4, 5, 6], [7, 8, 9]])
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

When `axis` is specified, `values` must have the correct shape.

>>> b = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.append(b, [[7, 8, 9]], axis=0)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> np.append(b, [7, 8, 9], axis=0)
Traceback (most recent call last):
...
ValueError: all the input arrays must have same number of dimensions, but
the array at index 0 has 2 dimension(s) and the array at index 1 has 1
dimension(s)

"""

dpnp.check_supported_arrays_type(arr)
if not dpnp.is_supported_array_type(values):
values = dpnp.array(
values, usm_type=arr.usm_type, sycl_queue=arr.sycl_queue
)

if axis is None:
if arr.ndim != 1:
arr = dpnp.ravel(arr)
if values.ndim != 1:
values = dpnp.ravel(values)
axis = 0
return dpnp.concatenate((arr, values), axis=axis)


def asarray_chkfinite(
a, dtype=None, order=None, *, device=None, usm_type=None, sycl_queue=None
):
"""
Convert the input to an array, checking for NaNs or Infs.

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

Parameters
----------
arr : array_like
Input data, in any form that can be converted to an array. This
includes lists, lists of tuples, tuples, tuples of tuples, tuples
of lists and ndarrays. Success requires no NaNs or Infs.
dtype : str or dtype object, optional
By default, the data-type is inferred from the input data.
default: ``None``.
order : {"C", "F", "A", "K"}, optional
Memory layout of the newly output array.
Default: "K".
device : {None, string, SyclDevice, SyclQueue}, optional
An array API concept of device where the output array is created.
The `device` can be ``None`` (the default), an OneAPI filter selector
string, an instance of :class:`dpctl.SyclDevice` corresponding to
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
or a `Device` object returned by
:obj:`dpnp.dpnp_array.dpnp_array.device` property.
Default: ``None``.
usm_type : {None, "device", "shared", "host"}, optional
The type of SYCL USM allocation for the output array.
Default: ``None``.
sycl_queue : {None, SyclQueue}, optional
A SYCL queue to use for output array allocation and copying. The
`sycl_queue` can be passed as ``None`` (the default), which means
to get the SYCL queue from `device` keyword if present or to use
a default queue.
Default: ``None``.

Returns
-------
out : dpnp.ndarray
Array interpretation of `a`. No copy is performed if the input is
vtavana marked this conversation as resolved.
Show resolved Hide resolved
already an ndarray.

Raises
-------
ValueError
Raises ``ValueError`` if `a` contains NaN (Not a Number) or
Inf (Infinity).

See Also
--------
:obj:`dpnp.asarray` : Create an array.
:obj:`dpnp.asanyarray` : Converts an input object into array.
:obj:`dpnp.ascontiguousarray` : Convert input to a c-contiguous array.
:obj:`dpnp.asfortranarray` : Convert input to an array with column-major
memory order.
:obj:`dpnp.fromiter` : Create an array from an iterator.
:obj:`dpnp.fromfunction` : Construct an array by executing a function
on grid positions.

Examples
--------
>>> import dpnp as np

Convert a list into an array. If all elements are finite,
``asarray_chkfinite`` is identical to ``asarray``.

>>> a = [1, 2]
>>> np.asarray_chkfinite(a, dtype=np.float32)
array([1., 2.])

Raises ``ValueError`` if array_like contains Nans or Infs.

>>> a = [1, 2, np.inf]
>>> try:
... np.asarray_chkfinite(a)
... except ValueError:
... print('ValueError')
ValueError

Creating an array on a different device or with a specified usm_type

>>> x = np.asarray_chkfinite([1, 2, 3]) # default case
>>> x, x.device, x.usm_type
(array([1, 2, 3]), Device(level_zero:gpu:0), 'device')

>>> y = np.asarray_chkfinite([1, 2, 3], device="cpu")
>>> y, y.device, y.usm_type
(array([1, 2, 3]), Device(opencl:cpu:0), 'device')

>>> z = np.asarray_chkfinite([1, 2, 3], usm_type="host")
>>> z, z.device, z.usm_type
(array([1, 2, 3]), Device(level_zero:gpu:0), 'host')

"""

a = dpnp.asarray(
a,
dtype=dtype,
order=order,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
if dpnp.issubdtype(a.dtype, dpnp.inexact) and not dpnp.isfinite(a).all():
raise ValueError("array must not contain infs or NaNs")
return a


def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None):
"""
Return an array converted to a float type.
Expand Down
2 changes: 1 addition & 1 deletion dpnp/dpnp_iface_nanfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _replace_nan(a, val):
"""

dpnp.check_supported_arrays_type(a)
if issubclass(a.dtype.type, dpnp.inexact):
if dpnp.issubdtype(a.dtype, dpnp.inexact):
mask = dpnp.isnan(a)
if not dpnp.any(mask):
mask = None
Expand Down
22 changes: 16 additions & 6 deletions tests/test_arraycreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,34 @@ def test_out(self):
@pytest.mark.parametrize(
"func, args",
[
pytest.param("empty", [3]),
pytest.param("empty_like", [dpnp.ones(10)]),
pytest.param("eye", [3]),
pytest.param("full", [3, 7]),
pytest.param("full_like", [dpnp.ones(10), 7]),
pytest.param("ones", [3]),
pytest.param("ones_like", [dpnp.ones(10)]),
pytest.param("zeros", [3]),
pytest.param("zeros_like", [dpnp.ones(10)]),
],
)
def test_exception_order(func, args):
def test_exception_order1(func, args):
with pytest.raises(NotImplementedError):
getattr(dpnp, func)(*args, order="K")
with pytest.raises(ValueError):
getattr(dpnp, func)(*args, order="S")


@pytest.mark.parametrize(
"func, args",
[
pytest.param("empty", [3]),
pytest.param("eye", [3]),
pytest.param("full", [3, 7]),
pytest.param("ones", [3]),
pytest.param("zeros", [3]),
],
)
def test_exception_order2(func, args):
with pytest.raises(ValueError):
getattr(dpnp, func)(*args, order="S")


@pytest.mark.parametrize(
"func, args",
[
Expand Down
Loading
Loading