From d279e64d8b90739433f7d5a247b79e12fc29cf70 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 15 Jun 2026 16:09:03 +0200 Subject: [PATCH 1/3] Rever changes in the tests done in gh-2912 --- dpnp/tests/test_product.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dpnp/tests/test_product.py b/dpnp/tests/test_product.py index 9d43b6453e0b..f7ce082c079f 100644 --- a/dpnp/tests/test_product.py +++ b/dpnp/tests/test_product.py @@ -887,9 +887,7 @@ def test_order(self, dtype, order1, order2, order, shape1, shape2): ids=["-2", "2", "(-2, 2)", "(2, -2)"], ) def test_strided1(self, dtype, stride): - # TODO: enable back when the root cause is identified - # for dim in [1, 2, 3, 4]: - for dim in [1, 2, 3]: + for dim in [1, 2, 3, 4]: shape = tuple(20 for _ in range(dim)) A = generate_random_numpy_array(shape, dtype) iA = dpnp.array(A) @@ -1544,9 +1542,7 @@ def test_axes(self, axes): result = dpnp.matvec(ia, ib, axes=axes) expected = numpy.matvec(a, b, axes=axes) - - # TODO: check if failing with newer NumPy - assert_dtype_allclose(result, expected, factor=40) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_error(self, xp): From 808679672f616286e1e95f42166d047b59d53b70 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 15 Jul 2026 17:47:34 +0200 Subject: [PATCH 2/3] Keep matvec test tolerance while re-enabling dim=4 in strided matmul test The revert of gh-2912 removed the widened tolerance on TestMatvec::test_axes, which reintroduced a CI failure on ubuntu-latest: dpnp computes matvec via oneMKL gemm_batch while NumPy uses OpenBLAS gemv, so the summation order differs and the float64 result deviates at the noise floor (~1.4e-14), exceeding the default 8e-15 tolerance. Restore factor=40 on test_axes (with an explanatory comment) while keeping the rest of the revert, i.e. re-enabling dim=4 in TestMatmul::test_strided1, whose factor=16 tolerance already absorbs any cross-BLAS discrepancy. Co-Authored-By: Claude Opus 4.8 (1M context) --- dpnp/tests/test_product.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dpnp/tests/test_product.py b/dpnp/tests/test_product.py index f7ce082c079f..a66471907f0a 100644 --- a/dpnp/tests/test_product.py +++ b/dpnp/tests/test_product.py @@ -1542,7 +1542,11 @@ def test_axes(self, axes): result = dpnp.matvec(ia, ib, axes=axes) expected = numpy.matvec(a, b, axes=axes) - assert_dtype_allclose(result, expected) + + # dpnp uses oneMKL gemm_batch while NumPy uses OpenBLAS gemv, so the + # summation order differs and the float64 result deviates at the noise + # floor (~1e-14), which exceeds the default tolerance + assert_dtype_allclose(result, expected, factor=40) @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_error(self, xp): From 0ded231227157cb2a0a39396787a5fd47ff64815 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 16 Jul 2026 10:19:25 +0200 Subject: [PATCH 3/3] Widen float32 tolerance in test_strided1 instead of skipping dim=4 Re-enabling dim=4 in TestMatmul::test_strided1 reintroduced the CI failure gh-2912 had worked around by skipping it: for float32 the strided matmul deviates by ~1.87e-5, just above the factor=16 bound (~1.81e-5). The cause is benign cross-BLAS non-associativity -- dpnp copies the strided input to c-contiguous and runs oneMKL gemm_batch, while NumPy uses OpenBLAS, so the length-20 float32 contraction accumulates in a different order. Bump the tolerance to factor=24 (pass-bound ~2.27e-5) for float32 only; integer input is compared exactly, so the factor does not affect it. This keeps dim=4 covered without masking real regressions in the exact path. Co-Authored-By: Claude Opus 4.8 (1M context) --- dpnp/tests/test_product.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dpnp/tests/test_product.py b/dpnp/tests/test_product.py index a66471907f0a..88627b7d2cc5 100644 --- a/dpnp/tests/test_product.py +++ b/dpnp/tests/test_product.py @@ -887,6 +887,13 @@ def test_order(self, dtype, order1, order2, order, shape1, shape2): ids=["-2", "2", "(-2, 2)", "(2, -2)"], ) def test_strided1(self, dtype, stride): + # dpnp copies the strided input into a c-contiguous array and runs the + # batched product through oneMKL gemm_batch, while NumPy uses OpenBLAS. + # The two backends accumulate in a different order, so the float32 + # result deviates at the noise floor (~2e-5 for a length-20 contraction + # with dim=4), which exceeds the default tolerance. Integer input is + # exact, so the factor only affects the float32 case. + factor = 24 if dtype == numpy.float32 else 16 for dim in [1, 2, 3, 4]: shape = tuple(20 for _ in range(dim)) A = generate_random_numpy_array(shape, dtype) @@ -898,7 +905,7 @@ def test_strided1(self, dtype, stride): # the 2D base is not c-contiguous nor f-contigous result = dpnp.matmul(ia, ia) expected = numpy.matmul(a, a) - assert_dtype_allclose(result, expected, factor=16) + assert_dtype_allclose(result, expected, factor=factor) OUT = numpy.empty(shape, dtype=result.dtype) out = OUT[slices] @@ -907,7 +914,7 @@ def test_strided1(self, dtype, stride): 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) + assert_dtype_allclose(result, expected, factor=factor) @pytest.mark.parametrize("dtype", _selected_dtypes) @pytest.mark.parametrize(