From 1a0a4f1a2e344ad546fb425dce9fdc86e2316c9b Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 13 May 2026 06:46:34 -0700 Subject: [PATCH 1/6] Fix complex acosh for zero and NaN input --- .../libtensor/include/kernels/elementwise_functions/acosh.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dpnp/tensor/libtensor/include/kernels/elementwise_functions/acosh.hpp b/dpnp/tensor/libtensor/include/kernels/elementwise_functions/acosh.hpp index 44e33ce1411..559796984b9 100644 --- a/dpnp/tensor/libtensor/include/kernels/elementwise_functions/acosh.hpp +++ b/dpnp/tensor/libtensor/include/kernels/elementwise_functions/acosh.hpp @@ -150,10 +150,6 @@ struct AcoshFunctor if (std::isnan(rx)) { return resT{sycl::fabs(ry), rx}; } - /* acosh(0 + I*NaN) = NaN + I*NaN */ - if (std::isnan(ry)) { - return resT{ry, ry}; - } /* ordinary cases */ const realT res_im = sycl::copysign(rx, std::imag(in)); return resT{sycl::fabs(ry), res_im}; From 76e2760cb140ae430af0f6c0064dfb5f25b95b92 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 13 May 2026 06:47:27 -0700 Subject: [PATCH 2/6] Add test_acosh_zero_nan to cover the fix --- .../tensor/elementwise/test_hyperbolic.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dpnp/tests/tensor/elementwise/test_hyperbolic.py b/dpnp/tests/tensor/elementwise/test_hyperbolic.py index b94c5ede3f2..98c31ec440f 100644 --- a/dpnp/tests/tensor/elementwise/test_hyperbolic.py +++ b/dpnp/tests/tensor/elementwise/test_hyperbolic.py @@ -200,3 +200,24 @@ def test_hyper_real_special_cases(np_call, dpt_call, dtype): tol = 8 * dpt.finfo(dtype).resolution assert_allclose(dpt.asnumpy(dpt_call(yf)), Y_np, atol=tol, rtol=tol) + + +@pytest.mark.parametrize("dtype", ["c8", "c16"]) +def test_acosh_zero_nan(dtype): + # check acosh(0 + NaN j) = NaN ± πj/2 + q = get_queue_or_skip() + skip_if_dtype_not_supported(dtype, q) + + x = [complex(+0.0, np.nan), complex(-0.0, np.nan)] + + xf = np.array(x, dtype=dtype) + yf = dpt.asarray(xf, dtype=dtype, sycl_queue=q) + + with np.errstate(all="ignore"): + Y_np = np.arccosh(xf) + + Y_dpt = dpt.asnumpy(dpt.acosh(yf)) + + for i in range(len(x)): + assert np.isnan(Y_np[i].real) == np.isnan(Y_dpt[i].real) + assert_allclose(abs(Y_dpt[i].imag), abs(Y_np[i].imag), atol=1e-6) From fc2c728ff5d38e8ada3e86c3e59180af588bb4b9 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 13 May 2026 07:02:24 -0700 Subject: [PATCH 3/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 752bf2ad4b3..661b27375bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed incorrect in-place advanced indexing for 4D arrays when using `range` or `list` as index keys [#2872](https://github.com/IntelPython/dpnp/pull/2872) * Fixed `conda build` command syntax in GitHub workflows and documentation to use `conda-build` [#2888](https://github.com/IntelPython/dpnp/pull/2888) +* Fixed incorrect `dpnp.tensor.acosh` result for `complex(±0, NaN)` special case to match the Array API specification and NumPy [#2914](https://github.com/IntelPython/dpnp/pull/2914) ### Security From a82855e28d5d2f3f5582ef67ef47984a93cc634d Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 13 May 2026 12:30:17 -0700 Subject: [PATCH 4/6] Update test_hyperbolic.py --- .../tensor/elementwise/test_hyperbolic.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/dpnp/tests/tensor/elementwise/test_hyperbolic.py b/dpnp/tests/tensor/elementwise/test_hyperbolic.py index 98c31ec440f..48f3ccab46a 100644 --- a/dpnp/tests/tensor/elementwise/test_hyperbolic.py +++ b/dpnp/tests/tensor/elementwise/test_hyperbolic.py @@ -38,7 +38,9 @@ ) from .utils import ( _all_dtypes, + _complex_fp_dtypes, _map_to_device_dtype, + _real_fp_dtypes, ) _hyper_funcs = [(np.sinh, dpt.sinh), (np.cosh, dpt.cosh), (np.tanh, dpt.tanh)] @@ -65,7 +67,7 @@ def test_hyper_out_type(np_call, dpt_call, dtype): @pytest.mark.parametrize("np_call, dpt_call", _all_funcs) -@pytest.mark.parametrize("dtype", ["f2", "f4", "f8"]) +@pytest.mark.parametrize("dtype", _real_fp_dtypes) def test_hyper_real_contig(np_call, dpt_call, dtype): q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -96,7 +98,7 @@ def test_hyper_real_contig(np_call, dpt_call, dtype): @pytest.mark.parametrize("np_call, dpt_call", _all_funcs) -@pytest.mark.parametrize("dtype", ["c8", "c16"]) +@pytest.mark.parametrize("dtype", _complex_fp_dtypes) def test_hyper_complex_contig(np_call, dpt_call, dtype): q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -123,7 +125,7 @@ def test_hyper_complex_contig(np_call, dpt_call, dtype): @pytest.mark.parametrize("np_call, dpt_call", _all_funcs) -@pytest.mark.parametrize("dtype", ["f2", "f4", "f8"]) +@pytest.mark.parametrize("dtype", _real_fp_dtypes) def test_hyper_real_strided(np_call, dpt_call, dtype): q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -157,7 +159,7 @@ def test_hyper_real_strided(np_call, dpt_call, dtype): @pytest.mark.parametrize("np_call, dpt_call", _all_funcs) -@pytest.mark.parametrize("dtype", ["c8", "c16"]) +@pytest.mark.parametrize("dtype", _complex_fp_dtypes) def test_hyper_complex_strided(np_call, dpt_call, dtype): q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -185,7 +187,7 @@ def test_hyper_complex_strided(np_call, dpt_call, dtype): @pytest.mark.parametrize("np_call, dpt_call", _all_funcs) -@pytest.mark.parametrize("dtype", ["f2", "f4", "f8"]) +@pytest.mark.parametrize("dtype", _real_fp_dtypes) def test_hyper_real_special_cases(np_call, dpt_call, dtype): q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -202,9 +204,9 @@ def test_hyper_real_special_cases(np_call, dpt_call, dtype): assert_allclose(dpt.asnumpy(dpt_call(yf)), Y_np, atol=tol, rtol=tol) -@pytest.mark.parametrize("dtype", ["c8", "c16"]) +@pytest.mark.parametrize("dtype", _complex_fp_dtypes) def test_acosh_zero_nan(dtype): - # check acosh(0 + NaN j) = NaN ± πj/2 + # check acosh(±0 + NaN j) = NaN ± π/2 j (Array API spec) q = get_queue_or_skip() skip_if_dtype_not_supported(dtype, q) @@ -213,11 +215,8 @@ def test_acosh_zero_nan(dtype): xf = np.array(x, dtype=dtype) yf = dpt.asarray(xf, dtype=dtype, sycl_queue=q) - with np.errstate(all="ignore"): - Y_np = np.arccosh(xf) - Y_dpt = dpt.asnumpy(dpt.acosh(yf)) - for i in range(len(x)): - assert np.isnan(Y_np[i].real) == np.isnan(Y_dpt[i].real) - assert_allclose(abs(Y_dpt[i].imag), abs(Y_np[i].imag), atol=1e-6) + pi_half = np.full(len(x), np.pi / 2, dtype=xf.real.dtype) + assert np.all(np.isnan(Y_dpt.real)) + assert_allclose(abs(Y_dpt.imag), pi_half, atol=1e-6) From 33dd903a1e92da30ae498e8a5385a6cb94d5e13a Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 13 May 2026 12:31:59 -0700 Subject: [PATCH 5/6] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661b27375bd..070f0cfd1cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed incorrect in-place advanced indexing for 4D arrays when using `range` or `list` as index keys [#2872](https://github.com/IntelPython/dpnp/pull/2872) * Fixed `conda build` command syntax in GitHub workflows and documentation to use `conda-build` [#2888](https://github.com/IntelPython/dpnp/pull/2888) -* Fixed incorrect `dpnp.tensor.acosh` result for `complex(±0, NaN)` special case to match the Array API specification and NumPy [#2914](https://github.com/IntelPython/dpnp/pull/2914) +* Fixed incorrect `dpnp.tensor.acosh` result for `complex(±0, NaN)` special case to match the Python Array API specification [#2914](https://github.com/IntelPython/dpnp/pull/2914) ### Security From 36b350a49d092a21811aee5e7a0e0a84fdb85c1b Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Fri, 15 May 2026 03:07:39 -0700 Subject: [PATCH 6/6] Apply remark --- dpnp/tests/tensor/elementwise/test_hyperbolic.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dpnp/tests/tensor/elementwise/test_hyperbolic.py b/dpnp/tests/tensor/elementwise/test_hyperbolic.py index 48f3ccab46a..d25a9845358 100644 --- a/dpnp/tests/tensor/elementwise/test_hyperbolic.py +++ b/dpnp/tests/tensor/elementwise/test_hyperbolic.py @@ -217,6 +217,5 @@ def test_acosh_zero_nan(dtype): Y_dpt = dpt.asnumpy(dpt.acosh(yf)) - pi_half = np.full(len(x), np.pi / 2, dtype=xf.real.dtype) - assert np.all(np.isnan(Y_dpt.real)) - assert_allclose(abs(Y_dpt.imag), pi_half, atol=1e-6) + assert np.isnan(Y_dpt.real).all() + assert_allclose(np.abs(Y_dpt.imag), np.pi / 2, atol=1e-6, strict=False)