Skip to content

Commit b7bacd8

Browse files
Merge 9164caf into 323ce50
2 parents 323ce50 + 9164caf commit b7bacd8

File tree

6 files changed

+314
-11
lines changed

6 files changed

+314
-11
lines changed

doc/reference/logic.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Infinities and NaNs
2626
dpnp.isfinite
2727
dpnp.isinf
2828
dpnp.isnan
29+
dpnp.isneginf
30+
dpnp.isposinf
2931

3032

3133
Array type testing

dpnp/dpnp_iface_logic.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
"isfinite",
6767
"isinf",
6868
"isnan",
69+
"isneginf",
70+
"isposinf",
6971
"less",
7072
"less_equal",
7173
"logical_and",
@@ -766,6 +768,150 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False):
766768
)
767769

768770

771+
def isneginf(x, out=None):
772+
"""
773+
Test element-wise for negative infinity, return result as bool array.
774+
775+
For full documentation refer to :obj:`numpy.isneginf`.
776+
777+
Parameters
778+
----------
779+
x : {dpnp.ndarray, usm_ndarray}
780+
Input array.
781+
out : {None, dpnp.ndarray, usm_ndarray}, optional
782+
A location into which the result is stored. If provided, it must have a
783+
shape that the input broadcasts to and a boolean data type.
784+
If not provided or ``None``, a freshly-allocated boolean array
785+
is returned.
786+
Default: ``None``.
787+
788+
Returns
789+
-------
790+
out : dpnp.ndarray
791+
Boolean array of same shape as ``x``.
792+
793+
See Also
794+
--------
795+
:obj:`dpnp.isinf` : Test element-wise for positive or negative infinity.
796+
:obj:`dpnp.isposinf` : Test element-wise for positive infinity,
797+
return result as bool array.
798+
:obj:`dpnp.isnan` : Test element-wise for NaN and
799+
return result as a boolean array.
800+
:obj:`dpnp.isfinite` : Test element-wise for finiteness.
801+
802+
Examples
803+
--------
804+
>>> import dpnp as np
805+
>>> x = np.array(np.inf)
806+
>>> np.isneginf(-x)
807+
array(True)
808+
>>> np.isneginf(x)
809+
array(False)
810+
811+
>>> x = np.array([-np.inf, 0., np.inf])
812+
>>> np.isneginf(x)
813+
array([ True, False, False])
814+
815+
>>> x = np.array([-np.inf, 0., np.inf])
816+
>>> y = np.zeros(x.shape, dtype='bool')
817+
>>> np.isneginf(x, y)
818+
array([ True, False, False])
819+
>>> y
820+
array([ True, False, False])
821+
822+
"""
823+
824+
dpnp.check_supported_arrays_type(x)
825+
826+
if out is not None:
827+
dpnp.check_supported_arrays_type(out)
828+
829+
x_dtype = x.dtype
830+
if dpnp.issubdtype(x_dtype, dpnp.complexfloating):
831+
raise TypeError(
832+
f"This operation is not supported for {x_dtype} values "
833+
"because it would be ambiguous."
834+
)
835+
836+
is_inf = dpnp.isinf(x)
837+
signbit = dpnp.signbit(x)
838+
839+
# TODO: support different out dtype #1717(dpctl)
840+
return dpnp.logical_and(is_inf, signbit, out=out)
841+
842+
843+
def isposinf(x, out=None):
844+
"""
845+
Test element-wise for positive infinity, return result as bool array.
846+
847+
For full documentation refer to :obj:`numpy.isposinf`.
848+
849+
Parameters
850+
----------
851+
x : {dpnp.ndarray, usm_ndarray}
852+
Input array.
853+
out : {None, dpnp.ndarray, usm_ndarray}, optional
854+
A location into which the result is stored. If provided, it must have a
855+
shape that the input broadcasts to and a boolean data type.
856+
If not provided or ``None``, a freshly-allocated boolean array
857+
is returned.
858+
Default: ``None``.
859+
860+
Returns
861+
-------
862+
out : dpnp.ndarray
863+
Boolean array of same shape as ``x``.
864+
865+
See Also
866+
--------
867+
:obj:`dpnp.isinf` : Test element-wise for positive or negative infinity.
868+
:obj:`dpnp.isneginf` : Test element-wise for negative infinity,
869+
return result as bool array.
870+
:obj:`dpnp.isnan` : Test element-wise for NaN and
871+
return result as a boolean array.
872+
:obj:`dpnp.isfinite` : Test element-wise for finiteness.
873+
874+
Examples
875+
--------
876+
>>> import dpnp as np
877+
>>> x = np.array(np.inf)
878+
>>> np.isposinf(x)
879+
array(True)
880+
>>> np.isposinf(-x)
881+
array(False)
882+
883+
>>> x = np.array([-np.inf, 0., np.inf])
884+
>>> np.isposinf(x)
885+
array([False, False, True])
886+
887+
>>> x = np.array([-np.inf, 0., np.inf])
888+
>>> y = np.zeros(x.shape, dtype='bool')
889+
>>> np.isposinf(x, y)
890+
array([False, False, True])
891+
>>> y
892+
array([False, False, True])
893+
894+
"""
895+
896+
dpnp.check_supported_arrays_type(x)
897+
898+
if out is not None:
899+
dpnp.check_supported_arrays_type(out)
900+
901+
x_dtype = x.dtype
902+
if dpnp.issubdtype(x_dtype, dpnp.complexfloating):
903+
raise TypeError(
904+
f"This operation is not supported for {x_dtype} values "
905+
"because it would be ambiguous."
906+
)
907+
908+
is_inf = dpnp.isinf(x)
909+
signbit = ~dpnp.signbit(x)
910+
911+
# TODO: support different out dtype #1717(dpctl)
912+
return dpnp.logical_and(is_inf, signbit, out=out)
913+
914+
769915
_LESS_DOCSTRING = """
770916
Computes the less-than test results for each element `x1_i` of
771917
the input array `x1` with the respective element `x2_i` of the input array `x2`.

tests/test_logic.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .helper import (
88
get_all_dtypes,
99
get_float_complex_dtypes,
10+
get_float_dtypes,
1011
)
1112

1213

@@ -432,3 +433,49 @@ def test_finite(op, data, dtype):
432433
dpnp_res = getattr(dpnp, op)(x, out=dp_out)
433434
assert dp_out is dpnp_res
434435
assert_equal(dpnp_res, np_res)
436+
437+
438+
@pytest.mark.parametrize("func", ["isneginf", "isposinf"])
439+
@pytest.mark.parametrize(
440+
"data",
441+
[
442+
[dpnp.inf, -1, 0, 1, dpnp.nan, -dpnp.inf],
443+
[[dpnp.inf, dpnp.nan], [dpnp.nan, 0], [1, -dpnp.inf]],
444+
],
445+
ids=[
446+
"1D array",
447+
"2D array",
448+
],
449+
)
450+
@pytest.mark.parametrize("dtype", get_float_dtypes())
451+
def test_infinity_sign(func, data, dtype):
452+
x = dpnp.asarray(data, dtype=dtype)
453+
np_res = getattr(numpy, func)(x.asnumpy())
454+
dpnp_res = getattr(dpnp, func)(x)
455+
assert_equal(dpnp_res, np_res)
456+
457+
dp_out = dpnp.empty(np_res.shape, dtype=dpnp.bool)
458+
dpnp_res = getattr(dpnp, func)(x, out=dp_out)
459+
assert dp_out is dpnp_res
460+
assert_equal(dpnp_res, np_res)
461+
462+
463+
@pytest.mark.parametrize("func", ["isneginf", "isposinf"])
464+
def test_infinity_sign_errors(func):
465+
data = [dpnp.inf, 0, -dpnp.inf]
466+
467+
# unsupported data type
468+
x = dpnp.asarray(data, dtype="c8")
469+
x_np = dpnp.asnumpy(x)
470+
assert_raises(TypeError, getattr(dpnp, func), x)
471+
assert_raises(TypeError, getattr(numpy, func), x_np)
472+
473+
# unsupported type
474+
assert_raises(TypeError, getattr(dpnp, func), data)
475+
assert_raises(TypeError, getattr(dpnp, func), x_np)
476+
477+
# unsupported `out` data type
478+
x = dpnp.asarray(data, dtype=dpnp.default_float_type())
479+
out = dpnp.empty_like(x, dtype="int32")
480+
with pytest.raises(ValueError):
481+
getattr(dpnp, func)(x, out=out)

tests/test_sycl_queue.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,40 @@ def test_1in_1out(func, data, device):
501501
assert_sycl_queue_equal(result_queue, expected_queue)
502502

503503

504+
@pytest.mark.parametrize(
505+
"op",
506+
[
507+
"all",
508+
"any",
509+
"isfinite",
510+
"isinf",
511+
"isnan",
512+
"isneginf",
513+
"isposinf",
514+
"logical_not",
515+
],
516+
)
517+
@pytest.mark.parametrize(
518+
"device",
519+
valid_devices,
520+
ids=[device.filter_string for device in valid_devices],
521+
)
522+
def test_logic_op_1in(op, device):
523+
x = dpnp.array(
524+
[-dpnp.inf, -1.0, 0.0, 1.0, dpnp.inf, dpnp.nan], device=device
525+
)
526+
result = getattr(dpnp, op)(x)
527+
528+
x_orig = dpnp.asnumpy(x)
529+
expected = getattr(numpy, op)(x_orig)
530+
assert_dtype_allclose(result, expected)
531+
532+
expected_queue = x.get_array().sycl_queue
533+
result_queue = result.get_array().sycl_queue
534+
535+
assert_sycl_queue_equal(result_queue, expected_queue)
536+
537+
504538
@pytest.mark.parametrize(
505539
"device",
506540
valid_devices,
@@ -705,6 +739,55 @@ def test_2in_1out(func, data1, data2, device):
705739
assert_sycl_queue_equal(result.sycl_queue, x2.sycl_queue)
706740

707741

742+
@pytest.mark.parametrize(
743+
"op",
744+
[
745+
"equal",
746+
"greater",
747+
"greater_equal",
748+
# TODO: unblock when dpnp.isclose() is updated
749+
# "isclose",
750+
"less",
751+
"less_equal",
752+
"logical_and",
753+
"logical_or",
754+
"logical_xor",
755+
"not_equal",
756+
],
757+
)
758+
@pytest.mark.parametrize(
759+
"device",
760+
valid_devices,
761+
ids=[device.filter_string for device in valid_devices],
762+
)
763+
def test_logic_op_2in(op, device):
764+
x1 = dpnp.array(
765+
[-dpnp.inf, -1.0, 0.0, 1.0, dpnp.inf, dpnp.nan], device=device
766+
)
767+
x2 = dpnp.array(
768+
[dpnp.inf, 1.0, 0.0, -1.0, -dpnp.inf, dpnp.nan], device=device
769+
)
770+
# Remove NaN value from input arrays because numpy raises RuntimeWarning
771+
if op in [
772+
"greater",
773+
"greater_equal",
774+
"less",
775+
"less_equal",
776+
]:
777+
x1 = x1[:-1]
778+
x2 = x2[:-1]
779+
result = getattr(dpnp, op)(x1, x2)
780+
781+
x1_orig = dpnp.asnumpy(x1)
782+
x2_orig = dpnp.asnumpy(x2)
783+
expected = getattr(numpy, op)(x1_orig, x2_orig)
784+
785+
assert_dtype_allclose(result, expected)
786+
787+
assert_sycl_queue_equal(result.sycl_queue, x1.sycl_queue)
788+
assert_sycl_queue_equal(result.sycl_queue, x2.sycl_queue)
789+
790+
708791
@pytest.mark.parametrize(
709792
"func, data, scalar",
710793
[

tests/test_usm_type.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -357,20 +357,32 @@ def test_tril_triu(func, usm_type):
357357
@pytest.mark.parametrize(
358358
"op",
359359
[
360-
"equal",
361-
"greater",
362-
"greater_equal",
363-
"less",
364-
"less_equal",
365-
"logical_and",
366-
"logical_or",
367-
"logical_xor",
368-
"not_equal",
360+
"all",
361+
"any",
362+
"isfinite",
363+
"isinf",
364+
"isnan",
365+
"isneginf",
366+
"isposinf",
367+
"logical_not",
369368
],
370-
ids=[
369+
)
370+
@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types)
371+
def test_coerced_usm_types_logic_op_1in(op, usm_type_x):
372+
x = dp.arange(-10, 10, usm_type=usm_type_x)
373+
res = getattr(dp, op)(x)
374+
375+
assert x.usm_type == res.usm_type == usm_type_x
376+
377+
378+
@pytest.mark.parametrize(
379+
"op",
380+
[
371381
"equal",
372382
"greater",
373383
"greater_equal",
384+
# TODO: unblock when dpnp.isclose() is updated
385+
# "isclose",
374386
"less",
375387
"less_equal",
376388
"logical_and",
@@ -381,7 +393,7 @@ def test_tril_triu(func, usm_type):
381393
)
382394
@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types)
383395
@pytest.mark.parametrize("usm_type_y", list_of_usm_types, ids=list_of_usm_types)
384-
def test_coerced_usm_types_logic_op(op, usm_type_x, usm_type_y):
396+
def test_coerced_usm_types_logic_op_2in(op, usm_type_x, usm_type_y):
385397
x = dp.arange(100, usm_type=usm_type_x)
386398
y = dp.arange(100, usm_type=usm_type_y)[::-1]
387399

tests/third_party/cupy/logic_tests/test_content.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,16 @@ def test_isinf(self):
2929

3030
def test_isnan(self):
3131
self.check_unary_nan("isnan")
32+
33+
34+
class TestUfuncLike(unittest.TestCase):
35+
@testing.numpy_cupy_array_equal()
36+
def check_unary(self, name, xp):
37+
a = xp.array([-3, xp.inf, -1, -xp.inf, 0, 1, 2, xp.nan])
38+
return getattr(xp, name)(a)
39+
40+
def test_isneginf(self):
41+
self.check_unary("isneginf")
42+
43+
def test_isposinf(self):
44+
self.check_unary("isposinf")

0 commit comments

Comments
 (0)