Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit shape comparison for dpnp and numpy outputs #2295

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions dpnp/dpnp_iface_linearalgebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -1275,13 +1275,13 @@ def vdot(a, b):
if b.size != 1:
raise ValueError("The second array should be of size one.")
a_conj = numpy.conj(a)
return _call_multiply(a_conj, b)
return dpnp.squeeze(_call_multiply(a_conj, b))

if dpnp.isscalar(b):
if a.size != 1:
raise ValueError("The first array should be of size one.")
a_conj = dpnp.conj(a)
return _call_multiply(a_conj, b)
return dpnp.squeeze(_call_multiply(a_conj, b))

if a.ndim == 1 and b.ndim == 1:
return dpnp_dot(a, b, out=None, conjugate=True)
Expand Down
2 changes: 1 addition & 1 deletion dpnp/dpnp_utils/dpnp_utils_linearalgebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ def dpnp_multiplication(
result = dpnp.moveaxis(result, (-2, -1), axes_res)
elif len(axes_res) == 1:
result = dpnp.moveaxis(result, (-1,), axes_res)
return dpnp.ascontiguousarray(result)
return result

return dpnp.asarray(result, order=order)

Expand Down
36 changes: 24 additions & 12 deletions dpnp/tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@
from . import config


def _assert_dtype(a_dt, b_dt, check_only_type_kind=False):

if check_only_type_kind:
assert a_dt.kind == b_dt.kind, f"{a_dt.kind} != {b_dt.kind}"
else:
assert a_dt == b_dt, f"{a_dt} != {b_dt}"


def assert_dtype_allclose(
dpnp_arr,
numpy_arr,
check_type=True,
check_only_type_kind=False,
factor=8,
relative_factor=None,
check_shape=True,
):
"""
Assert DPNP and NumPy array based on maximum dtype resolution of input arrays
Expand All @@ -40,7 +48,13 @@ def assert_dtype_allclose(

"""

list_64bit_types = [numpy.float64, numpy.complex128]
if check_shape:
if hasattr(numpy_arr, "shape"):
assert dpnp_arr.shape == numpy_arr.shape
else:
# numpy output is scalar, then dpnp is 0-D array
assert dpnp_arr.shape == ()

is_inexact = lambda x: hasattr(x, "dtype") and dpnp.issubdtype(
x.dtype, dpnp.inexact
)
Expand All @@ -57,34 +71,32 @@ def assert_dtype_allclose(
else -dpnp.inf
)
tol = factor * max(tol_dpnp, tol_numpy)
assert_allclose(dpnp_arr.asnumpy(), numpy_arr, atol=tol, rtol=tol)
assert_allclose(dpnp_arr, numpy_arr, atol=tol, rtol=tol)
if check_type:
list_64bit_types = [numpy.float64, numpy.complex128]
numpy_arr_dtype = numpy_arr.dtype
dpnp_arr_dtype = dpnp_arr.dtype
dpnp_arr_dev = dpnp_arr.sycl_device

if check_only_type_kind:
assert dpnp_arr_dtype.kind == numpy_arr_dtype.kind
_assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, True)
else:
is_np_arr_f2 = numpy_arr_dtype == numpy.float16

if is_np_arr_f2:
if has_support_aspect16(dpnp_arr_dev):
assert dpnp_arr_dtype == numpy_arr_dtype
_assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, False)
elif (
numpy_arr_dtype not in list_64bit_types
or has_support_aspect64(dpnp_arr_dev)
):
assert dpnp_arr_dtype == numpy_arr_dtype
_assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, False)
else:
assert dpnp_arr_dtype.kind == numpy_arr_dtype.kind
_assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, True)
else:
assert_array_equal(dpnp_arr.asnumpy(), numpy_arr)
assert_array_equal(dpnp_arr, numpy_arr)
if check_type and hasattr(numpy_arr, "dtype"):
if check_only_type_kind:
assert dpnp_arr.dtype.kind == numpy_arr.dtype.kind
else:
assert dpnp_arr.dtype == numpy_arr.dtype
_assert_dtype(dpnp_arr.dtype, numpy_arr.dtype, check_only_type_kind)


def get_integer_dtypes(all_int_types=False, no_unsigned=False):
Expand Down
44 changes: 21 additions & 23 deletions dpnp/tests/test_amin_amax.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@pytest.mark.parametrize("func", ["amax", "amin"])
@pytest.mark.parametrize("keepdims", [True, False])
@pytest.mark.parametrize("dtype", get_all_dtypes())
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
def test_amax_amin(func, keepdims, dtype):
a = [
[[-2.0, 3.0], [9.1, 0.2]],
Expand All @@ -22,52 +22,50 @@ def test_amax_amin(func, keepdims, dtype):
for axis in range(len(a)):
result = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims)
expected = getattr(numpy, func)(a, axis=axis, keepdims=keepdims)
assert_allclose(expected, result)
assert_allclose(expected, result, strict=True)


def _get_min_max_input(type, shape):
def _get_min_max_input(dtype, shape):
size = numpy.prod(shape)
a = numpy.arange(size, dtype=type)
a = numpy.arange(size, dtype=dtype)
a[int(size / 2)] = size + 5
if numpy.issubdtype(type, numpy.unsignedinteger):
if numpy.issubdtype(dtype, numpy.unsignedinteger):
a[int(size / 3)] = size
else:
a[int(size / 3)] = -(size + 5)

return a.reshape(shape)


@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True, no_bool=True))
@pytest.mark.parametrize(
"shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2, 3)", "(4, 5, 6)"]
"shape", [(4,), (2, 3), (4, 5, 6)], ids=["1D", "2D", "3D"]
)
def test_amax_diff_shape(dtype, shape):
a = _get_min_max_input(dtype, shape)

ia = dpnp.array(a)

np_res = numpy.amax(a)
dpnp_res = dpnp.amax(ia)
assert_array_equal(dpnp_res, np_res)
expected = numpy.amax(a)
result = dpnp.amax(ia)
assert_array_equal(result, expected, strict=True)

np_res = a.max()
dpnp_res = ia.max()
numpy.testing.assert_array_equal(dpnp_res, np_res)
expected = a.max()
result = ia.max()
assert_array_equal(result, expected, strict=True)


@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True, no_bool=True))
@pytest.mark.parametrize(
"shape", [(4,), (2, 3), (4, 5, 6)], ids=["(4,)", "(2, 3)", "(4, 5, 6)"]
"shape", [(4,), (2, 3), (4, 5, 6)], ids=["1D", "2D", "3D"]
)
def test_amin_diff_shape(dtype, shape):
a = _get_min_max_input(dtype, shape)

ia = dpnp.array(a)

np_res = numpy.amin(a)
dpnp_res = dpnp.amin(ia)
assert_array_equal(dpnp_res, np_res)
expected = numpy.amin(a)
result = dpnp.amin(ia)
assert_array_equal(result, expected, strict=True)

np_res = a.min()
dpnp_res = ia.min()
assert_array_equal(dpnp_res, np_res)
expected = a.min()
result = ia.min()
assert_array_equal(result, expected, strict=True)
42 changes: 13 additions & 29 deletions dpnp/tests/test_mathematical.py
Original file line number Diff line number Diff line change
Expand Up @@ -2091,14 +2091,12 @@ def test_discont(self, dt):


@pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings")
@pytest.mark.parametrize(
"val_type", [bool, int, float], ids=["bool", "int", "float"]
)
@pytest.mark.parametrize("val_type", [bool, int, float])
@pytest.mark.parametrize("data_type", get_all_dtypes())
@pytest.mark.parametrize(
"func", ["add", "divide", "multiply", "power", "subtract"]
)
@pytest.mark.parametrize("val", [0, 1, 5], ids=["0", "1", "5"])
@pytest.mark.parametrize("val", [0, 1, 5])
@pytest.mark.parametrize(
"array",
[
Expand Down Expand Up @@ -2151,7 +2149,7 @@ def test_op_with_scalar(array, val, func, data_type, val_type):
assert_allclose(result, expected, rtol=1e-6)


@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"])
@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["0D", "2D"])
@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_multiply_scalar(shape, dtype):
np_a = numpy.ones(shape, dtype=dtype)
Expand All @@ -2162,7 +2160,7 @@ def test_multiply_scalar(shape, dtype):
assert_allclose(result, expected)


@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"])
@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["0D", "2D"])
@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_add_scalar(shape, dtype):
np_a = numpy.ones(shape, dtype=dtype)
Expand All @@ -2173,7 +2171,7 @@ def test_add_scalar(shape, dtype):
assert_allclose(result, expected)


@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"])
@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["0D", "2D"])
@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_subtract_scalar(shape, dtype):
np_a = numpy.ones(shape, dtype=dtype)
Expand All @@ -2184,7 +2182,7 @@ def test_subtract_scalar(shape, dtype):
assert_allclose(result, expected)


@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["()", "(3, 2)"])
@pytest.mark.parametrize("shape", [(), (3, 2)], ids=["0D", "2D"])
@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_divide_scalar(shape, dtype):
np_a = numpy.ones(shape, dtype=dtype)
Expand All @@ -2196,9 +2194,7 @@ def test_divide_scalar(shape, dtype):


@pytest.mark.parametrize(
"data",
[[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]],
ids=["[[1., -1.], [0.1, -0.1]]", "[-2, -1, 0, 1, 2]"],
"data", [[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]], ids=["2D", "1D"]
)
@pytest.mark.parametrize(
"dtype", get_all_dtypes(no_bool=True, no_unsigned=True)
Expand Down Expand Up @@ -2231,9 +2227,7 @@ def test_negative_boolean():


@pytest.mark.parametrize(
"data",
[[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]],
ids=["[[1., -1.], [0.1, -0.1]]", "[-2, -1, 0, 1, 2]"],
"data", [[[1.0, -1.0], [0.1, -0.1]], [-2, -1, 0, 1, 2]], ids=["2D", "1D"]
)
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
def test_positive(data, dtype):
Expand Down Expand Up @@ -2399,13 +2393,13 @@ def test_projection_infinity(self, dtype):
a = dpnp.array(X, dtype=dtype)
result = dpnp.proj(a)
expected = dpnp.array(Y, dtype=dtype)
assert_dtype_allclose(result, expected)
assert_array_equal(result, expected, strict=True)

# out keyword
dp_out = dpnp.empty(expected.shape, dtype=expected.dtype)
result = dpnp.proj(a, out=dp_out)
assert dp_out is result
assert_dtype_allclose(result, expected)
assert_array_equal(result, expected, strict=True)

@pytest.mark.parametrize("dtype", get_all_dtypes())
def test_projection(self, dtype):
Expand Down Expand Up @@ -2793,21 +2787,11 @@ def test_bitwise_1array_input():

@pytest.mark.parametrize(
"x_shape",
[
(),
(2),
(3, 4),
(3, 4, 5),
],
[(), (2), (3, 4), (3, 4, 5)],
)
@pytest.mark.parametrize(
"y_shape",
[
(),
(2),
(3, 4),
(3, 4, 5),
],
[(), (2), (3, 4), (3, 4, 5)],
)
def test_elemenwise_outer(x_shape, y_shape):
x_np = numpy.random.random(x_shape)
Expand All @@ -2830,4 +2814,4 @@ def test_elemenwise_outer_scalar():
y = dpnp.asarray(s)
expected = dpnp.add.outer(x, y)
result = dpnp.add.outer(x, s)
assert_dtype_allclose(result, expected)
assert_array_equal(result, expected, strict=True)
4 changes: 3 additions & 1 deletion dpnp/tests/test_nanfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ def test_allnans(self, dtype, array):

result = getattr(dpnp, self.func)(ia)
expected = getattr(numpy, self.func)(a)
assert_dtype_allclose(result, expected)
# for "0d" case, dpnp returns 0D array, numpy returns 1D array
# Array API indicates that the behavior is unspecified
assert_dtype_allclose(result, expected, check_shape=False)

@pytest.mark.parametrize("axis", [None, 0, 1])
def test_empty(self, axis):
Expand Down
5 changes: 4 additions & 1 deletion dpnp/tests/test_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -902,10 +902,13 @@ def test_strided1(self, dtype, stride):
expected = numpy.matmul(a, a)
assert_dtype_allclose(result, expected, factor=16)

iOUT = dpnp.empty(shape, dtype=result.dtype)
OUT = numpy.empty(shape, dtype=result.dtype)
out = OUT[slices]
iOUT = dpnp.array(OUT)
iout = iOUT[slices]
result = dpnp.matmul(ia, ia, out=iout)
assert result is iout
expected = numpy.matmul(a, a, out=out)
assert_dtype_allclose(result, expected, factor=16)

@pytest.mark.parametrize("dtype", _selected_dtypes)
Expand Down
9 changes: 9 additions & 0 deletions dpnp/tests/testing/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ def _assert(assert_func, result, expected, *args, **kwargs):
result = convert_item(result)
expected = convert_item(expected)

# original versions of assert_equal, assert_array_equal, and assert_allclose
# (since NumPy 2.0) have `strict` parameter. Added here for
# assert_almost_equal, assert_array_almost_equal, and assert_allclose
# (NumPy < 2.0)
if kwargs.get("strict"):
assert result.dtype == expected.dtype
assert result.shape == expected.shape
kwargs.pop("strict")

assert_func(result, expected, *args, **kwargs)


Expand Down
Loading