From 149c8c9fe59ca483ca4dc3f395f86cbf6c01c71f Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 16 Aug 2023 16:04:52 +0200 Subject: [PATCH 1/9] Impove dpnp_fft impl for Iris Xe --- dpnp/backend/kernels/dpnp_krnl_fft.cpp | 22 +++++++++++++++------- dpnp/fft/dpnp_algo_fft.pyx | 9 +++++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/dpnp/backend/kernels/dpnp_krnl_fft.cpp b/dpnp/backend/kernels/dpnp_krnl_fft.cpp index 25787a7331fd..69c7bcc1188f 100644 --- a/dpnp/backend/kernels/dpnp_krnl_fft.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_fft.cpp @@ -476,8 +476,12 @@ DPCTLSyclEventRef dpnp_fft_fft_c(DPCTLSyclQueueRef q_ref, else if constexpr (std::is_same<_DataType_input, int32_t>::value || std::is_same<_DataType_input, int64_t>::value) { - double *array1_copy = reinterpret_cast( - dpnp_memory_alloc_c(q_ref, input_size * sizeof(double))); + using CastType = std::conditional_t< + std::is_same<_DataType_output, std::complex>::value, + double, float>; + + CastType *array1_copy = reinterpret_cast( + dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); shape_elem_type *copy_strides = reinterpret_cast( dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); @@ -486,15 +490,17 @@ DPCTLSyclEventRef dpnp_fft_fft_c(DPCTLSyclQueueRef q_ref, dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); *copy_shape = input_size; shape_elem_type copy_shape_size = 1; - event_ref = dpnp_copyto_c<_DataType_input, double>( + event_ref = dpnp_copyto_c<_DataType_input, CastType>( q_ref, array1_copy, input_size, copy_shape_size, copy_shape, copy_strides, array1_in, input_size, copy_shape_size, copy_shape, copy_strides, NULL, dep_event_vec_ref); DPCTLEvent_WaitAndThrow(event_ref); DPCTLEvent_Delete(event_ref); - event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c( + event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c< + CastType, CastType, + std::conditional_t::value, + desc_dp_real_t, desc_sp_real_t>>( q_ref, array1_copy, result_out, input_shape, result_shape, shape_size, input_size, result_size, inverse, norm, 0); @@ -721,9 +727,11 @@ void func_map_init_fft_func(func_map_t &fmap) dpnp_fft_fft_default_c, std::complex>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_INT][eft_INT] = { - eft_C128, (void *)dpnp_fft_fft_ext_c>}; + eft_C128, (void *)dpnp_fft_fft_ext_c>, + eft_C64, (void *)dpnp_fft_fft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_LNG][eft_LNG] = { - eft_C128, (void *)dpnp_fft_fft_ext_c>}; + eft_C128, (void *)dpnp_fft_fft_ext_c>, + eft_C64, (void *)dpnp_fft_fft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_FLT][eft_FLT] = { eft_C64, (void *)dpnp_fft_fft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_DBL][eft_DBL] = { diff --git a/dpnp/fft/dpnp_algo_fft.pyx b/dpnp/fft/dpnp_algo_fft.pyx index 3424459a527b..c77552610443 100644 --- a/dpnp/fft/dpnp_algo_fft.pyx +++ b/dpnp/fft/dpnp_algo_fft.pyx @@ -68,9 +68,15 @@ cpdef utils.dpnp_descriptor dpnp_fft(utils.dpnp_descriptor input, input_obj = input.get_array() + # get FPTR function and return type + cdef (DPNPFuncType, void *) ret_type_and_func = utils.get_ret_type_and_func(kernel_data, + input_obj.sycl_device.has_aspect_fp64) + cdef DPNPFuncType return_type = ret_type_and_func[0] + cdef fptr_dpnp_fft_fft_t func = < fptr_dpnp_fft_fft_t > ret_type_and_func[1] + # ceate result array with type given by FPTR data cdef utils.dpnp_descriptor result = utils.create_output_descriptor(output_shape, - kernel_data.return_type, + return_type, None, device=input_obj.sycl_device, usm_type=input_obj.usm_type, @@ -81,7 +87,6 @@ cpdef utils.dpnp_descriptor dpnp_fft(utils.dpnp_descriptor input, cdef c_dpctl.SyclQueue q = result_sycl_queue cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - cdef fptr_dpnp_fft_fft_t func = kernel_data.ptr # call FPTR function cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, input.get_data(), From 58e87a361331ac493cf9514d576b8dbb30e6a91a Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 16 Aug 2023 16:30:41 +0200 Subject: [PATCH 2/9] Impove dpnp_rfft impl for Iris Xe --- dpnp/backend/kernels/dpnp_krnl_fft.cpp | 22 +++++++++++++++------- dpnp/fft/dpnp_algo_fft.pyx | 9 +++++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/dpnp/backend/kernels/dpnp_krnl_fft.cpp b/dpnp/backend/kernels/dpnp_krnl_fft.cpp index 69c7bcc1188f..3ead850953e9 100644 --- a/dpnp/backend/kernels/dpnp_krnl_fft.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_fft.cpp @@ -623,8 +623,12 @@ DPCTLSyclEventRef dpnp_fft_rfft_c(DPCTLSyclQueueRef q_ref, else if constexpr (std::is_same<_DataType_input, int32_t>::value || std::is_same<_DataType_input, int64_t>::value) { - double *array1_copy = reinterpret_cast( - dpnp_memory_alloc_c(q_ref, input_size * sizeof(double))); + using CastType = std::conditional_t< + std::is_same<_DataType_output, std::complex>::value, + double, float>; + + CastType *array1_copy = reinterpret_cast( + dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); shape_elem_type *copy_strides = reinterpret_cast( dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); @@ -633,15 +637,17 @@ DPCTLSyclEventRef dpnp_fft_rfft_c(DPCTLSyclQueueRef q_ref, dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); *copy_shape = input_size; shape_elem_type copy_shape_size = 1; - event_ref = dpnp_copyto_c<_DataType_input, double>( + event_ref = dpnp_copyto_c<_DataType_input, CastType>( q_ref, array1_copy, input_size, copy_shape_size, copy_shape, copy_strides, array1_in, input_size, copy_shape_size, copy_shape, copy_strides, NULL, dep_event_vec_ref); DPCTLEvent_WaitAndThrow(event_ref); DPCTLEvent_Delete(event_ref); - event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c( + event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c< + CastType, CastType, + std::conditional_t::value, + desc_dp_real_t, desc_sp_real_t>>( q_ref, array1_copy, result_out, input_shape, result_shape, shape_size, input_size, result_size, inverse, norm, 1); @@ -756,9 +762,11 @@ void func_map_init_fft_func(func_map_t &fmap) (void *)dpnp_fft_rfft_default_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_INT][eft_INT] = { - eft_C128, (void *)dpnp_fft_rfft_ext_c>}; + eft_C128, (void *)dpnp_fft_rfft_ext_c>, + eft_C64, (void *)dpnp_fft_rfft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_LNG][eft_LNG] = { - eft_C128, (void *)dpnp_fft_rfft_ext_c>}; + eft_C128, (void *)dpnp_fft_rfft_ext_c>, + eft_C64, (void *)dpnp_fft_rfft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_FLT][eft_FLT] = { eft_C64, (void *)dpnp_fft_rfft_ext_c>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_DBL][eft_DBL] = { diff --git a/dpnp/fft/dpnp_algo_fft.pyx b/dpnp/fft/dpnp_algo_fft.pyx index c77552610443..b751354a1e07 100644 --- a/dpnp/fft/dpnp_algo_fft.pyx +++ b/dpnp/fft/dpnp_algo_fft.pyx @@ -127,9 +127,15 @@ cpdef utils.dpnp_descriptor dpnp_rfft(utils.dpnp_descriptor input, input_obj = input.get_array() + # get FPTR function and return type + cdef (DPNPFuncType, void *) ret_type_and_func = utils.get_ret_type_and_func(kernel_data, + input_obj.sycl_device.has_aspect_fp64) + cdef DPNPFuncType return_type = ret_type_and_func[0] + cdef fptr_dpnp_fft_fft_t func = < fptr_dpnp_fft_fft_t > ret_type_and_func[1] + # ceate result array with type given by FPTR data cdef utils.dpnp_descriptor result = utils.create_output_descriptor(output_shape, - kernel_data.return_type, + return_type, None, device=input_obj.sycl_device, usm_type=input_obj.usm_type, @@ -140,7 +146,6 @@ cpdef utils.dpnp_descriptor dpnp_rfft(utils.dpnp_descriptor input, cdef c_dpctl.SyclQueue q = result_sycl_queue cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - cdef fptr_dpnp_fft_fft_t func = kernel_data.ptr # call FPTR function cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, input.get_data(), From 34714dfcfe496abb6720b5792197081758ceabb1 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 16 Aug 2023 16:31:06 +0200 Subject: [PATCH 3/9] Update test_fft and cupy test --- tests/test_fft.py | 42 +++++------ tests/third_party/cupy/fft_tests/test_fft.py | 75 +++++++++++++++----- 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/tests/test_fft.py b/tests/test_fft.py index ae6835b86eda..ea68e2c51af4 100644 --- a/tests/test_fft.py +++ b/tests/test_fft.py @@ -3,20 +3,14 @@ import dpnp -from .helper import assert_dtype_allclose, has_support_aspect64 - -pytestmark = pytest.mark.skipif( - not has_support_aspect64(), reason="Aborted on Iris Xe: SAT-6028" -) +from .helper import assert_dtype_allclose, get_all_dtypes -@pytest.mark.parametrize( - "type", ["complex128", "complex64", "float32", "float64", "int32", "int64"] -) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize("norm", [None, "forward", "ortho"]) -def test_fft(type, norm): +def test_fft(dtype, norm): # 1 dim array - data = numpy.arange(100, dtype=numpy.dtype(type)) + data = numpy.arange(100, dtype=dtype) dpnp_data = dpnp.array(data) np_res = numpy.fft.fft(data, norm=norm) @@ -25,14 +19,12 @@ def test_fft(type, norm): assert_dtype_allclose(dpnp_res, np_res) -@pytest.mark.parametrize( - "type", ["complex128", "complex64", "float32", "float64", "int32", "int64"] -) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize("shape", [(8, 8), (4, 16), (4, 4, 4), (2, 4, 4, 2)]) @pytest.mark.parametrize("norm", [None, "forward", "ortho"]) -def test_fft_ndim(type, shape, norm): - np_data = numpy.arange(64, dtype=numpy.dtype(type)).reshape(shape) - dpnp_data = dpnp.arange(64, dtype=numpy.dtype(type)).reshape(shape) +def test_fft_ndim(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) @@ -40,16 +32,14 @@ def test_fft_ndim(type, shape, norm): assert_dtype_allclose(dpnp_res, np_res) -@pytest.mark.parametrize( - "type", ["complex128", "complex64", "float32", "float64", "int32", "int64"] -) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) @pytest.mark.parametrize( "shape", [(64,), (8, 8), (4, 16), (4, 4, 4), (2, 4, 4, 2)] ) @pytest.mark.parametrize("norm", [None, "forward", "ortho"]) -def test_fft_ifft(type, shape, norm): - np_data = numpy.arange(64, dtype=numpy.dtype(type)).reshape(shape) - dpnp_data = dpnp.arange(64, dtype=numpy.dtype(type)).reshape(shape) +def test_fft_ifft(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.ifft(np_data, norm=norm) dpnp_res = dpnp.fft.ifft(dpnp_data, norm=norm) @@ -57,13 +47,13 @@ def test_fft_ifft(type, shape, norm): assert_dtype_allclose(dpnp_res, np_res) -@pytest.mark.parametrize("type", ["float32", "float64", "int32", "int64"]) +@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True)) @pytest.mark.parametrize( "shape", [(64,), (8, 8), (4, 16), (4, 4, 4), (2, 4, 4, 2)] ) -def test_fft_rfft(type, shape): - np_data = numpy.arange(64, dtype=numpy.dtype(type)).reshape(shape) - dpnp_data = dpnp.arange(64, dtype=numpy.dtype(type)).reshape(shape) +def test_fft_rfft(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) diff --git a/tests/third_party/cupy/fft_tests/test_fft.py b/tests/third_party/cupy/fft_tests/test_fft.py index 0ddd3cc56c17..b8cd16852587 100644 --- a/tests/third_party/cupy/fft_tests/test_fft.py +++ b/tests/third_party/cupy/fft_tests/test_fft.py @@ -6,6 +6,7 @@ import pytest import dpnp as cupy +from tests.helper import has_support_aspect64 from tests.third_party.cupy import testing @@ -14,7 +15,7 @@ { "n": [None, 0, 5, 10, 15], "shape": [(0,), (10, 0), (10,), (10, 10)], - "norm": [None, "ortho", ""], + "norm": [None, "backward", "ortho", "forward", ""], } ) ) @@ -26,8 +27,7 @@ class TestFft(unittest.TestCase): rtol=1e-4, atol=1e-7, accept_error=ValueError, - contiguous_check=False, - type_check=False, + type_check=True if has_support_aspect64() else False, ) def test_fft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -40,8 +40,7 @@ def test_fft(self, xp, dtype): rtol=1e-4, atol=1e-7, accept_error=ValueError, - contiguous_check=False, - type_check=False, + type_check=True if has_support_aspect64() else False, ) def test_ifft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -80,7 +79,10 @@ def test_ifft(self, xp, dtype): class TestFft2(unittest.TestCase): @testing.for_all_dtypes() @testing.numpy_cupy_allclose( - rtol=1e-4, atol=1e-7, accept_error=ValueError, contiguous_check=False + rtol=1e-4, + atol=1e-7, + accept_error=ValueError, + type_check=True if has_support_aspect64() else False, ) def test_fft2(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -90,7 +92,10 @@ def test_fft2(self, xp, dtype): @testing.for_all_dtypes() @testing.numpy_cupy_allclose( - rtol=1e-4, atol=1e-7, accept_error=ValueError, contiguous_check=False + rtol=1e-4, + atol=1e-7, + accept_error=ValueError, + type_check=True if has_support_aspect64() else False, ) def test_ifft2(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -130,7 +135,10 @@ def test_ifft2(self, xp, dtype): class TestFftn(unittest.TestCase): @testing.for_all_dtypes() @testing.numpy_cupy_allclose( - rtol=1e-4, atol=1e-7, accept_error=ValueError, contiguous_check=False + rtol=1e-4, + atol=1e-7, + accept_error=ValueError, + type_check=True if has_support_aspect64() else False, ) def test_fftn(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -140,7 +148,10 @@ def test_fftn(self, xp, dtype): @testing.for_all_dtypes() @testing.numpy_cupy_allclose( - rtol=1e-4, atol=1e-7, accept_error=ValueError, contiguous_check=False + rtol=1e-4, + atol=1e-7, + accept_error=ValueError, + type_check=True if has_support_aspect64() else False, ) def test_ifftn(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -163,7 +174,9 @@ def test_ifftn(self, xp, dtype): class TestRfft(unittest.TestCase): @testing.for_all_dtypes(no_complex=True) @testing.numpy_cupy_allclose( - rtol=1e-4, atol=1e-7, contiguous_check=False, type_check=False + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, ) def test_rfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -172,7 +185,11 @@ def test_rfft(self, xp, dtype): return out @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_irfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.irfft(a, n=self.n, norm=self.norm) @@ -237,7 +254,11 @@ def test_irfftn(self, dtype): @testing.gpu class TestHfft(unittest.TestCase): @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_hfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.hfft(a, n=self.n, norm=self.norm) @@ -245,7 +266,11 @@ def test_hfft(self, xp, dtype): return out @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_ihfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.ihfft(a, n=self.n, norm=self.norm) @@ -262,14 +287,22 @@ def test_ihfft(self, xp, dtype): @testing.gpu class TestFftfreq(unittest.TestCase): @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_fftfreq(self, xp, dtype): out = xp.fft.fftfreq(self.n, self.d) return out @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_rfftfreq(self, xp, dtype): out = xp.fft.rfftfreq(self.n, self.d) @@ -289,7 +322,11 @@ def test_rfftfreq(self, xp, dtype): @testing.gpu class TestFftshift(unittest.TestCase): @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_fftshift(self, xp, dtype): x = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.fftshift(x, self.axes) @@ -297,7 +334,11 @@ def test_fftshift(self, xp, dtype): return out @testing.for_all_dtypes() - @testing.numpy_cupy_allclose(rtol=1e-4, atol=1e-7, contiguous_check=False) + @testing.numpy_cupy_allclose( + rtol=1e-4, + atol=1e-7, + type_check=True if has_support_aspect64() else False, + ) def test_ifftshift(self, xp, dtype): x = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.ifftshift(x, self.axes) From e7d7da077b5800fdece4a685c2042fcb53cc596c Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 16 Aug 2023 18:53:50 +0200 Subject: [PATCH 4/9] Refresh dpnp_iface_fft.py --- dpnp/fft/dpnp_iface_fft.py | 471 ++++++++++++++++++++----------------- 1 file changed, 254 insertions(+), 217 deletions(-) diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index d5cb09e5819f..8d32fbcf84cf 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -86,23 +86,24 @@ def get_validated_norm(norm): raise ValueError("Unknown norm value.") -def fft(x1, n=None, axis=-1, norm=None): +def fft(x, n=None, axis=-1, norm=None): """ Compute the one-dimensional discrete Fourier Transform. + For full documentation refer to :obj:`numpy.fft.fft`. + Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``axis`` is supported with its default value. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64``, - ``dpnp.complex64`` and ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.fft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `axis` is supported with its default value. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128`, `dpnp.complex64` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: norm_ = get_validated_norm(norm) if axis is None: @@ -111,11 +112,11 @@ def fft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -126,89 +127,93 @@ def fft(x1, n=None, axis=-1, norm=None): else: output_boundarie = input_boundarie return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, False, norm_.value, ).get_pyobj() - return call_origin(numpy.fft.fft, x1, n, axis, norm) + return call_origin(numpy.fft.fft, x, n, axis, norm) -def fft2(x1, s=None, axes=(-2, -1), norm=None): +def fft2(x, s=None, axes=(-2, -1), norm=None): """ - Compute the 2-dimensional discrete Fourier Transform + Compute the 2-dimensional discrete Fourier Transform. + + Multi-dimensional arrays computed as batch of 1-D arrays. - Multi-dimensional arrays computed as batch of 1-D arrays + For full documentation refer to :obj:`numpy.fft.fft2`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.fft2`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: if norm is not None: pass else: - return fftn(x1, s, axes, norm) + return fftn(x, s, axes, norm) - return call_origin(numpy.fft.fft2, x1, s, axes, norm) + return call_origin(numpy.fft.fft2, x, s, axes, norm) def fftfreq(n=None, d=1.0): """ Compute the one-dimensional discrete Fourier Transform sample frequencies. + For full documentation refer to :obj:`numpy.fft.fftfreq`. + Limitations ----------- - Parameter ``d`` is unsupported. - - For full documentation refer to :obj:`numpy.fft.fftfreq`. + Parameter `d` is unsupported. """ return call_origin(numpy.fft.fftfreq, n, d) -def fftn(x1, s=None, axes=None, norm=None): +def fftn(x, s=None, axes=None, norm=None): """ Compute the N-dimensional FFT. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.fftn`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.fftn`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: if s is None: - boundaries = tuple([x1_desc.shape[i] for i in range(x1_desc.ndim)]) + boundaries = tuple([x_desc.shape[i] for i in range(x_desc.ndim)]) else: boundaries = s if axes is None: - axes_param = tuple([i for i in range(x1_desc.ndim)]) + axes_param = tuple([i for i in range(x_desc.ndim)]) else: axes_param = axes if norm is not None: pass else: - x1_iter = x1 + x_iter = x iteration_list = list(range(len(axes_param))) iteration_list.reverse() # inplace operation for it in iteration_list: @@ -223,41 +228,43 @@ def fftn(x1, s=None, axes=None, norm=None): f"< {len(boundaries)}", ) - x1_iter = fft(x1_iter, n=param_n, axis=param_axis, norm=norm) + x_iter = fft(x_iter, n=param_n, axis=param_axis, norm=norm) - return x1_iter + return x_iter - return call_origin(numpy.fft.fftn, x1, s, axes, norm) + return call_origin(numpy.fft.fftn, x, s, axes, norm) -def fftshift(x1, axes=None): +def fftshift(x, axes=None): """ Shift the zero-frequency component to the center of the spectrum. + For full documentation refer to :obj:`numpy.fft.fftshift`. + Limitations ----------- - Parameter ``axes`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.fftshift`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `axes` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: norm_ = Norm.backward - if axis is None: + if axes is None: axis_param = -1 # the most right dimension (default value) else: axis_param = axes - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception else: return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -265,25 +272,27 @@ def fftshift(x1, axes=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.fftshift, x1, axes) + return call_origin(numpy.fft.fftshift, x, axes) -def hfft(x1, n=None, axis=-1, norm=None): +def hfft(x, n=None, axis=-1, norm=None): """ Compute the one-dimensional discrete Fourier Transform of a signal that has Hermitian symmetry. + For full documentation refer to :obj:`numpy.fft.hfft`. + Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.hfft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: norm_ = get_validated_norm(norm) if axis is None: @@ -292,11 +301,11 @@ def hfft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1.size < 1: + if x.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -306,7 +315,7 @@ def hfft(x1, n=None, axis=-1, norm=None): output_boundarie = input_boundarie return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -314,25 +323,27 @@ def hfft(x1, n=None, axis=-1, norm=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.hfft, x1, n, axis, norm) + return call_origin(numpy.fft.hfft, x, n, axis, norm) -def ifft(x1, n=None, axis=-1, norm=None): +def ifft(x, n=None, axis=-1, norm=None): """ Compute the one-dimensional inverse discrete Fourier Transform. + For full documentation refer to :obj:`numpy.fft.ifft`. + Limitations ----------- - Parameter ``axis`` is supported with its default value. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64``, - ``dpnp.complex64``and ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.ifft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `axis` is supported with its default value. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`,, + `dpnp.complex128`, `dpnp.complex64` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: norm_ = get_validated_norm(norm) if axis is None: @@ -341,11 +352,11 @@ def ifft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -354,7 +365,7 @@ def ifft(x1, n=None, axis=-1, norm=None): else: output_boundarie = input_boundarie return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -362,63 +373,73 @@ def ifft(x1, n=None, axis=-1, norm=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.ifft, x1, n, axis, norm) + return call_origin(numpy.fft.ifft, x, n, axis, norm) -def ifft2(x1, s=None, axes=(-2, -1), norm=None): +def ifft2(x, s=None, axes=(-2, -1), norm=None): """ - Compute the 2-dimensional inverse discrete Fourier Transform + Compute the 2-dimensional inverse discrete Fourier Transform. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.ifft2`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.ifft2`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: if norm is not None: pass else: - return ifftn(x1, s, axes, norm) + return ifftn(x, s, axes, norm) - return call_origin(numpy.fft.ifft2, x1, s, axes, norm) + return call_origin(numpy.fft.ifft2, x, s, axes, norm) -def ifftshift(x1, axes=None): +def ifftshift(x, axes=None): """ Inverse shift the zero-frequency component to the center of the spectrum. + For full documentation refer to :obj:`numpy.fft.ifftshift`. + Limitations ----------- - Parameter ``axes`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.ifftshift`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `axes` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: norm_ = Norm.backward - if axis is None: + if axes is None: axis_param = -1 # the most right dimension (default value) else: axis_param = axes - if x1_desc.size < 1: + input_boundarie = x_desc.shape[axis_param] + + if x_desc.size < 1: + pass # let fallback to handle exception + elif input_boundarie < 1: pass # let fallback to handle exception else: + output_boundarie = input_boundarie + return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -426,41 +447,43 @@ def ifftshift(x1, axes=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.ifftshift, x1, axes) + return call_origin(numpy.fft.ifftshift, x, axes) -def ifftn(x1, s=None, axes=None, norm=None): +def ifftn(x, s=None, axes=None, norm=None): """ Compute the N-dimensional inverse discrete Fourier Transform. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.ifftn`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.ifftn`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: if s is None: - boundaries = tuple([x1_desc.shape[i] for i in range(x1_desc.ndim)]) + boundaries = tuple([x_desc.shape[i] for i in range(x_desc.ndim)]) else: boundaries = s if axes is None: - axes_param = tuple([i for i in range(x1_desc.ndim)]) + axes_param = tuple([i for i in range(x_desc.ndim)]) else: axes_param = axes if norm is not None: pass else: - x1_iter = x1 + x_iter = x iteration_list = list(range(len(axes_param))) iteration_list.reverse() # inplace operation for it in iteration_list: @@ -475,35 +498,37 @@ def ifftn(x1, s=None, axes=None, norm=None): f"< {len(boundaries)}", ) - x1_iter_desc = dpnp.get_dpnp_descriptor(x1_iter) - x1_iter = ifft( - x1_iter_desc.get_pyobj(), + x_iter_desc = dpnp.get_dpnp_descriptor(x_iter) + x_iter = ifft( + x_iter_desc.get_pyobj(), n=param_n, axis=param_axis, norm=norm, ) - return x1_iter + return x_iter - return call_origin(numpy.fft.ifftn, x1, s, axes, norm) + return call_origin(numpy.fft.ifftn, x, s, axes, norm) -def ihfft(x1, n=None, axis=-1, norm=None): +def ihfft(x, n=None, axis=-1, norm=None): """ Compute inverse one-dimensional discrete Fourier Transform of a signal that has Hermitian symmetry. + For full documentation refer to :obj:`numpy.fft.ihfft`. + Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.ihfft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: norm_ = get_validated_norm(norm) if axis is None: @@ -512,11 +537,11 @@ def ihfft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -528,7 +553,7 @@ def ihfft(x1, n=None, axis=-1, norm=None): output_boundarie = input_boundarie return dpnp_fft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -536,25 +561,27 @@ def ihfft(x1, n=None, axis=-1, norm=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.ihfft, x1, n, axis, norm) + return call_origin(numpy.fft.ihfft, x, n, axis, norm) -def irfft(x1, n=None, axis=-1, norm=None): +def irfft(x, n=None, axis=-1, norm=None): """ - Compute the one-dimensional inverse discrete Fourier Transform for real input.. + Compute the one-dimensional inverse discrete Fourier Transform for real input. + + For full documentation refer to :obj:`numpy.fft.irfft`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.irfft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: norm_ = get_validated_norm(norm) if axis is None: @@ -563,11 +590,11 @@ def irfft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -579,7 +606,7 @@ def irfft(x1, n=None, axis=-1, norm=None): output_boundarie = 2 * (input_boundarie - 1) result = dpnp_rfft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -592,67 +619,71 @@ def irfft(x1, n=None, axis=-1, norm=None): # tmp[it] = result[it].real return result - return call_origin(numpy.fft.irfft, x1, n, axis, norm) + return call_origin(numpy.fft.irfft, x, n, axis, norm) -def irfft2(x1, s=None, axes=(-2, -1), norm=None): +def irfft2(x, s=None, axes=(-2, -1), norm=None): """ Compute the 2-dimensional inverse discrete Fourier Transform for real input. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.irfft2`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.irfft2`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: if norm is not None: pass else: - return irfftn(x1_desc.get_pyobj(), s, axes, norm) + return irfftn(x_desc.get_pyobj(), s, axes, norm) - return call_origin(numpy.fft.irfft2, x1, s, axes, norm) + return call_origin(numpy.fft.irfft2, x, s, axes, norm) -def irfftn(x1, s=None, axes=None, norm=None): +def irfftn(x, s=None, axes=None, norm=None): """ Compute the N-dimensional inverse discrete Fourier Transform for real input. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.irfftn`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.irfftn`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: if s is None: - boundaries = tuple([x1_desc.shape[i] for i in range(x1_desc.ndim)]) + boundaries = tuple([x_desc.shape[i] for i in range(x_desc.ndim)]) else: boundaries = s if axes is None: - axes_param = tuple([i for i in range(x1_desc.ndim)]) + axes_param = tuple([i for i in range(x_desc.ndim)]) else: axes_param = axes if norm is not None: pass else: - x1_iter = x1 + x_iter = x iteration_list = list(range(len(axes_param))) iteration_list.reverse() # inplace operation for it in iteration_list: @@ -667,35 +698,37 @@ def irfftn(x1, s=None, axes=None, norm=None): f"< {len(boundaries)}", ) - x1_iter_desc = dpnp.get_dpnp_descriptor(x1_iter) - x1_iter = irfft( - x1_iter_desc.get_pyobj(), + x_iter_desc = dpnp.get_dpnp_descriptor(x_iter) + x_iter = irfft( + x_iter_desc.get_pyobj(), n=param_n, axis=param_axis, norm=norm, ) - return x1_iter + return x_iter - return call_origin(numpy.fft.irfftn, x1, s, axes, norm) + return call_origin(numpy.fft.irfftn, x, s, axes, norm) -def rfft(x1, n=None, axis=-1, norm=None): +def rfft(x, n=None, axis=-1, norm=None): """ Compute the one-dimensional discrete Fourier Transform for real input. + For full documentation refer to :obj:`numpy.fft.rfft`. + Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.rfft`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: norm_ = get_validated_norm(norm) if axis is None: @@ -704,11 +737,11 @@ def rfft(x1, n=None, axis=-1, norm=None): axis_param = axis if n is None: - input_boundarie = x1_desc.shape[axis_param] + input_boundarie = x_desc.shape[axis_param] else: input_boundarie = n - if x1_desc.size < 1: + if x_desc.size < 1: pass # let fallback to handle exception elif input_boundarie < 1: pass # let fallback to handle exception @@ -718,14 +751,14 @@ def rfft(x1, n=None, axis=-1, norm=None): pass elif n is not None: pass - elif x1_desc.dtype in (numpy.complex128, numpy.complex64): + elif x_desc.dtype in (numpy.complex128, numpy.complex64): pass else: output_boundarie = ( input_boundarie // 2 + 1 ) # rfft specific requirenment return dpnp_rfft( - x1_desc, + x_desc, input_boundarie, output_boundarie, axis_param, @@ -733,75 +766,79 @@ def rfft(x1, n=None, axis=-1, norm=None): norm_.value, ).get_pyobj() - return call_origin(numpy.fft.rfft, x1, n, axis, norm) + return call_origin(numpy.fft.rfft, x, n, axis, norm) -def rfft2(x1, s=None, axes=(-2, -1), norm=None): +def rfft2(x, s=None, axes=(-2, -1), norm=None): """ Compute the 2-dimensional discrete Fourier Transform for real input. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.rfft2`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.rfft2`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc: if norm is not None: pass else: - return rfftn(x1_desc.get_pyobj(), s, axes, norm) + return rfftn(x_desc.get_pyobj(), s, axes, norm) - return call_origin(numpy.fft.rfft2, x1, s, axes, norm) + return call_origin(numpy.fft.rfft2, x, s, axes, norm) def rfftfreq(n=None, d=1.0): """ Compute the one-dimensional discrete Fourier Transform sample frequencies. + For full documentation refer to :obj:`numpy.fft.rfftfreq`. + Limitations ----------- Parameter ``d`` is unsupported. - For full documentation refer to :obj:`numpy.fft.rfftfreq`. - """ return call_origin(numpy.fft.rfftfreq, n, d) -def rfftn(x1, s=None, axes=None, norm=None): +def rfftn(x, s=None, axes=None, norm=None): """ Compute the N-dimensional discrete Fourier Transform for real input. - Multi-dimensional arrays computed as batch of 1-D arrays + Multi-dimensional arrays computed as batch of 1-D arrays. + + For full documentation refer to :obj:`numpy.fft.rfftn`. Limitations ----------- - Parameter ``norm`` is unsupported. - Parameter ``x1`` supports ``dpnp.int32``, ``dpnp.int64``, ``dpnp.float32``, ``dpnp.float64`` and - ``dpnp.complex128`` datatypes only. - - For full documentation refer to :obj:`numpy.fft.rfftn`. + Parameter `x` is supported either as :class:`dpnp.ndarray`. + Parameter `norm` is unsupported. + Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, + `dpnp.complex128` data types are supported. + Otherwise the function will be executed sequentially on CPU. """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if x1_desc and 0: + x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) + if x_desc and 0: if s is None: - boundaries = tuple([x1_desc.shape[i] for i in range(x1_desc.ndim)]) + boundaries = tuple([x_desc.shape[i] for i in range(x_desc.ndim)]) else: boundaries = s if axes is None: - axes_param = tuple([i for i in range(x1_desc.ndim)]) + axes_param = tuple([i for i in range(x_desc.ndim)]) else: axes_param = axes @@ -810,7 +847,7 @@ def rfftn(x1, s=None, axes=None, norm=None): elif len(axes) < 1: pass # let fallback to handle exception else: - x1_iter = x1 + x_iter = x iteration_list = list(range(len(axes_param))) iteration_list.reverse() # inplace operation for it in iteration_list: @@ -825,16 +862,16 @@ def rfftn(x1, s=None, axes=None, norm=None): f"< {len(boundaries)}", ) - x1_iter_desc = dpnp.get_dpnp_descriptor( - x1_iter, copy_when_nondefault_queue=False + x_iter_desc = dpnp.get_dpnp_descriptor( + x_iter, copy_when_nondefault_queue=False ) - x1_iter = rfft( - x1_iter_desc.get_pyobj(), + x_iter = rfft( + x_iter_desc.get_pyobj(), n=param_n, axis=param_axis, norm=norm, ) - return x1_iter + return x_iter - return call_origin(numpy.fft.rfftn, x1, s, axes, norm) + return call_origin(numpy.fft.rfftn, x, s, axes, norm) From 46f84f14a1e793d91ee139ea5d7e33ef2c8be5c7 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Thu, 17 Aug 2023 11:58:11 +0200 Subject: [PATCH 5/9] Fix cupy test_fft.py --- tests/third_party/cupy/fft_tests/test_fft.py | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/third_party/cupy/fft_tests/test_fft.py b/tests/third_party/cupy/fft_tests/test_fft.py index b8cd16852587..0cc49200a245 100644 --- a/tests/third_party/cupy/fft_tests/test_fft.py +++ b/tests/third_party/cupy/fft_tests/test_fft.py @@ -27,7 +27,7 @@ class TestFft(unittest.TestCase): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_fft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -40,7 +40,7 @@ def test_fft(self, xp, dtype): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_ifft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -82,7 +82,7 @@ class TestFft2(unittest.TestCase): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_fft2(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -95,7 +95,7 @@ def test_fft2(self, xp, dtype): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_ifft2(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -138,7 +138,7 @@ class TestFftn(unittest.TestCase): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_fftn(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -151,7 +151,7 @@ def test_fftn(self, xp, dtype): rtol=1e-4, atol=1e-7, accept_error=ValueError, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_ifftn(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -176,7 +176,7 @@ class TestRfft(unittest.TestCase): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_rfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -188,7 +188,7 @@ def test_rfft(self, xp, dtype): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_irfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -257,7 +257,7 @@ class TestHfft(unittest.TestCase): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_hfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -269,7 +269,7 @@ def test_hfft(self, xp, dtype): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_ihfft(self, xp, dtype): a = testing.shaped_random(self.shape, xp, dtype) @@ -290,7 +290,7 @@ class TestFftfreq(unittest.TestCase): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_fftfreq(self, xp, dtype): out = xp.fft.fftfreq(self.n, self.d) @@ -301,7 +301,7 @@ def test_fftfreq(self, xp, dtype): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_rfftfreq(self, xp, dtype): out = xp.fft.rfftfreq(self.n, self.d) @@ -325,7 +325,7 @@ class TestFftshift(unittest.TestCase): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_fftshift(self, xp, dtype): x = testing.shaped_random(self.shape, xp, dtype) @@ -337,7 +337,7 @@ def test_fftshift(self, xp, dtype): @testing.numpy_cupy_allclose( rtol=1e-4, atol=1e-7, - type_check=True if has_support_aspect64() else False, + type_check=has_support_aspect64(), ) def test_ifftshift(self, xp, dtype): x = testing.shaped_random(self.shape, xp, dtype) From 098fd99a6faff6206bc165ed24a754dd6d4fa5b6 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Fri, 18 Aug 2023 15:06:15 +0200 Subject: [PATCH 6/9] Apply review remarks --- dpnp/backend/kernels/dpnp_krnl_fft.cpp | 13 +++++++------ dpnp/fft/dpnp_iface_fft.py | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dpnp/backend/kernels/dpnp_krnl_fft.cpp b/dpnp/backend/kernels/dpnp_krnl_fft.cpp index 3ead850953e9..fa88ea923153 100644 --- a/dpnp/backend/kernels/dpnp_krnl_fft.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_fft.cpp @@ -414,6 +414,9 @@ DPCTLSyclEventRef dpnp_fft_fft_c(DPCTLSyclQueueRef q_ref, const size_t norm, const DPCTLEventVectorRef dep_event_vec_ref) { + static_assert(sycl::detail::is_complex<_DataType_output>::value, + "Output data type must be a complex type."); + DPCTLSyclEventRef event_ref = nullptr; if (!shape_size || !array1_in || !result_out) { @@ -476,9 +479,7 @@ DPCTLSyclEventRef dpnp_fft_fft_c(DPCTLSyclQueueRef q_ref, else if constexpr (std::is_same<_DataType_input, int32_t>::value || std::is_same<_DataType_input, int64_t>::value) { - using CastType = std::conditional_t< - std::is_same<_DataType_output, std::complex>::value, - double, float>; + using CastType = typename _DataType_output::value_type; CastType *array1_copy = reinterpret_cast( dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); @@ -583,6 +584,8 @@ DPCTLSyclEventRef dpnp_fft_rfft_c(DPCTLSyclQueueRef q_ref, const size_t norm, const DPCTLEventVectorRef dep_event_vec_ref) { + static_assert(sycl::detail::is_complex<_DataType_output>::value, + "Output data type must be a complex type."); DPCTLSyclEventRef event_ref = nullptr; if (!shape_size || !array1_in || !result_out) { @@ -623,9 +626,7 @@ DPCTLSyclEventRef dpnp_fft_rfft_c(DPCTLSyclQueueRef q_ref, else if constexpr (std::is_same<_DataType_input, int32_t>::value || std::is_same<_DataType_input, int64_t>::value) { - using CastType = std::conditional_t< - std::is_same<_DataType_output, std::complex>::value, - double, float>; + using CastType = typename _DataType_output::value_type; CastType *array1_copy = reinterpret_cast( dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index 8d32fbcf84cf..df359bf68e61 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -98,8 +98,8 @@ def fft(x, n=None, axis=-1, norm=None): Parameter `axis` is supported with its default value. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, `dpnp.complex128`, `dpnp.complex64` data types are supported. + The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. Otherwise the function will be executed sequentially on CPU. - """ x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) @@ -338,6 +338,7 @@ def ifft(x, n=None, axis=-1, norm=None): Parameter `axis` is supported with its default value. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`,, `dpnp.complex128`, `dpnp.complex64` data types are supported. + The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. Otherwise the function will be executed sequentially on CPU. """ @@ -723,8 +724,8 @@ def rfft(x, n=None, axis=-1, norm=None): Parameter `norm` is unsupported. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, `dpnp.complex128` data types are supported. + The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. Otherwise the function will be executed sequentially on CPU. - """ x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) From 0b80e7b4f3512d155be81fa157d9014adfbe4364 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Fri, 18 Aug 2023 15:08:04 +0200 Subject: [PATCH 7/9] Reduce python version to 3.10 for generate_coverage --- .github/workflows/generate_coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate_coverage.yaml b/.github/workflows/generate_coverage.yaml index d3a217a03f81..413835d336cf 100644 --- a/.github/workflows/generate_coverage.yaml +++ b/.github/workflows/generate_coverage.yaml @@ -14,7 +14,7 @@ jobs: shell: bash -l {0} env: - python-ver: '3.11' + python-ver: '3.10' CHANNELS: '-c dppy/label/dev -c intel -c conda-forge --override-channels' steps: From b73341ec45f30917d81507b050b9fb4568146ef2 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 21 Aug 2023 02:01:48 +0200 Subject: [PATCH 8/9] Raise TypeError for boolean data type --- dpnp/fft/dpnp_iface_fft.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index df359bf68e61..0e1a5a982233 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -98,12 +98,16 @@ def fft(x, n=None, axis=-1, norm=None): Parameter `axis` is supported with its default value. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, `dpnp.complex128`, `dpnp.complex64` data types are supported. - The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. Otherwise the function will be executed sequentially on CPU. """ x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) if x_desc: + dt = x_desc.dtype + if dpnp.issubdtype(dt, dpnp.bool): + raise TypeError(f"The `{dt}` data type is unsupported.") + norm_ = get_validated_norm(norm) if axis is None: @@ -338,13 +342,17 @@ def ifft(x, n=None, axis=-1, norm=None): Parameter `axis` is supported with its default value. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`,, `dpnp.complex128`, `dpnp.complex64` data types are supported. - The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. Otherwise the function will be executed sequentially on CPU. """ x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) if x_desc: + dt = x_desc.dtype + if dpnp.issubdtype(dt, dpnp.bool): + raise TypeError(f"The `{dt}` data type is unsupported.") + norm_ = get_validated_norm(norm) if axis is None: @@ -724,12 +732,16 @@ def rfft(x, n=None, axis=-1, norm=None): Parameter `norm` is unsupported. Only `dpnp.float64`, `dpnp.float32`, `dpnp.int64`, `dpnp.int32`, `dpnp.complex128` data types are supported. - The `dpnp.bool` data type is not supported and will raise a `RuntimeError` exception. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. Otherwise the function will be executed sequentially on CPU. """ x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False) if x_desc: + dt = x_desc.dtype + if dpnp.issubdtype(dt, dpnp.bool): + raise TypeError(f"The `{dt}` data type is unsupported.") + norm_ = get_validated_norm(norm) if axis is None: From 41efab4bce0e2058925632ba44108d749da1ae23 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 21 Aug 2023 10:49:30 +0200 Subject: [PATCH 9/9] Add a new test for fft funcs --- tests/test_fft.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_fft.py b/tests/test_fft.py index ea68e2c51af4..0d2ea664b58d 100644 --- a/tests/test_fft.py +++ b/tests/test_fft.py @@ -59,3 +59,18 @@ def test_fft_rfft(dtype, shape): dpnp_res = dpnp.fft.rfft(dpnp_data) assert_dtype_allclose(dpnp_res, np_res) + + +@pytest.mark.parametrize( + "func_name", + [ + "fft", + "ifft", + "rfft", + ], +) +def test_fft_invalid_dtype(func_name): + a = dpnp.array([True, False, True]) + dpnp_func = getattr(dpnp.fft, func_name) + with pytest.raises(TypeError): + dpnp_func(a)