diff --git a/CHANGELOG.md b/CHANGELOG.md index fb1c5b78f904..2a64541ae099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +* Extended `dpnp.fft.fftfreq` and `dpnp.fft.rfftfreq` functions to support `dtype` keyword per Python Array API spec 2024.12 [#2384](https://github.com/IntelPython/dpnp/pull/2384) * Allowed input array of `uint64` dtype in `dpnp.bincount` [#2361](https://github.com/IntelPython/dpnp/pull/2361) * The vector norms `ord={None, 1, 2, inf}` and the matrix norms `ord={None, 1, 2, inf, "fro", "nuc"}` now consistently return zero for empty arrays, which are arrays with at least one axis of size zero. This change affects `dpnp.linalg.norm`, `dpnp.linalg.vector_norm`, and `dpnp.linalg.matrix_norm`. Previously, dpnp would either raise errors or return zero depending on the parameters provided [#2371](https://github.com/IntelPython/dpnp/pull/2371) diff --git a/dpnp/fft/dpnp_iface_fft.py b/dpnp/fft/dpnp_iface_fft.py index c82daad70d0a..52753e5362e0 100644 --- a/dpnp/fft/dpnp_iface_fft.py +++ b/dpnp/fft/dpnp_iface_fft.py @@ -41,6 +41,7 @@ from .dpnp_utils_fft import ( dpnp_fft, dpnp_fftn, + dpnp_fillfreq, ) __all__ = [ @@ -101,19 +102,24 @@ def fft(a, n=None, axis=-1, norm=None, out=None): If `n` is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros. If `n` is not given, the length of the input along the axis specified by `axis` is used. + Default: ``None``. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is - used. Default: ``-1``. + used. + + Default: ``-1``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `n`) and dtype. + Default: ``None``. Returns @@ -183,7 +189,9 @@ def fft2(a, s=None, axes=(-2, -1), norm=None, out=None): If it is ``-1``, the whole input is used (no padding/trimming). If `s` is not given, the shape of the input along the axes specified by `axes` is used. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the FFT. If not given, the last two axes are used. A repeated index in `axes` means the transform over that axis is @@ -191,16 +199,19 @@ def fft2(a, s=None, axes=(-2, -1), norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``(-2, -1)``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `s`) and dtype. + Default: ``None``. Returns @@ -257,7 +268,9 @@ def fft2(a, s=None, axes=(-2, -1), norm=None, out=None): ) -def fftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): +def fftfreq( + n, /, d=1.0, *, dtype=None, device=None, usm_type=None, sycl_queue=None +): """ Return the Discrete Fourier Transform sample frequencies. @@ -278,7 +291,14 @@ def fftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): Window length. d : scalar, optional Sample spacing (inverse of the sampling rate). + Default: ``1.0``. + dtype : {None, str, dtype object}, optional + The output array data type. Must be a real-valued floating-point data + type. If `dtype` is ``None``, the output array data type must be the + default real-valued floating-point data type. + + Default: ``None``. device : {None, string, SyclDevice, SyclQueue, Device}, optional An array API concept of device where the output array is created. `device` can be ``None``, a oneAPI filter selector string, an instance @@ -290,12 +310,14 @@ def fftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): Default: ``None``. usm_type : {None, "device", "shared", "host"}, optional The type of SYCL USM allocation for the output array. + Default: ``None``. sycl_queue : {None, SyclQueue}, optional A SYCL queue to use for output array allocation and copying. The `sycl_queue` can be passed as ``None`` (the default), which means to get the SYCL queue from `device` keyword if present or to use a default queue. + Default: ``None``. Returns @@ -342,23 +364,19 @@ def fftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): if not dpnp.isscalar(d): raise ValueError("`d` should be an scalar") - cfd_kwarg = { - "device": device, - "usm_type": usm_type, - "sycl_queue": sycl_queue, - } + if dtype and not dpnp.issubdtype(dtype, dpnp.floating): + raise ValueError( + "dtype must a real-valued floating-point data type, " + f"but got {dtype}" + ) val = 1.0 / (n * d) - results = dpnp.empty(n, dtype=dpnp.intp, **cfd_kwarg) + results = dpnp.empty( + n, dtype=dtype, device=device, usm_type=usm_type, sycl_queue=sycl_queue + ) m = (n - 1) // 2 + 1 - p1 = dpnp.arange(0, m, dtype=dpnp.intp, **cfd_kwarg) - - results[:m] = p1 - p2 = dpnp.arange(m - n, 0, dtype=dpnp.intp, **cfd_kwarg) - - results[m:] = p2 - return results * val + return dpnp_fillfreq(results, m, n, val) def fftn(a, s=None, axes=None, norm=None, out=None): @@ -384,7 +402,9 @@ def fftn(a, s=None, axes=None, norm=None, out=None): If it is ``-1``, the whole input is used (no padding/trimming). If `s` is not given, the shape of the input along the axes specified by `axes` is used. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the FFT. If not given, the last ``len(s)`` axes are used, or all axes if `s` is also not specified. @@ -393,16 +413,19 @@ def fftn(a, s=None, axes=None, norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``None``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `s`) and dtype. + Default: ``None``. Returns @@ -476,8 +499,9 @@ def fftshift(x, axes=None): x : {dpnp.ndarray, usm_ndarray} Input array. axes : {None, int, list or tuple of ints}, optional - Axes over which to shift. - Default is ``None``, which shifts all axes. + Axes over which to shift. By default, it shifts over all axes. + + Default: ``None``. Returns ------- @@ -541,19 +565,25 @@ def hfft(a, n=None, axis=-1, norm=None, out=None): input is longer than this, it is cropped. If it is shorter than this, it is padded with zeros. If `n` is not given, it is taken to be ``2*(m-1)`` where `m` is the length of the input along the axis - specified by `axis`. Default: ``None``. + specified by `axis`. + + Default: ``None``. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is - used. Default: ``-1``. + used. + + Default: ``-1``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be placed in this array. It should be of the appropriate shape and dtype. + Default: ``None``. Returns @@ -651,19 +681,24 @@ def ifft(a, n=None, axis=-1, norm=None, out=None): If `n` is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros. If `n` is not given, the length of the input along the axis specified by `axis` is used. + Default: ``None``. axis : int, optional Axis over which to compute the inverse FFT. If not given, the last - axis is used. Default: ``-1``. - norm : {"backward", "ortho", "forward"}, optional + axis is used. + + Default: ``-1``. + norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `n`) and dtype. + Default: ``None``. Returns @@ -736,7 +771,9 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None, out=None): If `s` is not given, the shape of the input along the axes specified by `axes` is used. See notes for issue on :obj:`dpnp.fft.ifft` zero padding. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the inverse FFT. If not given, the last two axes are used. A repeated index in `axes` means the transform over that @@ -744,16 +781,19 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None, out=None): corresponding `axes` to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``(-2, -1)``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `s`) and dtype. + Default: ``None``. Returns @@ -834,7 +874,9 @@ def ifftn(a, s=None, axes=None, norm=None, out=None): If it is ``-1``, the whole input is used (no padding/trimming). if `s` is not given, the shape of the input along the axes specified by `axes` is used. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the inverse FFT. If not given, the last ``len(s)`` axes are used, or all axes if `s` is also not specified. @@ -843,16 +885,19 @@ def ifftn(a, s=None, axes=None, norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``None``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape (consistent with the choice of `s`) and dtype. + Default: ``None``. Returns @@ -914,8 +959,9 @@ def ifftshift(x, axes=None): x : {dpnp.ndarray, usm_ndarray} Input array. axes : {None, int, list or tuple of ints}, optional - Axes over which to calculate. - Defaults to ``None``, which shifts all axes. + Axes over which to shift. By default, it shifts over all axes. + + Default: ``None``. Returns ------- @@ -971,19 +1017,24 @@ def ihfft(a, n=None, axis=-1, norm=None, out=None): the length of the input, the input is cropped. If it is larger, the input is padded with zeros. If `n` is not given, the length of the input along the axis specified by `axis` is used. + Default: ``None``. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is - used. Default: ``-1``. + used. + + Default: ``-1``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape and dtype. + Default: ``None``. Returns @@ -1055,19 +1106,25 @@ def irfft(a, n=None, axis=-1, norm=None, out=None): input is longer than this, it is cropped. If it is shorter than this, it is padded with zeros. If `n` is not given, it is taken to be ``2*(m-1)`` where `m` is the length of the input along the axis - specified by `axis`. Default: ``None``. + specified by `axis`. + + Default: ``None``. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is - used. Default: ``-1``. + used. + + Default: ``-1``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be placed in this array. It should be of the appropriate shape and dtype. + Default: ``None``. Returns @@ -1153,7 +1210,8 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None, out=None): If `s` is not given, the shape of the input along the axes specified by `axes` is used. Except for the last axis which is taken to be ``2*(m-1)`` where `m` is the length of the input along that axis. - If `s` is not ``None``, `axes` must not be ``None`` + If `s` is not ``None``, `axes` must not be ``None`` either. + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the inverse FFT. If not given, the last @@ -1163,17 +1221,20 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``(-2, -1)``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. - out : {None, dpnp.ndarray or usm_ndarray}, optional + out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be placed in this array. It should be of the appropriate dtype and shape for the last transformation (consistent with the choice of `s`). + Default: ``None``. Returns @@ -1250,9 +1311,10 @@ def irfftn(a, s=None, axes=None, norm=None, out=None): the input is cropped. If it is larger, the input is padded with zeros. If it is ``-1``, the whole input is used (no padding/trimming). If `s` is not given, the shape of the input along the axes - specified by axes is used. Except for the last axis which is taken to + specified by `axes` is used. Except for the last axis which is taken to be ``2*(m-1)`` where `m` is the length of the input along that axis. - If `s` is not ``None``, `axes` must not be ``None`` + If `s` is not ``None``, `axes` must not be ``None`` either. + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the inverse FFT. If not given, the last @@ -1262,17 +1324,20 @@ def irfftn(a, s=None, axes=None, norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``None``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. - out : {None, dpnp.ndarray or usm_ndarray}, optional + out : {None, dpnp.ndarray, usm_ndarray}, optional If provided, the result will be placed in this array. It should be of the appropriate dtype and shape for the last transformation (consistent with the choice of `s`). + Default: ``None``. Returns @@ -1356,19 +1421,24 @@ def rfft(a, n=None, axis=-1, norm=None, out=None): If `n` is smaller than the length of the input, the input is cropped. If it is larger, the input is padded with zeros. If `n` is not given, the length of the input along the axis specified by `axis` is used. + Default: ``None``. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is - used. Default: ``-1``. + used. + + Default: ``-1``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate shape and dtype. + Default: ``None``. Returns @@ -1448,7 +1518,9 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None, out=None): If it is ``-1``, the whole input is used (no padding/trimming). If `s` is not given, the shape of the input along the axes specified by `axes` is used. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the FFT. If not given, the last two axes are used. A repeated index in `axes` means the transform over that axis is @@ -1456,17 +1528,20 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``(-2, -1)``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate dtype and shape for the last transformation (consistent with the choice of `s`). + Default: ``None``. Returns @@ -1507,7 +1582,9 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None, out=None): ) -def rfftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): +def rfftfreq( + n, /, d=1.0, *, dtype=None, device=None, usm_type=None, sycl_queue=None +): """ Return the Discrete Fourier Transform sample frequencies (for usage with :obj:`dpnp.fft.rfft`, :obj:`dpnp.fft.irfft`). @@ -1532,7 +1609,14 @@ def rfftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): Window length. d : scalar, optional Sample spacing (inverse of the sampling rate). + Default: ``1.0``. + dtype : {None, str, dtype object}, optional + The output array data type. Must be a real-valued floating-point data + type. If `dtype` is ``None``, the output array data type must be the + default real-valued floating-point data type. + + Default: ``None``. device : {None, string, SyclDevice, SyclQueue, Device}, optional An array API concept of device where the output array is created. `device` can be ``None``, a oneAPI filter selector string, an instance @@ -1544,12 +1628,14 @@ def rfftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): Default: ``None``. usm_type : {None, "device", "shared", "host"}, optional The type of SYCL USM allocation for the output array. + Default: ``None``. sycl_queue : {None, SyclQueue}, optional A SYCL queue to use for output array allocation and copying. The `sycl_queue` can be passed as ``None`` (the default), which means to get the SYCL queue from `device` keyword if present or to use a default queue. + Default: ``None``. Returns @@ -1598,12 +1684,19 @@ def rfftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None): raise ValueError("`n` should be an integer") if not dpnp.isscalar(d): raise ValueError("`d` should be an scalar") + + if dtype and not dpnp.issubdtype(dtype, dpnp.floating): + raise ValueError( + "dtype must a real-valued floating-point data type, " + f"but got {dtype}" + ) + val = 1.0 / (n * d) m = n // 2 + 1 results = dpnp.arange( 0, m, - dtype=dpnp.intp, + dtype=dtype, device=device, usm_type=usm_type, sycl_queue=sycl_queue, @@ -1637,7 +1730,9 @@ def rfftn(a, s=None, axes=None, norm=None, out=None): If it is ``-1``, the whole input is used (no padding/trimming). If `s` is not given, the shape of the input along the axes specified by `axes` is used. If `s` is not ``None``, `axes` must not be ``None`` - either. Default: ``None``. + either. + + Default: ``None``. axes : {None, sequence of ints}, optional Axes over which to compute the FFT. If not given, the last ``len(s)`` axes are used, or all axes if `s` is also not specified. @@ -1646,17 +1741,20 @@ def rfftn(a, s=None, axes=None, norm=None, out=None): to be transformed must be explicitly specified too. A one-element sequence means that a one-dimensional FFT is performed. An empty sequence means that no FFT is performed. + Default: ``None``. norm : {None, "backward", "ortho", "forward"}, optional Normalization mode (see :obj:`dpnp.fft`). Indicates which direction of the forward/backward pair of transforms is scaled and with what normalization factor. ``None`` is an alias of the default option ``"backward"``. + Default: ``"backward"``. out : {None, dpnp.ndarray or usm_ndarray of complex dtype}, optional If provided, the result will be placed in this array. It should be of the appropriate dtype and shape for the last transformation (consistent with the choice of `s`). + Default: ``None``. Returns diff --git a/dpnp/fft/dpnp_utils_fft.py b/dpnp/fft/dpnp_utils_fft.py index c6978eddb120..1393d22255e7 100644 --- a/dpnp/fft/dpnp_utils_fft.py +++ b/dpnp/fft/dpnp_utils_fft.py @@ -60,6 +60,7 @@ __all__ = [ "dpnp_fft", "dpnp_fftn", + "dpnp_fillfreq", ] @@ -698,3 +699,18 @@ def dpnp_fftn(a, forward, real, s=None, axes=None, norm=None, out=None): return _complex_nd_fft( a, s, norm, out, forward, in_place, c2c, axes, a.ndim != len_axes ) + + +def dpnp_fillfreq(a, m, n, val): + """Fill an array with the sample frequencies""" + + exec_q = a.sycl_queue + _manager = dpctl.utils.SequentialOrderManager[exec_q] + + # it's assumed there are no dependent events to populate the array + ht_lin_ev, lin_ev = ti._linspace_step(0, 1, a[:m].get_array(), exec_q) + _manager.add_event_pair(ht_lin_ev, lin_ev) + + ht_lin_ev, lin_ev = ti._linspace_step(m - n, 1, a[m:].get_array(), exec_q) + _manager.add_event_pair(ht_lin_ev, lin_ev) + return a * val diff --git a/dpnp/tests/test_fft.py b/dpnp/tests/test_fft.py index b60ecbba2b5a..8a65d2857a77 100644 --- a/dpnp/tests/test_fft.py +++ b/dpnp/tests/test_fft.py @@ -411,22 +411,35 @@ def test_fft_error(self, xp): assert_raises(IndexError, xp.fft.fft2, a) +@pytest.mark.parametrize("func", ["fftfreq", "rfftfreq"]) class TestFftfreq: - @pytest.mark.parametrize("func", ["fftfreq", "rfftfreq"]) @pytest.mark.parametrize("n", [10, 20]) @pytest.mark.parametrize("d", [0.5, 2]) def test_fftfreq(self, func, n, d): - expected = getattr(dpnp.fft, func)(n, d) - result = getattr(numpy.fft, func)(n, d) - assert_dtype_allclose(expected, result) + result = getattr(dpnp.fft, func)(n, d) + expected = getattr(numpy.fft, func)(n, d) + assert_dtype_allclose(result, expected) - @pytest.mark.parametrize("func", ["fftfreq", "rfftfreq"]) - def test_error(self, func): - # n should be an integer - assert_raises(ValueError, getattr(dpnp.fft, func), 10.0) + @pytest.mark.parametrize("dt", [None] + get_float_dtypes()) + def test_dtype(self, func, dt): + n = 15 + result = getattr(dpnp.fft, func)(n, dtype=dt) + expected = getattr(numpy.fft, func)(n).astype(dt) + assert_dtype_allclose(result, expected) - # d should be an scalar - assert_raises(ValueError, getattr(dpnp.fft, func), 10, (2,)) + def test_error(self, func): + func = getattr(dpnp.fft, func) + # n must be an integer + assert_raises(ValueError, func, 10.0) + + # d must be an scalar + assert_raises(ValueError, func, 10, (2,)) + + # dtype must be None or a real-valued floating-point dtype + # which is passed as a keyword argument only + assert_raises(TypeError, func, 10, 2, None) + assert_raises(ValueError, func, 10, 2, dtype=dpnp.intp) + assert_raises(ValueError, func, 10, 2, dtype=dpnp.complex64) class TestFftn: