Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum
* Added the missing positional-only and keyword-only parameter markers to bring the ufunc signatures into alignment with NumPy [#2660](https://github.com/IntelPython/dpnp/pull/2660)
* Redesigned `dpnp.modf` function to be a part of `ufunc` and `vm` pybind11 extensions [#2654](https://github.com/IntelPython/dpnp/pull/2654)
* Refactored `dpnp.fft` and `dpnp.random` submodules by removing wildcard imports and defining explicit public exports [#2649](https://github.com/IntelPython/dpnp/pull/2649)
* Added support for the `out` keyword to accept a tuple, bringing ufunc signatures into alignment with those in NumPy [#2664](https://github.com/IntelPython/dpnp/pull/2664)

### Deprecated

Expand Down
39 changes: 33 additions & 6 deletions dpnp/dpnp_algo/dpnp_elementwise_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,25 @@ def __call__(
if dtype is not None:
x_usm = dpt.astype(x_usm, dtype, copy=False)

out = self._unpack_out_kw(out)
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
res_usm = super().__call__(x_usm, out=out_usm, order=order)

res_usm = super().__call__(x_usm, out=out_usm, order=order)
if out is not None and isinstance(out, dpnp_array):
return out
return dpnp_array._create_from_usm_ndarray(res_usm)

def _unpack_out_kw(self, out):
"""Unpack `out` keyword if passed as a tuple."""

if isinstance(out, tuple):
if len(out) != self.nout:
raise ValueError(
"'out' tuple must have exactly one entry per ufunc output"
)
return out[0]
return out


class DPNPUnaryTwoOutputsFunc(UnaryElementwiseFunc):
"""
Expand Down Expand Up @@ -361,7 +373,7 @@ def __call__(
orig_out, out = list(out), list(out)
res_dts = [res1_dt, res2_dt]

for i in range(2):
for i in range(self.nout):
if out[i] is None:
continue

Expand Down Expand Up @@ -419,7 +431,7 @@ def __call__(
dep_evs = copy_ev

# Allocate a buffer for the output arrays if needed
for i in range(2):
for i in range(self.nout):
if out[i] is None:
res_dt = res_dts[i]
if order == "K":
Expand All @@ -438,7 +450,7 @@ def __call__(
)
_manager.add_event_pair(ht_unary_ev, unary_ev)

for i in range(2):
for i in range(self.nout):
orig_res, res = orig_out[i], out[i]
if not (orig_res is None or orig_res is res):
# Copy the out data from temporary buffer to original memory
Expand Down Expand Up @@ -606,6 +618,13 @@ def __call__(

x1_usm = dpnp.get_usm_ndarray_or_scalar(x1)
x2_usm = dpnp.get_usm_ndarray_or_scalar(x2)

if isinstance(out, tuple):
if len(out) != self.nout:
raise ValueError(
"'out' tuple must have exactly one entry per ufunc output"
)
out = out[0]
out_usm = None if out is None else dpnp.get_usm_ndarray(out)

if (
Expand Down Expand Up @@ -806,15 +825,22 @@ def __call__(self, x, /, out=None, *, order="K"):
pass # pass to raise error in main implementation
elif dpnp.issubdtype(x.dtype, dpnp.inexact):
pass # for inexact types, pass to calculate in the backend
elif out is not None and not dpnp.is_supported_array_type(out):
elif not (
out is None
or isinstance(out, tuple)
or dpnp.is_supported_array_type(out)
):
pass # pass to raise error in main implementation
elif out is not None and out.dtype != x.dtype:
elif not (
out is None or isinstance(out, tuple) or out.dtype == x.dtype
):
# passing will raise an error but with incorrect needed dtype
raise ValueError(
f"Output array of type {x.dtype} is needed, got {out.dtype}"
)
else:
# for exact types, return the input
out = self._unpack_out_kw(out)
if out is None:
return dpnp.copy(x, order=order)

Expand Down Expand Up @@ -919,6 +945,7 @@ def __init__(
def __call__(self, x, /, decimals=0, out=None, *, dtype=None):
if decimals != 0:
x_usm = dpnp.get_usm_ndarray(x)
out = self._unpack_out_kw(out)
out_usm = None if out is None else dpnp.get_usm_ndarray(out)

if dpnp.issubdtype(x_usm.dtype, dpnp.integer):
Expand Down
28 changes: 21 additions & 7 deletions dpnp/dpnp_iface_bitwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,11 @@ def binary_repr(num, width=None):
First input array, expected to have an integer or boolean data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also expected to have an integer or boolean data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -233,9 +235,11 @@ def binary_repr(num, width=None):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, expected to have an integer data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -290,9 +294,11 @@ def binary_repr(num, width=None):
First input array, expected to have an integer or boolean data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also expected to have an integer or boolean data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -374,9 +380,11 @@ def binary_repr(num, width=None):
First input array, expected to have an integer or boolean data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also expected to have an integer or boolean data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -460,9 +468,11 @@ def binary_repr(num, width=None):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, expected to have an integer or boolean data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -544,9 +554,11 @@ def binary_repr(num, width=None):
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also expected to have an integer data type.
Each element must be greater than or equal to ``0``.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -627,9 +639,11 @@ def binary_repr(num, width=None):
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also expected to have an integer data type.
Each element must be greater than or equal to ``0``.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down
54 changes: 40 additions & 14 deletions dpnp/dpnp_iface_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,9 +624,11 @@ def array_equiv(a1, a2):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array have the correct shape and the expected data type.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -704,9 +706,11 @@ def array_equiv(a1, a2):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -778,9 +782,11 @@ def array_equiv(a1, a2):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1066,9 +1072,11 @@ def iscomplexobj(x):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1198,9 +1206,11 @@ def isfortran(a):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1256,9 +1266,11 @@ def isfortran(a):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1593,9 +1605,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1667,9 +1681,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1740,9 +1756,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1813,9 +1831,11 @@ def isscalar(element):
----------
x : {dpnp.ndarray, usm_ndarray}
Input array, may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1879,9 +1899,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -1955,9 +1977,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down Expand Up @@ -2029,9 +2053,11 @@ def isscalar(element):
First input array, may have any data type.
x2 : {dpnp.ndarray, usm_ndarray, scalar}
Second input array, also may have any data type.
out : {None, dpnp.ndarray, usm_ndarray}, optional
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
Output array to populate.
Array must have the correct shape and the expected data type.
A tuple (possible only as a keyword argument) must have length equal to the
number of outputs.

Default: ``None``.
order : {None, "C", "F", "A", "K"}, optional
Expand Down
Loading
Loading