Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions dpnp/dpnp_iface_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@
"greater",
"greater_equal",
"isclose",
"iscomplex",
"iscomplexobj",
"isfinite",
"isinf",
"isnan",
"isneginf",
"isposinf",
"isreal",
"isrealobj",
"less",
"less_equal",
"logical_and",
Expand Down Expand Up @@ -610,6 +614,94 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False):
)


def iscomplex(x):
"""
Returns a bool array, where ``True`` if input element is complex.

What is tested is whether the input has a non-zero imaginary part, not if
the input type is complex.

For full documentation refer to :obj:`numpy.iscomplex`.

Parameters
----------
x : {dpnp.ndarray, usm_ndarray}
Input array.

Returns
-------
out : dpnp.ndarray
Output array.

See Also
--------
:obj:`dpnp.isreal` : Returns a bool array, where ``True`` if input element
is real.
:obj:`dpnp.iscomplexobj` : Return ``True`` if `x` is a complex type or an
array of complex numbers.

Examples
--------
>>> import dpnp as np
>>> np.iscomplex([1+1j, 1+0j, 4.5, 3, 2, 2j])
array([ True, False, False, False, False, True])

"""
ax = dpnp.asanyarray(x)
if issubclass(ax.dtype.type, dpnp.complexfloating):
return ax.imag != 0
res = dpnp.zeros(ax.shape, dtype=dpnp.bool)
return res[()] # convert to scalar if needed


def iscomplexobj(x):
"""
Check for a complex type or an array of complex numbers.

The type of the input is checked, not the value. Even if the input
has an imaginary part equal to zero, `iscomplexobj` evaluates to ``True``.

For full documentation refer to :obj:`numpy.iscomplexobj`.

Parameters
----------
x : array_like
Input data, in any form that can be converted to an array. This
includes scalars, lists, lists of tuples, tuples, tuples of tuples,
tuples of lists, and ndarrays.

Returns
-------
out : dpnp.ndarray
The return value, ``True`` if `x` is of a complex type or has at least
one complex element.

See Also
--------
:obj:`dpnp.isrealobj` : Return ``True`` if `x` is a not complex type or an
array of complex numbers.
:obj:`dpnp.iscomplex` : Returns a bool array, where ``True`` if input
element is complex.

Examples
--------
>>> import dpnp as np
>>> np.iscomplexobj(1)
False
>>> np.iscomplexobj(1+0j)
True
>>> np.iscomplexobj([3, 1+0j, True])
True

"""
try:
dtype = x.dtype
type_ = dtype.type
except AttributeError:
type_ = dpnp.asarray(x).dtype.type
return issubclass(type_, dpnp.complexfloating)


_ISFINITE_DOCSTRING = """
Test if each element of input array is a finite number.

Expand Down Expand Up @@ -923,6 +1015,86 @@ def isposinf(x, out=None):
return dpnp.logical_and(is_inf, signbit, out=out)


def isreal(x):
"""
Returns a bool array, where ``True`` if input element is real.

If element has complex type with zero imaginary part, the return value
for that element is ``True``.

For full documentation refer to :obj:`numpy.isreal`.

Parameters
----------
x : {dpnp.ndarray, usm_ndarray}
Input array.

Returns
-------
out : : dpnp.ndarray
Boolean array of same shape as `x`.

See Also
--------
:obj:`dpnp.iscomplex` : Returns a bool array, where ``True`` if input
element is complex.
:obj:`dpnp.isrealobj` : Return ``True`` if `x` is not a complex type.

Examples
--------
>>> import dpnp as np
>>> a = np.array([1+1j, 1+0j, 4.5, 3, 2, 2j], dtype=dpnp.complex64)
>>> np.isreal(a)
array([False, True, True, True, True, False])

"""
return dpnp.imag(x) == 0


def isrealobj(x):
"""
Return ``True`` if `x` is a not complex type or an array of complex numbers.

The type of the input is checked, not the value. So even if the input
has an imaginary part equal to zero, `isrealobj` evaluates to ``False``
if the data type is complex.

For full documentation refer to :obj:`numpy.isrealobj`.

Parameters
----------
x : array_like
Input data, in any form that can be converted to an array. This
includes scalars, lists, lists of tuples, tuples, tuples of tuples,
tuples of lists, and ndarrays.

Returns
-------
out : dpnp.ndarray
The return value, ``False`` if `x` is of a complex type.

See Also
--------
:obj:`dpnp.iscomplexobj` : Check for a complex type or an array of complex
numbers.
:obj:`dpnp.isreal` : Returns a bool array, where ``True`` if input element
is real.

Examples
--------
>>> np.isrealobj(False)
True
>>> np.isrealobj(1)
True
>>> np.isrealobj(1+0j)
False
>>> np.isrealobj([3, 1+0j, True])
False

"""
return not iscomplexobj(x)


_LESS_DOCSTRING = """
Computes the less-than test results for each element `x1_i` of
the input array `x1` with the respective element `x2_i` of the input array `x2`.
Expand Down
6 changes: 3 additions & 3 deletions dpnp/dpnp_iface_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,14 @@ def iinfo(dtype):
return dpt.iinfo(dtype)


def isscalar(obj):
def isscalar(element):
"""
Returns ``True`` if the type of `obj` is a scalar type.
Returns ``True`` if the type of `element` is a scalar type.

For full documentation refer to :obj:`numpy.isscalar`.

"""
return numpy.isscalar(obj)
return numpy.isscalar(element)


def issubdtype(arg1, arg2):
Expand Down
129 changes: 129 additions & 0 deletions tests/third_party/cupy/logic_tests/test_type_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import unittest

import numpy
import pytest

from tests.third_party.cupy import testing


class TestIsScalar(testing.NumpyAliasBasicTestBase):

func = "isscalar"

@testing.with_requires("numpy>=1.18")
def test_argspec(self):
super().test_argspec()


@testing.parameterize(
*testing.product(
{
"value": [
0,
0.0,
True,
numpy.int32(1),
numpy.array([1, 2], numpy.int32),
numpy.complex128(1),
numpy.complex128(1j),
numpy.complex128(1 + 1j),
None,
"abc",
"",
int,
numpy.int32,
]
}
)
)
class TestIsScalarValues(testing.NumpyAliasValuesTestBase):

func = "isscalar"

def setUp(self):
self.args = (self.value,)


class TestIsScalarValues2(testing.NumpyAliasValuesTestBase):

func = "isscalar"

def setUp(self):
value = object()
self.args = (value,)


@pytest.mark.skip("isfortran not implemented")
@testing.parameterize(
*testing.product(
{
"value": [
# C and F
numpy.ones(24, order="C"),
# C and not F
numpy.ones((4, 6), order="C"),
# not C and F
numpy.ones((4, 6), order="F"),
# not C and not F
numpy.ones((4, 6), order="C")[1:3][1:3],
]
}
)
)
class TestIsFortran(unittest.TestCase):

@pytest.mark.skip("isfortran not implemented")
@testing.numpy_cupy_equal()
def test(self, xp):
return xp.isfortran(xp.asarray(self.value))


@testing.parameterize(
{"func": "iscomplex"},
{"func": "isreal"},
)
class TestTypeTestingFunctions(unittest.TestCase):

@testing.for_all_dtypes()
@testing.numpy_cupy_array_equal()
def test(self, xp, dtype):
return getattr(xp, self.func)(xp.ones(5, dtype=dtype))

@pytest.mark.skip("support for scalar not implemented")
@testing.for_all_dtypes()
@testing.numpy_cupy_equal()
def test_scalar(self, xp, dtype):
return getattr(xp, self.func)(dtype(3))

@pytest.mark.skip("tolist not implemented")
@testing.for_all_dtypes()
@testing.numpy_cupy_array_equal()
def test_list(self, xp, dtype):
return getattr(xp, self.func)(
testing.shaped_arange((2, 3), xp, dtype).tolist()
)


@testing.parameterize(
{"func": "iscomplexobj"},
{"func": "isrealobj"},
)
class TestTypeTestingObjFunctions(unittest.TestCase):

@testing.for_all_dtypes()
@testing.numpy_cupy_equal()
def test(self, xp, dtype):
return getattr(xp, self.func)(xp.ones(5, dtype=dtype))

@testing.for_all_dtypes()
@testing.numpy_cupy_equal()
def test_scalar(self, xp, dtype):
return getattr(xp, self.func)(dtype(3))

@pytest.mark.skip("tolist not implemented")
@testing.for_all_dtypes()
@testing.numpy_cupy_equal()
def test_list(self, xp, dtype):
return getattr(xp, self.func)(
testing.shaped_arange((2, 3), xp, dtype).tolist()
)