# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2016-2024, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
# *****************************************************************************
"""
Interface of the Discrete Fourier Transform part of the DPNP
Notes
-----
This module is a face or public interface file for the library
it contains:
- Interface functions
- documentation for the functions
- The functions parameters check
"""
# pylint: disable=invalid-name
from enum import Enum
import numpy
import dpnp
# pylint: disable=no-name-in-module
from dpnp.dpnp_utils import (
call_origin,
checker_throw_axis_error,
)
from dpnp.fft.dpnp_algo_fft import (
dpnp_fft_deprecated,
dpnp_rfft,
)
from .dpnp_utils_fft import (
dpnp_fft,
)
__all__ = [
"fft",
"fft2",
"fftfreq",
"fftn",
"fftshift",
"hfft",
"ifft",
"ifft2",
"ifftn",
"ifftshift",
"ihfft",
"irfft",
"irfft2",
"irfftn",
"rfft",
"rfft2",
"rfftfreq",
"rfftn",
]
# TODO: remove pylint disable, once new implementation is ready
# pylint: disable=missing-class-docstring
class Norm(Enum):
backward = 0
forward = 1
ortho = 2
# TODO: remove pylint disable, once new implementation is ready
# pylint: disable=missing-function-docstring
def get_validated_norm(norm):
if norm is None or norm == "backward":
return Norm.backward
if norm == "forward":
return Norm.forward
if norm == "ortho":
return Norm.ortho
raise ValueError("Unknown norm value.")
[docs]
def fft(a, n=None, axis=-1, norm=None, out=None):
"""
Compute the one-dimensional discrete Fourier Transform.
For full documentation refer to :obj:`numpy.fft.fft`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array, can be complex.
n : {None, int}, optional
Length of the transformed axis of the output.
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``.
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
-------
out : dpnp.ndarray of complex dtype
The truncated or zero-padded input, transformed along the axis
indicated by `axis`, or the last one if `axis` is not specified.
See Also
--------
:obj:`dpnp.fft` : For definition of the DFT and conventions used.
:obj:`dpnp.fft.ifft` : The inverse of :obj:`dpnp.fft.fft`.
:obj:`dpnp.fft.fft2` : The two-dimensional FFT.
:obj:`dpnp.fft.fftn` : The `n`-dimensional FFT.
:obj:`dpnp.fft.rfftn` : The `n`-dimensional FFT of real input.
:obj:`dpnp.fft.fftfreq` : Frequency bins for given FFT parameters.
Notes
-----
FFT (Fast Fourier Transform) refers to a way the discrete Fourier
Transform (DFT) can be calculated efficiently, by using symmetries in the
calculated terms. The symmetry is highest when `n` is a power of 2, and
the transform is therefore most efficient for these sizes.
Examples
--------
>>> import dpnp as np
>>> a = np.exp(2j * np.pi * np.arange(8) / 8)
>>> np.fft.fft(a)
array([-3.44509285e-16+1.14423775e-17j, 8.00000000e+00-8.52069395e-16j,
2.33486982e-16+1.22464680e-16j, 0.00000000e+00+1.22464680e-16j,
9.95799250e-17+2.33486982e-16j, -8.88178420e-16+1.17281316e-16j,
1.14423775e-17+1.22464680e-16j, 0.00000000e+00+1.22464680e-16j])
"""
dpnp.check_supported_arrays_type(a)
return dpnp_fft(a, forward=True, n=n, axis=axis, norm=norm, out=out)
[docs]
def fft2(x, s=None, axes=(-2, -1), norm=None):
"""
Compute the 2-dimensional discrete Fourier Transform.
Multi-dimensional arrays computed as batch of 1-D arrays.
For full documentation refer to :obj:`numpy.fft.fft2`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
if x_desc:
if norm is not None:
pass
else:
return fftn(x, s, axes, norm)
return call_origin(numpy.fft.fft2, x, s, axes, norm)
[docs]
def fftfreq(n, d=1.0, device=None, usm_type=None, sycl_queue=None):
"""
Return the Discrete Fourier Transform sample frequencies.
The returned float array `f` contains the frequency bin centers in cycles
per unit of the sample spacing (with zero at the start). For instance, if
the sample spacing is in seconds, then the frequency unit is cycles/second.
Given a window length `n` and a sample spacing `d`::
f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even
f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd
For full documentation refer to :obj:`numpy.fft.fftfreq`.
Parameters
----------
n : int
Window length.
d : scalar, optional
Sample spacing (inverse of the sampling rate).
Default: ``1.0``.
device : {None, string, SyclDevice, SyclQueue}, optional
An array API concept of device where the output array is created.
The `device` can be ``None`` (the default), an OneAPI filter selector
string, an instance of :class:`dpctl.SyclDevice` corresponding to
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
or a `Device` object returned by
:obj:`dpnp.dpnp_array.dpnp_array.device` property.
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.
Default: ``None``.
Returns
-------
f : dpnp.ndarray
Array of length `n` containing the sample frequencies.
See Also
--------
:obj:`dpnp.fft.rfftfreq` : Return the Discrete Fourier Transform sample
frequencies (for usage with :obj:`dpnp.fft.rfft` and
:obj:`dpnp.fft.irfft`).
Examples
--------
>>> import dpnp as np
>>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5])
>>> fourier = np.fft.fft(signal)
>>> n = signal.size
>>> timestep = 0.1
>>> freq = np.fft.fftfreq(n, d=timestep)
>>> freq
array([ 0. , 1.25, 2.5 , 3.75, -5. , -3.75, -2.5 , -1.25])
Creating the output array on a different device or with a
specified usm_type:
>>> x = np.fft.fftfreq(n, d=timestep) # default case
>>> x.shape, x.device, x.usm_type
((8,), Device(level_zero:gpu:0), 'device')
>>> y = np.fft.fftfreq(n, d=timestep, device="cpu")
>>> y.shape, y.device, y.usm_type
((8,), Device(opencl:cpu:0), 'device')
>>> z = np.fft.fftfreq(n, d=timestep, usm_type="host")
>>> z.shape, z.device, z.usm_type
((8,), Device(level_zero:gpu:0), 'host')
"""
if not isinstance(n, int):
raise ValueError("`n` should be an integer")
if not dpnp.isscalar(d):
raise ValueError("`d` should be an scalar")
val = 1.0 / (n * d)
results = dpnp.empty(
n,
dtype=dpnp.intp,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
N = (n - 1) // 2 + 1
p1 = dpnp.arange(
0,
N,
dtype=dpnp.intp,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
results[:N] = p1
p2 = dpnp.arange(
-(n // 2),
0,
dtype=dpnp.intp,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
results[N:] = p2
return results * val
[docs]
def fftn(x, s=None, axes=None, norm=None):
"""
Compute the N-dimensional FFT.
Multi-dimensional arrays computed as batch of 1-D arrays.
For full documentation refer to :obj:`numpy.fft.fftn`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
if x_desc:
if s is None:
boundaries = tuple(x_desc.shape[i] for i in range(x_desc.ndim))
else:
boundaries = s
if axes is None:
axes_param = list(range(x_desc.ndim))
else:
axes_param = axes
if norm is not None:
pass
else:
x_iter = x
iteration_list = list(range(len(axes_param)))
iteration_list.reverse() # inplace operation
for it in iteration_list:
param_axis = axes_param[it]
try:
param_n = boundaries[param_axis]
except IndexError:
checker_throw_axis_error(
"fft.fftn",
"is out of bounds",
param_axis,
f"< {len(boundaries)}",
)
x_iter = fft(x_iter, n=param_n, axis=param_axis, norm=norm)
return x_iter
return call_origin(numpy.fft.fftn, x, s, axes, norm)
[docs]
def fftshift(x, axes=None):
"""
Shift the zero-frequency component to the center of the spectrum.
This function swaps half-spaces for all axes listed (defaults to all).
Note that ``out[0]`` is the Nyquist component only if ``len(x)`` is even.
For full documentation refer to :obj:`numpy.fft.fftshift`.
Parameters
----------
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.
Returns
-------
out : dpnp.ndarray
The shifted array.
See Also
--------
:obj:`dpnp.fft.ifftshift` : The inverse of :obj:`dpnp.fft.fftshift`.
Examples
--------
>>> import dpnp as np
>>> freqs = np.fft.fftfreq(10, 0.1)
>>> freqs
array([ 0., 1., 2., 3., 4., -5., -4., -3., -2., -1.])
>>> np.fft.fftshift(freqs)
array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.])
Shift the zero-frequency component only along the second axis:
>>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
>>> freqs
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
>>> np.fft.fftshift(freqs, axes=(1,))
array([[ 2., 0., 1.],
[-4., 3., 4.],
[-1., -3., -2.]])
"""
dpnp.check_supported_arrays_type(x)
if axes is None:
axes = tuple(range(x.ndim))
shift = [dim // 2 for dim in x.shape]
elif isinstance(axes, int):
shift = x.shape[axes] // 2
else:
x_shape = x.shape
shift = [x_shape[ax] // 2 for ax in axes]
return dpnp.roll(x, shift, axes)
[docs]
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 `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.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
norm_ = get_validated_norm(norm)
if axis is None:
axis_param = -1 # the most right dimension (default value)
else:
axis_param = axis
if n is None:
input_boundarie = x_desc.shape[axis_param]
else:
input_boundarie = n
if x.size < 1:
pass # let fallback to handle exception
elif input_boundarie < 1:
pass # let fallback to handle exception
elif norm is not None:
pass
else:
output_boundarie = input_boundarie
return dpnp_fft_deprecated(
x_desc,
input_boundarie,
output_boundarie,
axis_param,
False,
norm_.value,
).get_pyobj()
return call_origin(numpy.fft.hfft, x, n, axis, norm)
[docs]
def ifft(a, n=None, axis=-1, norm=None, out=None):
"""
Compute the one-dimensional inverse discrete Fourier Transform.
For full documentation refer to :obj:`numpy.fft.ifft`.
Parameters
----------
a : {dpnp.ndarray, usm_ndarray}
Input array, can be complex.
n : {None, int}, optional
Length of the transformed axis of the output.
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
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
-------
out : dpnp.ndarray of complex dtype
The truncated or zero-padded input, transformed along the axis
indicated by `axis`, or the last one if `axis` is not specified.
See Also
--------
:obj:`dpnp.fft` : For definition of the DFT and conventions used.
:obj:`dpnp.fft.fft` : The one-dimensional (forward) FFT,
of which :obj:`dpnp.fft.ifft` is the inverse.
:obj:`dpnp.fft.ifft2` : The two-dimensional inverse FFT.
:obj:`dpnp.fft.ifftn` : The `n`-dimensional inverse FFT.
Notes
-----
If the input parameter `n` is larger than the size of the input, the input
is padded by appending zeros at the end. Even though this is the common
approach, it might lead to surprising results. If a different padding is
desired, it must be performed before calling :obj:`dpnp.fft.ifft`.
Examples
--------
>>> import dpnp as np
>>> a = np.array([0, 4, 0, 0])
>>> np.fft.ifft(a)
array([ 1.+0.j, 0.+1.j, -1.+0.j, 0.-1.j]) # may vary
"""
dpnp.check_supported_arrays_type(a)
return dpnp_fft(a, forward=False, n=n, axis=axis, norm=norm, out=out)
[docs]
def ifft2(x, s=None, axes=(-2, -1), norm=None):
"""
Compute the 2-dimensional inverse discrete Fourier Transform.
Multi-dimensional arrays computed as batch of 1-D arrays.
For full documentation refer to :obj:`numpy.fft.ifft2`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
if x_desc:
if norm is not None:
pass
else:
return ifftn(x, s, axes, norm)
return call_origin(numpy.fft.ifft2, x, s, axes, norm)
[docs]
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.
For full documentation refer to :obj:`numpy.fft.ifftn`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
if s is None:
boundaries = tuple(x_desc.shape[i] for i in range(x_desc.ndim))
else:
boundaries = s
if axes is None:
axes_param = list(range(x_desc.ndim))
else:
axes_param = axes
if norm is not None:
pass
else:
x_iter = x
iteration_list = list(range(len(axes_param)))
iteration_list.reverse() # inplace operation
for it in iteration_list:
param_axis = axes_param[it]
try:
param_n = boundaries[param_axis]
except IndexError:
checker_throw_axis_error(
"fft.ifftn",
"is out of bounds",
param_axis,
f"< {len(boundaries)}",
)
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 x_iter
return call_origin(numpy.fft.ifftn, x, s, axes, norm)
[docs]
def ifftshift(x, axes=None):
"""
Inverse shift the zero-frequency component to the center of the spectrum.
Although identical for even-length `x`, the functions differ by one sample
for odd-length `x`.
For full documentation refer to :obj:`numpy.fft.ifftshift`.
Parameters
----------
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.
Returns
-------
out : dpnp.ndarray
The shifted array.
See Also
--------
:obj:`dpnp.fft.fftshift` : Shift zero-frequency component to the center
of the spectrum.
Examples
--------
>>> import dpnp as np
>>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
>>> freqs
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
>>> np.fft.ifftshift(np.fft.fftshift(freqs))
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
"""
dpnp.check_supported_arrays_type(x)
if axes is None:
axes = tuple(range(x.ndim))
shift = [-(dim // 2) for dim in x.shape]
elif isinstance(axes, int):
shift = -(x.shape[axes] // 2)
else:
x_shape = x.shape
shift = [-(x_shape[ax] // 2) for ax in axes]
return dpnp.roll(x, shift, axes)
[docs]
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 `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.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
norm_ = get_validated_norm(norm)
if axis is None:
axis_param = -1 # the most right dimension (default value)
else:
axis_param = axis
if n is None:
input_boundarie = x_desc.shape[axis_param]
else:
input_boundarie = n
if x_desc.size < 1:
pass # let fallback to handle exception
elif input_boundarie < 1:
pass # let fallback to handle exception
elif norm is not None:
pass
elif n is not None:
pass
else:
output_boundarie = input_boundarie
return dpnp_fft_deprecated(
x_desc,
input_boundarie,
output_boundarie,
axis_param,
True,
norm_.value,
).get_pyobj()
return call_origin(numpy.fft.ihfft, x, n, axis, norm)
[docs]
def irfft(x, n=None, axis=-1, norm=None):
"""
Compute the one-dimensional inverse discrete Fourier Transform for real
input.
For full documentation refer to :obj:`numpy.fft.irfft`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
norm_ = get_validated_norm(norm)
if axis is None:
axis_param = -1 # the most right dimension (default value)
else:
axis_param = axis
if n is None:
input_boundarie = x_desc.shape[axis_param]
else:
input_boundarie = n
if x_desc.size < 1:
pass # let fallback to handle exception
elif input_boundarie < 1:
pass # let fallback to handle exception
elif norm is not None:
pass
elif n is not None:
pass
else:
output_boundarie = 2 * (input_boundarie - 1)
result = dpnp_rfft(
x_desc,
input_boundarie,
output_boundarie,
axis_param,
True,
norm_.value,
).get_pyobj()
# TODO:
# tmp = utils.create_output_array(result_shape, result_c_type, out)
# tmp = dpnp.ndarray(result.shape, dtype=dpnp.float64)
# for it in range(tmp.size):
# tmp[it] = result[it].real
return result
return call_origin(numpy.fft.irfft, x, n, axis, norm)
[docs]
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.
For full documentation refer to :obj:`numpy.fft.irfft2`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
if x_desc:
if norm is not None:
pass
else:
return irfftn(x_desc.get_pyobj(), s, axes, norm)
return call_origin(numpy.fft.irfft2, x, s, axes, norm)
[docs]
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.
For full documentation refer to :obj:`numpy.fft.irfftn`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
if s is None:
boundaries = tuple(x_desc.shape[i] for i in range(x_desc.ndim))
else:
boundaries = s
if axes is None:
axes_param = list(range(x_desc.ndim))
else:
axes_param = axes
if norm is not None:
pass
else:
x_iter = x
iteration_list = list(range(len(axes_param)))
iteration_list.reverse() # inplace operation
for it in iteration_list:
param_axis = axes_param[it]
try:
param_n = boundaries[param_axis]
except IndexError:
checker_throw_axis_error(
"fft.irfftn",
"is out of bounds",
param_axis,
f"< {len(boundaries)}",
)
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 x_iter
return call_origin(numpy.fft.irfftn, x, s, axes, norm)
[docs]
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 `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.
"""
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:
axis_param = -1 # the most right dimension (default value)
else:
axis_param = axis
if n is None:
input_boundarie = x_desc.shape[axis_param]
else:
input_boundarie = n
if x_desc.size < 1:
pass # let fallback to handle exception
elif input_boundarie < 1:
pass # let fallback to handle exception
elif axis != -1:
pass
elif norm is not None:
pass
elif n is not None:
pass
elif x_desc.dtype in (numpy.complex128, numpy.complex64):
pass
else:
output_boundarie = (
input_boundarie // 2 + 1
) # rfft specific requirenment
return dpnp_rfft(
x_desc,
input_boundarie,
output_boundarie,
axis_param,
False,
norm_.value,
).get_pyobj()
return call_origin(numpy.fft.rfft, x, n, axis, norm)
[docs]
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.
For full documentation refer to :obj:`numpy.fft.rfft2`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
if x_desc:
if norm is not None:
pass
else:
return rfftn(x_desc.get_pyobj(), s, axes, norm)
return call_origin(numpy.fft.rfft2, x, s, axes, norm)
[docs]
def rfftfreq(n, d=1.0, 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`).
The returned float array `f` contains the frequency bin centers in cycles
per unit of the sample spacing (with zero at the start). For instance, if
the sample spacing is in seconds, then the frequency unit is cycles/second.
Given a window length `n` and a sample spacing `d`::
f = [0, 1, ..., n/2-1, n/2] / (d*n) if n is even
f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) if n is odd
Unlike :obj:`dpnp.fft.fftfreq` the Nyquist frequency component is
considered to be positive.
For full documentation refer to :obj:`numpy.fft.rfftfreq`.
Parameters
----------
n : int
Window length.
d : scalar, optional
Sample spacing (inverse of the sampling rate).
Default: ``1.0``.
device : {None, string, SyclDevice, SyclQueue}, optional
An array API concept of device where the output array is created.
The `device` can be ``None`` (the default), an OneAPI filter selector
string, an instance of :class:`dpctl.SyclDevice` corresponding to
a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`,
or a `Device` object returned by
:obj:`dpnp.dpnp_array.dpnp_array.device` property.
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.
Default: ``None``.
Returns
-------
f : dpnp.ndarray
Array of length ``n//2 + 1`` containing the sample frequencies.
See Also
--------
:obj:`dpnp.fft.fftfreq` : Return the Discrete Fourier Transform sample
frequencies (for usage with :obj:`dpnp.fft.fft` and
:obj:`dpnp.fft.ifft`).
Examples
--------
>>> import dpnp as np
>>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4])
>>> fourier = np.fft.fft(signal)
>>> n = signal.size
>>> sample_rate = 100
>>> freq = np.fft.fftfreq(n, d=1./sample_rate)
>>> freq
array([ 0., 10., 20., 30., 40., -50., -40., -30., -20., -10.])
>>> freq = np.fft.rfftfreq(n, d=1./sample_rate)
>>> freq
array([ 0., 10., 20., 30., 40., 50.])
Creating the output array on a different device or with a
specified usm_type:
>>> x = np.fft.rfftfreq(n, d=1./sample_rate) # default case
>>> x.shape, x.device, x.usm_type
((6,), Device(level_zero:gpu:0), 'device')
>>> y = np.fft.rfftfreq(n, d=1./sample_rate, device="cpu")
>>> y.shape, y.device, y.usm_type
((6,), Device(opencl:cpu:0), 'device')
>>> z = np.fft.rfftfreq(n, d=1./sample_rate, usm_type="host")
>>> z.shape, z.device, z.usm_type
((6,), Device(level_zero:gpu:0), 'host')
"""
if not isinstance(n, int):
raise ValueError("`n` should be an integer")
if not dpnp.isscalar(d):
raise ValueError("`d` should be an scalar")
val = 1.0 / (n * d)
N = n // 2 + 1
results = dpnp.arange(
0,
N,
dtype=dpnp.intp,
device=device,
usm_type=usm_type,
sycl_queue=sycl_queue,
)
return results * val
[docs]
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.
For full documentation refer to :obj:`numpy.fft.rfftn`.
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.
Otherwise the function will be executed sequentially on CPU.
"""
x_desc = dpnp.get_dpnp_descriptor(x, copy_when_nondefault_queue=False)
# TODO: enable implementation
# pylint: disable=condition-evals-to-constant
if x_desc and 0:
if s is None:
boundaries = tuple(x_desc.shape[i] for i in range(x_desc.ndim))
else:
boundaries = s
if axes is None:
axes_param = list(range(x_desc.ndim))
else:
axes_param = axes
if norm is not None:
pass
elif len(axes) < 1:
pass # let fallback to handle exception
else:
x_iter = x
iteration_list = list(range(len(axes_param)))
iteration_list.reverse() # inplace operation
for it in iteration_list:
param_axis = axes_param[it]
try:
param_n = boundaries[param_axis]
except IndexError:
checker_throw_axis_error(
"fft.rfftn",
"is out of bounds",
param_axis,
f"< {len(boundaries)}",
)
x_iter_desc = dpnp.get_dpnp_descriptor(
x_iter, copy_when_nondefault_queue=False
)
x_iter = rfft(
x_iter_desc.get_pyobj(),
n=param_n,
axis=param_axis,
norm=norm,
)
return x_iter
return call_origin(numpy.fft.rfftn, x, s, axes, norm)