Skip to content

Commit 0abd5e4

Browse files
committed
implement dpnp.signbit and dpnp.proj
1 parent 57e7359 commit 0abd5e4

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
@@ -68,9 +68,13 @@
6868
"dpnp_logical_or",
6969
"dpnp_logical_xor",
7070
"dpnp_multiply",
71+
"dpnp_negative",
7172
"dpnp_not_equal",
73+
"dpnp_proj",
7274
"dpnp_remainder",
7375
"dpnp_right_shift",
76+
"dpnp_sign",
77+
"dpnp_signbit",
7478
"dpnp_sin",
7579
"dpnp_sqrt",
7680
"dpnp_square",
@@ -1478,6 +1482,43 @@ def dpnp_not_equal(x1, x2, out=None, order="K"):
14781482
return dpnp_array._create_from_usm_ndarray(res_usm)
14791483

14801484

1485+
_proj_docstring = """
1486+
proj(x, out=None, order="K")
1487+
1488+
Computes projection of each element `x_i` for input array `x`.
1489+
1490+
Args:
1491+
x (dpnp.ndarray):
1492+
Input array, expected to have numeric data type.
1493+
out ({None, dpnp.ndarray}, optional):
1494+
Output array to populate.
1495+
Array have the correct shape and the expected data type.
1496+
order ("C","F","A","K", optional):
1497+
Memory layout of the newly output array, if parameter `out` is `None`.
1498+
Default: "K".
1499+
Returns:
1500+
dpnp.ndarray:
1501+
An array containing the element-wise projection.
1502+
The returned array has the same data type as `x`.
1503+
"""
1504+
1505+
1506+
proj_func = UnaryElementwiseFunc(
1507+
"proj", ti._proj_result_type, ti._proj, _proj_docstring
1508+
)
1509+
1510+
1511+
def dpnp_proj(x, out=None, order="K"):
1512+
"""Invokes proj() from dpctl.tensor implementation for proj() function."""
1513+
1514+
# dpctl.tensor only works with usm_ndarray
1515+
x1_usm = dpnp.get_usm_ndarray(x)
1516+
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
1517+
1518+
res_usm = proj_func(x1_usm, out=out_usm, order=order)
1519+
return dpnp_array._create_from_usm_ndarray(res_usm)
1520+
1521+
14811522
_remainder_docstring_ = """
14821523
remainder(x1, x2, out=None, order='K')
14831524
Calculates the remainder of division for each element `x1_i` of the input array
@@ -1613,6 +1654,44 @@ def dpnp_sign(x, out=None, order="K"):
16131654
return dpnp_array._create_from_usm_ndarray(res_usm)
16141655

16151656

1657+
_signbit_docstring = """
1658+
signbit(x, out=None, order="K")
1659+
1660+
Computes an indication of whether the sign bit of each element `x_i` of
1661+
input array `x` is set.
1662+
1663+
Args:
1664+
x (dpnp.ndarray):
1665+
Input array, expected to have numeric data type.
1666+
out ({None, dpnp.ndarray}, optional):
1667+
Output array to populate.
1668+
Array have the correct shape and the expected data type.
1669+
order ("C","F","A","K", optional):
1670+
Memory layout of the newly output array, if parameter `out` is `None`.
1671+
Default: "K".
1672+
Returns:
1673+
dpnp.ndarray:
1674+
An array containing the element-wise results. The returned array
1675+
must have a data type of `bool`.
1676+
"""
1677+
1678+
1679+
signbit_func = UnaryElementwiseFunc(
1680+
"signbit", ti._signbit_result_type, ti._signbit, _signbit_docstring
1681+
)
1682+
1683+
1684+
def dpnp_signbit(x, out=None, order="K"):
1685+
"""Invokes signbit() from dpctl.tensor implementation for signbit() function."""
1686+
1687+
# dpctl.tensor only works with usm_ndarray
1688+
x1_usm = dpnp.get_usm_ndarray(x)
1689+
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
1690+
1691+
res_usm = signbit_func(x1_usm, out=out_usm, order=order)
1692+
return dpnp_array._create_from_usm_ndarray(res_usm)
1693+
1694+
16161695
_sin_docstring = """
16171696
sin(x, out=None, order='K')
16181697
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,8 +58,10 @@
5858
dpnp_floor_divide,
5959
dpnp_multiply,
6060
dpnp_negative,
61+
dpnp_proj,
6162
dpnp_remainder,
6263
dpnp_sign,
64+
dpnp_signbit,
6365
dpnp_subtract,
6466
dpnp_trunc,
6567
)
@@ -100,9 +102,11 @@
100102
"negative",
101103
"power",
102104
"prod",
105+
"proj",
103106
"remainder",
104107
"round_",
105108
"sign",
109+
"signbit",
106110
"subtract",
107111
"sum",
108112
"trapz",
@@ -1548,6 +1552,64 @@ def negative(
15481552
)
15491553

15501554

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

18551921

1922+
def signbit(
1923+
x,
1924+
/,
1925+
out=None,
1926+
*,
1927+
order="K",
1928+
where=True,
1929+
dtype=None,
1930+
subok=True,
1931+
**kwargs,
1932+
):
1933+
"""
1934+
Returns element-wise `True` where signbit is set (less than zero).
1935+
1936+
For full documentation refer to :obj:`numpy.signbit`.
1937+
1938+
Returns
1939+
-------
1940+
out : dpnp.ndarray
1941+
A boolean array with indication of the sign of each element of `x`.
1942+
1943+
Limitations
1944+
-----------
1945+
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
1946+
Parameters `where`, `dtype` and `subok` are supported with their default values.
1947+
Keyword argument `kwargs` is currently unsupported.
1948+
Otherwise the function will be executed sequentially on CPU.
1949+
Input array data types are limited by supported real-valued data types.
1950+
1951+
See Also
1952+
--------
1953+
:obj:`dpnp.sign` : Returns an element-wise indication of the sign of a number.
1954+
1955+
Examples
1956+
--------
1957+
>>> import dpnp as np
1958+
>>> np.signbit(np.array([-1.2]))
1959+
array([True])
1960+
>>> np.signbit(np.array([1, -2.3, 2.1]))
1961+
array([False, True, False])
1962+
1963+
"""
1964+
1965+
return check_nd_call_func(
1966+
numpy.signbit,
1967+
dpnp_signbit,
1968+
x,
1969+
out=out,
1970+
where=where,
1971+
order=order,
1972+
dtype=dtype,
1973+
subok=subok,
1974+
**kwargs,
1975+
)
1976+
1977+
18561978
def subtract(
18571979
x1,
18581980
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

@@ -527,7 +525,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
527525
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
528526
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
529527
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
530-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
531528

532529
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
533530
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

@@ -669,7 +667,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
669667
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
670668
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
671669
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
672-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit
673670

674671
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
675672
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,
@@ -432,6 +433,49 @@ def test_sign_boolean():
432433
dpnp.sign(dpnp_a)
433434

434435

436+
@pytest.mark.parametrize(
437+
"data",
438+
[[2, 0, -2], [1.1, -1.1]],
439+
ids=["[2, 0, -2]", "[1.1, -1.1]"],
440+
)
441+
@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True))
442+
@pytest.mark.usefixtures("allow_fall_back_on_numpy")
443+
def test_signbit(data, dtype):
444+
np_a = numpy.array(data, dtype=dtype)
445+
dpnp_a = dpnp.array(data, dtype=dtype)
446+
447+
result = dpnp.signbit(dpnp_a)
448+
expected = numpy.signbit(np_a)
449+
assert_allclose(result, expected)
450+
451+
452+
@pytest.mark.parametrize("dtype", get_complex_dtypes())
453+
def test_projection_infinity(dtype):
454+
X = [
455+
complex(1, 2),
456+
complex(dpnp.inf, -1),
457+
complex(0, -dpnp.inf),
458+
complex(-dpnp.inf, dpnp.nan),
459+
]
460+
Y = [
461+
complex(1, 2),
462+
complex(dpnp.inf, -0.0),
463+
complex(dpnp.inf, -0.0),
464+
complex(dpnp.inf, 0.0),
465+
]
466+
467+
result = dpnp.proj(dpnp.array(X, dtype=dtype))
468+
expected = dpnp.array(Y, dtype=dtype)
469+
assert_allclose(result, expected)
470+
471+
472+
@pytest.mark.parametrize("dtype", get_all_dtypes())
473+
def test_projection(dtype):
474+
result = dpnp.proj(dpnp.array(1, dtype=dtype))
475+
expected = dpnp.array(complex(1, 0))
476+
assert_allclose(result, expected)
477+
478+
435479
@pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True))
436480
@pytest.mark.parametrize("data_type", get_all_dtypes())
437481
@pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"])

0 commit comments

Comments
 (0)