Skip to content

Commit

Permalink
implement dpnp.signbit and dpnp.proj
Browse files Browse the repository at this point in the history
  • Loading branch information
vtavana committed Aug 25, 2023
1 parent a78ae52 commit 019478b
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 6 deletions.
79 changes: 79 additions & 0 deletions dpnp/dpnp_algo/dpnp_elementwise_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@
"dpnp_logical_or",
"dpnp_logical_xor",
"dpnp_multiply",
"dpnp_negative",
"dpnp_not_equal",
"dpnp_proj",
"dpnp_remainder",
"dpnp_right_shift",
"dpnp_round",
"dpnp_sign",
"dpnp_signbit",
"dpnp_sin",
"dpnp_sqrt",
"dpnp_square",
Expand Down Expand Up @@ -1456,6 +1460,43 @@ def dpnp_not_equal(x1, x2, out=None, order="K"):
return dpnp_array._create_from_usm_ndarray(res_usm)


_proj_docstring = """
proj(x, out=None, order="K")
Computes projection of each element `x_i` for input array `x`.
Args:
x (dpnp.ndarray):
Input array, expected to have numeric data type.
out ({None, dpnp.ndarray}, optional):
Output array to populate.
Array have the correct shape and the expected data type.
order ("C","F","A","K", optional):
Memory layout of the newly output array, if parameter `out` is `None`.
Default: "K".
Returns:
dpnp.ndarray:
An array containing the element-wise projection.
The returned array has the same data type as `x`.
"""


proj_func = UnaryElementwiseFunc(
"proj", ti._proj_result_type, ti._proj, _proj_docstring
)


def dpnp_proj(x, out=None, order="K"):
"""Invokes proj() from dpctl.tensor implementation for proj() function."""

# dpctl.tensor only works with usm_ndarray
x1_usm = dpnp.get_usm_ndarray(x)
out_usm = None if out is None else dpnp.get_usm_ndarray(out)

res_usm = proj_func(x1_usm, out=out_usm, order=order)
return dpnp_array._create_from_usm_ndarray(res_usm)


_remainder_docstring_ = """
remainder(x1, x2, out=None, order='K')
Calculates the remainder of division for each element `x1_i` of the input array
Expand Down Expand Up @@ -1642,6 +1683,44 @@ def dpnp_sign(x, out=None, order="K"):
return dpnp_array._create_from_usm_ndarray(res_usm)


_signbit_docstring = """
signbit(x, out=None, order="K")
Computes an indication of whether the sign bit of each element `x_i` of
input array `x` is set.
Args:
x (dpnp.ndarray):
Input array, expected to have numeric data type.
out ({None, dpnp.ndarray}, optional):
Output array to populate.
Array have the correct shape and the expected data type.
order ("C","F","A","K", optional):
Memory layout of the newly output array, if parameter `out` is `None`.
Default: "K".
Returns:
dpnp.ndarray:
An array containing the element-wise results. The returned array
must have a data type of `bool`.
"""


signbit_func = UnaryElementwiseFunc(
"signbit", ti._signbit_result_type, ti._signbit, _signbit_docstring
)


def dpnp_signbit(x, out=None, order="K"):
"""Invokes signbit() from dpctl.tensor implementation for signbit() function."""

# dpctl.tensor only works with usm_ndarray
x1_usm = dpnp.get_usm_ndarray(x)
out_usm = None if out is None else dpnp.get_usm_ndarray(out)

res_usm = signbit_func(x1_usm, out=out_usm, order=order)
return dpnp_array._create_from_usm_ndarray(res_usm)


_sin_docstring = """
sin(x, out=None, order='K')
Computes sine for each element `x_i` of input array `x`.
Expand Down
122 changes: 122 additions & 0 deletions dpnp/dpnp_iface_mathematical.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@
dpnp_floor_divide,
dpnp_multiply,
dpnp_negative,
dpnp_proj,
dpnp_remainder,
dpnp_round,
dpnp_sign,
dpnp_signbit,
dpnp_subtract,
dpnp_trunc,
)
Expand Down Expand Up @@ -101,10 +103,12 @@
"negative",
"power",
"prod",
"proj",
"remainder",
"rint",
"round",
"sign",
"signbit",
"subtract",
"sum",
"trapz",
Expand Down Expand Up @@ -1562,6 +1566,64 @@ def negative(
)


def proj(
x,
/,
out=None,
*,
order="K",
where=True,
dtype=None,
subok=True,
**kwargs,
):
"""
Returns the projection of a number onto the Riemann sphere.
For all infinite complex numbers (including the cases where one component is infinite and the other is `NaN`),
the function returns `(inf, 0.0)` or `(inf, -0.0)`.
For finite complex numbers, the input is returned.
All real-valued numbers are treated as complex numbers with positive zero imaginary part.
Returns
-------
out : dpnp.ndarray
The projection of each element of `x`.
Limitations
-----------
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
Parameters `where`, `dtype` and `subok` are supported with their default values.
Keyword arguments `kwargs` are currently unsupported.
Input array data types are limited by supported DPNP :ref:`Data types`.
See Also
--------
:obj:`dpnp.abs` : Returns the magnitude of a complex number, element-wise.
Examples
--------
>>> import dpnp as np
>>> np.proj(np.array([1, -2.3, 2.1-1.7j]))
array([ 1. +0.j, -2.3+0.j, 2.1-1.7.j])
>>> np.proj(np.array([complex(1,np.inf), complex(1,-np.inf), complex(np.inf,-1),]))
array([inf+0.j, inf-0.j, inf-0.j])
"""

return check_nd_call_func(
None,
dpnp_proj,
x,
out=out,
where=where,
order=order,
dtype=dtype,
subok=subok,
**kwargs,
)


def power(x1, x2, /, out=None, *, where=True, dtype=None, subok=True, **kwargs):
"""
First array elements raised to powers from second array, element-wise.
Expand Down Expand Up @@ -1931,6 +1993,10 @@ def sign(
Input array data types are limited by supported DPNP :ref:`Data types`.
However, if the input array data type is complex, the function will be executed sequentially on CPU.
See Also
--------
:obj:`dpnp.signbit` : Returns element-wise `True` where signbit is set (less than zero).
Examples
--------
>>> import dpnp as np
Expand Down Expand Up @@ -1968,6 +2034,62 @@ def sign(
)


def signbit(
x,
/,
out=None,
*,
order="K",
where=True,
dtype=None,
subok=True,
**kwargs,
):
"""
Returns element-wise `True` where signbit is set (less than zero).
For full documentation refer to :obj:`numpy.signbit`.
Returns
-------
out : dpnp.ndarray
A boolean array with indication of the sign of each element of `x`.
Limitations
-----------
Parameters `x` is only supported as either :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`.
Parameters `where`, `dtype` and `subok` are supported with their default values.
Keyword argument `kwargs` is currently unsupported.
Otherwise the function will be executed sequentially on CPU.
Input array data types are limited by supported real-valued data types.
See Also
--------
:obj:`dpnp.sign` : Returns an element-wise indication of the sign of a number.
Examples
--------
>>> import dpnp as np
>>> np.signbit(np.array([-1.2]))
array([True])
>>> np.signbit(np.array([1, -2.3, 2.1]))
array([False, True, False])
"""

return check_nd_call_func(
numpy.signbit,
dpnp_signbit,
x,
out=out,
where=where,
order=order,
dtype=dtype,
subok=subok,
**kwargs,
)


def subtract(
x1,
x2,
Expand Down
3 changes: 0 additions & 3 deletions tests/skipped_tests.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@ tests/test_umath.py::test_umaths[('positive', 'i')]
tests/test_umath.py::test_umaths[('positive', 'l')]
tests/test_umath.py::test_umaths[('positive', 'f')]
tests/test_umath.py::test_umaths[('positive', 'd')]
tests/test_umath.py::test_umaths[('signbit', 'f')]
tests/test_umath.py::test_umaths[('signbit', 'd')]
tests/test_umath.py::test_umaths[('spacing', 'f')]
tests/test_umath.py::test_umaths[('spacing', 'd')]

Expand Down Expand Up @@ -517,7 +515,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit

tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4
Expand Down
3 changes: 0 additions & 3 deletions tests/skipped_tests_gpu.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ tests/test_umath.py::test_umaths[('positive', 'i')]
tests/test_umath.py::test_umaths[('positive', 'l')]
tests/test_umath.py::test_umaths[('positive', 'f')]
tests/test_umath.py::test_umaths[('positive', 'd')]
tests/test_umath.py::test_umaths[('signbit', 'f')]
tests/test_umath.py::test_umaths[('signbit', 'd')]
tests/test_umath.py::test_umaths[('spacing', 'f')]
tests/test_umath.py::test_umaths[('spacing', 'd')]

Expand Down Expand Up @@ -659,7 +657,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_signbit

tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4
Expand Down
44 changes: 44 additions & 0 deletions tests/test_mathematical.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from .helper import (
get_all_dtypes,
get_complex_dtypes,
get_float_complex_dtypes,
get_float_dtypes,
has_support_aspect64,
Expand Down Expand Up @@ -442,6 +443,49 @@ def test_sign_boolean():
dpnp.sign(dpnp_a)


@pytest.mark.parametrize(
"data",
[[2, 0, -2], [1.1, -1.1]],
ids=["[2, 0, -2]", "[1.1, -1.1]"],
)
@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True))
@pytest.mark.usefixtures("allow_fall_back_on_numpy")
def test_signbit(data, dtype):
np_a = numpy.array(data, dtype=dtype)
dpnp_a = dpnp.array(data, dtype=dtype)

result = dpnp.signbit(dpnp_a)
expected = numpy.signbit(np_a)
assert_allclose(result, expected)


@pytest.mark.parametrize("dtype", get_complex_dtypes())
def test_projection_infinity(dtype):
X = [
complex(1, 2),
complex(dpnp.inf, -1),
complex(0, -dpnp.inf),
complex(-dpnp.inf, dpnp.nan),
]
Y = [
complex(1, 2),
complex(dpnp.inf, -0.0),
complex(dpnp.inf, -0.0),
complex(dpnp.inf, 0.0),
]

result = dpnp.proj(dpnp.array(X, dtype=dtype))
expected = dpnp.array(Y, dtype=dtype)
assert_allclose(result, expected)


@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_projection(dtype):
result = dpnp.proj(dpnp.array(1, dtype=dtype))
expected = dpnp.array(complex(1, 0))
assert_allclose(result, expected)


@pytest.mark.parametrize("val_type", get_all_dtypes(no_none=True))
@pytest.mark.parametrize("data_type", get_all_dtypes())
@pytest.mark.parametrize("val", [1.5, 1, 5], ids=["1.5", "1", "5"])
Expand Down

0 comments on commit 019478b

Please sign in to comment.