diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index 7d822834b67d..624fc60ded1b 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -15,172 +15,133 @@ get_complex_dtypes, get_float_dtypes, has_support_aspect16, + 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 -# 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): - 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) - - 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) - assert_dtype_allclose( - result, expected, factor=factor, check_only_type_kind=True - ) - - iresult = dpnp.fft.ifft(result, n=n, norm=norm) - iexpected = numpy.fft.ifft(expected, n=n, norm=norm) - assert_dtype_allclose( - iresult, iexpected, factor=factor, check_only_type_kind=True - ) - - @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) + def test_basic(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype) + ia = dpnp.array(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) + result = dpnp.fft.fft(ia, n=n, norm=norm) + expected = numpy.fft.fft(a, n=n, norm=norm) + flag = True if numpy_version() < "2.0.0" else False + assert_dtype_allclose(result, expected, check_only_type_kind=flag) - iresult = dpnp.fft.ifft(result, norm=norm) - iexpected = numpy.fft.ifft(expected, norm=norm) - assert_dtype_allclose(iresult, iexpected, check_only_type_kind=True) + # 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, check_only_type_kind=flag) @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): - 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) + def test_usm_ndarray(self, n): + 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() - 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): - 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) - - result = dpnp.fft.fft(a, n=n, norm=norm, out=out) + def test_out(self, dtype, n, norm): + 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 - 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) @@ -259,71 +220,65 @@ 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 + # dpnp and Intel NumPy raise ValueError # stock NumPy raises IndexError assert_raises((ValueError, IndexError), xp.fft.fft, a) @@ -331,7 +286,7 @@ def test_fft_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) @@ -345,7 +300,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()) @@ -361,52 +316,51 @@ def test_fft_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): - a = dpnp.arange(10, dtype=dtype) - result = dpnp.fft.fft(a[::-1]) - expected = numpy.fft.fft(a.asnumpy()[::-1]) + @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) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.fft(ia[::stride]) + expected = numpy.fft.fft(a[::stride]) + 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) @@ -416,7 +370,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) @@ -444,155 +398,149 @@ 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) - # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + result = dpnp.fft.fftn(ia, axes=axes) + # 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) - 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) - # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + result = dpnp.fft.fftn(ia, s=s, axes=axes) + # 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) - 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 - # Intel® NumPy ignores repeated axes, handle it one by one - expected = a_np + 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 (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) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + out = dpnp.empty(expected.shape, dtype=a.dtype) + + result = dpnp.fft.fftn(ia, out=out, s=s, axes=axes) + assert out is result + assert_dtype_allclose(result, expected) - 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 + # 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 # 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)) - 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 - # 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) @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 - # Intel® NumPy raises ValueError + # Intel NumPy raises ValueError assert_raises( (TypeError, ValueError), xp.fft.fftn, a, s=(5.0,), axes=(0,) ) @@ -606,7 +554,7 @@ def test_fft_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,)) @@ -617,82 +565,74 @@ def test_fft_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_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, 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) 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): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) + def test_basic(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype) 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): - 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) - - @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) + def test_inverse(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype) + ia = dpnp.array(a) - result = dpnp.fft.ihfft(a, n=n, norm=norm) - expected = numpy.fft.ihfft(a_np, n=n, norm=norm) + result = dpnp.fft.ihfft(ia, n=n, norm=norm) + expected = numpy.fft.ihfft(a, n=n, norm=norm) + flag = True if numpy_version() < "2.0.0" else False assert_dtype_allclose(result, expected, 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") + 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_complex_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: - def setup_method(self): - numpy.random.seed(42) +class TestIrfft: @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): - x = generate_random_numpy_array(11, dtype, low=-1, high=1) - a_np = numpy.sin(x) + def test_basic(self, dtype, n, norm): + a = generate_random_numpy_array(11) 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) @@ -701,102 +641,80 @@ 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) + 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) + # 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(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) + 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) - # each 1-D array of input should be Hermitian - if axis == 0: - a_np[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 - elif axis == 1: - a_np[:, 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 - elif axis == 2: - a_np[..., 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 = 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, 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_3d_array(self, dtype, n, axis, norm, order): + a = generate_random_numpy_array((4, 5, 6), dtype, 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) + assert_dtype_allclose(result, expected, factor=16) + + @pytest.mark.parametrize("n", [None, 5, 17, 18]) + def test_usm_ndarray(self, n): + 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() - 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): - 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) - - out_shape = n if n is not None else 2 * (a.shape[0] - 1) - out = dpnp.empty(out_shape, dtype=a.real.dtype) + def test_out(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype=dtype) + ia = dpnp.array(a) + ia = _make_array_Hermitian(ia, n) - result = dpnp.fft.irfft(a, n=n, norm=norm, out=out) + 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 - 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, factor=24) @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) + 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) + ia = dpnp.moveaxis(ia, axis, 0) + ia = _make_array_Hermitian(ia, n) + ia = dpnp.moveaxis(ia, 0, axis) - result = dpnp.fft.irfft(a, n=n, axis=axis, norm=norm, out=out) + 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) @@ -804,128 +722,87 @@ 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): - 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) + def test_usm_ndarray(self, n): + 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) + 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): - 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 = 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) + def test_out(self, dtype, n, norm): + a = generate_random_numpy_array(11, dtype=dtype) + ia = dpnp.array(a) - result = dpnp.fft.rfft(a, n=n, norm=norm, out=out) + 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 - 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.skipif(not has_support_aspect16(), reason="no fp16 support") def test_float16(self): @@ -937,16 +814,14 @@ def test_float16(self): # check_only_type_kind=True since Intel NumPy returns complex128 assert_dtype_allclose(result, expected, check_only_type_kind=True) + @testing.with_requires("numpy>=2.0.0") @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: - # 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_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) @@ -954,9 +829,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) @@ -964,45 +836,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=()) @@ -1016,9 +888,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) @@ -1028,112 +897,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) - - result = dpnp.fft.rfftn(a, 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 + def test_repeated_axes(self, axes): + a = generate_random_numpy_array((2, 3, 4, 5)) + ia = dpnp.array(a) + + result = dpnp.fft.rfftn(ia, axes=axes) + # 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 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) - # Intel® NumPy ignores repeated axes, handle it one by one - expected = numpy.fft.rfft(a_np, n=s[-1], axis=axes[-1]) + result = dpnp.fft.rfftn(ia, s=s, axes=axes) + # 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) - 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 - # Intel® NumPy ignores repeated axes, handle it one by one - expected = numpy.fft.rfft(a_np, n=s[-1], axis=axes[-1]) + 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 (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) - 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.irfftn(a) - expected = numpy.fft.irfftn(a_np) - assert_dtype_allclose(result, expected, check_only_type_kind=True) + result = dpnp.fft.rfftn(ia) + expected = numpy.fft.rfftn(a) + assert_dtype_allclose(result, expected) + + result = dpnp.fft.irfftn(ia) + expected = numpy.fft.irfftn(a) + flag = True if numpy_version() < "2.0.0" else False + assert_dtype_allclose(result, expected, check_only_type_kind=flag) 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)