From 705d2553ca443b019810e40ad488a7f06879cd2e Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Thu, 20 Mar 2025 10:00:48 -0700 Subject: [PATCH 1/4] update test_fft.py --- dpnp/tests/test_fft.py | 912 +++++++++++++++++--------------------- dpnp/tests/test_linalg.py | 5 +- 2 files changed, 399 insertions(+), 518 deletions(-) diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 8a65d2857a77..945e3e760660 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -35,151 +35,114 @@ def _make_array_Hermitian(a, n): return a -# TODO: `assert_dtype_allclose` calls in this file have `check_only_type_kind=True` -# since stock NumPy is currently used in public CI for code coverege which -# always returns complex128/float64 for FFT functions, but Intel® NumPy and -# dpnp return complex64/float32 if input is complex64/float32 class TestFft: - def setup_method(self): - numpy.random.seed(42) - - @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True) - ) - @pytest.mark.parametrize( - "shape", [(64,), (8, 8), (4, 16), (4, 4, 4), (2, 4, 4, 2)] - ) - @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_fft_ndim(self, dtype, shape, norm): - np_data = numpy.arange(64, dtype=dtype).reshape(shape) - dpnp_data = dpnp.arange(64, dtype=dtype).reshape(shape) - - np_res = numpy.fft.fft(np_data, norm=norm) - dpnp_res = dpnp.fft.fft(dpnp_data, norm=norm) - assert_dtype_allclose(dpnp_res, np_res, check_only_type_kind=True) - - np_res = numpy.fft.ifft(np_data, norm=norm) - dpnp_res = dpnp.fft.ifft(dpnp_data, norm=norm) - assert_dtype_allclose(dpnp_res, np_res, check_only_type_kind=True) - @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_fft_1D(self, dtype, n, norm): + def test_basic(self, dtype, n, norm): x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) # a.dtype is float16 if x.dtype is bool - a = dpnp.array(a_np) + a = numpy.sin(x) # a.dtype is float16 if x.dtype is bool + ia = dpnp.array(a) factor = 140 if dtype == dpnp.bool else 8 - result = dpnp.fft.fft(a, n=n, norm=norm) - expected = numpy.fft.fft(a_np, n=n, norm=norm) + result = dpnp.fft.fft(ia, n=n, norm=norm) + expected = numpy.fft.fft(a, n=n, norm=norm) + # flag is needed for Intel NumPy 1.26.4 since it returns complex128 + dt_list = [dpnp.bool, dpnp.int8, dpnp.uint8] + flag = True if dtype in dt_list else False assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=True + result, expected, factor=factor, check_only_type_kind=flag ) - iresult = dpnp.fft.ifft(result, n=n, norm=norm) - iexpected = numpy.fft.ifft(expected, n=n, norm=norm) + # inverse FFT + result = dpnp.fft.ifft(result, n=n, norm=norm) + expected = numpy.fft.ifft(expected, n=n, norm=norm) assert_dtype_allclose( - iresult, iexpected, factor=factor, check_only_type_kind=True + result, expected, factor=factor, check_only_type_kind=flag ) - @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_fft_1D_bool(self, norm): - a = dpnp.linspace(-1, 1, 11, dtype=dpnp.bool) - a_np = dpnp.asnumpy(a) - - result = dpnp.fft.fft(a, norm=norm) - expected = numpy.fft.fft(a_np, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) - - iresult = dpnp.fft.ifft(result, norm=norm) - iexpected = numpy.fft.ifft(expected, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) - @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [-1, 1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_fft_1D_on_2D_array(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) + def test_2d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) - result = dpnp.fft.fft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.fft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.fft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm) - iexpected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm) + expected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [0, 1, 2]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_fft_1D_on_3D_array(self, dtype, n, axis, norm, order): - x1 = numpy.random.uniform(-10, 10, 24) - x2 = numpy.random.uniform(-10, 10, 24) - a_np = numpy.array(x1 + 1j * x2, dtype=dtype).reshape( - 2, 3, 4, order=order - ) - a = dpnp.asarray(a_np) + def test_3d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((2, 3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) - result = dpnp.fft.fft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.fft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.fft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm) - iexpected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm) + expected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("n", [None, 5, 20]) - def test_fft_usm_ndarray(self, n): + def test_usm_ndarray(self, n): x = dpt.linspace(-1, 1, 11) - a = dpt.sin(x) + 1j * dpt.cos(x) - a_usm = dpt.asarray(a, dtype=dpt.complex64) - a_np = dpt.asnumpy(a_usm) - out_shape = (n,) if n is not None else a_usm.shape - out = dpt.empty(out_shape, dtype=a_usm.dtype) + a_usm = dpt.sin(x) + 1j * dpt.cos(x) + a = dpt.asnumpy(a_usm) + + expected = numpy.fft.fft(a, n=n) + out = dpt.empty(expected.shape, dtype=a_usm.dtype) result = dpnp.fft.fft(a_usm, n=n, out=out) assert out is result.get_array() - expected = numpy.fft.fft(a_np, n=n) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) # in-place if n is None: result = dpnp.fft.fft(a_usm, n=n, out=a_usm) assert a_usm is result.get_array() - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_fft_1D_out(self, dtype, n, norm): + def test_out(self, dtype, n, norm): x = dpnp.linspace(-1, 1, 11) - a = dpnp.sin(x) + 1j * dpnp.cos(x) - a = dpnp.asarray(a, dtype=dtype) - a_np = dpnp.asnumpy(a) - out_shape = (n,) if n is not None else a.shape - out = dpnp.empty(out_shape, dtype=a.dtype) + x = dpnp.sin(x) + 1j * dpnp.cos(x) + ia = dpnp.asarray(x, dtype=dtype) + a = dpnp.asnumpy(ia) - result = dpnp.fft.fft(a, n=n, norm=norm, out=out) + expected = numpy.fft.fft(a, n=n, norm=norm) + out = dpnp.empty(expected.shape, dtype=a.dtype) + + result = dpnp.fft.fft(ia, n=n, norm=norm, out=out) assert out is result - expected = numpy.fft.fft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft(result, n=n, norm=norm, out=out) - assert out is iresult - iexpected = numpy.fft.ifft(expected, n=n, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft(result, n=n, norm=norm, out=out) + assert out is result + expected = numpy.fft.ifft(expected, n=n, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axis", [0, 1]) - def test_fft_inplace_out(self, axis): + def test_inplace_out(self, axis): # Test some weirder in-place combinations - y_np = numpy.random.rand(20, 20) + 1j * numpy.random.rand(20, 20) - y = dpnp.asarray(y_np) + y_np = generate_random_numpy_array((20, 20), dtype=numpy.complex64) + y = dpnp.array(y_np) # Fully in-place. y1 = y.copy() expected1 = numpy.fft.fft(y1.asnumpy(), axis=axis) @@ -258,68 +221,62 @@ def test_fft_inplace_out(self, axis): @pytest.mark.parametrize("axis", [-1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_fft_1D_on_2D_array_out(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) - out_shape = list(a.shape) - if n is not None: - out_shape[axis] = n - out_shape = tuple(out_shape) - out = dpnp.empty(out_shape, dtype=a.dtype) - - result = dpnp.fft.fft(a, n=n, axis=axis, norm=norm, out=out) + def test_2d_array_out(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) + + expected = numpy.fft.fft(a, n=n, axis=axis, norm=norm) + out = dpnp.empty(expected.shape, dtype=a.dtype) + + result = dpnp.fft.fft(ia, n=n, axis=axis, norm=norm, out=out) assert out is result - expected = numpy.fft.fft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm, out=out) - assert out is iresult - iexpected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft(result, n=n, axis=axis, norm=norm, out=out) + assert out is result + expected = numpy.fft.ifft(expected, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("stride", [-1, -3, 2, 5]) - def test_fft_strided_1D(self, stride): - x1 = numpy.random.uniform(-10, 10, 20) - x2 = numpy.random.uniform(-10, 10, 20) - A_np = numpy.array(x1 + 1j * x2, dtype=numpy.complex64) - A = dpnp.asarray(A_np) - a_np = A_np[::stride] - a = A[::stride] - - result = dpnp.fft.fft(a) - expected = numpy.fft.fft(a_np) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + def test_strided_1d(self, stride): + a = generate_random_numpy_array(20, dtype=numpy.complex64) + ia = dpnp.array(a) + a = a[::stride] + ia = ia[::stride] + + result = dpnp.fft.fft(ia) + expected = numpy.fft.fft(a) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("stride_x", [-1, -3, 2, 3]) @pytest.mark.parametrize("stride_y", [-1, -3, 2, 3]) - def test_fft_strided_2D(self, stride_x, stride_y): - x1 = numpy.random.uniform(-10, 10, 120) - x2 = numpy.random.uniform(-10, 10, 120) - a_np = numpy.array(x1 + 1j * x2, dtype=numpy.complex64).reshape(12, 10) - a = dpnp.asarray(a_np) - a_np = a_np[::stride_x, ::stride_y] + def test_strided_2d(self, stride_x, stride_y): + a = generate_random_numpy_array((12, 10), dtype=numpy.complex64) + ia = dpnp.array(a) a = a[::stride_x, ::stride_y] + ia = ia[::stride_x, ::stride_y] - result = dpnp.fft.fft(a) - expected = numpy.fft.fft(a_np) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia) + expected = numpy.fft.fft(a) + assert_dtype_allclose(result, expected) - def test_fft_empty_array(self): - a_np = numpy.empty((10, 0, 4), dtype=numpy.complex64) - a = dpnp.array(a_np) + def test_empty_array(self): + a = numpy.empty((10, 0, 4), dtype=numpy.complex64) + ia = dpnp.array(a) # returns empty array, a.size=0 - result = dpnp.fft.fft(a, axis=0) - expected = numpy.fft.fft(a_np, axis=0) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia, axis=0) + expected = numpy.fft.fft(a, axis=0) + assert_dtype_allclose(result, expected) # calculates FFT, a.size become non-zero because of n=2 - result = dpnp.fft.fft(a, axis=1, n=2) - expected = numpy.fft.fft(a_np, axis=1, n=2) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia, axis=1, n=2) + expected = numpy.fft.fft(a, axis=1, n=2) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_fft_error(self, xp): + def test_error(self, xp): # 0-D input a = xp.array(3) # dpnp and Intel® NumPy raise ValueError @@ -344,7 +301,7 @@ def test_fft_error(self, xp): a = xp.ones((5, 0, 4)) assert_raises(ValueError, xp.fft.fft, a, axis=1) - def test_fft_validate_out(self): + def test_validate_out(self): # Inconsistent sycl_queue a = dpnp.ones((10,), dtype=dpnp.complex64, sycl_queue=dpctl.SyclQueue()) out = dpnp.empty((10,), sycl_queue=dpctl.SyclQueue()) @@ -364,48 +321,47 @@ def test_fft_validate_out(self): "dtype", get_all_dtypes(no_none=True, no_bool=True) ) def test_negative_stride(self, dtype): - a = dpnp.arange(10, dtype=dtype) - result = dpnp.fft.fft(a[::-1]) - expected = numpy.fft.fft(a.asnumpy()[::-1]) + ia = dpnp.arange(10, dtype=dtype) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia[::-1]) + expected = numpy.fft.fft(ia.asnumpy()[::-1]) + assert_dtype_allclose(result, expected) class TestFft2: - def setup_method(self): - numpy.random.seed(42) - @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("axes", [(0, 1), (1, 2), (0, 2), (2, 1), (2, 0)]) @pytest.mark.parametrize("norm", [None, "forward", "backward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_fft2(self, dtype, axes, norm, order): - a_np = generate_random_numpy_array((2, 3, 4), dtype, order) - a = dpnp.array(a_np) + def test_basic(self, dtype, axes, norm, order): + a = generate_random_numpy_array((2, 3, 4), dtype, order) + ia = dpnp.array(a) - result = dpnp.fft.fft2(a, axes=axes, norm=norm) - expected = numpy.fft.fft2(a_np, axes=axes, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft2(ia, axes=axes, norm=norm) + expected = numpy.fft.fft2(a, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft2(result, axes=axes, norm=norm) - iexpected = numpy.fft.ifft2(expected, axes=axes, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft2(result, axes=axes, norm=norm) + expected = numpy.fft.ifft2(expected, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("s", [None, (3, 3), (10, 10), (3, 10)]) - def test_fft2_s(self, s): - a_np = generate_random_numpy_array((6, 8), dtype=numpy.complex64) - a = dpnp.array(a_np) + def test_s(self, s): + a = generate_random_numpy_array((6, 8), dtype=numpy.complex64) + ia = dpnp.array(a) - result = dpnp.fft.fft2(a, s=s) - expected = numpy.fft.fft2(a_np, s=s) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft2(ia, s=s) + expected = numpy.fft.fft2(a, s=s) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifft2(result, s=s) - iexpected = numpy.fft.ifft2(expected, s=s) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifft2(result, s=s) + expected = numpy.fft.ifft2(expected, s=s) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_fft_error(self, xp): + def test_error(self, xp): # 0-D input a = xp.ones(()) assert_raises(IndexError, xp.fft.fft2, a) @@ -415,7 +371,7 @@ def test_fft_error(self, xp): class TestFftfreq: @pytest.mark.parametrize("n", [10, 20]) @pytest.mark.parametrize("d", [0.5, 2]) - def test_fftfreq(self, func, n, d): + def test_basic(self, func, n, d): result = getattr(dpnp.fft, func)(n, d) expected = getattr(numpy.fft, func)(n, d) assert_dtype_allclose(result, expected) @@ -443,118 +399,112 @@ def test_error(self, func): class TestFftn: - def setup_method(self): - numpy.random.seed(42) - - @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True) - ) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "axes", [None, (0, 1, 2), (-1, -4, -2), (-2, -4, -1, -3)] ) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_fftn(self, dtype, axes, norm, order): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype, order) - a = dpnp.array(a_np) + def test_basic(self, dtype, axes, norm, order): + a = generate_random_numpy_array((2, 3, 4, 5), dtype, order) + ia = dpnp.array(a) - result = dpnp.fft.fftn(a, axes=axes, norm=norm) - expected = numpy.fft.fftn(a_np, axes=axes, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fftn(ia, axes=axes, norm=norm) + expected = numpy.fft.fftn(a, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifftn(result, axes=axes, norm=norm) - iexpected = numpy.fft.ifftn(expected, axes=axes, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # inverse FFT + result = dpnp.fft.ifftn(result, axes=axes, norm=norm) + expected = numpy.fft.ifftn(expected, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize( "axes", [(2, 0, 2, 0), (0, 1, 1), (2, 0, 1, 3, 2, 1)] ) - def test_fftn_repeated_axes(self, axes): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) - a = dpnp.array(a_np) + def test_repeated_axes(self, axes): + a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) + ia = dpnp.array(a) - result = dpnp.fft.fftn(a, axes=axes) + result = dpnp.fft.fftn(ia, axes=axes) # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + expected = a for ii in axes: expected = numpy.fft.fft(expected, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifftn(result, axes=axes) - iexpected = expected + # inverse FFT + result = dpnp.fft.ifftn(result, axes=axes) for ii in axes: - iexpected = numpy.fft.ifft(iexpected, axis=ii) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, axis=ii) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axes", [(2, 3, 3, 2), (0, 0, 3, 3)]) @pytest.mark.parametrize("s", [(5, 4, 3, 3), (7, 8, 10, 9)]) - def test_fftn_repeated_axes_with_s(self, axes, s): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) - a = dpnp.array(a_np) + def test_repeated_axes_with_s(self, axes, s): + a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) + ia = dpnp.array(a) - result = dpnp.fft.fftn(a, s=s, axes=axes) + result = dpnp.fft.fftn(ia, s=s, axes=axes) # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + expected = a for jj, ii in zip(s[::-1], axes[::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.ifftn(result, s=s, axes=axes) - iexpected = expected + # inverse FFT + result = dpnp.fft.ifftn(result, s=s, axes=axes) for jj, ii in zip(s[::-1], axes[::-1]): - iexpected = numpy.fft.ifft(iexpected, n=jj, axis=ii) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, n=jj, axis=ii) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axes", [(0, 1, 2, 3), (1, 2, 1, 2), (2, 2, 2, 3)]) @pytest.mark.parametrize("s", [(2, 3, 4, 5), (5, 4, 7, 8), (2, 5, 1, 2)]) - def test_fftn_out(self, axes, s): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) - a = dpnp.array(a_np) - - out_shape = list(a.shape) - for s_i, axis in zip(s[::-1], axes[::-1]): - out_shape[axis] = s_i - out = dpnp.empty(out_shape, dtype=a.dtype) - result = dpnp.fft.fftn(a, out=out, s=s, axes=axes) - assert out is result + def test_out(self, axes, s): + a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) + ia = dpnp.array(a) + # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + expected = a for jj, ii in zip(s[::-1], axes[::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + out = dpnp.empty(expected.shape, dtype=a.dtype) - out = dpnp.empty(out_shape, dtype=a.dtype) - iresult = dpnp.fft.ifftn(result, out=out, s=s, axes=axes) - assert out is iresult - iexpected = expected + result = dpnp.fft.fftn(ia, out=out, s=s, axes=axes) + assert out is result + assert_dtype_allclose(result, expected) + + # inverse FFT + out = dpnp.empty(expected.shape, dtype=a.dtype) + result = dpnp.fft.ifftn(result, out=out, s=s, axes=axes) + assert out is result for jj, ii in zip(s[::-1], axes[::-1]): - iexpected = numpy.fft.ifft(iexpected, n=jj, axis=ii) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, n=jj, axis=ii) + assert_dtype_allclose(result, expected) def test_negative_s(self): - a_np = generate_random_numpy_array((3, 4, 5), dtype=numpy.complex64) - a = dpnp.array(a_np) + a = generate_random_numpy_array((3, 4, 5), dtype=numpy.complex64) + ia = dpnp.array(a) # For dpnp and stock NumPy 2.0, if s is -1, the whole input is used # (no padding or trimming). - result = dpnp.fft.fftn(a, s=(-1, -1), axes=(0, 2)) - expected = numpy.fft.fftn(a_np, s=(3, 5), axes=(0, 2)) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fftn(ia, s=(-1, -1), axes=(0, 2)) + expected = numpy.fft.fftn(a, s=(3, 5), axes=(0, 2)) + assert_dtype_allclose(result, expected) - def test_fftn_empty_array(self): - a_np = numpy.empty((10, 0, 4), dtype=numpy.complex64) - a = dpnp.array(a_np) + def test_empty_array(self): + a = numpy.empty((10, 0, 4), dtype=numpy.complex64) + ia = dpnp.array(a) - result = dpnp.fft.fftn(a, axes=(0, 2)) - expected = numpy.fft.fftn(a_np, axes=(0, 2)) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fftn(ia, axes=(0, 2)) + expected = numpy.fft.fftn(a, axes=(0, 2)) + assert_dtype_allclose(result, expected) - result = dpnp.fft.fftn(a, axes=(0, 1, 2), s=(5, 2, 4)) - expected = numpy.fft.fftn(a_np, axes=(0, 1, 2), s=(5, 2, 4)) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fftn(ia, axes=(0, 1, 2), s=(5, 2, 4)) + expected = numpy.fft.fftn(a, axes=(0, 1, 2), s=(5, 2, 4)) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) - def test_fftn_0D(self, dtype): + def test_0D(self, dtype): a = dpnp.array(3, dtype=dtype) # 0-D input # axes is None @@ -577,7 +527,7 @@ def test_fftn_0D(self, dtype): assert_raises(IndexError, dpnp.fft.fftn, a, axes=(0,)) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) - def test_fftn_empty_axes(self, dtype): + def test_empty_axes(self, dtype): a = dpnp.ones((2, 3, 4), dtype=dtype) # For axes=(), stock Numpy and dpnp return input array @@ -587,7 +537,7 @@ def test_fftn_empty_axes(self, dtype): assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_fft_error(self, xp): + def test_error(self, xp): # s is not int a = xp.ones((4, 3)) # dpnp and stock NumPy raise TypeError @@ -617,81 +567,70 @@ def test_fft_error(self, xp): class TestFftshift: @pytest.mark.parametrize("func", ["fftshift", "ifftshift"]) @pytest.mark.parametrize("axes", [None, 1, (0, 1)]) - def test_fftshift(self, func, axes): - x = dpnp.arange(12).reshape(3, 4) - x_np = x.asnumpy() - expected = getattr(dpnp.fft, func)(x, axes=axes) - result = getattr(numpy.fft, func)(x_np, axes=axes) + def test_basic(self, func, axes): + ia = dpnp.arange(12).reshape(3, 4) + a = ia.asnumpy() + + expected = getattr(dpnp.fft, func)(ia, axes=axes) + result = getattr(numpy.fft, func)(a, axes=axes) assert_dtype_allclose(expected, result) class TestHfft: - def setup_method(self): - numpy.random.seed(42) - @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_hfft_1D(self, dtype, n, norm): + def test_basic(self, dtype, n, norm): x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) + a = numpy.sin(x) if numpy.issubdtype(dtype, numpy.complexfloating): - a_np = _make_array_Hermitian(a_np, n) - a = dpnp.array(a_np) + a = _make_array_Hermitian(a, n) + ia = dpnp.array(a) - result = dpnp.fft.hfft(a, n=n, norm=norm) - expected = numpy.fft.hfft(a_np, n=n, norm=norm) - # check_only_type_kind=True since numpy always returns float64 + result = dpnp.fft.hfft(ia, n=n, norm=norm) + expected = numpy.fft.hfft(a, n=n, norm=norm) + # check_only_type_kind=True since NumPy always returns float64 # but dpnp return float32 if input is float32 assert_dtype_allclose(result, expected, check_only_type_kind=True) @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + "dtype", get_all_dtypes(no_none=True, no_complex=True) ) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_ihfft_1D(self, dtype, n, norm): + def test_inverse(self, dtype, n, norm): x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) - a = dpnp.array(a_np) - - result = dpnp.fft.ihfft(a, n=n, norm=norm) - expected = numpy.fft.ihfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + a = numpy.sin(x) # a.dtype is float16 if x.dtype is bool + ia = dpnp.array(a) - @pytest.mark.parametrize("n", [None, 5, 20]) - @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_ihfft_bool(self, n, norm): - a = dpnp.ones(11, dtype=dpnp.bool) - a_np = dpnp.asnumpy(a) - - result = dpnp.fft.ihfft(a, n=n, norm=norm) - expected = numpy.fft.ihfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + factor = 140 if dtype == dpnp.bool else 8 + result = dpnp.fft.ihfft(ia, n=n, norm=norm) + expected = numpy.fft.ihfft(a, n=n, norm=norm) + # check_only_type_kind=True since Intel NumPy always returns complex128 + assert_dtype_allclose( + result, expected, factor=factor, check_only_type_kind=True + ) - def test_ihfft_error(self): + def test_error(self): a = dpnp.ones(11) # incorrect norm assert_raises(ValueError, dpnp.fft.ihfft, a, norm="backwards") class TestIrfft: - def setup_method(self): - numpy.random.seed(42) - @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_irfft_1D(self, dtype, n, norm): + def test_basic(self, dtype, n, norm): x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) + a = numpy.sin(x) if numpy.issubdtype(dtype, numpy.complexfloating): - a_np = _make_array_Hermitian(a_np, n) - a = dpnp.array(a_np) + a = _make_array_Hermitian(a, n) + ia = dpnp.array(a) - result = dpnp.fft.irfft(a, n=n, norm=norm) - expected = numpy.fft.irfft(a_np, n=n, norm=norm) - # check_only_type_kind=True since Intel® NumPy always returns float64 + result = dpnp.fft.irfft(ia, n=n, norm=norm) + expected = numpy.fft.irfft(a, n=n, norm=norm) + # check_only_type_kind=True since NumPy always returns float64 # but dpnp return float32 if input is float32 assert_dtype_allclose(result, expected, check_only_type_kind=True) @@ -700,102 +639,98 @@ def test_irfft_1D(self, dtype, n, norm): @pytest.mark.parametrize("axis", [-1, 1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_irfft_1D_on_2D_array(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) - - result = dpnp.fft.irfft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.irfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + def test_2d_array(self, dtype, n, axis, norm, order): + # TODO: resolve gh-2377 and use the following line + # a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + a = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) + ia = dpnp.array(a) + + result = dpnp.fft.irfft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [0, 1, 2]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_irfft_1D_on_3D_array(self, dtype, n, axis, norm, order): - a_np = generate_random_numpy_array((4, 5, 6), dtype, order) + def test_3d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((4, 5, 6), dtype, order) # each 1-D array of input should be Hermitian if axis == 0: - a_np[0].imag = 0 + a[0].imag = 0 if n is None: # for axis=0 and n=8, Nyquist mode is not present f_ny = -1 # Nyquist mode - a_np[-1].imag = 0 + a[-1].imag = 0 elif axis == 1: - a_np[:, 0, :].imag = 0 + a[:, 0, :].imag = 0 if n in [None, 8]: f_ny = -1 # Nyquist mode - a_np[:, f_ny, :].imag = 0 - a_np[:, f_ny:, :] = 0 # no data needed after Nyquist mode + a[:, f_ny, :].imag = 0 + a[:, f_ny:, :] = 0 # no data needed after Nyquist mode elif axis == 2: - a_np[..., 0].imag = 0 + a[..., 0].imag = 0 if n in [None, 8]: f_ny = -1 if n is None else n // 2 # Nyquist mode - a_np[..., f_ny].imag = 0 - a_np[..., f_ny:] = 0 # no data needed after Nyquist mode + a[..., f_ny].imag = 0 + a[..., f_ny:] = 0 # no data needed after Nyquist mode - a = dpnp.asarray(a_np) + ia = dpnp.array(a) - result = dpnp.fft.irfft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.irfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose( - result, expected, check_only_type_kind=True, factor=16 - ) + result = dpnp.fft.irfft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected, factor=16) @pytest.mark.parametrize("n", [None, 5, 18]) - def test_irfft_usm_ndarray(self, n): - x = dpnp.linspace(-1, 1, 11) - a = dpnp.sin(x) + 1j * dpnp.cos(x) - a = _make_array_Hermitian(a, n) - a_usm = dpt.asarray(a, dtype=dpt.complex64) - a_np = dpt.asnumpy(a_usm) - out_shape = n if n is not None else 2 * (a_usm.shape[0] - 1) - out = dpt.empty(out_shape, dtype=a_usm.real.dtype) + def test_usm_ndarray(self, n): + x = dpt.linspace(-1, 1, 11) + x = dpt.sin(x) + 1j * dpt.cos(x) + a_usm = _make_array_Hermitian(x, n) + a = dpt.asnumpy(a_usm) + + expected = numpy.fft.irfft(a, n=n) + out = dpt.empty(expected.shape, dtype=a_usm.real.dtype) result = dpnp.fft.irfft(a_usm, n=n, out=out) assert out is result.get_array() - expected = numpy.fft.irfft(a_np, n=n) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_irfft_1D_out(self, dtype, n, norm): + def test_out(self, dtype, n, norm): x = dpnp.linspace(-1, 1, 11) - a = dpnp.sin(x) + 1j * dpnp.cos(x) - a = _make_array_Hermitian(a, n) - a = dpnp.asarray(a, dtype=dtype) - a_np = dpnp.asnumpy(a) + x = dpnp.sin(x) + 1j * dpnp.cos(x) + x = _make_array_Hermitian(x, n) + ia = dpnp.array(x, dtype=dtype) + a = dpnp.asnumpy(ia) - out_shape = n if n is not None else 2 * (a.shape[0] - 1) - out = dpnp.empty(out_shape, dtype=a.real.dtype) + expected = numpy.fft.irfft(a, n=n, norm=norm) + out = dpnp.empty(expected.shape, dtype=a.real.dtype) - result = dpnp.fft.irfft(a, n=n, norm=norm, out=out) + result = dpnp.fft.irfft(ia, n=n, norm=norm, out=out) assert out is result - expected = numpy.fft.irfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [-1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_irfft_1D_on_2D_array_out(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) - - out_shape = list(a.shape) - out_shape[axis] = 2 * (a.shape[axis] - 1) if n is None else n - out_shape = tuple(out_shape) - out = dpnp.empty(out_shape, dtype=a.real.dtype) - - result = dpnp.fft.irfft(a, n=n, axis=axis, norm=norm, out=out) + def test_2d_array_out(self, dtype, n, axis, norm, order): + # TODO: resolve gh-2377 and use the following line + # a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + a = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) + ia = dpnp.array(a) + + expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) + out = dpnp.empty(expected.shape, dtype=expected.dtype) + result = dpnp.fft.irfft(ia, n=n, axis=axis, norm=norm, out=out) assert out is result - expected = numpy.fft.irfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - def test_irfft_validate_out(self): + def test_validate_out(self): # Invalid dtype for c2r FFT a = dpnp.ones((10,), dtype=dpnp.complex64) out = dpnp.empty((18,), dtype=dpnp.complex64) @@ -803,131 +738,94 @@ def test_irfft_validate_out(self): class TestRfft: - def setup_method(self): - numpy.random.seed(42) - - @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) - ) - @pytest.mark.parametrize( - "shape", [(64,), (8, 8), (4, 16), (4, 4, 4), (2, 4, 4, 2)] - ) - def test_rfft(self, dtype, shape): - np_data = numpy.arange(64, dtype=dtype).reshape(shape) - dpnp_data = dpnp.arange(64, dtype=dtype).reshape(shape) - - np_res = numpy.fft.rfft(np_data) - dpnp_res = dpnp.fft.rfft(dpnp_data) - - assert_dtype_allclose(dpnp_res, np_res, check_only_type_kind=True) - @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + "dtype", get_all_dtypes(no_none=True, no_complex=True) ) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_rfft_1D(self, dtype, n, norm): - x = dpnp.linspace(-1, 1, 11, dtype=dtype) - a = dpnp.sin(x) - a_np = dpnp.asnumpy(a) + def test_basic(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype, low=-1, high=1) + ia = dpnp.array(a) - result = dpnp.fft.rfft(a, n=n, norm=norm) - expected = numpy.fft.rfft(a_np, n=n, norm=norm) + result = dpnp.fft.rfft(ia, n=n, norm=norm) + expected = numpy.fft.rfft(a, n=n, norm=norm) factor = 120 if dtype in [dpnp.int8, dpnp.uint8] else 8 - assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=True - ) - - @pytest.mark.parametrize("n", [None, 5, 20]) - @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_rfft_bool(self, n, norm): - a = dpnp.ones(11, dtype=dpnp.bool) - a_np = dpnp.asnumpy(a) - - result = dpnp.fft.rfft(a, n=n, norm=norm) - expected = numpy.fft.rfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected, factor=factor) @pytest.mark.parametrize("dtype", get_float_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [-1, 1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_rfft_1D_on_2D_array(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) + def test_2d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) - result = dpnp.fft.rfft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.rfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.rfft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_float_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [0, 1, 2]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_rfft_1D_on_3D_array(self, dtype, n, axis, norm, order): - a_np = numpy.arange(24, dtype=dtype).reshape(2, 3, 4, order=order) - a = dpnp.asarray(a_np) + def test_3d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((2, 3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) - result = dpnp.fft.rfft(a, n=n, axis=axis, norm=norm) - expected = numpy.fft.rfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfft(ia, n=n, axis=axis, norm=norm) + expected = numpy.fft.rfft(a, n=n, axis=axis, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("n", [None, 5, 20]) - def test_rfft_usm_ndarray(self, n): + def test_usm_ndarray(self, n): x = dpt.linspace(-1, 1, 11) - a_usm = dpt.asarray(dpt.sin(x)) - a_np = dpt.asnumpy(a_usm) - out_shape = a_usm.shape[0] // 2 + 1 if n is None else n // 2 + 1 - out_dtype = map_dtype_to_device(dpnp.complex128, a_usm.sycl_device) - out = dpt.empty(out_shape, dtype=out_dtype) + a_usm = dpt.sin(x) + a = dpt.asnumpy(a_usm) + + expected = numpy.fft.rfft(a, n=n) + out_dt = map_dtype_to_device(dpnp.complex128, a_usm.sycl_device) + out = dpt.empty(expected.shape, dtype=out_dt) result = dpnp.fft.rfft(a_usm, n=n, out=out) assert out is result.get_array() - expected = numpy.fft.rfft(a_np, n=n) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_float_dtypes()) @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) - def test_rfft_1D_out(self, dtype, n, norm): + def test_out(self, dtype, n, norm): x = dpnp.linspace(-1, 1, 11) - a = dpnp.sin(x) + 1j * dpnp.cos(x) - a = dpnp.asarray(a, dtype=dtype) - a_np = dpnp.asnumpy(a) + x = dpnp.sin(x) + 1j * dpnp.cos(x) + ia = dpnp.asarray(x, dtype=dtype) + a = dpnp.asnumpy(ia) - out_shape = a.shape[0] // 2 + 1 if n is None else n // 2 + 1 - out_dtype = dpnp.complex64 if dtype == dpnp.float32 else dpnp.complex128 - out = dpnp.empty(out_shape, dtype=out_dtype) + expected = numpy.fft.rfft(a, n=n, norm=norm) + out = dpnp.empty(expected.shape, dtype=expected.dtype) - result = dpnp.fft.rfft(a, n=n, norm=norm, out=out) + result = dpnp.fft.rfft(ia, n=n, norm=norm, out=out) assert out is result - expected = numpy.fft.rfft(a_np, n=n, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_float_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @pytest.mark.parametrize("axis", [-1, 0]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_rfft_1D_on_2D_array_out(self, dtype, n, axis, norm, order): - a_np = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) - a = dpnp.asarray(a_np) + def test_2d_array_out(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) + ia = dpnp.array(a) - out_shape = list(a.shape) - out_shape[axis] = a.shape[axis] // 2 + 1 if n is None else n // 2 + 1 - out_shape = tuple(out_shape) - out_dtype = dpnp.complex64 if dtype == dpnp.float32 else dpnp.complex128 - out = dpnp.empty(out_shape, dtype=out_dtype) + expected = numpy.fft.rfft(a, n=n, axis=axis, norm=norm) + out = dpnp.empty(expected.shape, dtype=expected.dtype) - result = dpnp.fft.rfft(a, n=n, axis=axis, norm=norm, out=out) + result = dpnp.fft.rfft(ia, n=n, axis=axis, norm=norm, out=out) assert out is result - expected = numpy.fft.rfft(a_np, n=n, axis=axis, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_rfft_error(self, xp): + def test_error(self, xp): a = xp.ones((4, 3), dtype=xp.complex64) # invalid dtype of input array for r2c FFT if xp == dpnp: @@ -935,7 +833,7 @@ def test_rfft_error(self, xp): # Intel® NumPy, dpnp, stock NumPy-2.0 raise TypeError assert_raises(TypeError, xp.fft.rfft, a) - def test_fft_validate_out(self): + def test_validate_out(self): # Invalid shape for r2c FFT a = dpnp.ones((10,), dtype=dpnp.float32) out = dpnp.empty((10,), dtype=dpnp.complex64) @@ -943,9 +841,6 @@ def test_fft_validate_out(self): class TestRfft2: - def setup_method(self): - numpy.random.seed(42) - # TODO: add other axes when mkl_fft gh-119 is addressed @pytest.mark.parametrize( "dtype", get_all_dtypes(no_none=True, no_complex=True) @@ -953,45 +848,45 @@ def setup_method(self): @pytest.mark.parametrize("axes", [(0, 1)]) # (1, 2),(0, 2),(2, 1),(2, 0) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_rfft2(self, dtype, axes, norm, order): - a_np = generate_random_numpy_array((2, 3, 4), dtype, order) - a = dpnp.asarray(a_np) + def test_basic(self, dtype, axes, norm, order): + a = generate_random_numpy_array((2, 3, 4), dtype, order) + ia = dpnp.array(a) - result = dpnp.fft.rfft2(a, axes=axes, norm=norm) - expected = numpy.fft.rfft2(a_np, axes=axes, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfft2(ia, axes=axes, norm=norm) + expected = numpy.fft.rfft2(a, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) s = (a.shape[axes[0]], a.shape[axes[1]]) result = dpnp.fft.irfft2(result, s=s, axes=axes, norm=norm) expected = numpy.fft.irfft2(expected, s=s, axes=axes, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) - def test_irfft2(self, dtype): + def test_inverse(self, dtype): # x is Hermitian symmetric x = numpy.array([[0, 1, 2], [5, 4, 6], [5, 7, 6]]) - a_np = numpy.array(x, dtype=dtype) - a = dpnp.asarray(a_np) + a = numpy.array(x, dtype=dtype) + ia = dpnp.array(a) - result = dpnp.fft.irfft2(a) - expected = numpy.fft.irfft2(a_np) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.irfft2(ia) + expected = numpy.fft.irfft2(a) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("s", [None, (3, 3), (10, 10), (3, 10)]) - def test_rfft2_s(self, s): - a_np = generate_random_numpy_array((6, 8)) - a = dpnp.array(a_np) + def test_s(self, s): + a = generate_random_numpy_array((6, 8)) + ia = dpnp.array(a) - result = dpnp.fft.rfft2(a, s=s) - expected = numpy.fft.rfft2(a_np, s=s) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfft2(ia, s=s) + expected = numpy.fft.rfft2(a, s=s) + assert_dtype_allclose(result, expected) result = dpnp.fft.irfft2(result, s=s) expected = numpy.fft.irfft2(expected, s=s) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_rfft2_error(self, xp): + def test_error(self, xp): a = xp.ones((2, 3)) # empty axes assert_raises(IndexError, xp.fft.rfft2, a, axes=()) @@ -1005,9 +900,6 @@ def test_rfft2_error(self, xp): class TestRfftn: - def setup_method(self): - numpy.random.seed(42) - # TODO: add additional axes when mkl_fft gh-119 is addressed @pytest.mark.parametrize( "dtype", get_all_dtypes(no_none=True, no_complex=True) @@ -1017,112 +909,102 @@ def setup_method(self): ) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) - def test_rfftn(self, dtype, axes, norm, order): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype, order) - a = dpnp.asarray(a_np) + def test_basic(self, dtype, axes, norm, order): + a = generate_random_numpy_array((2, 3, 4, 5), dtype, order) + ia = dpnp.array(a) - result = dpnp.fft.rfftn(a, axes=axes, norm=norm) - expected = numpy.fft.rfftn(a_np, axes=axes, norm=norm) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfftn(ia, axes=axes, norm=norm) + expected = numpy.fft.rfftn(a, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) + # inverse FFT s = [] for axis in axes: s.append(a.shape[axis]) - iresult = dpnp.fft.irfftn(result, s=s, axes=axes, norm=norm) - iexpected = numpy.fft.irfftn(expected, s=s, axes=axes, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + result = dpnp.fft.irfftn(result, s=s, axes=axes, norm=norm) + expected = numpy.fft.irfftn(expected, s=s, axes=axes, norm=norm) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize( "axes", [(2, 0, 2, 0), (0, 1, 1), (2, 0, 1, 3, 2, 1)] ) - def test_rfftn_repeated_axes(self, axes): - a_np = generate_random_numpy_array((2, 3, 4, 5)) - a = dpnp.array(a_np) + def test_repeated_axes(self, axes): + a = generate_random_numpy_array((2, 3, 4, 5)) + ia = dpnp.array(a) - result = dpnp.fft.rfftn(a, axes=axes) + result = dpnp.fft.rfftn(ia, axes=axes) # Intel® NumPy ignores repeated axes, handle it one by one - expected = numpy.fft.rfft(a_np, axis=axes[-1]) - # need to pass shape for c2c FFT since expected and a_np + expected = numpy.fft.rfft(a, axis=axes[-1]) + # need to pass shape for c2c FFT since expected and a # do not have the same shape after calling rfft shape = [] for axis in axes: - shape.append(a_np.shape[axis]) + shape.append(a.shape[axis]) for jj, ii in zip(shape[-2::-1], axes[-2::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.irfftn(result, axes=axes) - iexpected = expected + # inverse FFT + result = dpnp.fft.irfftn(result, axes=axes) for ii in axes[-2::-1]: - iexpected = numpy.fft.ifft(iexpected, axis=ii) - iexpected = numpy.fft.irfft(iexpected, axis=axes[-1]) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, axis=ii) + expected = numpy.fft.irfft(expected, axis=axes[-1]) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axes", [(2, 3, 3, 2), (0, 0, 3, 3)]) @pytest.mark.parametrize("s", [(5, 4, 3, 3), (7, 8, 10, 9)]) - def test_rfftn_repeated_axes_with_s(self, axes, s): - a_np = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.float32) - a = dpnp.asarray(a_np) + def test_repeated_axes_with_s(self, axes, s): + a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.float32) + ia = dpnp.array(a) - result = dpnp.fft.rfftn(a, s=s, axes=axes) + result = dpnp.fft.rfftn(ia, s=s, axes=axes) # Intel® NumPy ignores repeated axes, handle it one by one - expected = numpy.fft.rfft(a_np, n=s[-1], axis=axes[-1]) + expected = numpy.fft.rfft(a, n=s[-1], axis=axes[-1]) for jj, ii in zip(s[-2::-1], axes[-2::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + assert_dtype_allclose(result, expected) - iresult = dpnp.fft.irfftn(result, s=s, axes=axes) - iexpected = expected + result = dpnp.fft.irfftn(result, s=s, axes=axes) for jj, ii in zip(s[-2::-1], axes[-2::-1]): - iexpected = numpy.fft.ifft(iexpected, n=jj, axis=ii) - iexpected = numpy.fft.irfft(iexpected, n=s[-1], axis=axes[-1]) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, n=jj, axis=ii) + expected = numpy.fft.irfft(expected, n=s[-1], axis=axes[-1]) + assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axes", [(0, 1, 2, 3), (1, 2, 1, 2), (2, 2, 2, 3)]) @pytest.mark.parametrize("s", [(2, 3, 4, 5), (5, 6, 7, 9), (2, 5, 1, 2)]) - def test_rfftn_out(self, axes, s): - x = numpy.random.uniform(-10, 10, 120) - a_np = numpy.array(x, dtype=numpy.float32).reshape(2, 3, 4, 5) - a = dpnp.asarray(a_np) - - out_shape = list(a.shape) - out_shape[axes[-1]] = s[-1] // 2 + 1 - for s_i, axis in zip(s[-2::-1], axes[-2::-1]): - out_shape[axis] = s_i - out = dpnp.empty(out_shape, dtype=numpy.complex64) - - result = dpnp.fft.rfftn(a, out=out, s=s, axes=axes) - assert out is result + def test_out(self, axes, s): + a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.float32) + ia = dpnp.array(a) + # Intel® NumPy ignores repeated axes, handle it one by one - expected = numpy.fft.rfft(a_np, n=s[-1], axis=axes[-1]) + expected = numpy.fft.rfft(a, n=s[-1], axis=axes[-1]) for jj, ii in zip(s[-2::-1], axes[-2::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) - assert_dtype_allclose(result, expected, check_only_type_kind=True) - - out_shape = list(a.shape) - for s_i, axis in zip(s[-2::-1], axes[-2::-1]): - out_shape[axis] = s_i - out_shape[axes[-1]] = s[-1] - out = dpnp.empty(out_shape, dtype=numpy.float32) + out = dpnp.empty(expected.shape, dtype=numpy.complex64) - iresult = dpnp.fft.irfftn(result, out=out, s=s, axes=axes) - assert out is iresult + result = dpnp.fft.rfftn(ia, out=out, s=s, axes=axes) + assert out is result + assert_dtype_allclose(result, expected) - iexpected = expected + # inverse FFT for jj, ii in zip(s[-2::-1], axes[-2::-1]): - iexpected = numpy.fft.ifft(iexpected, n=jj, axis=ii) - iexpected = numpy.fft.irfft(iexpected, n=s[-1], axis=axes[-1]) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + expected = numpy.fft.ifft(expected, n=jj, axis=ii) + expected = numpy.fft.irfft(expected, n=s[-1], axis=axes[-1]) + out = dpnp.empty(expected.shape, dtype=numpy.float32) - def test_rfftn_1d_array(self): - x = numpy.random.uniform(-10, 10, 20) - a_np = numpy.array(x, dtype=numpy.float32) - a = dpnp.asarray(a_np) + result = dpnp.fft.irfftn(result, out=out, s=s, axes=axes) + assert out is result + assert_dtype_allclose(result, expected) - result = dpnp.fft.rfftn(a) - expected = numpy.fft.rfftn(a_np) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + def test_1d_array(self): + a = generate_random_numpy_array(20, dtype=numpy.float32) + ia = dpnp.array(a) + + result = dpnp.fft.rfftn(ia) + expected = numpy.fft.rfftn(a) + assert_dtype_allclose(result, expected) - result = dpnp.fft.irfftn(a) - expected = numpy.fft.irfftn(a_np) + result = dpnp.fft.irfftn(ia) + expected = numpy.fft.irfftn(a) + # check_only_type_kind=True since Intel NumPy returns float64 assert_dtype_allclose(result, expected, check_only_type_kind=True) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 07533f159d76..3e02985a82eb 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2315,11 +2315,10 @@ def test_matrix_norm(self, ord, keepdims): ) @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) @pytest.mark.parametrize( - "shape_axis", [[(2, 0), None], [(2, 0), (0, 1)], [(0, 2), (0, 1)]] + "shape, axis", [[(2, 0), None], [(2, 0), (0, 1)], [(0, 2), (0, 1)]] ) @pytest.mark.parametrize("ord", [None, "fro", "nuc", 1, 2, dpnp.inf]) - def test_matrix_norm_empty(self, xp, dtype, shape_axis, ord): - shape, axis = shape_axis[0], shape_axis[1] + def test_matrix_norm_empty(self, xp, dtype, shape, axis, ord): x = xp.zeros(shape, dtype=dtype) assert_equal(xp.linalg.norm(x, axis=axis, ord=ord), 0) From 1aea3c4514b58ffea664b05ebc8a131cc64d6380 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 28 Mar 2025 11:05:34 -0700 Subject: [PATCH 2/4] address comments --- dpnp/tests/test_fft.py | 221 ++++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 122 deletions(-) diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 945e3e760660..0aa24f752d0d 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -14,23 +14,33 @@ get_all_dtypes, get_complex_dtypes, get_float_dtypes, + numpy_version, ) +from .third_party.cupy import testing def _make_array_Hermitian(a, n): """ - This function makes necessary changes of the input array of - `dpnp.fft.irfft` and `dpnp.fft.hfft` functions to make sure the - given array is Hermitian. - + For `dpnp.fft.irfft` and `dpnp.fft.hfft`, the input array should be Hermitian. + If it is not, the behavior is undefined. This function makes necessary changes + to make sure the given array is Hermitian. """ a[0] = a[0].real - if n in [None, 18]: - # f_ny is Nyquist mode (n//2+1 mode) which is n//2 element - f_ny = -1 if n is None else n // 2 - a[f_ny] = a[f_ny].real - a[f_ny:] = 0 # no data needed after Nyquist mode + if n is None: + # last element is Nyquist mode + a[-1] = a[-1].real + elif n % 2 == 0: + # Nyquist mode (n//2+1 mode) is n//2-th element + f_ny = n // 2 + if a.shape[0] > f_ny: + a[f_ny] = a[f_ny].real + a[f_ny + 1 :] = 0 # no data needed after Nyquist mode + else: + # No Nyquist mode + f_ny = n // 2 + if a.shape[0] > f_ny: + a[f_ny + 1 :] = 0 # no data needed for the second half return a @@ -40,26 +50,18 @@ class TestFft: @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_basic(self, dtype, n, norm): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a = numpy.sin(x) # a.dtype is float16 if x.dtype is bool + a = generate_random_numpy_array(11, dtype) ia = dpnp.array(a) - factor = 140 if dtype == dpnp.bool else 8 result = dpnp.fft.fft(ia, n=n, norm=norm) expected = numpy.fft.fft(a, n=n, norm=norm) - # flag is needed for Intel NumPy 1.26.4 since it returns complex128 - dt_list = [dpnp.bool, dpnp.int8, dpnp.uint8] - flag = True if dtype in dt_list else False - assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=flag - ) + flag = True if numpy_version() < "2.0.0" else False + assert_dtype_allclose(result, expected, check_only_type_kind=flag) # inverse FFT result = dpnp.fft.ifft(result, n=n, norm=norm) expected = numpy.fft.ifft(expected, n=n, norm=norm) - assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=flag - ) + assert_dtype_allclose(result, expected, check_only_type_kind=flag) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @@ -99,13 +101,11 @@ def test_3d_array(self, dtype, n, axis, norm, order): @pytest.mark.parametrize("n", [None, 5, 20]) def test_usm_ndarray(self, n): - x = dpt.linspace(-1, 1, 11) - a_usm = dpt.sin(x) + 1j * dpt.cos(x) - a = dpt.asnumpy(a_usm) + a = generate_random_numpy_array(11, dtype=numpy.complex64) + a_usm = dpt.asarray(a) expected = numpy.fft.fft(a, n=n) out = dpt.empty(expected.shape, dtype=a_usm.dtype) - result = dpnp.fft.fft(a_usm, n=n, out=out) assert out is result.get_array() assert_dtype_allclose(result, expected) @@ -120,14 +120,12 @@ def test_usm_ndarray(self, n): @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_out(self, dtype, n, norm): - x = dpnp.linspace(-1, 1, 11) - x = dpnp.sin(x) + 1j * dpnp.cos(x) - ia = dpnp.asarray(x, dtype=dtype) - a = dpnp.asnumpy(ia) + a = generate_random_numpy_array(11, dtype=dtype) + ia = dpnp.array(a) + # FFT expected = numpy.fft.fft(a, n=n, norm=norm) out = dpnp.empty(expected.shape, dtype=a.dtype) - result = dpnp.fft.fft(ia, n=n, norm=norm, out=out) assert out is result assert_dtype_allclose(result, expected) @@ -279,7 +277,7 @@ def test_empty_array(self): def test_error(self, xp): # 0-D input a = xp.array(3) - # dpnp and Intel® NumPy raise ValueError + # dpnp and Intel NumPy raise ValueError # stock NumPy raises IndexError assert_raises((ValueError, IndexError), xp.fft.fft, a) @@ -287,7 +285,7 @@ def test_error(self, xp): a = xp.ones((4, 3)) if xp == dpnp: # dpnp and stock NumPy raise TypeError - # Intel® NumPy raises SystemError for Python 3.10 and 3.11 + # Intel NumPy raises SystemError for Python 3.10 and 3.11 # and no error for Python 3.9 assert_raises(TypeError, xp.fft.fft, a, n=5.0) @@ -317,14 +315,14 @@ def test_validate_out(self): out = dpnp.empty((10,), dtype=dpnp.float32) assert_raises(TypeError, dpnp.fft.fft, a, out=out) - @pytest.mark.parametrize( - "dtype", get_all_dtypes(no_none=True, no_bool=True) - ) - def test_negative_stride(self, dtype): - ia = dpnp.arange(10, dtype=dtype) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) + @pytest.mark.parametrize("stride", [2, 3, -1, -3]) + def test_strided(self, dtype, stride): + a = generate_random_numpy_array(20, dtype=dtype) + ia = dpnp.array(a) - result = dpnp.fft.fft(ia[::-1]) - expected = numpy.fft.fft(ia.asnumpy()[::-1]) + result = dpnp.fft.fft(ia[::stride]) + expected = numpy.fft.fft(a[::stride]) assert_dtype_allclose(result, expected) @@ -426,7 +424,7 @@ def test_repeated_axes(self, axes): ia = dpnp.array(a) result = dpnp.fft.fftn(ia, axes=axes) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = a for ii in axes: expected = numpy.fft.fft(expected, axis=ii) @@ -445,7 +443,7 @@ def test_repeated_axes_with_s(self, axes, s): ia = dpnp.array(a) result = dpnp.fft.fftn(ia, s=s, axes=axes) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = a for jj, ii in zip(s[::-1], axes[::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) @@ -463,7 +461,7 @@ def test_out(self, axes, s): a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.complex64) ia = dpnp.array(a) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = a for jj, ii in zip(s[::-1], axes[::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) @@ -509,21 +507,21 @@ def test_0D(self, dtype): # axes is None # For 0-D array, stock Numpy and dpnp return input array - # while Intel® NumPy return a complex zero + # while Intel NumPy return a complex zero result = dpnp.fft.fftn(a) expected = a.asnumpy() assert_dtype_allclose(result, expected) # axes=() # For 0-D array with axes=(), stock Numpy and dpnp return input array - # Intel® NumPy does not support empty axes and raises an Error + # Intel NumPy does not support empty axes and raises an Error result = dpnp.fft.fftn(a, axes=()) expected = a.asnumpy() assert_dtype_allclose(result, expected) # axes=(0,) # For 0-D array with non-empty axes, stock Numpy and dpnp raise - # IndexError, while Intel® NumPy raises ZeroDivisionError + # IndexError, while Intel NumPy raises ZeroDivisionError assert_raises(IndexError, dpnp.fft.fftn, a, axes=(0,)) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @@ -531,7 +529,7 @@ def test_empty_axes(self, dtype): a = dpnp.ones((2, 3, 4), dtype=dtype) # For axes=(), stock Numpy and dpnp return input array - # Intel® NumPy does not support empty axes and raises an Error + # Intel NumPy does not support empty axes and raises an Error result = dpnp.fft.fftn(a, axes=()) expected = a.asnumpy() assert_dtype_allclose(result, expected) @@ -541,7 +539,7 @@ def test_error(self, xp): # s is not int a = xp.ones((4, 3)) # dpnp and stock NumPy raise TypeError - # Intel® NumPy raises ValueError + # Intel NumPy raises ValueError assert_raises( (TypeError, ValueError), xp.fft.fftn, a, s=(5.0,), axes=(0,) ) @@ -555,7 +553,7 @@ def test_error(self, xp): # axes should be given if s is not None # dpnp raises ValueError # stock NumPy will raise an Error in future versions - # Intel® NumPy raises TypeError for a different reason: + # Intel NumPy raises TypeError for a different reason: # when given, axes and shape arguments have to be of the same length if xp == dpnp: assert_raises(ValueError, xp.fft.fftn, a, s=(5,)) @@ -566,10 +564,11 @@ def test_error(self, xp): class TestFftshift: @pytest.mark.parametrize("func", ["fftshift", "ifftshift"]) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize("axes", [None, 1, (0, 1)]) - def test_basic(self, func, axes): - ia = dpnp.arange(12).reshape(3, 4) - a = ia.asnumpy() + def test_basic(self, func, dtype, axes): + a = generate_random_numpy_array((3, 4), dtype=dtype) + ia = dpnp.array(a) expected = getattr(dpnp.fft, func)(ia, axes=axes) result = getattr(numpy.fft, func)(a, axes=axes) @@ -581,8 +580,7 @@ class TestHfft: @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_basic(self, dtype, n, norm): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a = numpy.sin(x) + a = generate_random_numpy_array(11, dtype) if numpy.issubdtype(dtype, numpy.complexfloating): a = _make_array_Hermitian(a, n) ia = dpnp.array(a) @@ -599,22 +597,21 @@ def test_basic(self, dtype, n, norm): @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_inverse(self, dtype, n, norm): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a = numpy.sin(x) # a.dtype is float16 if x.dtype is bool + a = generate_random_numpy_array(11, dtype) ia = dpnp.array(a) - factor = 140 if dtype == dpnp.bool else 8 result = dpnp.fft.ihfft(ia, n=n, norm=norm) expected = numpy.fft.ihfft(a, n=n, norm=norm) - # check_only_type_kind=True since Intel NumPy always returns complex128 - assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=True - ) + flag = True if numpy_version() < "2.0.0" else False + assert_dtype_allclose(result, expected, check_only_type_kind=True) - def test_error(self): - a = dpnp.ones(11) - # incorrect norm - assert_raises(ValueError, dpnp.fft.ihfft, a, norm="backwards") + @pytest.mark.parametrize("dtype", get_complex_dtypes()) + def test_error(self, dtype): + a = generate_random_numpy_array(11, dtype) + ia = dpnp.array(a) + + assert_raises(TypeError, dpnp.fft.ihfft, ia) + assert_raises(TypeError, numpy.fft.ihfft, a) class TestIrfft: @@ -622,8 +619,7 @@ class TestIrfft: @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_basic(self, dtype, n, norm): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a = numpy.sin(x) + a = generate_random_numpy_array(11) if numpy.issubdtype(dtype, numpy.complexfloating): a = _make_array_Hermitian(a, n) ia = dpnp.array(a) @@ -640,10 +636,12 @@ def test_basic(self, dtype, n, norm): @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) def test_2d_array(self, dtype, n, axis, norm, order): - # TODO: resolve gh-2377 and use the following line - # a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) - a = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) ia = dpnp.array(a) + # For dpnp, each 1-D array of input should be Hermitian + ia = dpnp.moveaxis(ia, axis, 0) + ia = _make_array_Hermitian(ia, n) + ia = dpnp.moveaxis(ia, 0, axis) result = dpnp.fft.irfft(ia, n=n, axis=axis, norm=norm) expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) @@ -656,42 +654,24 @@ def test_2d_array(self, dtype, n, axis, norm, order): @pytest.mark.parametrize("order", ["C", "F"]) def test_3d_array(self, dtype, n, axis, norm, order): a = generate_random_numpy_array((4, 5, 6), dtype, order) - # each 1-D array of input should be Hermitian - if axis == 0: - a[0].imag = 0 - if n is None: - # for axis=0 and n=8, Nyquist mode is not present - f_ny = -1 # Nyquist mode - a[-1].imag = 0 - elif axis == 1: - a[:, 0, :].imag = 0 - if n in [None, 8]: - f_ny = -1 # Nyquist mode - a[:, f_ny, :].imag = 0 - a[:, f_ny:, :] = 0 # no data needed after Nyquist mode - elif axis == 2: - a[..., 0].imag = 0 - if n in [None, 8]: - f_ny = -1 if n is None else n // 2 # Nyquist mode - a[..., f_ny].imag = 0 - a[..., f_ny:] = 0 # no data needed after Nyquist mode - ia = dpnp.array(a) + # For dpnp, each 1-D array of input should be Hermitian + ia = dpnp.moveaxis(ia, axis, 0) + ia = _make_array_Hermitian(ia, n) + ia = dpnp.moveaxis(ia, 0, axis) result = dpnp.fft.irfft(ia, n=n, axis=axis, norm=norm) expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) assert_dtype_allclose(result, expected, factor=16) - @pytest.mark.parametrize("n", [None, 5, 18]) + @pytest.mark.parametrize("n", [None, 5, 17, 18]) def test_usm_ndarray(self, n): - x = dpt.linspace(-1, 1, 11) - x = dpt.sin(x) + 1j * dpt.cos(x) - a_usm = _make_array_Hermitian(x, n) - a = dpt.asnumpy(a_usm) + a = generate_random_numpy_array(11, dtype=numpy.complex64) + a_usm = dpt.asarray(a) + a_usm = _make_array_Hermitian(a_usm, n) expected = numpy.fft.irfft(a, n=n) out = dpt.empty(expected.shape, dtype=a_usm.real.dtype) - result = dpnp.fft.irfft(a_usm, n=n, out=out) assert out is result.get_array() assert_dtype_allclose(result, expected) @@ -700,18 +680,15 @@ def test_usm_ndarray(self, n): @pytest.mark.parametrize("n", [None, 5, 18]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_out(self, dtype, n, norm): - x = dpnp.linspace(-1, 1, 11) - x = dpnp.sin(x) + 1j * dpnp.cos(x) - x = _make_array_Hermitian(x, n) - ia = dpnp.array(x, dtype=dtype) - a = dpnp.asnumpy(ia) + a = generate_random_numpy_array(11, dtype=dtype) + ia = dpnp.array(a) + ia = _make_array_Hermitian(ia, n) expected = numpy.fft.irfft(a, n=n, norm=norm) out = dpnp.empty(expected.shape, dtype=a.real.dtype) - result = dpnp.fft.irfft(ia, n=n, norm=norm, out=out) assert out is result - assert_dtype_allclose(result, expected) + assert_dtype_allclose(result, expected, factor=24) @pytest.mark.parametrize("dtype", get_complex_dtypes()) @pytest.mark.parametrize("n", [None, 5, 8]) @@ -719,10 +696,11 @@ def test_out(self, dtype, n, norm): @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) @pytest.mark.parametrize("order", ["C", "F"]) def test_2d_array_out(self, dtype, n, axis, norm, order): - # TODO: resolve gh-2377 and use the following line - # a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) - a = numpy.arange(12, dtype=dtype).reshape(3, 4, order=order) + a = generate_random_numpy_array((3, 4), dtype=dtype, order=order) ia = dpnp.array(a) + ia = dpnp.moveaxis(ia, axis, 0) + ia = _make_array_Hermitian(ia, n) + ia = dpnp.moveaxis(ia, 0, axis) expected = numpy.fft.irfft(a, n=n, axis=axis, norm=norm) out = dpnp.empty(expected.shape, dtype=expected.dtype) @@ -736,6 +714,11 @@ def test_validate_out(self): out = dpnp.empty((18,), dtype=dpnp.complex64) assert_raises(TypeError, dpnp.fft.irfft, a, out=out) + def test_error(self): + a = dpnp.ones(11) + # incorrect norm + assert_raises(ValueError, dpnp.fft.hfft, a, norm="backwards") + class TestRfft: @pytest.mark.parametrize( @@ -780,9 +763,8 @@ def test_3d_array(self, dtype, n, axis, norm, order): @pytest.mark.parametrize("n", [None, 5, 20]) def test_usm_ndarray(self, n): - x = dpt.linspace(-1, 1, 11) - a_usm = dpt.sin(x) - a = dpt.asnumpy(a_usm) + a = generate_random_numpy_array(11) + a_usm = dpt.asarray(a) expected = numpy.fft.rfft(a, n=n) out_dt = map_dtype_to_device(dpnp.complex128, a_usm.sycl_device) @@ -796,14 +778,11 @@ def test_usm_ndarray(self, n): @pytest.mark.parametrize("n", [None, 5, 20]) @pytest.mark.parametrize("norm", [None, "backward", "forward", "ortho"]) def test_out(self, dtype, n, norm): - x = dpnp.linspace(-1, 1, 11) - x = dpnp.sin(x) + 1j * dpnp.cos(x) - ia = dpnp.asarray(x, dtype=dtype) - a = dpnp.asnumpy(ia) + a = generate_random_numpy_array(11, dtype=dtype) + ia = dpnp.array(a) expected = numpy.fft.rfft(a, n=n, norm=norm) out = dpnp.empty(expected.shape, dtype=expected.dtype) - result = dpnp.fft.rfft(ia, n=n, norm=norm, out=out) assert out is result assert_dtype_allclose(result, expected) @@ -824,14 +803,12 @@ def test_2d_array_out(self, dtype, n, axis, norm, order): assert out is result assert_dtype_allclose(result, expected) + @testing.with_requires("numpy>=2.0.0") @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_error(self, xp): a = xp.ones((4, 3), dtype=xp.complex64) # invalid dtype of input array for r2c FFT - if xp == dpnp: - # stock NumPy-1.26 ignores imaginary part - # Intel® NumPy, dpnp, stock NumPy-2.0 raise TypeError - assert_raises(TypeError, xp.fft.rfft, a) + assert_raises(TypeError, xp.fft.rfft, a) def test_validate_out(self): # Invalid shape for r2c FFT @@ -933,7 +910,7 @@ def test_repeated_axes(self, axes): ia = dpnp.array(a) result = dpnp.fft.rfftn(ia, axes=axes) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = numpy.fft.rfft(a, axis=axes[-1]) # need to pass shape for c2c FFT since expected and a # do not have the same shape after calling rfft @@ -958,7 +935,7 @@ def test_repeated_axes_with_s(self, axes, s): ia = dpnp.array(a) result = dpnp.fft.rfftn(ia, s=s, axes=axes) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = numpy.fft.rfft(a, n=s[-1], axis=axes[-1]) for jj, ii in zip(s[-2::-1], axes[-2::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) @@ -976,7 +953,7 @@ def test_out(self, axes, s): a = generate_random_numpy_array((2, 3, 4, 5), dtype=numpy.float32) ia = dpnp.array(a) - # Intel® NumPy ignores repeated axes, handle it one by one + # Intel NumPy ignores repeated axes (mkl_fft-gh-104), handle it one by one expected = numpy.fft.rfft(a, n=s[-1], axis=axes[-1]) for jj, ii in zip(s[-2::-1], axes[-2::-1]): expected = numpy.fft.fft(expected, n=jj, axis=ii) @@ -1006,5 +983,5 @@ def test_1d_array(self): result = dpnp.fft.irfftn(ia) expected = numpy.fft.irfftn(a) - # check_only_type_kind=True since Intel NumPy returns float64 - assert_dtype_allclose(result, expected, check_only_type_kind=True) + flag = True if numpy_version() < "2.0.0" else False + assert_dtype_allclose(result, expected, check_only_type_kind=flag) From c61f25b3fd9899266edfb179fa01ce4e89193b92 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 31 Mar 2025 08:18:43 -0700 Subject: [PATCH 3/4] move a test to its appropriate class --- dpnp/tests/test_fft.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 0aa24f752d0d..c826dec379b4 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -605,11 +605,15 @@ def test_inverse(self, dtype, n, norm): flag = True if numpy_version() < "2.0.0" else False assert_dtype_allclose(result, expected, check_only_type_kind=True) + def test_error(self): + a = dpnp.ones(11) + # incorrect norm + assert_raises(ValueError, dpnp.fft.hfft, a, norm="backwards") + @pytest.mark.parametrize("dtype", get_complex_dtypes()) def test_error(self, dtype): a = generate_random_numpy_array(11, dtype) ia = dpnp.array(a) - assert_raises(TypeError, dpnp.fft.ihfft, ia) assert_raises(TypeError, numpy.fft.ihfft, a) @@ -714,11 +718,6 @@ def test_validate_out(self): out = dpnp.empty((18,), dtype=dpnp.complex64) assert_raises(TypeError, dpnp.fft.irfft, a, out=out) - def test_error(self): - a = dpnp.ones(11) - # incorrect norm - assert_raises(ValueError, dpnp.fft.hfft, a, norm="backwards") - class TestRfft: @pytest.mark.parametrize( From d73cdbaf9a022dbd0cf9a47fbd79c913d9062089 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 31 Mar 2025 09:13:22 -0700 Subject: [PATCH 4/4] fix a test --- dpnp/tests/test_fft.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 4a684a9ae3d5..624fc60ded1b 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -611,8 +611,9 @@ def test_error(self): # incorrect norm assert_raises(ValueError, dpnp.fft.hfft, a, norm="backwards") + @testing.with_requires("numpy>=2.0.0") @pytest.mark.parametrize("dtype", get_complex_dtypes()) - def test_error(self, dtype): + def test_complex_error(self, dtype): a = generate_random_numpy_array(11, dtype) ia = dpnp.array(a) assert_raises(TypeError, dpnp.fft.ihfft, ia)