From 47af40137d91a63ef7bc80d70d1520ed264f915b Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 11:53:00 +0100 Subject: [PATCH 1/8] Accept tuple value for `out` keyword passing to ufuncs --- dpnp/dpnp_algo/dpnp_elementwise_common.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_elementwise_common.py b/dpnp/dpnp_algo/dpnp_elementwise_common.py index d7bc7c7fc56..c64bee9dce0 100644 --- a/dpnp/dpnp_algo/dpnp_elementwise_common.py +++ b/dpnp/dpnp_algo/dpnp_elementwise_common.py @@ -199,9 +199,15 @@ def __call__( if dtype is not None: x_usm = dpt.astype(x_usm, dtype, copy=False) + 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) - 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) @@ -361,7 +367,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 @@ -419,7 +425,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": @@ -438,7 +444,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 @@ -606,6 +612,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 ( From a51968f2f34c96029f728de488afea9d337b0a6e Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 11:55:16 +0100 Subject: [PATCH 2/8] Add a test to ufuncs scope to validate the behavior --- dpnp/tests/test_mathematical.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 5a1626360a5..6467a328844 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -2009,22 +2009,32 @@ def test_out_dtype(self, func): ): fn(*args, out=out, dtype="f4") + @pytest.mark.parametrize("xp", [numpy, dpnp]) + @pytest.mark.parametrize("func", ["abs", "add", "frexp"]) + def test_out_wrong_tuple_len(self, xp, func): + x = xp.array([1, 2, 3]) + + fn = getattr(xp, func) + args = [x] * fn.nin + + nout = fn.nout + outs = [(), tuple(range(nout + 1))] + if nout > 1: + outs.append(tuple(range(nout - 1))) + + for out in outs: + with pytest.raises( + ValueError, + match="'out' tuple must have exactly one entry per ufunc output", + ): + _ = fn(*args, out=out) + @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_unary_two_outs_out_ndarray(self, xp): x = xp.array(0.5) with pytest.raises(TypeError, match="'out' must be a tuple of arrays"): _ = xp.frexp(x, out=xp.empty(())) - @pytest.mark.parametrize("xp", [numpy, dpnp]) - @pytest.mark.parametrize("out", [(), (1,), (1, 2, 3)]) - def test_unary_two_outs_out_wrong_tuple_len(self, xp, out): - x = xp.array(0.5) - with pytest.raises( - ValueError, - match="'out' tuple must have exactly one entry per ufunc output", - ): - _ = xp.frexp(x, out=out) - @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_unary_two_outs_out_mixed(self, xp): x = xp.array(0.5) From f954927b84b1c4102b975eebc9b101837ff7a4f8 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 11:56:16 +0100 Subject: [PATCH 3/8] update existing tests for binary ufuncs --- dpnp/tests/test_binary_ufuncs.py | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/dpnp/tests/test_binary_ufuncs.py b/dpnp/tests/test_binary_ufuncs.py index ab1146201b4..8de0c2468af 100644 --- a/dpnp/tests/test_binary_ufuncs.py +++ b/dpnp/tests/test_binary_ufuncs.py @@ -131,12 +131,12 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, xp, out): + def test_invalid_out_type(self, xp, out): a = xp.arange(10) - assert_raises(TypeError, xp.add, a, 2, out) + assert_raises(TypeError, xp.add, a, 2, out=out) @pytest.mark.parametrize("func", ["fmax", "fmin", "maximum", "minimum"]) @@ -178,10 +178,10 @@ def test_invalid_shape(self, func, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, func, xp, out): + def test_invalid_out_type(self, func, xp, out): a = xp.arange(10) assert_raises(TypeError, getattr(xp, func), a, 2, out) @@ -269,10 +269,10 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, xp, out): + def test_invalid_out_type(self, xp, out): a = xp.arange(10) assert_raises(TypeError, xp.divide, a, 2, out) @@ -364,10 +364,10 @@ def test_invalid_shape(self, func, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, func, xp, out): + def test_invalid_out_type(self, func, xp, out): a = xp.arange(10) assert_raises(TypeError, getattr(xp, func), a, 2, out) @@ -645,10 +645,10 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, xp, out): + def test_invalid_out_type(self, xp, out): a = xp.arange(10) assert_raises(TypeError, xp.multiply, a, 2, out) @@ -907,10 +907,10 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, xp, out): + def test_invalid_out_type(self, xp, out): a = xp.arange(10) assert_raises(TypeError, xp.power, a, 2, out) @@ -1123,9 +1123,9 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) - def test_invalid_out(self, xp, out): + def test_invalid_out_type(self, xp, out): a = xp.arange(10) assert_raises(TypeError, xp.subtract, a, 2, out) From ae861697f30675af5cf544f0fd7c2f0546ab4c09 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 12:15:01 +0100 Subject: [PATCH 4/8] Update the docstrings of ufuncs --- dpnp/dpnp_iface_bitwise.py | 28 +++-- dpnp/dpnp_iface_logic.py | 54 +++++++--- dpnp/dpnp_iface_mathematical.py | 176 ++++++++++++++++++++++--------- dpnp/dpnp_iface_trigonometric.py | 128 ++++++++++++++++------ 4 files changed, 284 insertions(+), 102 deletions(-) diff --git a/dpnp/dpnp_iface_bitwise.py b/dpnp/dpnp_iface_bitwise.py index f8ac12a3c48..34b0594af06 100644 --- a/dpnp/dpnp_iface_bitwise.py +++ b/dpnp/dpnp_iface_bitwise.py @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/dpnp/dpnp_iface_logic.py b/dpnp/dpnp_iface_logic.py index 01cc1eee478..67ce9b65b54 100644 --- a/dpnp/dpnp_iface_logic.py +++ b/dpnp/dpnp_iface_logic.py @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index f815631991b..576b0ac63ae 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -395,9 +395,11 @@ def _validate_interp_param(param, name, exec_q, usm_type, dtype=None): ---------- 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 @@ -467,9 +469,11 @@ def _validate_interp_param(param, name, exec_q, usm_type, dtype=None): 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 @@ -549,9 +553,11 @@ def _validate_interp_param(param, name, exec_q, usm_type, dtype=None): Return angle in degrees if ``True``, radians if ``False``. Default: ``False``. -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 @@ -661,9 +667,11 @@ def around(x, /, decimals=0, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a boolean or real-valued 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 @@ -799,9 +807,11 @@ def clip(a, /, min=None, max=None, *, out=None, order="K", **kwargs): ---------- 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 @@ -856,9 +866,11 @@ def clip(a, /, min=None, max=None, *, out=None, order="K", **kwargs): x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point 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 @@ -1545,9 +1557,11 @@ def diff(a, n=1, axis=-1, prepend=None, append=None): First input array, expected to have a floating-point data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a floating-point 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 @@ -1720,9 +1734,11 @@ def ediff1d(ary, to_end=None, to_begin=None): ---------- x : {dpnp.ndarray, usm_ndarray} The array of numbers for which the absolute values are required. -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 @@ -1779,9 +1795,11 @@ def ediff1d(ary, to_end=None, to_begin=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a boolean or real-valued 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 @@ -1849,9 +1867,11 @@ def ediff1d(ary, to_end=None, to_begin=None): First input array, expected to have a numeric data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to a numeric data type. -out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. Array must have the correct shape and - the expected data type. +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 @@ -1946,9 +1966,11 @@ def ediff1d(ary, to_end=None, to_begin=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a boolean or real-valued 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 @@ -2014,9 +2036,11 @@ def ediff1d(ary, to_end=None, to_begin=None): First input array, expected to have a real-valued data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued 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 @@ -2096,9 +2120,11 @@ def ediff1d(ary, to_end=None, to_begin=None): 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 @@ -2187,9 +2213,11 @@ def ediff1d(ary, to_end=None, to_begin=None): 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 @@ -2276,9 +2304,11 @@ def ediff1d(ary, to_end=None, to_begin=None): x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a boolean or real-valued 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 @@ -2421,7 +2451,7 @@ def ediff1d(ary, to_end=None, to_begin=None): ) -_GCD_DOCSTRING = r""" +_GCD_DOCSTRING = """ Returns the greatest common divisor of :math:`|x_1|` and :math:`|x_2|`. For full documentation refer to :obj:`numpy.gcd`. @@ -2432,9 +2462,11 @@ def ediff1d(ary, to_end=None, to_begin=None): First input array, expected to have an integer data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also 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 @@ -2706,9 +2738,11 @@ def gradient(f, *varargs, axis=None, edge_order=1): x2 : {dpnp.ndarray, usm_ndarray, scalar} The value of the function when `x1` is ``0``, also expected to have a real-valued floating-point 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 @@ -2765,9 +2799,11 @@ def gradient(f, *varargs, axis=None, edge_order=1): x : {dpnp.ndarray, usm_ndarray} Argument of the Bessel function, expected to have a real-valued floating-point 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 @@ -2813,9 +2849,11 @@ def gradient(f, *varargs, axis=None, edge_order=1): ---------- 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 @@ -3040,7 +3078,7 @@ def interp(x, xp, fp, left=None, right=None, period=None): return output -_LCM_DOCSTRING = r""" +_LCM_DOCSTRING = """ Returns the lowest common multiple of :math:`|x_1|` and :math:`|x_2|`. For full documentation refer to :obj:`numpy.lcm`. @@ -3051,9 +3089,11 @@ def interp(x, xp, fp, left=None, right=None, period=None): First input array, expected to have an integer data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also 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 @@ -3117,9 +3157,11 @@ def interp(x, xp, fp, left=None, right=None, period=None): type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Array of exponents of two, expected to have an integer data type. -out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. Array must have the correct shape and - the expected data type. +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 @@ -3190,9 +3232,11 @@ def interp(x, xp, fp, left=None, right=None, period=None): 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 @@ -3279,9 +3323,11 @@ def interp(x, xp, fp, left=None, right=None, period=None): 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 @@ -3441,9 +3487,11 @@ def interp(x, xp, fp, left=None, right=None, period=None): 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 @@ -3657,9 +3705,11 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a numeric 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 @@ -3720,9 +3770,11 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): x2 : {dpnp.ndarray, usm_ndarray, scalar} The direction where to look for the next representable value of `x1`, also expected to have a real-valued floating-point data type. -out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. Array must have the correct shape and - the expected data type. +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 @@ -3785,9 +3837,11 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a numeric 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 @@ -3854,9 +3908,11 @@ def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None): First input array, expected to have a numeric data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a numeric data type. -out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. Array must have the correct shape and - the expected data type. +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 @@ -4051,9 +4107,11 @@ def prod( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a complex floating-point 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 @@ -4106,9 +4164,11 @@ def prod( ---------- 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 @@ -4235,9 +4295,11 @@ def real_if_close(a, tol=100): First input array, expected to have a real-valued data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued 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 @@ -4323,9 +4385,11 @@ def real_if_close(a, tol=100): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a numeric 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 @@ -4388,9 +4452,11 @@ def real_if_close(a, tol=100): decimals : int, optional Number of decimal places to round to (default: 0). If decimals is negative, it specifies the number of positions to the left of the decimal point. -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``. @@ -4456,9 +4522,11 @@ def real_if_close(a, tol=100): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a numeric 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 @@ -4518,9 +4586,11 @@ def real_if_close(a, tol=100): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -4576,9 +4646,11 @@ def real_if_close(a, tol=100): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -4639,9 +4711,11 @@ def real_if_close(a, tol=100): x : {dpnp.ndarray, usm_ndarray} The array of values to find the spacing of, expected to have a real-valued floating-point 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 @@ -4700,9 +4774,11 @@ def real_if_close(a, tol=100): First input array, expected to have a numeric data type. x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a numeric 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 @@ -5008,9 +5084,11 @@ def trapezoid(y, x=None, dx=1.0, axis=-1): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a boolean or real-valued 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 diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index b068cfee231..feed2966d9e 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -123,9 +123,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -205,9 +207,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -287,9 +291,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -373,9 +379,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -454,9 +462,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -543,9 +553,11 @@ def _get_accumulation_res_dt(a, dtype): x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point 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 @@ -628,9 +640,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -705,9 +719,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -763,9 +779,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -824,9 +842,11 @@ def _get_accumulation_res_dt(a, dtype): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -976,9 +996,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -1038,9 +1060,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -1106,9 +1130,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1163,9 +1189,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1221,9 +1249,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1295,9 +1325,11 @@ def cumlogsumexp( x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point 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 @@ -1369,9 +1401,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1443,9 +1477,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1521,9 +1557,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1603,9 +1641,11 @@ def cumlogsumexp( ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -1687,9 +1727,11 @@ def cumlogsumexp( x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point 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 @@ -1765,9 +1807,11 @@ def cumlogsumexp( x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point 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 @@ -1929,9 +1973,11 @@ def logsumexp(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -1991,9 +2037,11 @@ def logsumexp(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -2060,9 +2108,11 @@ def logsumexp(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -2202,9 +2252,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point 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 @@ -2259,9 +2311,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -2320,9 +2374,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -2378,9 +2434,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -2452,9 +2510,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- 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 @@ -2509,9 +2569,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 @@ -2572,9 +2634,11 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a floating-point 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 From 8a27ab9587fd1943424ab34950de9aaafbc514de Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 12:15:54 +0100 Subject: [PATCH 5/8] Update the docstrings of erf functions, because they are also ufuncs --- dpnp/scipy/special/_erf.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/dpnp/scipy/special/_erf.py b/dpnp/scipy/special/_erf.py index ea960916e74..f9699aa79a6 100644 --- a/dpnp/scipy/special/_erf.py +++ b/dpnp/scipy/special/_erf.py @@ -69,7 +69,7 @@ def __init__( mkl_impl_fn=mkl_impl_fn, ) - def __call__(self, x, out=None): # pylint: disable=signature-differs + def __call__(self, x, /, out=None): return super().__call__(x, out=out) @@ -84,8 +84,12 @@ def __call__(self, x, out=None): # pylint: disable=signature-differs ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point data type. -out : {dpnp.ndarray, usm_ndarray}, optional +out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional Optional output array for the function values. + A tuple (possible only as a keyword argument) must have length equal to the + number of outputs. + + Default: ``None``. Returns ------- @@ -140,8 +144,12 @@ def __call__(self, x, out=None): # pylint: disable=signature-differs ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point data type. -out : {dpnp.ndarray, usm_ndarray}, optional +out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional Optional output array for the function values. + A tuple (possible only as a keyword argument) must have length equal to the + number of outputs. + + Default: ``None``. Returns ------- @@ -185,8 +193,12 @@ def __call__(self, x, out=None): # pylint: disable=signature-differs ---------- x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point data type. -out : {dpnp.ndarray, usm_ndarray}, optional +out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional Optional output array for the function values. + A tuple (possible only as a keyword argument) must have length equal to the + number of outputs. + + Default: ``None``.. Returns ------- @@ -231,8 +243,12 @@ def __call__(self, x, out=None): # pylint: disable=signature-differs x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point data type. Domain: [-1, 1]. -out : {dpnp.ndarray, usm_ndarray}, optional +out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional Optional output array for the function values. + A tuple (possible only as a keyword argument) must have length equal to the + number of outputs. + + Default: ``None``. Returns ------- @@ -284,8 +300,12 @@ def __call__(self, x, out=None): # pylint: disable=signature-differs x : {dpnp.ndarray, usm_ndarray} Input array, expected to have a real-valued floating-point data type. Domain: [0, 2]. -out : {dpnp.ndarray, usm_ndarray}, optional +out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional Optional output array for the function values. + A tuple (possible only as a keyword argument) must have length equal to the + number of outputs. + + Default: ``None``. Returns ------- From dcd40aaca5a8e3e971497688f6ed4033eb71dbb0 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 12:48:38 +0100 Subject: [PATCH 6/8] Add a special handling for fix() and round() ufuncs --- dpnp/dpnp_algo/dpnp_elementwise_common.py | 30 +++++++++++++++++------ dpnp/tests/test_mathematical.py | 9 ++++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/dpnp/dpnp_algo/dpnp_elementwise_common.py b/dpnp/dpnp_algo/dpnp_elementwise_common.py index c64bee9dce0..b0832f4e80c 100644 --- a/dpnp/dpnp_algo/dpnp_elementwise_common.py +++ b/dpnp/dpnp_algo/dpnp_elementwise_common.py @@ -199,12 +199,7 @@ def __call__( if dtype is not None: x_usm = dpt.astype(x_usm, dtype, copy=False) - 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 = 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) @@ -212,6 +207,17 @@ def __call__( 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): """ @@ -819,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) @@ -932,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): diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 6467a328844..04ecfc176b9 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -2010,14 +2010,17 @@ def test_out_dtype(self, func): fn(*args, out=out, dtype="f4") @pytest.mark.parametrize("xp", [numpy, dpnp]) - @pytest.mark.parametrize("func", ["abs", "add", "frexp"]) + @pytest.mark.parametrize("func", ["abs", "fix", "round", "add", "frexp"]) def test_out_wrong_tuple_len(self, xp, func): + if func == "round" and xp is numpy: + pytest.skip("numpy.round(x, out=(...)) is not supported") + x = xp.array([1, 2, 3]) fn = getattr(xp, func) - args = [x] * fn.nin + args = [x] * getattr(fn, "nin", getattr(dpnp, func).nin) - nout = fn.nout + nout = getattr(fn, "nout", getattr(dpnp, func).nout) outs = [(), tuple(range(nout + 1))] if nout > 1: outs.append(tuple(range(nout - 1))) From fcfb6e755ec6613a015ee5c2e39444e45bd9b100 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 12:55:16 +0100 Subject: [PATCH 7/8] Add PR to the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6514d1d23c2..7e56153fa1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum * Aligned documentation with NumPy and CuPy style by using short function names [#2633](https://github.com/IntelPython/dpnp/pull/2633) * 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) +* 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 From 4a6e4d79ee1f0921befce359a1ce237464246648 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 12 Nov 2025 13:36:30 +0100 Subject: [PATCH 8/8] Update more impacted tests --- dpnp/tests/test_mathematical.py | 4 ++-- dpnp/tests/test_umath.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 04ecfc176b9..c68dfbe9768 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -2612,8 +2612,8 @@ def test_invalid_shape(self, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) def test_invalid_out(self, xp, out): a = xp.arange(10) diff --git a/dpnp/tests/test_umath.py b/dpnp/tests/test_umath.py index 2e272327b8a..ca025fd27c5 100644 --- a/dpnp/tests/test_umath.py +++ b/dpnp/tests/test_umath.py @@ -524,8 +524,8 @@ def test_invalid_shape(self, func_params, shape): @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["4", "()", "[]", "(3, 7)", "[2, 4]"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) def test_invalid_out(self, func_params, out): func = func_params["func"] @@ -625,8 +625,8 @@ def test_invalid_shape(self, xp, func_params, shape): @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", - [4, (), [], (3, 7), [2, 4]], - ids=["scalar", "empty_tuple", "empty_list", "tuple", "list"], + [4, [], range(2), [2, 4]], + ids=["scalar", "empty_list", "range", "list"], ) def test_invalid_out(self, func_params, xp, out): func = func_params["func"]