From a717c6911c6fcca57d0a3478ae72fb88ae87077b Mon Sep 17 00:00:00 2001 From: vlad-perevezentsev <vladislav.perevezentsev@intel.com> Date: Mon, 21 Aug 2023 14:30:24 +0200 Subject: [PATCH] Update dpnp fft implementations to run on Iris Xe (#1524) * Impove dpnp_fft impl for Iris Xe * Impove dpnp_rfft impl for Iris Xe * Update test_fft and cupy test * Refresh dpnp_iface_fft.py * Fix cupy test_fft.py * Apply review remarks * Reduce python version to 3.10 for generate_coverage * Raise TypeError for boolean data type * Add a new test for fft funcs --- .github/workflows/generate_coverage.yaml | 2 +- dpnp/backend/kernels/dpnp_krnl_fft.cpp | 45 +- dpnp/fft/dpnp_algo_fft.pyx | 18 +- dpnp/fft/dpnp_iface_fft.py | 488 ++++++++++--------- tests/test_fft.py | 57 ++- tests/third_party/cupy/fft_tests/test_fft.py | 75 ++- 6 files changed, 404 insertions(+), 281 deletions(-) diff --git a/.github/workflows/generate_coverage.yaml b/.github/workflows/generate_coverage.yaml index d3a217a03f8..413835d336c 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: diff --git a/dpnp/backend/kernels/dpnp_krnl_fft.cpp b/dpnp/backend/kernels/dpnp_krnl_fft.cpp index 25787a7331f..fa88ea92315 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,8 +479,10 @@ 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<double *>( - dpnp_memory_alloc_c(q_ref, input_size * sizeof(double))); + using CastType = typename _DataType_output::value_type; + + CastType *array1_copy = reinterpret_cast<CastType *>( + dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); shape_elem_type *copy_strides = reinterpret_cast<shape_elem_type *>( dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); @@ -486,15 +491,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<double, double, - desc_dp_real_t>( + event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c< + CastType, CastType, + std::conditional_t<std::is_same<CastType, double>::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); @@ -577,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) { @@ -617,8 +626,10 @@ 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<double *>( - dpnp_memory_alloc_c(q_ref, input_size * sizeof(double))); + using CastType = typename _DataType_output::value_type; + + CastType *array1_copy = reinterpret_cast<CastType *>( + dpnp_memory_alloc_c(q_ref, input_size * sizeof(CastType))); shape_elem_type *copy_strides = reinterpret_cast<shape_elem_type *>( dpnp_memory_alloc_c(q_ref, sizeof(shape_elem_type))); @@ -627,15 +638,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<double, double, - desc_dp_real_t>( + event_ref = dpnp_fft_fft_mathlib_real_to_cmplx_c< + CastType, CastType, + std::conditional_t<std::is_same<CastType, double>::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); @@ -721,9 +734,11 @@ void func_map_init_fft_func(func_map_t &fmap) dpnp_fft_fft_default_c<std::complex<double>, std::complex<double>>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_INT][eft_INT] = { - eft_C128, (void *)dpnp_fft_fft_ext_c<int32_t, std::complex<double>>}; + eft_C128, (void *)dpnp_fft_fft_ext_c<int32_t, std::complex<double>>, + eft_C64, (void *)dpnp_fft_fft_ext_c<int32_t, std::complex<float>>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_LNG][eft_LNG] = { - eft_C128, (void *)dpnp_fft_fft_ext_c<int64_t, std::complex<double>>}; + eft_C128, (void *)dpnp_fft_fft_ext_c<int64_t, std::complex<double>>, + eft_C64, (void *)dpnp_fft_fft_ext_c<int64_t, std::complex<float>>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_FLT][eft_FLT] = { eft_C64, (void *)dpnp_fft_fft_ext_c<float, std::complex<float>>}; fmap[DPNPFuncName::DPNP_FN_FFT_FFT_EXT][eft_DBL][eft_DBL] = { @@ -748,9 +763,11 @@ void func_map_init_fft_func(func_map_t &fmap) (void *)dpnp_fft_rfft_default_c<double, std::complex<double>>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_INT][eft_INT] = { - eft_C128, (void *)dpnp_fft_rfft_ext_c<int32_t, std::complex<double>>}; + eft_C128, (void *)dpnp_fft_rfft_ext_c<int32_t, std::complex<double>>, + eft_C64, (void *)dpnp_fft_rfft_ext_c<int32_t, std::complex<float>>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_LNG][eft_LNG] = { - eft_C128, (void *)dpnp_fft_rfft_ext_c<int64_t, std::complex<double>>}; + eft_C128, (void *)dpnp_fft_rfft_ext_c<int64_t, std::complex<double>>, + eft_C64, (void *)dpnp_fft_rfft_ext_c<int64_t, std::complex<float>>}; fmap[DPNPFuncName::DPNP_FN_FFT_RFFT_EXT][eft_FLT][eft_FLT] = { eft_C64, (void *)dpnp_fft_rfft_ext_c<float, std::complex<float>>}; 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 3424459a527..b751354a1e0 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 = <c_dpctl.SyclQueue> result_sycl_queue cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - cdef fptr_dpnp_fft_fft_t func = <fptr_dpnp_fft_fft_t > kernel_data.ptr # call FPTR function cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, input.get_data(), @@ -122,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, @@ -135,7 +146,6 @@ cpdef utils.dpnp_descriptor dpnp_rfft(utils.dpnp_descriptor input, cdef c_dpctl.SyclQueue q = <c_dpctl.SyclQueue> result_sycl_queue cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - cdef fptr_dpnp_fft_fft_t func = <fptr_dpnp_fft_fft_t > kernel_data.ptr # call FPTR function cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, input.get_data(), diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index d5cb09e5819..0e1a5a98223 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -86,23 +86,28 @@ 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. - 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`. + Limitations + ----------- + 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. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. + 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: + 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: @@ -111,11 +116,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 +131,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 +232,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 +276,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 +305,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 +319,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 +327,32 @@ 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. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. + 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: + 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: @@ -341,11 +361,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 +374,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 +382,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 +456,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 +507,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 +546,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 +562,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 +570,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 +599,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 +615,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 +628,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 +707,41 @@ 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. - 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`. + Limitations + ----------- + 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. + The `dpnp.bool` data type is not supported and will raise a `TypeError` exception. + 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: + 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: @@ -704,11 +750,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 +764,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 +779,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 +860,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 +875,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) diff --git a/tests/test_fft.py b/tests/test_fft.py index ae6835b86ed..0d2ea664b58 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,15 +47,30 @@ 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) 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) diff --git a/tests/third_party/cupy/fft_tests/test_fft.py b/tests/third_party/cupy/fft_tests/test_fft.py index 0ddd3cc56c1..0cc49200a24 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) 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=has_support_aspect64(), + ) def test_ifftshift(self, xp, dtype): x = testing.shaped_random(self.shape, xp, dtype) out = xp.fft.ifftshift(x, self.axes)