Skip to content
5 changes: 4 additions & 1 deletion dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ def __gt__(self, other):
return dpnp.greater(self, other)

# '__hash__',
# '__iadd__',

def __iadd__(self, other):
dpnp.add(self, other, out=self)
return self

def __iand__(self, other):
dpnp.bitwise_and(self, other, out=self)
Expand Down
26 changes: 2 additions & 24 deletions dpnp/dpnp_iface_mathematical.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def add(x1,
-----------
Parameters `x1` and `x2` are supported as either scalar, :class:`dpnp.ndarray`
or :class:`dpctl.tensor.usm_ndarray`, but both `x1` and `x2` can not be scalars at the same time.
Parameters `out`, `where`, `dtype` and `subok` are supported with their default values.
Parameters `where`, `dtype` and `subok` are supported with their default values.
Keyword arguments ``kwargs`` are currently unsupported.
Otherwise the function will be executed sequentially on CPU.
Input array data types are limited by supported DPNP :ref:`Data types`.
Expand All @@ -251,29 +251,7 @@ def add(x1,

"""

if out is not None:
pass
elif where is not True:
pass
elif dtype is not None:
pass
elif subok is not True:
pass
elif dpnp.isscalar(x1) and dpnp.isscalar(x2):
# at least either x1 or x2 has to be an array
pass
else:
# get USM type and queue to copy scalar from the host memory into a USM allocation
usm_type, queue = get_usm_allocations([x1, x2]) if dpnp.isscalar(x1) or dpnp.isscalar(x2) else (None, None)

x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_strides=False, copy_when_nondefault_queue=False,
alloc_usm_type=usm_type, alloc_queue=queue)
x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_strides=False, copy_when_nondefault_queue=False,
alloc_usm_type=usm_type, alloc_queue=queue)
if x1_desc and x2_desc:
return dpnp_add(x1_desc, x2_desc, dtype=dtype, out=out, where=where).get_pyobj()

return call_origin(numpy.add, x1, x2, out=out, where=where, dtype=dtype, subok=subok, **kwargs)
return _check_nd_call(numpy.add, dpnp_add, x1, x2, out=out, where=where, dtype=dtype, subok=subok, **kwargs)


def around(x1, decimals=0, out=None):
Expand Down
103 changes: 94 additions & 9 deletions tests/test_mathematical.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from .helper import (
get_all_dtypes,
get_float_complex_dtypes,
is_cpu_device,
is_win_platform
)
Expand Down Expand Up @@ -634,24 +635,108 @@ def test_invalid_shape(self, shape):
dpnp.trunc(dp_array, out=dp_out)


class TestAdd:
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
def test_add(self, dtype):
array1_data = numpy.arange(10)
array2_data = numpy.arange(5, 15)
out = numpy.empty(10, dtype=dtype)

# DPNP
dp_array1 = dpnp.array(array1_data, dtype=dtype)
dp_array2 = dpnp.array(array2_data, dtype=dtype)
dp_out = dpnp.array(out, dtype=dtype)
result = dpnp.add(dp_array1, dp_array2, out=dp_out)

# original
np_array1 = numpy.array(array1_data, dtype=dtype)
np_array2 = numpy.array(array2_data, dtype=dtype)
expected = numpy.add(np_array1, np_array2, out=out)

assert_allclose(expected, result)
assert_allclose(out, dp_out)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
def test_out_dtypes(self, dtype):
size = 2 if dtype == dpnp.bool else 10

np_array1 = numpy.arange(size, 2 * size, dtype=dtype)
np_array2 = numpy.arange(size, dtype=dtype)
np_out = numpy.empty(size, dtype=numpy.complex64)
expected = numpy.add(np_array1, np_array2, out=np_out)

dp_array1 = dpnp.arange(size, 2 * size, dtype=dtype)
dp_array2 = dpnp.arange(size, dtype=dtype)
dp_out = dpnp.empty(size, dtype=dpnp.complex64)
result = dpnp.add(dp_array1, dp_array2, out=dp_out)

assert_array_equal(expected, result)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
def test_out_overlap(self, dtype):
size = 1 if dtype == dpnp.bool else 15

np_a = numpy.arange(2 * size, dtype=dtype)
expected = numpy.add(np_a[size::], np_a[::2], out=np_a[:size:])

dp_a = dpnp.arange(2 * size, dtype=dtype)
result = dpnp.add(dp_a[size::], dp_a[::2], out=dp_a[:size:])

assert_allclose(expected, result)
assert_allclose(dp_a, np_a)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_none=True))
def test_inplace_strided_out(self, dtype):
size = 21

np_a = numpy.arange(size, dtype=dtype)
np_a[::3] += 4

dp_a = dpnp.arange(size, dtype=dtype)
dp_a[::3] += 4

assert_allclose(dp_a, np_a)

@pytest.mark.parametrize("shape",
[(0,), (15, ), (2, 2)],
ids=['(0,)', '(15, )', '(2,2)'])
def test_invalid_shape(self, shape):
dp_array1 = dpnp.arange(10, dtype=dpnp.float64)
dp_array2 = dpnp.arange(5, 15, dtype=dpnp.float64)
dp_out = dpnp.empty(shape, dtype=dpnp.float64)

with pytest.raises(ValueError):
dpnp.add(dp_array1, dp_array2, out=dp_out)

@pytest.mark.parametrize("out",
[4, (), [], (3, 7), [2, 4]],
ids=['4', '()', '[]', '(3, 7)', '[2, 4]'])
def test_invalid_out(self, out):
a = dpnp.arange(10)

assert_raises(TypeError, dpnp.add, a, 2, out)
assert_raises(TypeError, numpy.add, a.asnumpy(), 2, out)


class TestPower:
def test_power(self):
@pytest.mark.parametrize("dtype", get_float_complex_dtypes())
def test_power(self, dtype):
array1_data = numpy.arange(10)
array2_data = numpy.arange(5, 15)
out = numpy.empty(10, dtype=numpy.float64)
out = numpy.empty(10, dtype=dtype)

# DPNP
dp_array1 = dpnp.array(array1_data, dtype=dpnp.float64)
dp_array2 = dpnp.array(array2_data, dtype=dpnp.float64)
dp_out = dpnp.array(out, dtype=dpnp.float64)
dp_array1 = dpnp.array(array1_data, dtype=dtype)
dp_array2 = dpnp.array(array2_data, dtype=dtype)
dp_out = dpnp.array(out, dtype=dtype)
result = dpnp.power(dp_array1, dp_array2, out=dp_out)

# original
np_array1 = numpy.array(array1_data, dtype=numpy.float64)
np_array2 = numpy.array(array2_data, dtype=numpy.float64)
np_array1 = numpy.array(array1_data, dtype=dtype)
np_array2 = numpy.array(array2_data, dtype=dtype)
expected = numpy.power(np_array1, np_array2, out=out)

assert_array_equal(expected, result)
assert_allclose(expected, result)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True, no_none=True))
def test_out_dtypes(self, dtype):
Expand All @@ -662,7 +747,7 @@ def test_out_dtypes(self, dtype):
np_out = numpy.empty(size, dtype=numpy.complex64)
expected = numpy.power(np_array1, np_array2, out=np_out)

dp_array1 = dpnp.arange(size, 2*size, dtype=dtype)
dp_array1 = dpnp.arange(size, 2 * size, dtype=dtype)
dp_array2 = dpnp.arange(size, dtype=dtype)
dp_out = dpnp.empty(size, dtype=dpnp.complex64)
result = dpnp.power(dp_array1, dp_array2, out=dp_out)
Expand Down
10 changes: 5 additions & 5 deletions tests/test_strides.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def test_strides_true_devide(dtype, shape):


@pytest.mark.parametrize("func_name",
["power"])
["add", "power"])
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True))
def test_strided_out_2args(func_name, dtype):
np_out = numpy.ones((5, 3, 2))[::3]
Expand All @@ -236,7 +236,7 @@ def test_strided_out_2args(func_name, dtype):


@pytest.mark.parametrize("func_name",
["power"])
["add", "power"])
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True))
def test_strided_in_out_2args(func_name, dtype):
sh = (3, 4, 2)
Expand All @@ -258,7 +258,7 @@ def test_strided_in_out_2args(func_name, dtype):


@pytest.mark.parametrize("func_name",
["power"])
["add", "power"])
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True))
def test_strided_in_out_2args_diff_out_dtype(func_name, dtype):
sh = (3, 3, 2)
Expand All @@ -280,7 +280,7 @@ def test_strided_in_out_2args_diff_out_dtype(func_name, dtype):


@pytest.mark.parametrize("func_name",
["power"])
["add", "power"])
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True, no_none=True))
def test_strided_in_2args_overlap(func_name, dtype):
size = 5
Expand All @@ -296,7 +296,7 @@ def test_strided_in_2args_overlap(func_name, dtype):


@pytest.mark.parametrize("func_name",
["power"])
["add", "power"])
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True, no_none=True))
def test_strided_in_out_2args_overlap(func_name, dtype):
sh = (4, 3, 2)
Expand Down
2 changes: 2 additions & 0 deletions tests/test_usm_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def test_coerced_usm_types_sum(usm_type_x, usm_type_y):
y = dp.arange(1000, usm_type = usm_type_y)

z = 1.3 + x + y + 2
z += x
z += 7.4

assert x.usm_type == usm_type_x
assert y.usm_type == usm_type_y
Expand Down