diff options
-rw-r--r-- | doc/release/upcoming_changes/16476.new_feature.rst | 9 | ||||
-rw-r--r-- | numpy/core/src/multiarray/abstractdtypes.h | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_coercion.c | 2 | ||||
-rw-r--r-- | numpy/distutils/__init__.py | 4 | ||||
-rw-r--r-- | numpy/fft/__init__.py | 16 | ||||
-rw-r--r-- | numpy/fft/_pocketfft.py | 267 | ||||
-rw-r--r-- | numpy/fft/tests/test_pocketfft.py | 82 | ||||
-rwxr-xr-x | setup.py | 4 |
8 files changed, 277 insertions, 109 deletions
diff --git a/doc/release/upcoming_changes/16476.new_feature.rst b/doc/release/upcoming_changes/16476.new_feature.rst new file mode 100644 index 000000000..acfe0bd72 --- /dev/null +++ b/doc/release/upcoming_changes/16476.new_feature.rst @@ -0,0 +1,9 @@ +``norm=backward``, ``forward`` keyword options for ``numpy.fft`` functions +-------------------------------------------------------------------------- +The keyword argument option ``norm=backward`` is added as an alias for ``None`` +and acts as the default option; using it has the direct transforms unscaled +and the inverse transforms scaled by ``1/n``. + +Using the new keyword argument option ``norm=forward`` has the direct +transforms scaled by ``1/n`` and the inverse transforms unscaled (i.e. exactly +opposite to the default option ``norm=backward``). diff --git a/numpy/core/src/multiarray/abstractdtypes.h b/numpy/core/src/multiarray/abstractdtypes.h index 50239acf2..3a982cd38 100644 --- a/numpy/core/src/multiarray/abstractdtypes.h +++ b/numpy/core/src/multiarray/abstractdtypes.h @@ -14,6 +14,6 @@ NPY_NO_EXPORT extern PyArray_DTypeMeta PyArray_PyFloatAbstractDType; NPY_NO_EXPORT extern PyArray_DTypeMeta PyArray_PyComplexAbstractDType; NPY_NO_EXPORT int -initialize_and_map_pytypes_to_dtypes(); +initialize_and_map_pytypes_to_dtypes(void); #endif /*_NPY_ABSTRACTDTYPES_H */ diff --git a/numpy/core/src/multiarray/array_coercion.c b/numpy/core/src/multiarray/array_coercion.c index 8fe996ed2..9d367da1f 100644 --- a/numpy/core/src/multiarray/array_coercion.c +++ b/numpy/core/src/multiarray/array_coercion.c @@ -102,7 +102,7 @@ enum _dtype_discovery_flags { * @return -1 on error 0 on success */ static int -_prime_global_pytype_to_type_dict() +_prime_global_pytype_to_type_dict(void) { int res; diff --git a/numpy/distutils/__init__.py b/numpy/distutils/__init__.py index 79974d1c2..528b76eb5 100644 --- a/numpy/distutils/__init__.py +++ b/numpy/distutils/__init__.py @@ -18,7 +18,9 @@ LAPACK, and for setting include paths and similar build options, please see ``site.cfg.example`` in the root of the NumPy repository or sdist. """ - +# from setuptools v49.2.0, setuptools warns if distutils is imported first, +# so pre-emptively import setuptools +import setuptools # Must import local ccompiler ASAP in order to get # customized CCompiler.spawn effective. from . import ccompiler diff --git a/numpy/fft/__init__.py b/numpy/fft/__init__.py index 36cfe81b3..af0859def 100644 --- a/numpy/fft/__init__.py +++ b/numpy/fft/__init__.py @@ -128,11 +128,17 @@ promote input arrays, see `scipy.fftpack`. Normalization ------------- -The default normalization has the direct transforms unscaled and the inverse -transforms are scaled by :math:`1/n`. It is possible to obtain unitary -transforms by setting the keyword argument ``norm`` to ``"ortho"`` (default is -`None`) so that both direct and inverse transforms will be scaled by -:math:`1/\\sqrt{n}`. +The argument ``norm`` indicates which direction of the pair of direct/inverse +transforms is scaled and with what normalization factor. +The default normalization (``"backward"``) has the direct (forward) transforms +unscaled and the inverse (backward) transforms scaled by :math:`1/n`. It is +possible to obtain unitary transforms by setting the keyword argument ``norm`` +to ``"ortho"`` so that both direct and inverse transforms are scaled by +:math:`1/\\sqrt{n}`. Finally, setting the keyword argument ``norm`` to +``"forward"`` has the direct transforms scaled by :math:`1/n` and the inverse +transforms unscaled (i.e. exactly opposite to the default ``"backward"``). +`None` is an alias of the default option ``"backward"`` for backward +compatibility. Real and Hermitian transforms ----------------------------- diff --git a/numpy/fft/_pocketfft.py b/numpy/fft/_pocketfft.py index e9f554fe7..38ea69834 100644 --- a/numpy/fft/_pocketfft.py +++ b/numpy/fft/_pocketfft.py @@ -3,20 +3,20 @@ Discrete Fourier Transforms Routines in this module: -fft(a, n=None, axis=-1) -ifft(a, n=None, axis=-1) -rfft(a, n=None, axis=-1) -irfft(a, n=None, axis=-1) -hfft(a, n=None, axis=-1) -ihfft(a, n=None, axis=-1) -fftn(a, s=None, axes=None) -ifftn(a, s=None, axes=None) -rfftn(a, s=None, axes=None) -irfftn(a, s=None, axes=None) -fft2(a, s=None, axes=(-2,-1)) -ifft2(a, s=None, axes=(-2, -1)) -rfft2(a, s=None, axes=(-2,-1)) -irfft2(a, s=None, axes=(-2, -1)) +fft(a, n=None, axis=-1, norm="backward") +ifft(a, n=None, axis=-1, norm="backward") +rfft(a, n=None, axis=-1, norm="backward") +irfft(a, n=None, axis=-1, norm="backward") +hfft(a, n=None, axis=-1, norm="backward") +ihfft(a, n=None, axis=-1, norm="backward") +fftn(a, s=None, axes=None, norm="backward") +ifftn(a, s=None, axes=None, norm="backward") +rfftn(a, s=None, axes=None, norm="backward") +irfftn(a, s=None, axes=None, norm="backward") +fft2(a, s=None, axes=(-2,-1), norm="backward") +ifft2(a, s=None, axes=(-2, -1), norm="backward") +rfft2(a, s=None, axes=(-2,-1), norm="backward") +irfft2(a, s=None, axes=(-2, -1), norm="backward") i = inverse transform r = transform of purely real data @@ -51,10 +51,6 @@ def _raw_fft(a, n, axis, is_real, is_forward, inv_norm): if n is None: n = a.shape[axis] - if n < 1: - raise ValueError("Invalid number of FFT data points (%d) specified." - % n) - fct = 1/inv_norm if a.shape[axis] != n: @@ -79,13 +75,44 @@ def _raw_fft(a, n, axis, is_real, is_forward, inv_norm): return r -def _unitary(norm): - if norm is None: - return False - if norm=="ortho": - return True - raise ValueError("Invalid norm value %s, should be None or \"ortho\"." - % norm) +def _get_forward_norm(n, norm): + if n < 1: + raise ValueError(f"Invalid number of FFT data points ({n}) specified.") + + if norm is None or norm == "backward": + return 1 + elif norm == "ortho": + return sqrt(n) + elif norm == "forward": + return n + raise ValueError(f'Invalid norm value {norm}; should be "backward",' + '"ortho" or "forward".') + + +def _get_backward_norm(n, norm): + if n < 1: + raise ValueError(f"Invalid number of FFT data points ({n}) specified.") + + if norm is None or norm == "backward": + return n + elif norm == "ortho": + return sqrt(n) + elif norm == "forward": + return 1 + raise ValueError(f'Invalid norm value {norm}; should be "backward", ' + '"ortho" or "forward".') + + +_SWAP_DIRECTION_MAP = {"backward": "forward", None: "forward", + "ortho": "ortho", "forward": "backward"} + + +def _swap_direction(norm): + try: + return _SWAP_DIRECTION_MAP[norm] + except KeyError: + raise ValueError(f'Invalid norm value {norm}; should be "backward", ' + '"ortho" or "forward".') def _fft_dispatcher(a, n=None, axis=None, norm=None): @@ -113,10 +140,16 @@ def fft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -175,13 +208,10 @@ def fft(a, n=None, axis=-1, norm=None): >>> plt.show() """ - a = asarray(a) if n is None: n = a.shape[axis] - inv_norm = 1 - if norm is not None and _unitary(norm): - inv_norm = sqrt(n) + inv_norm = _get_forward_norm(n, norm) output = _raw_fft(a, n, axis, False, True, inv_norm) return output @@ -222,10 +252,16 @@ def ifft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the inverse DFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -274,15 +310,11 @@ def ifft(a, n=None, axis=-1, norm=None): a = asarray(a) if n is None: n = a.shape[axis] - if norm is not None and _unitary(norm): - inv_norm = sqrt(max(n, 1)) - else: - inv_norm = n + inv_norm = _get_backward_norm(n, norm) output = _raw_fft(a, n, axis, False, False, inv_norm) return output - @array_function_dispatch(_fft_dispatcher) def rfft(a, n=None, axis=-1, norm=None): """ @@ -304,10 +336,16 @@ def rfft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -363,11 +401,9 @@ def rfft(a, n=None, axis=-1, norm=None): """ a = asarray(a) - inv_norm = 1 - if norm is not None and _unitary(norm): - if n is None: - n = a.shape[axis] - inv_norm = sqrt(n) + if n is None: + n = a.shape[axis] + inv_norm = _get_forward_norm(n, norm) output = _raw_fft(a, n, axis, True, True, inv_norm) return output @@ -402,10 +438,16 @@ def irfft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the inverse FFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -465,9 +507,7 @@ def irfft(a, n=None, axis=-1, norm=None): a = asarray(a) if n is None: n = (a.shape[axis] - 1) * 2 - inv_norm = n - if norm is not None and _unitary(norm): - inv_norm = sqrt(n) + inv_norm = _get_backward_norm(n, norm) output = _raw_fft(a, n, axis, True, False, inv_norm) return output @@ -492,11 +532,17 @@ def hfft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional - Normalization mode (see `numpy.fft`). Default is None. - + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. + Returns ------- out : ndarray @@ -559,8 +605,9 @@ def hfft(a, n=None, axis=-1, norm=None): a = asarray(a) if n is None: n = (a.shape[axis] - 1) * 2 - unitary = _unitary(norm) - return irfft(conjugate(a), n, axis) * (sqrt(n) if unitary else n) + new_norm = _swap_direction(norm) + output = irfft(conjugate(a), n, axis, norm=new_norm) + return output @array_function_dispatch(_fft_dispatcher) @@ -581,11 +628,17 @@ def ihfft(a, n=None, axis=-1, norm=None): axis : int, optional Axis over which to compute the inverse FFT. If not given, the last axis is used. - norm : {None, "ortho"}, optional - Normalization mode (see `numpy.fft`). Default is None. - + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. + Returns ------- out : complex ndarray @@ -619,9 +672,9 @@ def ihfft(a, n=None, axis=-1, norm=None): a = asarray(a) if n is None: n = a.shape[axis] - unitary = _unitary(norm) - output = conjugate(rfft(a, n, axis)) - return output * (1 / (sqrt(n) if unitary else n)) + new_norm = _swap_direction(norm) + output = conjugate(rfft(a, n, axis, norm=new_norm)) + return output def _cook_nd_args(a, s=None, axes=None, invreal=0): @@ -683,10 +736,16 @@ def fftn(a, s=None, axes=None, norm=None): axes are used, or all axes if `s` is also not specified. Repeated indices in `axes` means that the transform over that axis is performed multiple times. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -751,7 +810,6 @@ def fftn(a, s=None, axes=None, norm=None): >>> plt.show() """ - return _raw_fftnd(a, s, axes, fft, norm) @@ -790,10 +848,16 @@ def ifftn(a, s=None, axes=None, norm=None): axes are used, or all axes if `s` is also not specified. Repeated indices in `axes` means that the inverse transform over that axis is performed multiple times. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -849,14 +913,13 @@ def ifftn(a, s=None, axes=None, norm=None): >>> plt.show() """ - return _raw_fftnd(a, s, axes, ifft, norm) @array_function_dispatch(_fftn_dispatcher) def fft2(a, s=None, axes=(-2, -1), norm=None): """ - Compute the 2-dimensional discrete Fourier Transform + Compute the 2-dimensional discrete Fourier Transform. This function computes the *n*-dimensional discrete Fourier Transform over any axes in an *M*-dimensional array by means of the @@ -880,10 +943,16 @@ def fft2(a, s=None, axes=(-2, -1), norm=None): axes are used. A repeated index in `axes` means the transform over that axis is performed multiple times. A one-element sequence means that a one-dimensional FFT is performed. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -940,7 +1009,6 @@ def fft2(a, s=None, axes=(-2, -1), norm=None): 0. +0.j , 0. +0.j ]]) """ - return _raw_fftnd(a, s, axes, fft, norm) @@ -978,10 +1046,16 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None): axes are used. A repeated index in `axes` means the transform over that axis is performed multiple times. A one-element sequence means that a one-dimensional FFT is performed. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -1028,7 +1102,6 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None): [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]]) """ - return _raw_fftnd(a, s, axes, ifft, norm) @@ -1059,10 +1132,16 @@ def rfftn(a, s=None, axes=None, norm=None): axes : 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. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -1137,10 +1216,16 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None): Shape of the FFT. axes : sequence of ints, optional Axes over which to compute the FFT. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -1158,7 +1243,6 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None): For more details see `rfftn`. """ - return rfftn(a, s, axes, norm) @@ -1190,17 +1274,23 @@ def irfftn(a, s=None, axes=None, norm=None): Along any axis, if the shape indicated by `s` is smaller than that of the input, the input is cropped. If it is larger, the input is padded with zeros. 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. + 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. axes : 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. Repeated indices in `axes` means that the inverse transform over that axis is performed multiple times. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -1280,10 +1370,16 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None): axes : sequence of ints, optional The axes over which to compute the inverse fft. Default is the last two axes. - norm : {None, "ortho"}, optional + norm : {"backward", "ortho", "forward"}, optional .. versionadded:: 1.10.0 - Normalization mode (see `numpy.fft`). Default is None. + Normalization mode (see `numpy.fft`). Default is "backward". + Indicates which direction of the forward/backward pair of transforms + is scaled and with what normalization factor. + + .. versionadded:: 1.20.0 + + The "backward", "forward" values were added. Returns ------- @@ -1300,5 +1396,4 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None): For more details see `irfftn`. """ - return irfftn(a, s, axes, norm) diff --git a/numpy/fft/tests/test_pocketfft.py b/numpy/fft/tests/test_pocketfft.py index 7c3db0485..604ac8fde 100644 --- a/numpy/fft/tests/test_pocketfft.py +++ b/numpy/fft/tests/test_pocketfft.py @@ -27,19 +27,22 @@ class TestFFT1D: maxlen = 512 x = random(maxlen) + 1j*random(maxlen) xr = random(maxlen) - for i in range(1,maxlen): + for i in range(1, maxlen): assert_allclose(np.fft.ifft(np.fft.fft(x[0:i])), x[0:i], atol=1e-12) - assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]),i), + assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]), i), xr[0:i], atol=1e-12) def test_fft(self): x = random(30) + 1j*random(30) assert_allclose(fft1(x), np.fft.fft(x), atol=1e-6) + assert_allclose(fft1(x), np.fft.fft(x, norm="backward"), atol=1e-6) assert_allclose(fft1(x) / np.sqrt(30), np.fft.fft(x, norm="ortho"), atol=1e-6) + assert_allclose(fft1(x) / 30., + np.fft.fft(x, norm="forward"), atol=1e-6) - @pytest.mark.parametrize('norm', (None, 'ortho')) + @pytest.mark.parametrize('norm', (None, 'backward', 'ortho', 'forward')) def test_ifft(self, norm): x = random(30) + 1j*random(30) assert_allclose( @@ -54,89 +57,138 @@ class TestFFT1D: x = random((30, 20)) + 1j*random((30, 20)) assert_allclose(np.fft.fft(np.fft.fft(x, axis=1), axis=0), np.fft.fft2(x), atol=1e-6) + assert_allclose(np.fft.fft2(x), + np.fft.fft2(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.fft2(x) / np.sqrt(30 * 20), np.fft.fft2(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.fft2(x) / (30. * 20.), + np.fft.fft2(x, norm="forward"), atol=1e-6) def test_ifft2(self): x = random((30, 20)) + 1j*random((30, 20)) assert_allclose(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0), np.fft.ifft2(x), atol=1e-6) + assert_allclose(np.fft.ifft2(x), + np.fft.ifft2(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.ifft2(x) * np.sqrt(30 * 20), np.fft.ifft2(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.ifft2(x) * (30. * 20.), + np.fft.ifft2(x, norm="forward"), atol=1e-6) def test_fftn(self): x = random((30, 20, 10)) + 1j*random((30, 20, 10)) assert_allclose( np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0), np.fft.fftn(x), atol=1e-6) + assert_allclose(np.fft.fftn(x), + np.fft.fftn(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.fftn(x) / np.sqrt(30 * 20 * 10), np.fft.fftn(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.fftn(x) / (30. * 20. * 10.), + np.fft.fftn(x, norm="forward"), atol=1e-6) def test_ifftn(self): x = random((30, 20, 10)) + 1j*random((30, 20, 10)) assert_allclose( np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0), np.fft.ifftn(x), atol=1e-6) + assert_allclose(np.fft.ifftn(x), + np.fft.ifftn(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10), np.fft.ifftn(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.ifftn(x) * (30. * 20. * 10.), + np.fft.ifftn(x, norm="forward"), atol=1e-6) def test_rfft(self): x = random(30) for n in [x.size, 2*x.size]: - for norm in [None, 'ortho']: + for norm in [None, 'backward', 'ortho', 'forward']: assert_allclose( np.fft.fft(x, n=n, norm=norm)[:(n//2 + 1)], np.fft.rfft(x, n=n, norm=norm), atol=1e-6) assert_allclose( + np.fft.rfft(x, n=n), + np.fft.rfft(x, n=n, norm="backward"), atol=1e-6) + assert_allclose( np.fft.rfft(x, n=n) / np.sqrt(n), np.fft.rfft(x, n=n, norm="ortho"), atol=1e-6) + assert_allclose( + np.fft.rfft(x, n=n) / n, + np.fft.rfft(x, n=n, norm="forward"), atol=1e-6) def test_irfft(self): x = random(30) assert_allclose(x, np.fft.irfft(np.fft.rfft(x)), atol=1e-6) - assert_allclose( - x, np.fft.irfft(np.fft.rfft(x, norm="ortho"), norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="backward"), + norm="backward"), atol=1e-6) + assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="ortho"), + norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="forward"), + norm="forward"), atol=1e-6) def test_rfft2(self): x = random((30, 20)) assert_allclose(np.fft.fft2(x)[:, :11], np.fft.rfft2(x), atol=1e-6) + assert_allclose(np.fft.rfft2(x), + np.fft.rfft2(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.rfft2(x) / np.sqrt(30 * 20), np.fft.rfft2(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.rfft2(x) / (30. * 20.), + np.fft.rfft2(x, norm="forward"), atol=1e-6) def test_irfft2(self): x = random((30, 20)) assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x)), atol=1e-6) - assert_allclose( - x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"), norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="backward"), + norm="backward"), atol=1e-6) + assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"), + norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="forward"), + norm="forward"), atol=1e-6) def test_rfftn(self): x = random((30, 20, 10)) assert_allclose(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x), atol=1e-6) + assert_allclose(np.fft.rfftn(x), + np.fft.rfftn(x, norm="backward"), atol=1e-6) assert_allclose(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10), np.fft.rfftn(x, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.rfftn(x) / (30. * 20. * 10.), + np.fft.rfftn(x, norm="forward"), atol=1e-6) def test_irfftn(self): x = random((30, 20, 10)) assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x)), atol=1e-6) - assert_allclose( - x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"), norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="backward"), + norm="backward"), atol=1e-6) + assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"), + norm="ortho"), atol=1e-6) + assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="forward"), + norm="forward"), atol=1e-6) def test_hfft(self): x = random(14) + 1j*random(14) x_herm = np.concatenate((random(1), x, random(1))) x = np.concatenate((x_herm, x[::-1].conj())) assert_allclose(np.fft.fft(x), np.fft.hfft(x_herm), atol=1e-6) + assert_allclose(np.fft.hfft(x_herm), + np.fft.hfft(x_herm, norm="backward"), atol=1e-6) assert_allclose(np.fft.hfft(x_herm) / np.sqrt(30), np.fft.hfft(x_herm, norm="ortho"), atol=1e-6) + assert_allclose(np.fft.hfft(x_herm) / 30., + np.fft.hfft(x_herm, norm="forward"), atol=1e-6) - def test_ihttf(self): + def test_ihfft(self): x = random(14) + 1j*random(14) x_herm = np.concatenate((random(1), x, random(1))) x = np.concatenate((x_herm, x[::-1].conj())) assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm)), atol=1e-6) - assert_allclose( - x_herm, np.fft.ihfft(np.fft.hfft(x_herm, norm="ortho"), - norm="ortho"), atol=1e-6) + assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm, + norm="backward"), norm="backward"), atol=1e-6) + assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm, + norm="ortho"), norm="ortho"), atol=1e-6) + assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm, + norm="forward"), norm="forward"), atol=1e-6) @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn, np.fft.rfftn, np.fft.irfftn]) @@ -161,7 +213,7 @@ class TestFFT1D: ] for forw, back in func_pairs: for n in [x.size, 2*x.size]: - for norm in [None, 'ortho']: + for norm in [None, 'backward', 'ortho', 'forward']: tmp = forw(x, n=n, norm=norm) tmp = back(tmp, n=n, norm=norm) assert_allclose(x_norm, @@ -219,6 +219,10 @@ class concat_license_files(): f.write(self.bsd_text) +# from setuptools v49.2.0, setuptools warns if distutils is imported first, +# so pre-emptively import setuptools. Eventually we can migrate to using +# setuptools.command +import setuptools from distutils.command.sdist import sdist class sdist_checked(sdist): """ check submodules on sdist to prevent incomplete tarballs """ |