Skip to content

Commit 884aa03

Browse files
committed
implement dpnp.signbit and dpnp.proj
1 parent 1595ab7 commit 884aa03

File tree

5 files changed

+245
-6
lines changed

5 files changed

+245
-6
lines changed

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: 122 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,9 +103,11 @@
101103
"negative",
102104
"power",
103105
"prod",
106+
"proj",
104107
"remainder",
105108
"round",
106109
"sign",
110+
"signbit",
107111
"subtract",
108112
"sum",
109113
"trapz",
@@ -1544,6 +1548,64 @@ def negative(
15441548
)
15451549

15461550

1551+
def proj(
1552+
x,
1553+
/,
1554+
out=None,
1555+
*,
1556+
order="K",
1557+
where=True,
1558+
dtype=None,
1559+
subok=True,
1560+
**kwargs,
1561+
):
1562+
"""
1563+
Returns the projection of a number onto the Riemann sphere.
1564+
1565+
For all infinite complex numbers (including the cases where one component is infinite and the other is `NaN`),
1566+
the function returns `(inf, 0.0)` or `(inf, -0.0)`.
1567+
For finite complex numbers, the input is returned.
1568+
All real-valued numbers are treated as complex numbers with positive zero imaginary part.
1569+
1570+
Returns
1571+
-------
1572+
out : dpnp.ndarray
1573+
The projection of each element of `x`.
1574+
1575+
Limitations
1576+
-----------
1577+
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
1578+
Parameters `where`, `dtype` and `subok` are supported with their default values.
1579+
Keyword arguments `kwargs` are currently unsupported.
1580+
Input array data types are limited by supported DPNP :ref:`Data types`.
1581+
1582+
See Also
1583+
--------
1584+
:obj:`dpnp.abs` : Returns the magnitude of a complex number, element-wise.
1585+
1586+
Examples
1587+
--------
1588+
>>> import dpnp as np
1589+
>>> np.proj(np.array([1, -2.3, 2.1-1.7j]))
1590+
array([ 1. +0.j, -2.3+0.j, 2.1-1.7.j])
1591+
1592+
>>> np.proj(np.array([complex(1,np.inf), complex(1,-np.inf), complex(np.inf,-1),]))
1593+
array([inf+0.j, inf-0.j, inf-0.j])
1594+
"""
1595+
1596+
return check_nd_call_func(
1597+
None,
1598+
dpnp_proj,
1599+
x,
1600+
out=out,
1601+
where=where,
1602+
order=order,
1603+
dtype=dtype,
1604+
subok=subok,
1605+
**kwargs,
1606+
)
1607+
1608+
15471609
def power(x1, x2, /, out=None, *, where=True, dtype=None, subok=True, **kwargs):
15481610
"""
15491611
First array elements raised to powers from second array, element-wise.
@@ -1843,6 +1905,10 @@ def sign(
18431905
Input array data types are limited by supported DPNP :ref:`Data types`.
18441906
However, if the input array data type is complex, the function will be executed sequentially on CPU.
18451907
1908+
See Also
1909+
--------
1910+
:obj:`dpnp.signbit` : Returns element-wise `True` where signbit is set (less than zero).
1911+
18461912
Examples
18471913
--------
18481914
>>> import dpnp as np
@@ -1880,6 +1946,62 @@ def sign(
18801946
)
18811947

18821948

1949+
def signbit(
1950+
x,
1951+
/,
1952+
out=None,
1953+
*,
1954+
order="K",
1955+
where=True,
1956+
dtype=None,
1957+
subok=True,
1958+
**kwargs,
1959+
):
1960+
"""
1961+
Returns element-wise `True` where signbit is set (less than zero).
1962+
1963+
For full documentation refer to :obj:`numpy.signbit`.
1964+
1965+
Returns
1966+
-------
1967+
out : dpnp.ndarray
1968+
A boolean array with indication of the sign of each element of `x`.
1969+
1970+
Limitations
1971+
-----------
1972+
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
1973+
Parameters `where`, `dtype` and `subok` are supported with their default values.
1974+
Keyword argument `kwargs` is currently unsupported.
1975+
Otherwise the function will be executed sequentially on CPU.
1976+
Input array data types are limited by supported real-valued data types.
1977+
1978+
See Also
1979+
--------
1980+
:obj:`dpnp.sign` : Returns an element-wise indication of the sign of a number.
1981+
1982+
Examples
1983+
--------
1984+
>>> import dpnp as np
1985+
>>> np.signbit(np.array([-1.2]))
1986+
array([True])
1987+
>>> np.signbit(np.array([1, -2.3, 2.1]))
1988+
array([False, True, False])
1989+
1990+
"""
1991+
1992+
return check_nd_call_func(
1993+
numpy.signbit,
1994+
dpnp_signbit,
1995+
x,
1996+
out=out,
1997+
where=where,
1998+
order=order,
1999+
dtype=dtype,
2000+
subok=subok,
2001+
**kwargs,
2002+
)
2003+
2004+
18832005
def subtract(
18842006
x1,
18852007
x2,

tests/skipped_tests.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ tests/test_umath.py::test_umaths[('positive', 'f')]
113113
tests/test_umath.py::test_umaths[('positive', 'd')]
114114
tests/test_umath.py::test_umaths[('rint', 'f')]
115115
tests/test_umath.py::test_umaths[('rint', 'd')]
116-
tests/test_umath.py::test_umaths[('signbit', 'f')]
117-
tests/test_umath.py::test_umaths[('signbit', 'd')]
118116
tests/test_umath.py::test_umaths[('spacing', 'f')]
119117
tests/test_umath.py::test_umaths[('spacing', 'd')]
120118

@@ -519,7 +517,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
519517
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
520518
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
521519
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
522-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
523520

524521
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
525522
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
@@ -65,8 +65,6 @@ tests/test_umath.py::test_umaths[('positive', 'f')]
6565
tests/test_umath.py::test_umaths[('positive', 'd')]
6666
tests/test_umath.py::test_umaths[('rint', 'f')]
6767
tests/test_umath.py::test_umaths[('rint', 'd')]
68-
tests/test_umath.py::test_umaths[('signbit', 'f')]
69-
tests/test_umath.py::test_umaths[('signbit', 'd')]
7068
tests/test_umath.py::test_umaths[('spacing', 'f')]
7169
tests/test_umath.py::test_umaths[('spacing', 'd')]
7270

@@ -661,7 +659,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
661659
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
662660
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
663661
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
664-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
665662

666663
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
667664
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4

tests/test_mathematical.py

Lines changed: 44 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,49 @@ 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+
@pytest.mark.usefixtures("allow_fall_back_on_numpy")
453+
def test_signbit(data, dtype):
454+
np_a = numpy.array(data, dtype=dtype)
455+
dpnp_a = dpnp.array(data, dtype=dtype)
456+
457+
result = dpnp.signbit(dpnp_a)
458+
expected = numpy.signbit(np_a)
459+
assert_allclose(result, expected)
460+
461+
462+
@pytest.mark.parametrize("dtype", get_complex_dtypes())
463+
def test_projection_infinity(dtype):
464+
X = [
465+
complex(1, 2),
466+
complex(dpnp.inf, -1),
467+
complex(0, -dpnp.inf),
468+
complex(-dpnp.inf, dpnp.nan),
469+
]
470+
Y = [
471+
complex(1, 2),
472+
complex(dpnp.inf, -0.0),
473+
complex(dpnp.inf, -0.0),
474+
complex(dpnp.inf, 0.0),
475+
]
476+
477+
result = dpnp.proj(dpnp.array(X, dtype=dtype))
478+
expected = dpnp.array(Y, dtype=dtype)
479+
assert_allclose(result, expected)
480+
481+
482+
@pytest.mark.parametrize("dtype", get_all_dtypes())
483+
def test_projection(dtype):
484+
result = dpnp.proj(dpnp.array(1, dtype=dtype))
485+
expected = dpnp.array(complex(1, 0))
486+
assert_allclose(result, expected)
487+
488+
445489
@pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True))
446490
@pytest.mark.parametrize("data_type", get_all_dtypes())
447491
@pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"])

0 commit comments

Comments
 (0)