Skip to content

Commit d836714

Browse files
committed
Implement dpnp.nextafter
1 parent 87cdaff commit d836714

File tree

7 files changed

+196
-14
lines changed

7 files changed

+196
-14
lines changed

dpnp/dpnp_iface_mathematical.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"modf",
112112
"multiply",
113113
"negative",
114+
"nextafter",
114115
"positive",
115116
"power",
116117
"prod",
@@ -2359,6 +2360,63 @@ def modf(x1, **kwargs):
23592360
)
23602361

23612362

2363+
_NEXTAFTER_DOCSTRING = """
2364+
Return the next floating-point value after `x1` towards `x2`, element-wise.
2365+
2366+
For full documentation refer to :obj:`numpy.nextafter`.
2367+
2368+
Parameters
2369+
----------
2370+
x1 : {dpnp.ndarray, usm_ndarray, scalar}
2371+
Values to find the next representable value of.
2372+
Both inputs `x1` and `x2` can not be scalars at the same time.
2373+
x2 : {dpnp.ndarray, usm_ndarray, scalar}
2374+
The direction where to look for the next representable value of `x1`.
2375+
Both inputs `x1` and `x2` can not be scalars at the same time.
2376+
out : {None, dpnp.ndarray, usm_ndarray}, optional
2377+
Output array to populate. Array must have the correct shape and
2378+
the expected data type.
2379+
Default: ``None``.
2380+
order : {"C", "F", "A", "K"}, optional
2381+
Output array, if parameter `out` is ``None``.
2382+
Default: ``"K"``.
2383+
2384+
Returns
2385+
-------
2386+
out : dpnp.ndarray
2387+
The next representable values of `x1` in the direction of `x2`. The data
2388+
type of the returned array is determined by the Type Promotion Rules.
2389+
2390+
Limitations
2391+
-----------
2392+
Parameters `where` and `subok` are supported with their default values.
2393+
Keyword argument `kwargs` is currently unsupported.
2394+
Otherwise ``NotImplementedError`` exception will be raised.
2395+
2396+
Examples
2397+
--------
2398+
>>> import dpnp as np
2399+
>>> eps = np.finfo(np.float64).eps
2400+
>>> np.nextafter(np.array(1), 2) == eps + 1
2401+
array(True)
2402+
2403+
>>> a = np.array([1, 2])
2404+
>>> b = np.array([2, 1])
2405+
>>> c = np.array([eps + 1, 2 - eps])
2406+
>>> np.nextafter(a, b) == c
2407+
array([ True, True])
2408+
"""
2409+
2410+
nextafter = DPNPBinaryFunc(
2411+
"nextafter",
2412+
ti._nextafter_result_type,
2413+
ti._nextafter,
2414+
_NEXTAFTER_DOCSTRING,
2415+
# mkl_fn_to_call=vmi._mkl_nextafter_to_call,
2416+
# mkl_impl_fn=vmi._nextafter,
2417+
)
2418+
2419+
23622420
_POSITIVE_DOCSTRING = """
23632421
Computes the numerical positive for each element `x_i` of input array `x`.
23642422

tests/skipped_tests.tbl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ tests/test_umath.py::test_umaths[('ldexp', 'di')]
5757
tests/test_umath.py::test_umaths[('ldexp', 'dl')]
5858
tests/test_umath.py::test_umaths[('logaddexp2', 'ff')]
5959
tests/test_umath.py::test_umaths[('logaddexp2', 'dd')]
60-
tests/test_umath.py::test_umaths[('nextafter', 'ff')]
61-
tests/test_umath.py::test_umaths[('nextafter', 'dd')]
6260
tests/test_umath.py::test_umaths[('spacing', 'f')]
6361
tests/test_umath.py::test_umaths[('spacing', 'd')]
6462

@@ -217,11 +215,6 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_par
217215
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2
218216
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2_infinities
219217

220-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
221-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
222-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
223-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
224-
225218
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num
226219
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_negative
227220
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_for_old_numpy

tests/skipped_tests_gpu.tbl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ tests/test_umath.py::test_umaths[('ldexp', 'di')]
3737
tests/test_umath.py::test_umaths[('ldexp', 'dl')]
3838
tests/test_umath.py::test_umaths[('logaddexp2', 'ff')]
3939
tests/test_umath.py::test_umaths[('logaddexp2', 'dd')]
40-
tests/test_umath.py::test_umaths[('nextafter', 'ff')]
41-
tests/test_umath.py::test_umaths[('nextafter', 'dd')]
4240
tests/test_umath.py::test_umaths[('spacing', 'f')]
4341
tests/test_umath.py::test_umaths[('spacing', 'd')]
4442

@@ -268,11 +266,6 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_par
268266
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2
269267
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2_infinities
270268

271-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_frexp
272-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp
273-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination
274-
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float
275-
276269
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num
277270
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_negative
278271
tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_for_old_numpy

tests/test_mathematical.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,139 @@ def test_power(self, dtype, lhs, rhs):
11131113
def test_subtract(self, dtype, lhs, rhs):
11141114
self._test_mathematical("subtract", dtype, lhs, rhs, check_type=False)
11151115

1116+
class TestNextafter:
1117+
@pytest.mark.parametrize("dt", get_float_dtypes())
1118+
@pytest.mark.parametrize(
1119+
"val1, val2",
1120+
[
1121+
pytest.param(1, 2),
1122+
pytest.param(1, 0),
1123+
pytest.param(1, 1),
1124+
],
1125+
)
1126+
def test_float(self, val1, val2, dt):
1127+
v1 = numpy.array(val1, dtype=dt)
1128+
v2 = numpy.array(val2, dtype=dt)
1129+
iv1, iv2 = dpnp.array(v1), dpnp.array(v2)
1130+
1131+
result = dpnp.nextafter(iv1, iv2)
1132+
expected = numpy.nextafter(v1, v2)
1133+
assert_equal(result, expected)
1134+
1135+
@pytest.mark.parametrize("dt", get_float_dtypes())
1136+
def test_float_nan(self, dt):
1137+
a = numpy.array(1, dtype=dt)
1138+
ia = dpnp.array(a)
1139+
1140+
result = dpnp.nextafter(ia, dpnp.nan)
1141+
expected = numpy.nextafter(numpy.nan, a)
1142+
assert_equal(result, expected)
1143+
1144+
result = dpnp.nextafter(dpnp.nan, ia)
1145+
expected = numpy.nextafter(a, numpy.nan)
1146+
assert_equal(result, expected)
1147+
1148+
@pytest.mark.parametrize("val", [0x7c00, 0x8000], ids=["val1", "val2"])
1149+
def test_f16_strides(self, val):
1150+
a = numpy.arange(val, dtype=numpy.uint16).astype(numpy.float16)
1151+
hinf = numpy.array((numpy.inf,), dtype=numpy.float16)
1152+
ia, ihinf = dpnp.array(a), dpnp.array(hinf)
1153+
1154+
result = dpnp.nextafter(ia[:-1], ihinf)
1155+
expected = numpy.nextafter(a[:-1], hinf)
1156+
assert_equal(result, expected)
1157+
1158+
result = dpnp.nextafter(ia[0], -ihinf)
1159+
expected = numpy.nextafter(a[0], -hinf)
1160+
assert_equal(result, expected)
1161+
1162+
result = dpnp.nextafter(ia[1:], -ihinf)
1163+
expected = numpy.nextafter(a[1:], -hinf)
1164+
assert_equal(result, expected)
1165+
1166+
@pytest.mark.parametrize("val", [0x7c00, 0x8000], ids=["val1", "val2"])
1167+
def test_f16_array_inf(self, val):
1168+
a = numpy.arange(val, dtype=numpy.uint16).astype(numpy.float16)
1169+
hinf = numpy.array((numpy.inf,), dtype=numpy.float16)
1170+
ia, ihinf = dpnp.array(a), dpnp.array(hinf)
1171+
1172+
result = dpnp.nextafter(ihinf, ia)
1173+
expected = numpy.nextafter(hinf, a)
1174+
assert_equal(result, expected)
1175+
1176+
result = dpnp.nextafter(-ihinf, ia)
1177+
expected = numpy.nextafter(-hinf, a)
1178+
assert_equal(result, expected)
1179+
1180+
@pytest.mark.parametrize(
1181+
"sign1, sign2",
1182+
[
1183+
pytest.param(1, 1),
1184+
pytest.param(1, -1),
1185+
pytest.param(-1, 1),
1186+
pytest.param(-1, -1),
1187+
],
1188+
)
1189+
def test_f16_inf(self, sign1, sign2):
1190+
hinf1 = numpy.array((sign1 * numpy.inf,), dtype=numpy.float16)
1191+
hinf2 = numpy.array((sign2 * numpy.inf,), dtype=numpy.float16)
1192+
ihinf1, ihinf2 = dpnp.array(hinf1), dpnp.array(hinf2)
1193+
1194+
result = dpnp.nextafter(ihinf1, ihinf2)
1195+
expected = numpy.nextafter(hinf1, hinf2)
1196+
assert_equal(result, expected)
1197+
1198+
@pytest.mark.parametrize("val", [0x7c00, 0x8000], ids=["val1", "val2"])
1199+
def test_f16_array_nan(self, val):
1200+
a = numpy.arange(val, dtype=numpy.uint16).astype(numpy.float16)
1201+
nan = numpy.array((numpy.nan,), dtype=numpy.float16)
1202+
ia, inan = dpnp.array(a), dpnp.array(nan)
1203+
1204+
result = dpnp.nextafter(ia, inan)
1205+
expected = numpy.nextafter(a, nan)
1206+
assert_equal(result, expected)
1207+
1208+
result = dpnp.nextafter(inan, ia)
1209+
expected = numpy.nextafter(nan, a)
1210+
assert_equal(result, expected)
1211+
1212+
@pytest.mark.parametrize(
1213+
"val1, val2",
1214+
[
1215+
pytest.param(numpy.nan, numpy.nan),
1216+
pytest.param(numpy.inf, numpy.nan),
1217+
pytest.param(numpy.nan, numpy.inf),
1218+
],
1219+
)
1220+
def test_f16_inf_nan(self, val1, val2):
1221+
v1 = numpy.array((val1,), dtype=numpy.float16)
1222+
v2 = numpy.array((val2,), dtype=numpy.float16)
1223+
iv1, iv2 =dpnp.array(v1), dpnp.array(v2)
1224+
1225+
result = dpnp.nextafter(iv1, iv2)
1226+
expected = numpy.nextafter(v1, v2)
1227+
assert_equal(result, expected)
1228+
1229+
@pytest.mark.parametrize(
1230+
"val, scalar",
1231+
[
1232+
pytest.param(65504, -numpy.inf),
1233+
pytest.param(-65504, numpy.inf),
1234+
pytest.param(numpy.inf, 0),
1235+
pytest.param(-numpy.inf, 0),
1236+
pytest.param(0, numpy.nan),
1237+
pytest.param(numpy.nan, 0),
1238+
],
1239+
)
1240+
def test_f16_corner_values_with_scalar(self, val, scalar):
1241+
a = numpy.array(val, dtype=numpy.float16)
1242+
ia = dpnp.array(a)
1243+
scalar = numpy.float16(scalar)
1244+
1245+
result = dpnp.nextafter(ia, scalar)
1246+
expected = numpy.nextafter(a, scalar)
1247+
assert_equal(result, expected)
1248+
11161249

11171250
@pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings")
11181251
@pytest.mark.parametrize(

tests/test_sycl_queue.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ def test_reduce_hypot(device):
686686
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0],
687687
[0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0],
688688
),
689+
pytest.param("nextafter", [1, 2], [2, 1]),
689690
pytest.param(
690691
"outer", [0.0, 1.0, 2.0, 3.0, 4.0, 5.0], [0.0, 1.0, 2.0, 0.0]
691692
),

tests/test_usm_type.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ def test_1in_1out(func, data, usm_type):
655655
pytest.param("logaddexp", [[-1, 2, 5, 9]], [[4, -3, 2, -8]]),
656656
pytest.param("maximum", [0.0, 1.0, 2.0], [3.0, 4.0, 5.0]),
657657
pytest.param("minimum", [0.0, 1.0, 2.0], [3.0, 4.0, 5.0]),
658+
pytest.param("nextafter", [1, 2], [2, 1]),
658659
pytest.param("searchsorted", [11, 12, 13, 14, 15], [-10, 20, 12, 13]),
659660
pytest.param(
660661
"tensordot",

tests/third_party/cupy/math_tests/test_floating.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import unittest
2+
import pytest
23

34
import numpy
45

@@ -28,6 +29,7 @@ def test_copysign_float(self, xp, dtype):
2829
b = xp.array([-xp.inf, -3, -0.0, 0, 3, xp.inf], dtype=dtype)[None, :]
2930
return xp.copysign(a, b)
3031

32+
@pytest.mark.skip("ldexp() is not implemented yet")
3133
@testing.for_float_dtypes(name="ftype")
3234
@testing.for_dtypes(["i", "l"], name="itype")
3335
@testing.numpy_cupy_array_equal()
@@ -36,6 +38,7 @@ def test_ldexp(self, xp, ftype, itype):
3638
b = xp.array([-3, -2, -1, 0, 1, 2, 3], dtype=itype)
3739
return xp.ldexp(a, b)
3840

41+
@pytest.mark.skip("frexp() is not implemented yet")
3942
@testing.for_float_dtypes()
4043
def test_frexp(self, dtype):
4144
numpy_a = numpy.array(

0 commit comments

Comments
 (0)