Skip to content

Commit b5d8308

Browse files
Merge master into refactor_public_api_exports
2 parents 382f144 + 486b00d commit b5d8308

File tree

10 files changed

+395
-152
lines changed

10 files changed

+395
-152
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum
3333
* 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)
3434
* Redesigned `dpnp.modf` function to be a part of `ufunc` and `vm` pybind11 extensions [#2654](https://github.com/IntelPython/dpnp/pull/2654)
3535
* Refactored `dpnp.fft` and `dpnp.random` submodules by removing wildcard imports and defining explicit public exports [#2649](https://github.com/IntelPython/dpnp/pull/2649)
36+
* 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)
3637

3738
### Deprecated
3839

dpnp/dpnp_algo/dpnp_elementwise_common.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,25 @@ def __call__(
199199
if dtype is not None:
200200
x_usm = dpt.astype(x_usm, dtype, copy=False)
201201

202+
out = self._unpack_out_kw(out)
202203
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
203-
res_usm = super().__call__(x_usm, out=out_usm, order=order)
204204

205+
res_usm = super().__call__(x_usm, out=out_usm, order=order)
205206
if out is not None and isinstance(out, dpnp_array):
206207
return out
207208
return dpnp_array._create_from_usm_ndarray(res_usm)
208209

210+
def _unpack_out_kw(self, out):
211+
"""Unpack `out` keyword if passed as a tuple."""
212+
213+
if isinstance(out, tuple):
214+
if len(out) != self.nout:
215+
raise ValueError(
216+
"'out' tuple must have exactly one entry per ufunc output"
217+
)
218+
return out[0]
219+
return out
220+
209221

210222
class DPNPUnaryTwoOutputsFunc(UnaryElementwiseFunc):
211223
"""
@@ -361,7 +373,7 @@ def __call__(
361373
orig_out, out = list(out), list(out)
362374
res_dts = [res1_dt, res2_dt]
363375

364-
for i in range(2):
376+
for i in range(self.nout):
365377
if out[i] is None:
366378
continue
367379

@@ -419,7 +431,7 @@ def __call__(
419431
dep_evs = copy_ev
420432

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

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

607619
x1_usm = dpnp.get_usm_ndarray_or_scalar(x1)
608620
x2_usm = dpnp.get_usm_ndarray_or_scalar(x2)
621+
622+
if isinstance(out, tuple):
623+
if len(out) != self.nout:
624+
raise ValueError(
625+
"'out' tuple must have exactly one entry per ufunc output"
626+
)
627+
out = out[0]
609628
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
610629

611630
if (
@@ -806,15 +825,22 @@ def __call__(self, x, /, out=None, *, order="K"):
806825
pass # pass to raise error in main implementation
807826
elif dpnp.issubdtype(x.dtype, dpnp.inexact):
808827
pass # for inexact types, pass to calculate in the backend
809-
elif out is not None and not dpnp.is_supported_array_type(out):
828+
elif not (
829+
out is None
830+
or isinstance(out, tuple)
831+
or dpnp.is_supported_array_type(out)
832+
):
810833
pass # pass to raise error in main implementation
811-
elif out is not None and out.dtype != x.dtype:
834+
elif not (
835+
out is None or isinstance(out, tuple) or out.dtype == x.dtype
836+
):
812837
# passing will raise an error but with incorrect needed dtype
813838
raise ValueError(
814839
f"Output array of type {x.dtype} is needed, got {out.dtype}"
815840
)
816841
else:
817842
# for exact types, return the input
843+
out = self._unpack_out_kw(out)
818844
if out is None:
819845
return dpnp.copy(x, order=order)
820846

@@ -919,6 +945,7 @@ def __init__(
919945
def __call__(self, x, /, decimals=0, out=None, *, dtype=None):
920946
if decimals != 0:
921947
x_usm = dpnp.get_usm_ndarray(x)
948+
out = self._unpack_out_kw(out)
922949
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
923950

924951
if dpnp.issubdtype(x_usm.dtype, dpnp.integer):

dpnp/dpnp_iface_bitwise.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,11 @@ def binary_repr(num, width=None):
129129
First input array, expected to have an integer or boolean data type.
130130
x2 : {dpnp.ndarray, usm_ndarray, scalar}
131131
Second input array, also expected to have an integer or boolean data type.
132-
out : {None, dpnp.ndarray, usm_ndarray}, optional
132+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
133133
Output array to populate.
134134
Array must have the correct shape and the expected data type.
135+
A tuple (possible only as a keyword argument) must have length equal to the
136+
number of outputs.
135137
136138
Default: ``None``.
137139
order : {None, "C", "F", "A", "K"}, optional
@@ -218,9 +220,11 @@ def binary_repr(num, width=None):
218220
----------
219221
x : {dpnp.ndarray, usm_ndarray}
220222
Input array, expected to have an integer data type.
221-
out : {None, dpnp.ndarray, usm_ndarray}, optional
223+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
222224
Output array to populate.
223225
Array must have the correct shape and the expected data type.
226+
A tuple (possible only as a keyword argument) must have length equal to the
227+
number of outputs.
224228
225229
Default: ``None``.
226230
order : {None, "C", "F", "A", "K"}, optional
@@ -275,9 +279,11 @@ def binary_repr(num, width=None):
275279
First input array, expected to have an integer or boolean data type.
276280
x2 : {dpnp.ndarray, usm_ndarray, scalar}
277281
Second input array, also expected to have an integer or boolean data type.
278-
out : {None, dpnp.ndarray, usm_ndarray}, optional
282+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
279283
Output array to populate.
280284
Array must have the correct shape and the expected data type.
285+
A tuple (possible only as a keyword argument) must have length equal to the
286+
number of outputs.
281287
282288
Default: ``None``.
283289
order : {None, "C", "F", "A", "K"}, optional
@@ -359,9 +365,11 @@ def binary_repr(num, width=None):
359365
First input array, expected to have an integer or boolean data type.
360366
x2 : {dpnp.ndarray, usm_ndarray, scalar}
361367
Second input array, also expected to have an integer or boolean data type.
362-
out : {None, dpnp.ndarray, usm_ndarray}, optional
368+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
363369
Output array to populate.
364370
Array must have the correct shape and the expected data type.
371+
A tuple (possible only as a keyword argument) must have length equal to the
372+
number of outputs.
365373
366374
Default: ``None``.
367375
order : {None, "C", "F", "A", "K"}, optional
@@ -445,9 +453,11 @@ def binary_repr(num, width=None):
445453
----------
446454
x : {dpnp.ndarray, usm_ndarray}
447455
Input array, expected to have an integer or boolean data type.
448-
out : {None, dpnp.ndarray, usm_ndarray}, optional
456+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
449457
Output array to populate.
450458
Array must have the correct shape and the expected data type.
459+
A tuple (possible only as a keyword argument) must have length equal to the
460+
number of outputs.
451461
452462
Default: ``None``.
453463
order : {None, "C", "F", "A", "K"}, optional
@@ -529,9 +539,11 @@ def binary_repr(num, width=None):
529539
x2 : {dpnp.ndarray, usm_ndarray, scalar}
530540
Second input array, also expected to have an integer data type.
531541
Each element must be greater than or equal to ``0``.
532-
out : {None, dpnp.ndarray, usm_ndarray}, optional
542+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
533543
Output array to populate.
534544
Array must have the correct shape and the expected data type.
545+
A tuple (possible only as a keyword argument) must have length equal to the
546+
number of outputs.
535547
536548
Default: ``None``.
537549
order : {None, "C", "F", "A", "K"}, optional
@@ -612,9 +624,11 @@ def binary_repr(num, width=None):
612624
x2 : {dpnp.ndarray, usm_ndarray, scalar}
613625
Second input array, also expected to have an integer data type.
614626
Each element must be greater than or equal to ``0``.
615-
out : {None, dpnp.ndarray, usm_ndarray}, optional
627+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
616628
Output array to populate.
617629
Array must have the correct shape and the expected data type.
630+
A tuple (possible only as a keyword argument) must have length equal to the
631+
number of outputs.
618632
619633
Default: ``None``.
620634
order : {None, "C", "F", "A", "K"}, optional

dpnp/dpnp_iface_logic.py

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,11 @@ def array_equiv(a1, a2):
594594
First input array, may have any data type.
595595
x2 : {dpnp.ndarray, usm_ndarray, scalar}
596596
Second input array, also may have any data type.
597-
out : {None, dpnp.ndarray, usm_ndarray}, optional
597+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
598598
Output array to populate.
599-
Array have the correct shape and the expected data type.
599+
Array must have the correct shape and the expected data type.
600+
A tuple (possible only as a keyword argument) must have length equal to the
601+
number of outputs.
600602
601603
Default: ``None``.
602604
order : {None, "C", "F", "A", "K"}, optional
@@ -674,9 +676,11 @@ def array_equiv(a1, a2):
674676
First input array, may have any data type.
675677
x2 : {dpnp.ndarray, usm_ndarray, scalar}
676678
Second input array, also may have any data type.
677-
out : {None, dpnp.ndarray, usm_ndarray}, optional
679+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
678680
Output array to populate.
679681
Array must have the correct shape and the expected data type.
682+
A tuple (possible only as a keyword argument) must have length equal to the
683+
number of outputs.
680684
681685
Default: ``None``.
682686
order : {None, "C", "F", "A", "K"}, optional
@@ -748,9 +752,11 @@ def array_equiv(a1, a2):
748752
First input array, may have any data type.
749753
x2 : {dpnp.ndarray, usm_ndarray, scalar}
750754
Second input array, also may have any data type.
751-
out : {None, dpnp.ndarray, usm_ndarray}, optional
755+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
752756
Output array to populate.
753757
Array must have the correct shape and the expected data type.
758+
A tuple (possible only as a keyword argument) must have length equal to the
759+
number of outputs.
754760
755761
Default: ``None``.
756762
order : {None, "C", "F", "A", "K"}, optional
@@ -1036,9 +1042,11 @@ def iscomplexobj(x):
10361042
----------
10371043
x : {dpnp.ndarray, usm_ndarray}
10381044
Input array, may have any data type.
1039-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1045+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
10401046
Output array to populate.
10411047
Array must have the correct shape and the expected data type.
1048+
A tuple (possible only as a keyword argument) must have length equal to the
1049+
number of outputs.
10421050
10431051
Default: ``None``.
10441052
order : {None, "C", "F", "A", "K"}, optional
@@ -1168,9 +1176,11 @@ def isfortran(a):
11681176
----------
11691177
x : {dpnp.ndarray, usm_ndarray}
11701178
Input array, may have any data type.
1171-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1179+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
11721180
Output array to populate.
11731181
Array must have the correct shape and the expected data type.
1182+
A tuple (possible only as a keyword argument) must have length equal to the
1183+
number of outputs.
11741184
11751185
Default: ``None``.
11761186
order : {None, "C", "F", "A", "K"}, optional
@@ -1226,9 +1236,11 @@ def isfortran(a):
12261236
----------
12271237
x : {dpnp.ndarray, usm_ndarray}
12281238
Input array, may have any data type.
1229-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1239+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
12301240
Output array to populate.
12311241
Array must have the correct shape and the expected data type.
1242+
A tuple (possible only as a keyword argument) must have length equal to the
1243+
number of outputs.
12321244
12331245
Default: ``None``.
12341246
order : {None, "C", "F", "A", "K"}, optional
@@ -1563,9 +1575,11 @@ def isscalar(element):
15631575
First input array, may have any data type.
15641576
x2 : {dpnp.ndarray, usm_ndarray, scalar}
15651577
Second input array, also may have any data type.
1566-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1578+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
15671579
Output array to populate.
15681580
Array must have the correct shape and the expected data type.
1581+
A tuple (possible only as a keyword argument) must have length equal to the
1582+
number of outputs.
15691583
15701584
Default: ``None``.
15711585
order : {None, "C", "F", "A", "K"}, optional
@@ -1637,9 +1651,11 @@ def isscalar(element):
16371651
First input array, may have any data type.
16381652
x2 : {dpnp.ndarray, usm_ndarray, scalar}
16391653
Second input array, also may have any data type.
1640-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1654+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
16411655
Output array to populate.
16421656
Array must have the correct shape and the expected data type.
1657+
A tuple (possible only as a keyword argument) must have length equal to the
1658+
number of outputs.
16431659
16441660
Default: ``None``.
16451661
order : {None, "C", "F", "A", "K"}, optional
@@ -1710,9 +1726,11 @@ def isscalar(element):
17101726
First input array, may have any data type.
17111727
x2 : {dpnp.ndarray, usm_ndarray, scalar}
17121728
Second input array, also may have any data type.
1713-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1729+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
17141730
Output array to populate.
17151731
Array must have the correct shape and the expected data type.
1732+
A tuple (possible only as a keyword argument) must have length equal to the
1733+
number of outputs.
17161734
17171735
Default: ``None``.
17181736
order : {None, "C", "F", "A", "K"}, optional
@@ -1783,9 +1801,11 @@ def isscalar(element):
17831801
----------
17841802
x : {dpnp.ndarray, usm_ndarray}
17851803
Input array, may have any data type.
1786-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1804+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
17871805
Output array to populate.
17881806
Array must have the correct shape and the expected data type.
1807+
A tuple (possible only as a keyword argument) must have length equal to the
1808+
number of outputs.
17891809
17901810
Default: ``None``.
17911811
order : {None, "C", "F", "A", "K"}, optional
@@ -1849,9 +1869,11 @@ def isscalar(element):
18491869
First input array, may have any data type.
18501870
x2 : {dpnp.ndarray, usm_ndarray, scalar}
18511871
Second input array, also may have any data type.
1852-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1872+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
18531873
Output array to populate.
18541874
Array must have the correct shape and the expected data type.
1875+
A tuple (possible only as a keyword argument) must have length equal to the
1876+
number of outputs.
18551877
18561878
Default: ``None``.
18571879
order : {None, "C", "F", "A", "K"}, optional
@@ -1925,9 +1947,11 @@ def isscalar(element):
19251947
First input array, may have any data type.
19261948
x2 : {dpnp.ndarray, usm_ndarray, scalar}
19271949
Second input array, also may have any data type.
1928-
out : {None, dpnp.ndarray, usm_ndarray}, optional
1950+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
19291951
Output array to populate.
19301952
Array must have the correct shape and the expected data type.
1953+
A tuple (possible only as a keyword argument) must have length equal to the
1954+
number of outputs.
19311955
19321956
Default: ``None``.
19331957
order : {None, "C", "F", "A", "K"}, optional
@@ -1999,9 +2023,11 @@ def isscalar(element):
19992023
First input array, may have any data type.
20002024
x2 : {dpnp.ndarray, usm_ndarray, scalar}
20012025
Second input array, also may have any data type.
2002-
out : {None, dpnp.ndarray, usm_ndarray}, optional
2026+
out : {None, dpnp.ndarray, usm_ndarray, tuple of ndarray}, optional
20032027
Output array to populate.
20042028
Array must have the correct shape and the expected data type.
2029+
A tuple (possible only as a keyword argument) must have length equal to the
2030+
number of outputs.
20052031
20062032
Default: ``None``.
20072033
order : {None, "C", "F", "A", "K"}, optional

0 commit comments

Comments
 (0)