Skip to content

Commit 7cb1fd7

Browse files
authored
implement dpnp.signbit and dpnp.proj (#1535)
* implement dpnp.signbit and dpnp.proj * address comments * add sycl_q and usm_type tests for dpnp.proj
1 parent a78ae52 commit 7cb1fd7

File tree

9 files changed

+284
-10
lines changed

9 files changed

+284
-10
lines changed

doc/reference/math.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ Handling complex numbers
169169
dpnp.imag
170170
dpnp.conj
171171
dpnp.conjugate
172+
dpnp.proj
172173

173174

174175
Extrema Finding

doc/reference/ufunc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Math operations
4242
dpnp.log10
4343
dpnp.expm1
4444
dpnp.log1p
45+
dpnp.proj
4546
dpnp.sqrt
4647
dpnp.square
4748
dpnp.reciprocal

dpnp/dpnp_algo/dpnp_elementwise_common.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,14 @@
6666
"dpnp_logical_or",
6767
"dpnp_logical_xor",
6868
"dpnp_multiply",
69+
"dpnp_negative",
6970
"dpnp_not_equal",
71+
"dpnp_proj",
7072
"dpnp_remainder",
7173
"dpnp_right_shift",
7274
"dpnp_round",
75+
"dpnp_sign",
76+
"dpnp_signbit",
7377
"dpnp_sin",
7478
"dpnp_sqrt",
7579
"dpnp_square",
@@ -1456,6 +1460,43 @@ def dpnp_not_equal(x1, x2, out=None, order="K"):
14561460
return dpnp_array._create_from_usm_ndarray(res_usm)
14571461

14581462

1463+
_proj_docstring = """
1464+
proj(x, out=None, order="K")
1465+
1466+
Computes projection of each element `x_i` for input array `x`.
1467+
1468+
Args:
1469+
x (dpnp.ndarray):
1470+
Input array, expected to have numeric data type.
1471+
out ({None, dpnp.ndarray}, optional):
1472+
Output array to populate.
1473+
Array have the correct shape and the expected data type.
1474+
order ("C","F","A","K", optional):
1475+
Memory layout of the newly output array, if parameter `out` is `None`.
1476+
Default: "K".
1477+
Returns:
1478+
dpnp.ndarray:
1479+
An array containing the element-wise projection.
1480+
The returned array has the same data type as `x`.
1481+
"""
1482+
1483+
1484+
proj_func = UnaryElementwiseFunc(
1485+
"proj", ti._proj_result_type, ti._proj, _proj_docstring
1486+
)
1487+
1488+
1489+
def dpnp_proj(x, out=None, order="K"):
1490+
"""Invokes proj() from dpctl.tensor implementation for proj() function."""
1491+
1492+
# dpctl.tensor only works with usm_ndarray
1493+
x1_usm = dpnp.get_usm_ndarray(x)
1494+
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
1495+
1496+
res_usm = proj_func(x1_usm, out=out_usm, order=order)
1497+
return dpnp_array._create_from_usm_ndarray(res_usm)
1498+
1499+
14591500
_remainder_docstring_ = """
14601501
remainder(x1, x2, out=None, order='K')
14611502
Calculates the remainder of division for each element `x1_i` of the input array
@@ -1642,6 +1683,44 @@ def dpnp_sign(x, out=None, order="K"):
16421683
return dpnp_array._create_from_usm_ndarray(res_usm)
16431684

16441685

1686+
_signbit_docstring = """
1687+
signbit(x, out=None, order="K")
1688+
1689+
Computes an indication of whether the sign bit of each element `x_i` of
1690+
input array `x` is set.
1691+
1692+
Args:
1693+
x (dpnp.ndarray):
1694+
Input array, expected to have numeric data type.
1695+
out ({None, dpnp.ndarray}, optional):
1696+
Output array to populate.
1697+
Array have the correct shape and the expected data type.
1698+
order ("C","F","A","K", optional):
1699+
Memory layout of the newly output array, if parameter `out` is `None`.
1700+
Default: "K".
1701+
Returns:
1702+
dpnp.ndarray:
1703+
An array containing the element-wise results. The returned array
1704+
must have a data type of `bool`.
1705+
"""
1706+
1707+
1708+
signbit_func = UnaryElementwiseFunc(
1709+
"signbit", ti._signbit_result_type, ti._signbit, _signbit_docstring
1710+
)
1711+
1712+
1713+
def dpnp_signbit(x, out=None, order="K"):
1714+
"""Invokes signbit() from dpctl.tensor implementation for signbit() function."""
1715+
1716+
# dpctl.tensor only works with usm_ndarray
1717+
x1_usm = dpnp.get_usm_ndarray(x)
1718+
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
1719+
1720+
res_usm = signbit_func(x1_usm, out=out_usm, order=order)
1721+
return dpnp_array._create_from_usm_ndarray(res_usm)
1722+
1723+
16451724
_sin_docstring = """
16461725
sin(x, out=None, order='K')
16471726
Computes sine for each element `x_i` of input array `x`.

dpnp/dpnp_iface_mathematical.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@
5858
dpnp_floor_divide,
5959
dpnp_multiply,
6060
dpnp_negative,
61+
dpnp_proj,
6162
dpnp_remainder,
6263
dpnp_round,
6364
dpnp_sign,
65+
dpnp_signbit,
6466
dpnp_subtract,
6567
dpnp_trunc,
6668
)
@@ -101,10 +103,12 @@
101103
"negative",
102104
"power",
103105
"prod",
106+
"proj",
104107
"remainder",
105108
"rint",
106109
"round",
107110
"sign",
111+
"signbit",
108112
"subtract",
109113
"sum",
110114
"trapz",
@@ -1562,6 +1566,65 @@ def negative(
15621566
)
15631567

15641568

1569+
def proj(
1570+
x,
1571+
/,
1572+
out=None,
1573+
*,
1574+
order="K",
1575+
where=True,
1576+
dtype=None,
1577+
subok=True,
1578+
**kwargs,
1579+
):
1580+
"""
1581+
Returns the projection of a number onto the Riemann sphere.
1582+
1583+
For all infinite complex numbers (including the cases where one component is infinite and the other is `NaN`),
1584+
the function returns `(inf, 0.0)` or `(inf, -0.0)`.
1585+
For finite complex numbers, the input is returned.
1586+
All real-valued numbers are treated as complex numbers with positive zero imaginary part.
1587+
1588+
Returns
1589+
-------
1590+
out : dpnp.ndarray
1591+
The projection of each element of `x`.
1592+
1593+
Limitations
1594+
-----------
1595+
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
1596+
Parameters `where`, `dtype` and `subok` are supported with their default values.
1597+
Keyword arguments `kwargs` are currently unsupported.
1598+
Input array data types are limited by supported DPNP :ref:`Data types`.
1599+
1600+
See Also
1601+
--------
1602+
:obj:`dpnp.abs` : Returns the magnitude of a complex number, element-wise.
1603+
:obj:`dpnp.conj` : Return the complex conjugate, element-wise.
1604+
1605+
Examples
1606+
--------
1607+
>>> import dpnp as np
1608+
>>> np.proj(np.array([1, -2.3, 2.1-1.7j]))
1609+
array([ 1. +0.j, -2.3+0.j, 2.1-1.7.j])
1610+
1611+
>>> np.proj(np.array([complex(1,np.inf), complex(1,-np.inf), complex(np.inf,-1),]))
1612+
array([inf+0.j, inf-0.j, inf-0.j])
1613+
"""
1614+
1615+
return check_nd_call_func(
1616+
None,
1617+
dpnp_proj,
1618+
x,
1619+
out=out,
1620+
where=where,
1621+
order=order,
1622+
dtype=dtype,
1623+
subok=subok,
1624+
**kwargs,
1625+
)
1626+
1627+
15651628
def power(x1, x2, /, out=None, *, where=True, dtype=None, subok=True, **kwargs):
15661629
"""
15671630
First array elements raised to powers from second array, element-wise.
@@ -1931,6 +1994,10 @@ def sign(
19311994
Input array data types are limited by supported DPNP :ref:`Data types`.
19321995
However, if the input array data type is complex, the function will be executed sequentially on CPU.
19331996
1997+
See Also
1998+
--------
1999+
:obj:`dpnp.signbit` : Returns element-wise `True` where signbit is set (less than zero).
2000+
19342001
Examples
19352002
--------
19362003
>>> import dpnp as np
@@ -1968,6 +2035,63 @@ def sign(
19682035
)
19692036

19702037

2038+
def signbit(
2039+
x,
2040+
/,
2041+
out=None,
2042+
*,
2043+
order="K",
2044+
where=True,
2045+
dtype=None,
2046+
subok=True,
2047+
**kwargs,
2048+
):
2049+
"""
2050+
Returns element-wise `True` where signbit is set (less than zero).
2051+
2052+
For full documentation refer to :obj:`numpy.signbit`.
2053+
2054+
Returns
2055+
-------
2056+
out : dpnp.ndarray
2057+
A boolean array with indication of the sign of each element of `x`.
2058+
2059+
Limitations
2060+
-----------
2061+
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
2062+
Parameters `where`, `dtype` and `subok` are supported with their default values.
2063+
Keyword argument `kwargs` is currently unsupported.
2064+
Otherwise the function will be executed sequentially on CPU.
2065+
Input array data types are limited by supported real-valued data types.
2066+
2067+
See Also
2068+
--------
2069+
:obj:`dpnp.sign` : Returns an element-wise indication of the sign of a number.
2070+
2071+
Examples
2072+
--------
2073+
>>> import dpnp as np
2074+
>>> np.signbit(np.array([-1.2]))
2075+
array([True])
2076+
2077+
>>> np.signbit(np.array([1, -2.3, 2.1]))
2078+
array([False, True, False])
2079+
2080+
"""
2081+
2082+
return check_nd_call_func(
2083+
numpy.signbit,
2084+
dpnp_signbit,
2085+
x,
2086+
out=out,
2087+
where=where,
2088+
order=order,
2089+
dtype=dtype,
2090+
subok=subok,
2091+
**kwargs,
2092+
)
2093+
2094+
19712095
def subtract(
19722096
x1,
19732097
x2,

tests/skipped_tests.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ tests/test_umath.py::test_umaths[('positive', 'i')]
111111
tests/test_umath.py::test_umaths[('positive', 'l')]
112112
tests/test_umath.py::test_umaths[('positive', 'f')]
113113
tests/test_umath.py::test_umaths[('positive', 'd')]
114-
tests/test_umath.py::test_umaths[('signbit', 'f')]
115-
tests/test_umath.py::test_umaths[('signbit', 'd')]
116114
tests/test_umath.py::test_umaths[('spacing', 'f')]
117115
tests/test_umath.py::test_umaths[('spacing', 'd')]
118116

@@ -517,7 +515,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
517515
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
518516
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
519517
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
520-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
521518

522519
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
523520
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4

tests/skipped_tests_gpu.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ tests/test_umath.py::test_umaths[('positive', 'i')]
6363
tests/test_umath.py::test_umaths[('positive', 'l')]
6464
tests/test_umath.py::test_umaths[('positive', 'f')]
6565
tests/test_umath.py::test_umaths[('positive', 'd')]
66-
tests/test_umath.py::test_umaths[('signbit', 'f')]
67-
tests/test_umath.py::test_umaths[('signbit', 'd')]
6866
tests/test_umath.py::test_umaths[('spacing', 'f')]
6967
tests/test_umath.py::test_umaths[('spacing', 'd')]
7068

@@ -659,7 +657,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
659657
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
660658
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
661659
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
662-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
663660

664661
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
665662
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4

tests/test_mathematical.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from .helper import (
1616
get_all_dtypes,
17+
get_complex_dtypes,
1718
get_float_complex_dtypes,
1819
get_float_dtypes,
1920
has_support_aspect64,
@@ -442,6 +443,48 @@ def test_sign_boolean():
442443
dpnp.sign(dpnp_a)
443444

444445

446+
@pytest.mark.parametrize(
447+
"data",
448+
[[2, 0, -2], [1.1, -1.1]],
449+
ids=["[2, 0, -2]", "[1.1, -1.1]"],
450+
)
451+
@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True))
452+
def test_signbit(data, dtype):
453+
np_a = numpy.array(data, dtype=dtype)
454+
dpnp_a = dpnp.array(data, dtype=dtype)
455+
456+
result = dpnp.signbit(dpnp_a)
457+
expected = numpy.signbit(np_a)
458+
assert_allclose(result, expected)
459+
460+
461+
@pytest.mark.parametrize("dtype", get_complex_dtypes())
462+
def test_projection_infinity(dtype):
463+
X = [
464+
complex(1, 2),
465+
complex(dpnp.inf, -1),
466+
complex(0, -dpnp.inf),
467+
complex(-dpnp.inf, dpnp.nan),
468+
]
469+
Y = [
470+
complex(1, 2),
471+
complex(dpnp.inf, -0.0),
472+
complex(dpnp.inf, -0.0),
473+
complex(dpnp.inf, 0.0),
474+
]
475+
476+
result = dpnp.proj(dpnp.array(X, dtype=dtype))
477+
expected = dpnp.array(Y, dtype=dtype)
478+
assert_allclose(result, expected)
479+
480+
481+
@pytest.mark.parametrize("dtype", get_all_dtypes())
482+
def test_projection(dtype):
483+
result = dpnp.proj(dpnp.array(1, dtype=dtype))
484+
expected = dpnp.array(complex(1, 0))
485+
assert_allclose(result, expected)
486+
487+
445488
@pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True))
446489
@pytest.mark.parametrize("data_type", get_all_dtypes())
447490
@pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"])

0 commit comments

Comments
 (0)