Skip to content
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
11 changes: 7 additions & 4 deletions dpnp/tests/third_party/cupy/math_tests/test_explog.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@


class TestExplog:
# rtol=1e-3 is used to pass the test when dtype is int8/unint8
# for such a case, output dtype is float16
_rtol_dict = {numpy.float16: 1e-3, "default": 1e-7}

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
rtol=_rtol_dict, atol=1e-5, type_check=has_support_aspect64()
)
def check_unary(self, name, xp, dtype, no_complex=False):
if no_complex:
if numpy.dtype(dtype).kind == "c":
return xp.array(True)
a = testing.shaped_arange((2, 3), xp, dtype)
return getattr(xp, name)(a)

# rtol=1e-3 is added for dpnp to pass the test when dtype is int8/unint8
# for such a case, output dtype is float16
@testing.for_all_dtypes()
@testing.numpy_cupy_allclose(
rtol=1e-3, atol=1e-5, type_check=has_support_aspect64()
rtol=_rtol_dict, atol=1e-5, type_check=has_support_aspect64()
)
def check_binary(self, name, xp, dtype, no_complex=False):
if no_complex:
Expand Down
10 changes: 7 additions & 3 deletions dpnp/tests/third_party/cupy/math_tests/test_hyperbolic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@


class TestHyperbolic(unittest.TestCase):
# rtol=1e-2 is used to pass the test when dtype is int8/unint8
# for such a case, output dtype is float16
_rtol_dict = {numpy.float16: 1e-2, "default": 1e-7}

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose(
atol={numpy.float16: 1e-3, "default": 1e-5},
rtol=_rtol_dict,
atol=1e-5,
type_check=has_support_aspect64(),
)
def check_unary(self, name, xp, dtype):
a = testing.shaped_arange((2, 3), xp, dtype)
return getattr(xp, name)(a)

@testing.for_dtypes(["e", "f", "d"])
@testing.numpy_cupy_allclose(atol={numpy.float16: 1e-3, "default": 1e-5})
@testing.numpy_cupy_allclose(rtol=_rtol_dict, atol=1e-5)
def check_unary_unit(self, name, xp, dtype):
a = xp.array([0.2, 0.4, 0.6, 0.8], dtype=dtype)
return getattr(xp, name)(a)
Expand All @@ -36,7 +40,7 @@ def test_arcsinh(self):
self.check_unary("arcsinh")

@testing.for_dtypes(["e", "f", "d"])
@testing.numpy_cupy_allclose(atol={numpy.float16: 1e-3, "default": 1e-5})
@testing.numpy_cupy_allclose(rtol=_rtol_dict, atol=1e-5)
def test_arccosh(self, xp, dtype):
a = xp.array([1, 2, 3], dtype=dtype)
return xp.arccosh(a)
Expand Down
66 changes: 55 additions & 11 deletions dpnp/tests/third_party/cupy/math_tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@


class TestMisc:
@staticmethod
def _interp_atol(_result_dtype, dtype_x=None, **_kwargs):
"""Compute absolute tolerance based on intermediate computation dtype.

Args:
_result_dtype: Output dtype (unused - we check input dtype instead)
dtype_x: Input dtype for fx coordinates
_kwargs: Additional test parameters (unused)

When dtype_x is int8/uint8/float16, xp.sin(fx) uses float16 precision,
so we need relaxed tolerance even if the final result is upcasted to float64.
Float16 has ~3 decimal digits of precision, hence atol=1e-3.
"""
if dtype_x is not None:
if numpy.dtype(dtype_x).type in (
numpy.int8,
numpy.uint8,
numpy.float16,
):
return 1e-3
return 1e-5

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
Expand Down Expand Up @@ -401,17 +422,22 @@ def test_real_if_close_with_float_tol_false(self, xp, dtype):

@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_all_dtypes(name="dtype_y", no_bool=True)
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
# tolerance is automatically adjusted based on dtype_x via resolver
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
fx = xp.asarray([1, 3, 5, 7, 9], dtype=dtype_x)
fy = xp.sin(fx).astype(dtype_y)
return xp.interp(x, fx, fy)

@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_all_dtypes(name="dtype_y", no_bool=True)
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_period(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -421,7 +447,9 @@ def test_interp_period(self, xp, dtype_y, dtype_x):

@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_all_dtypes(name="dtype_y", no_bool=True)
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_left_right(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -434,7 +462,9 @@ def test_interp_left_right(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_nan_fy(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -446,7 +476,9 @@ def test_interp_nan_fy(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_float_dtypes(name="dtype_x")
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_nan_fx(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -458,7 +490,9 @@ def test_interp_nan_fx(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_float_dtypes(name="dtype_x")
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_nan_x(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -470,7 +504,9 @@ def test_interp_nan_x(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_inf_fy(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -482,7 +518,9 @@ def test_interp_inf_fy(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_float_dtypes(name="dtype_x")
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_inf_fx(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -494,7 +532,9 @@ def test_interp_inf_fx(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_float_dtypes(name="dtype_x")
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_inf_x(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -505,7 +545,9 @@ def test_interp_inf_x(self, xp, dtype_y, dtype_x):

@testing.for_all_dtypes(name="dtype_x", no_bool=True, no_complex=True)
@testing.for_all_dtypes(name="dtype_y", no_bool=True)
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_size1(self, xp, dtype_y, dtype_x):
# interpolate at points on and outside the boundaries
x = xp.asarray([0, 1, 2, 4, 6, 8, 9, 10], dtype=dtype_x)
Expand All @@ -518,7 +560,9 @@ def test_interp_size1(self, xp, dtype_y, dtype_x):
@testing.with_requires("numpy>=1.17.0")
@testing.for_float_dtypes(name="dtype_x")
@testing.for_dtypes("efdFD", name="dtype_y")
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
@testing.numpy_cupy_allclose(
atol=_interp_atol, type_check=has_support_aspect64()
)
def test_interp_inf_to_nan(self, xp, dtype_y, dtype_x):
# from NumPy's test_non_finite_inf
x = xp.asarray([0.5], dtype=dtype_x)
Expand Down
72 changes: 47 additions & 25 deletions dpnp/tests/third_party/cupy/testing/_loops.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def test_func(*args, **kw):
numpy_r = numpy_r[mask]

if not skip:
check_func(cupy_r, numpy_r)
check_func(cupy_r, numpy_r, **kw)

return test_func

Expand Down Expand Up @@ -469,6 +469,9 @@ def _convert_output_to_ndarray(c_out, n_out, sp_name, check_sparse_format):

def _check_tolerance_keys(rtol, atol):
def _check(tol):
if callable(tol):
# Callable tolerance is allowed
return
if isinstance(tol, dict):
for k in tol.keys():
if type(k) is type:
Expand All @@ -486,9 +489,13 @@ def _check(tol):
_check(atol)


def _resolve_tolerance(type_check, result, rtol, atol):
def _resolve_tolerance(type_check, result, rtol, atol, **test_kwargs):
def _resolve(dtype, tol):
if isinstance(tol, dict):
if callable(tol):
# Support callable tolerance that can inspect test kwargs
return tol(dtype, **test_kwargs)
elif isinstance(tol, dict):
# Original dict lookup logic
tol1 = tol.get(dtype.type)
if tol1 is None:
tol1 = tol.get("default")
Expand Down Expand Up @@ -523,13 +530,15 @@ def numpy_cupy_allclose(
"""Decorator that checks NumPy results and CuPy ones are close.

Args:
rtol(float or dict): Relative tolerance. Besides a float value, a
dictionary that maps a dtypes to a float value can be supplied to
adjust tolerance per dtype. If the dictionary has ``'default'``
string as its key, its value is used as the default tolerance in
case any dtype keys do not match.
atol(float or dict): Absolute tolerance. Besides a float value, a
dictionary can be supplied as ``rtol``.
rtol(float, dict, or callable): Relative tolerance. Can be:
- A float value
- A dictionary that maps dtypes to float values. If the dictionary
has ``'default'`` string as its key, its value is used as the
default tolerance in case any dtype keys do not match.
- A callable with signature ``(dtype, **test_kwargs)`` that returns
a float. This allows dynamic tolerance based on test parameters
like input dtypes.
atol(float, dict, or callable): Absolute tolerance. Same options as ``rtol``.
err_msg(str): The error message to be printed in case of failure.
verbose(bool): If ``True``, the conflicting values are
appended to the error message.
Expand Down Expand Up @@ -583,10 +592,17 @@ def numpy_cupy_allclose(
# "must be supplied as float."
# )

def check_func(c, n):
rtol1, atol1 = _resolve_tolerance(type_check, c, rtol, atol)
def check_func(cupy_result, numpy_result, **test_kwargs):
rtol1, atol1 = _resolve_tolerance(
type_check, cupy_result, rtol, atol, **test_kwargs
)
_array.assert_allclose(
c, n, rtol1, atol1, err_msg=err_msg, verbose=verbose
cupy_result,
numpy_result,
rtol1,
atol1,
err_msg=err_msg,
verbose=verbose,
)

return _make_decorator(
Expand Down Expand Up @@ -641,8 +657,10 @@ def numpy_cupy_array_almost_equal(
.. seealso:: :func:`cupy.testing.assert_array_almost_equal`
"""

def check_func(x, y):
_array.assert_array_almost_equal(x, y, decimal, err_msg, verbose)
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_almost_equal(
cupy_result, numpy_result, decimal, err_msg, verbose
)

return _make_decorator(
check_func, name, type_check, False, accept_error, sp_name, scipy_name
Expand Down Expand Up @@ -684,8 +702,8 @@ def numpy_cupy_array_almost_equal_nulp(
.. seealso:: :func:`cupy.testing.assert_array_almost_equal_nulp`
"""

def check_func(x, y):
_array.assert_array_almost_equal_nulp(x, y, nulp)
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_almost_equal_nulp(cupy_result, numpy_result, nulp)

return _make_decorator(
check_func,
Expand Down Expand Up @@ -738,8 +756,8 @@ def numpy_cupy_array_max_ulp(

"""

def check_func(x, y):
_array.assert_array_max_ulp(x, y, maxulp, dtype)
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_max_ulp(cupy_result, numpy_result, maxulp, dtype)

return _make_decorator(
check_func, name, type_check, False, accept_error, sp_name, scipy_name
Expand Down Expand Up @@ -787,9 +805,13 @@ def numpy_cupy_array_equal(
.. seealso:: :func:`cupy.testing.assert_array_equal`
"""

def check_func(x, y):
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_equal(
x, y, err_msg, verbose, strides_check=strides_check
cupy_result,
numpy_result,
err_msg,
verbose,
strides_check=strides_check,
)

return _make_decorator(
Expand Down Expand Up @@ -826,8 +848,8 @@ def numpy_cupy_array_list_equal(
DeprecationWarning,
)

def check_func(x, y):
_array.assert_array_equal(x, y, err_msg, verbose)
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_equal(cupy_result, numpy_result, err_msg, verbose)

return _make_decorator(
check_func, name, False, False, False, sp_name, scipy_name
Expand Down Expand Up @@ -871,8 +893,8 @@ def numpy_cupy_array_less(
.. seealso:: :func:`cupy.testing.assert_array_less`
"""

def check_func(x, y):
_array.assert_array_less(x, y, err_msg, verbose)
def check_func(cupy_result, numpy_result, **test_kwargs):
_array.assert_array_less(cupy_result, numpy_result, err_msg, verbose)

return _make_decorator(
check_func, name, type_check, False, accept_error, sp_name, scipy_name
Expand Down
Loading