123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 |
- # Created by Pearu Peterson, September 2002
- from __future__ import division, print_function, absolute_import
- __usage__ = """
- Build fftpack:
- python setup_fftpack.py build
- Run tests if scipy is installed:
- python -c 'import scipy;scipy.fftpack.test()'
- Run tests if fftpack is not installed:
- python tests/test_basic.py
- """
- from numpy.testing import (assert_, assert_equal, assert_array_almost_equal,
- assert_array_almost_equal_nulp, assert_array_less)
- import pytest
- from pytest import raises as assert_raises
- from scipy.fftpack import ifft, fft, fftn, ifftn, rfft, irfft, fft2
- from scipy.fftpack import _fftpack as fftpack
- from scipy.fftpack.basic import _is_safe_size
- from numpy import (arange, add, array, asarray, zeros, dot, exp, pi,
- swapaxes, double, cdouble)
- import numpy as np
- import numpy.fft
- from numpy.random import rand
- # "large" composite numbers supported by FFTPACK
- LARGE_COMPOSITE_SIZES = [
- 2**13,
- 2**5 * 3**5,
- 2**3 * 3**3 * 5**2,
- ]
- SMALL_COMPOSITE_SIZES = [
- 2,
- 2*3*5,
- 2*2*3*3,
- ]
- # prime
- LARGE_PRIME_SIZES = [
- 2011
- ]
- SMALL_PRIME_SIZES = [
- 29
- ]
- def _assert_close_in_norm(x, y, rtol, size, rdt):
- # helper function for testing
- err_msg = "size: %s rdt: %s" % (size, rdt)
- assert_array_less(np.linalg.norm(x - y), rtol*np.linalg.norm(x), err_msg)
- def random(size):
- return rand(*size)
- def get_mat(n):
- data = arange(n)
- data = add.outer(data, data)
- return data
- def direct_dft(x):
- x = asarray(x)
- n = len(x)
- y = zeros(n, dtype=cdouble)
- w = -arange(n)*(2j*pi/n)
- for i in range(n):
- y[i] = dot(exp(i*w), x)
- return y
- def direct_idft(x):
- x = asarray(x)
- n = len(x)
- y = zeros(n, dtype=cdouble)
- w = arange(n)*(2j*pi/n)
- for i in range(n):
- y[i] = dot(exp(i*w), x)/n
- return y
- def direct_dftn(x):
- x = asarray(x)
- for axis in range(len(x.shape)):
- x = fft(x, axis=axis)
- return x
- def direct_idftn(x):
- x = asarray(x)
- for axis in range(len(x.shape)):
- x = ifft(x, axis=axis)
- return x
- def direct_rdft(x):
- x = asarray(x)
- n = len(x)
- w = -arange(n)*(2j*pi/n)
- r = zeros(n, dtype=double)
- for i in range(n//2+1):
- y = dot(exp(i*w), x)
- if i:
- r[2*i-1] = y.real
- if 2*i < n:
- r[2*i] = y.imag
- else:
- r[0] = y.real
- return r
- def direct_irdft(x):
- x = asarray(x)
- n = len(x)
- x1 = zeros(n, dtype=cdouble)
- for i in range(n//2+1):
- if i:
- if 2*i < n:
- x1[i] = x[2*i-1] + 1j*x[2*i]
- x1[n-i] = x[2*i-1] - 1j*x[2*i]
- else:
- x1[i] = x[2*i-1]
- else:
- x1[0] = x[0]
- return direct_idft(x1).real
- class _TestFFTBase(object):
- def setup_method(self):
- self.cdt = None
- self.rdt = None
- np.random.seed(1234)
- def test_definition(self):
- x = np.array([1,2,3,4+1j,1,2,3,4+2j], dtype=self.cdt)
- y = fft(x)
- assert_equal(y.dtype, self.cdt)
- y1 = direct_dft(x)
- assert_array_almost_equal(y,y1)
- x = np.array([1,2,3,4+0j,5], dtype=self.cdt)
- assert_array_almost_equal(fft(x),direct_dft(x))
- def test_n_argument_real(self):
- x1 = np.array([1,2,3,4], dtype=self.rdt)
- x2 = np.array([1,2,3,4], dtype=self.rdt)
- y = fft([x1,x2],n=4)
- assert_equal(y.dtype, self.cdt)
- assert_equal(y.shape,(2,4))
- assert_array_almost_equal(y[0],direct_dft(x1))
- assert_array_almost_equal(y[1],direct_dft(x2))
- def _test_n_argument_complex(self):
- x1 = np.array([1,2,3,4+1j], dtype=self.cdt)
- x2 = np.array([1,2,3,4+1j], dtype=self.cdt)
- y = fft([x1,x2],n=4)
- assert_equal(y.dtype, self.cdt)
- assert_equal(y.shape,(2,4))
- assert_array_almost_equal(y[0],direct_dft(x1))
- assert_array_almost_equal(y[1],direct_dft(x2))
- def test_djbfft(self):
- for i in range(2,14):
- n = 2**i
- x = list(range(n))
- y = fftpack.zfft(x)
- y2 = numpy.fft.fft(x)
- assert_array_almost_equal(y,y2)
- y = fftpack.zrfft(x)
- assert_array_almost_equal(y,y2)
- def test_invalid_sizes(self):
- assert_raises(ValueError, fft, [])
- assert_raises(ValueError, fft, [[1,1],[2,2]], -5)
- def test__is_safe_size(self):
- vals = [(0, True), (1, True), (2, True), (3, True), (4, True), (5, True), (6, True), (7, False),
- (15, True), (16, True), (17, False), (18, True), (21, False), (25, True), (50, True),
- (120, True), (210, False)]
- for n, is_safe in vals:
- assert_equal(_is_safe_size(n), is_safe)
- class TestDoubleFFT(_TestFFTBase):
- def setup_method(self):
- self.cdt = np.cdouble
- self.rdt = np.double
- class TestSingleFFT(_TestFFTBase):
- def setup_method(self):
- self.cdt = np.complex64
- self.rdt = np.float32
- @pytest.mark.xfail(run=False, reason="single-precision FFT implementation is partially disabled, until accuracy issues with large prime powers are resolved")
- def test_notice(self):
- pass
- class TestFloat16FFT(object):
- def test_1_argument_real(self):
- x1 = np.array([1, 2, 3, 4], dtype=np.float16)
- y = fft(x1, n=4)
- assert_equal(y.dtype, np.complex64)
- assert_equal(y.shape, (4, ))
- assert_array_almost_equal(y, direct_dft(x1.astype(np.float32)))
- def test_n_argument_real(self):
- x1 = np.array([1, 2, 3, 4], dtype=np.float16)
- x2 = np.array([1, 2, 3, 4], dtype=np.float16)
- y = fft([x1, x2], n=4)
- assert_equal(y.dtype, np.complex64)
- assert_equal(y.shape, (2, 4))
- assert_array_almost_equal(y[0], direct_dft(x1.astype(np.float32)))
- assert_array_almost_equal(y[1], direct_dft(x2.astype(np.float32)))
- class _TestIFFTBase(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_definition(self):
- x = np.array([1,2,3,4+1j,1,2,3,4+2j], self.cdt)
- y = ifft(x)
- y1 = direct_idft(x)
- assert_equal(y.dtype, self.cdt)
- assert_array_almost_equal(y,y1)
- x = np.array([1,2,3,4+0j,5], self.cdt)
- assert_array_almost_equal(ifft(x),direct_idft(x))
- def test_definition_real(self):
- x = np.array([1,2,3,4,1,2,3,4], self.rdt)
- y = ifft(x)
- assert_equal(y.dtype, self.cdt)
- y1 = direct_idft(x)
- assert_array_almost_equal(y,y1)
- x = np.array([1,2,3,4,5], dtype=self.rdt)
- assert_equal(y.dtype, self.cdt)
- assert_array_almost_equal(ifft(x),direct_idft(x))
- def test_djbfft(self):
- for i in range(2,14):
- n = 2**i
- x = list(range(n))
- y = fftpack.zfft(x,direction=-1)
- y2 = numpy.fft.ifft(x)
- assert_array_almost_equal(y,y2)
- y = fftpack.zrfft(x,direction=-1)
- assert_array_almost_equal(y,y2)
- def test_random_complex(self):
- for size in [1,51,111,100,200,64,128,256,1024]:
- x = random([size]).astype(self.cdt)
- x = random([size]).astype(self.cdt) + 1j*x
- y1 = ifft(fft(x))
- y2 = fft(ifft(x))
- assert_equal(y1.dtype, self.cdt)
- assert_equal(y2.dtype, self.cdt)
- assert_array_almost_equal(y1, x)
- assert_array_almost_equal(y2, x)
- def test_random_real(self):
- for size in [1,51,111,100,200,64,128,256,1024]:
- x = random([size]).astype(self.rdt)
- y1 = ifft(fft(x))
- y2 = fft(ifft(x))
- assert_equal(y1.dtype, self.cdt)
- assert_equal(y2.dtype, self.cdt)
- assert_array_almost_equal(y1, x)
- assert_array_almost_equal(y2, x)
- def test_size_accuracy(self):
- # Sanity check for the accuracy for prime and non-prime sized inputs
- if self.rdt == np.float32:
- rtol = 1e-5
- elif self.rdt == np.float64:
- rtol = 1e-10
- for size in LARGE_COMPOSITE_SIZES + LARGE_PRIME_SIZES:
- np.random.seed(1234)
- x = np.random.rand(size).astype(self.rdt)
- y = ifft(fft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- y = fft(ifft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- x = (x + 1j*np.random.rand(size)).astype(self.cdt)
- y = ifft(fft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- y = fft(ifft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- def test_invalid_sizes(self):
- assert_raises(ValueError, ifft, [])
- assert_raises(ValueError, ifft, [[1,1],[2,2]], -5)
- class TestDoubleIFFT(_TestIFFTBase):
- def setup_method(self):
- self.cdt = np.cdouble
- self.rdt = np.double
- class TestSingleIFFT(_TestIFFTBase):
- def setup_method(self):
- self.cdt = np.complex64
- self.rdt = np.float32
- class _TestRFFTBase(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_definition(self):
- for t in [[1, 2, 3, 4, 1, 2, 3, 4], [1, 2, 3, 4, 1, 2, 3, 4, 5]]:
- x = np.array(t, dtype=self.rdt)
- y = rfft(x)
- y1 = direct_rdft(x)
- assert_array_almost_equal(y,y1)
- assert_equal(y.dtype, self.rdt)
- def test_djbfft(self):
- from numpy.fft import fft as numpy_fft
- for i in range(2,14):
- n = 2**i
- x = list(range(n))
- y2 = numpy_fft(x)
- y1 = zeros((n,),dtype=double)
- y1[0] = y2[0].real
- y1[-1] = y2[n//2].real
- for k in range(1, n//2):
- y1[2*k-1] = y2[k].real
- y1[2*k] = y2[k].imag
- y = fftpack.drfft(x)
- assert_array_almost_equal(y,y1)
- def test_invalid_sizes(self):
- assert_raises(ValueError, rfft, [])
- assert_raises(ValueError, rfft, [[1,1],[2,2]], -5)
- # See gh-5790
- class MockSeries(object):
- def __init__(self, data):
- self.data = np.asarray(data)
- def __getattr__(self, item):
- try:
- return getattr(self.data, item)
- except AttributeError:
- raise AttributeError(("'MockSeries' object "
- "has no attribute '{attr}'".
- format(attr=item)))
- def test_non_ndarray_with_dtype(self):
- x = np.array([1., 2., 3., 4., 5.])
- xs = _TestRFFTBase.MockSeries(x)
- expected = [1, 2, 3, 4, 5]
- out = rfft(xs)
- # Data should not have been overwritten
- assert_equal(x, expected)
- assert_equal(xs.data, expected)
- class TestRFFTDouble(_TestRFFTBase):
- def setup_method(self):
- self.cdt = np.cdouble
- self.rdt = np.double
- class TestRFFTSingle(_TestRFFTBase):
- def setup_method(self):
- self.cdt = np.complex64
- self.rdt = np.float32
- class _TestIRFFTBase(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_definition(self):
- x1 = [1,2,3,4,1,2,3,4]
- x1_1 = [1,2+3j,4+1j,2+3j,4,2-3j,4-1j,2-3j]
- x2 = [1,2,3,4,1,2,3,4,5]
- x2_1 = [1,2+3j,4+1j,2+3j,4+5j,4-5j,2-3j,4-1j,2-3j]
- def _test(x, xr):
- y = irfft(np.array(x, dtype=self.rdt))
- y1 = direct_irdft(x)
- assert_equal(y.dtype, self.rdt)
- assert_array_almost_equal(y,y1, decimal=self.ndec)
- assert_array_almost_equal(y,ifft(xr), decimal=self.ndec)
- _test(x1, x1_1)
- _test(x2, x2_1)
- def test_djbfft(self):
- from numpy.fft import ifft as numpy_ifft
- for i in range(2,14):
- n = 2**i
- x = list(range(n))
- x1 = zeros((n,),dtype=cdouble)
- x1[0] = x[0]
- for k in range(1, n//2):
- x1[k] = x[2*k-1]+1j*x[2*k]
- x1[n-k] = x[2*k-1]-1j*x[2*k]
- x1[n//2] = x[-1]
- y1 = numpy_ifft(x1)
- y = fftpack.drfft(x,direction=-1)
- assert_array_almost_equal(y,y1)
- def test_random_real(self):
- for size in [1,51,111,100,200,64,128,256,1024]:
- x = random([size]).astype(self.rdt)
- y1 = irfft(rfft(x))
- y2 = rfft(irfft(x))
- assert_equal(y1.dtype, self.rdt)
- assert_equal(y2.dtype, self.rdt)
- assert_array_almost_equal(y1, x, decimal=self.ndec,
- err_msg="size=%d" % size)
- assert_array_almost_equal(y2, x, decimal=self.ndec,
- err_msg="size=%d" % size)
- def test_size_accuracy(self):
- # Sanity check for the accuracy for prime and non-prime sized inputs
- if self.rdt == np.float32:
- rtol = 1e-5
- elif self.rdt == np.float64:
- rtol = 1e-10
- for size in LARGE_COMPOSITE_SIZES + LARGE_PRIME_SIZES:
- np.random.seed(1234)
- x = np.random.rand(size).astype(self.rdt)
- y = irfft(rfft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- y = rfft(irfft(x))
- _assert_close_in_norm(x, y, rtol, size, self.rdt)
- def test_invalid_sizes(self):
- assert_raises(ValueError, irfft, [])
- assert_raises(ValueError, irfft, [[1,1],[2,2]], -5)
- # self.ndec is bogus; we should have a assert_array_approx_equal for number of
- # significant digits
- class TestIRFFTDouble(_TestIRFFTBase):
- def setup_method(self):
- self.cdt = np.cdouble
- self.rdt = np.double
- self.ndec = 14
- class TestIRFFTSingle(_TestIRFFTBase):
- def setup_method(self):
- self.cdt = np.complex64
- self.rdt = np.float32
- self.ndec = 5
- class Testfft2(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_regression_244(self):
- """FFT returns wrong result with axes parameter."""
- # fftn (and hence fft2) used to break when both axes and shape were
- # used
- x = numpy.ones((4, 4, 2))
- y = fft2(x, shape=(8, 8), axes=(-3, -2))
- y_r = numpy.fft.fftn(x, s=(8, 8), axes=(-3, -2))
- assert_array_almost_equal(y, y_r)
- def test_invalid_sizes(self):
- assert_raises(ValueError, fft2, [[]])
- assert_raises(ValueError, fft2, [[1, 1], [2, 2]], (4, -3))
- class TestFftnSingle(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_definition(self):
- x = [[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]]
- y = fftn(np.array(x, np.float32))
- assert_(y.dtype == np.complex64,
- msg="double precision output with single precision")
- y_r = np.array(fftn(x), np.complex64)
- assert_array_almost_equal_nulp(y, y_r)
- @pytest.mark.parametrize('size', SMALL_COMPOSITE_SIZES + SMALL_PRIME_SIZES)
- def test_size_accuracy_small(self, size):
- x = np.random.rand(size, size) + 1j*np.random.rand(size, size)
- y1 = fftn(x.real.astype(np.float32))
- y2 = fftn(x.real.astype(np.float64)).astype(np.complex64)
- assert_equal(y1.dtype, np.complex64)
- assert_array_almost_equal_nulp(y1, y2, 2000)
- @pytest.mark.parametrize('size', LARGE_COMPOSITE_SIZES + LARGE_PRIME_SIZES)
- def test_size_accuracy_large(self, size):
- x = np.random.rand(size, 3) + 1j*np.random.rand(size, 3)
- y1 = fftn(x.real.astype(np.float32))
- y2 = fftn(x.real.astype(np.float64)).astype(np.complex64)
- assert_equal(y1.dtype, np.complex64)
- assert_array_almost_equal_nulp(y1, y2, 2000)
- def test_definition_float16(self):
- x = [[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]]
- y = fftn(np.array(x, np.float16))
- assert_equal(y.dtype, np.complex64)
- y_r = np.array(fftn(x), np.complex64)
- assert_array_almost_equal_nulp(y, y_r)
- @pytest.mark.parametrize('size', SMALL_COMPOSITE_SIZES + SMALL_PRIME_SIZES)
- def test_float16_input_small(self, size):
- x = np.random.rand(size, size) + 1j*np.random.rand(size, size)
- y1 = fftn(x.real.astype(np.float16))
- y2 = fftn(x.real.astype(np.float64)).astype(np.complex64)
- assert_equal(y1.dtype, np.complex64)
- assert_array_almost_equal_nulp(y1, y2, 5e5)
- @pytest.mark.parametrize('size', LARGE_COMPOSITE_SIZES + LARGE_PRIME_SIZES)
- def test_float16_input_large(self, size):
- x = np.random.rand(size, 3) + 1j*np.random.rand(size, 3)
- y1 = fftn(x.real.astype(np.float16))
- y2 = fftn(x.real.astype(np.float64)).astype(np.complex64)
- assert_equal(y1.dtype, np.complex64)
- assert_array_almost_equal_nulp(y1, y2, 2e6)
- class TestFftn(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_definition(self):
- x = [[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]]
- y = fftn(x)
- assert_array_almost_equal(y, direct_dftn(x))
- x = random((20, 26))
- assert_array_almost_equal(fftn(x), direct_dftn(x))
- x = random((5, 4, 3, 20))
- assert_array_almost_equal(fftn(x), direct_dftn(x))
- def test_axes_argument(self):
- # plane == ji_plane, x== kji_space
- plane1 = [[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]]
- plane2 = [[10, 11, 12],
- [13, 14, 15],
- [16, 17, 18]]
- plane3 = [[19, 20, 21],
- [22, 23, 24],
- [25, 26, 27]]
- ki_plane1 = [[1, 2, 3],
- [10, 11, 12],
- [19, 20, 21]]
- ki_plane2 = [[4, 5, 6],
- [13, 14, 15],
- [22, 23, 24]]
- ki_plane3 = [[7, 8, 9],
- [16, 17, 18],
- [25, 26, 27]]
- jk_plane1 = [[1, 10, 19],
- [4, 13, 22],
- [7, 16, 25]]
- jk_plane2 = [[2, 11, 20],
- [5, 14, 23],
- [8, 17, 26]]
- jk_plane3 = [[3, 12, 21],
- [6, 15, 24],
- [9, 18, 27]]
- kj_plane1 = [[1, 4, 7],
- [10, 13, 16], [19, 22, 25]]
- kj_plane2 = [[2, 5, 8],
- [11, 14, 17], [20, 23, 26]]
- kj_plane3 = [[3, 6, 9],
- [12, 15, 18], [21, 24, 27]]
- ij_plane1 = [[1, 4, 7],
- [2, 5, 8],
- [3, 6, 9]]
- ij_plane2 = [[10, 13, 16],
- [11, 14, 17],
- [12, 15, 18]]
- ij_plane3 = [[19, 22, 25],
- [20, 23, 26],
- [21, 24, 27]]
- ik_plane1 = [[1, 10, 19],
- [2, 11, 20],
- [3, 12, 21]]
- ik_plane2 = [[4, 13, 22],
- [5, 14, 23],
- [6, 15, 24]]
- ik_plane3 = [[7, 16, 25],
- [8, 17, 26],
- [9, 18, 27]]
- ijk_space = [jk_plane1, jk_plane2, jk_plane3]
- ikj_space = [kj_plane1, kj_plane2, kj_plane3]
- jik_space = [ik_plane1, ik_plane2, ik_plane3]
- jki_space = [ki_plane1, ki_plane2, ki_plane3]
- kij_space = [ij_plane1, ij_plane2, ij_plane3]
- x = array([plane1, plane2, plane3])
- assert_array_almost_equal(fftn(x),
- fftn(x, axes=(-3, -2, -1))) # kji_space
- assert_array_almost_equal(fftn(x), fftn(x, axes=(0, 1, 2)))
- assert_array_almost_equal(fftn(x, axes=(0, 2)), fftn(x, axes=(0, -1)))
- y = fftn(x, axes=(2, 1, 0)) # ijk_space
- assert_array_almost_equal(swapaxes(y, -1, -3), fftn(ijk_space))
- y = fftn(x, axes=(2, 0, 1)) # ikj_space
- assert_array_almost_equal(swapaxes(swapaxes(y, -1, -3), -1, -2),
- fftn(ikj_space))
- y = fftn(x, axes=(1, 2, 0)) # jik_space
- assert_array_almost_equal(swapaxes(swapaxes(y, -1, -3), -3, -2),
- fftn(jik_space))
- y = fftn(x, axes=(1, 0, 2)) # jki_space
- assert_array_almost_equal(swapaxes(y, -2, -3), fftn(jki_space))
- y = fftn(x, axes=(0, 2, 1)) # kij_space
- assert_array_almost_equal(swapaxes(y, -2, -1), fftn(kij_space))
- y = fftn(x, axes=(-2, -1)) # ji_plane
- assert_array_almost_equal(fftn(plane1), y[0])
- assert_array_almost_equal(fftn(plane2), y[1])
- assert_array_almost_equal(fftn(plane3), y[2])
- y = fftn(x, axes=(1, 2)) # ji_plane
- assert_array_almost_equal(fftn(plane1), y[0])
- assert_array_almost_equal(fftn(plane2), y[1])
- assert_array_almost_equal(fftn(plane3), y[2])
- y = fftn(x, axes=(-3, -2)) # kj_plane
- assert_array_almost_equal(fftn(x[:, :, 0]), y[:, :, 0])
- assert_array_almost_equal(fftn(x[:, :, 1]), y[:, :, 1])
- assert_array_almost_equal(fftn(x[:, :, 2]), y[:, :, 2])
- y = fftn(x, axes=(-3, -1)) # ki_plane
- assert_array_almost_equal(fftn(x[:, 0, :]), y[:, 0, :])
- assert_array_almost_equal(fftn(x[:, 1, :]), y[:, 1, :])
- assert_array_almost_equal(fftn(x[:, 2, :]), y[:, 2, :])
- y = fftn(x, axes=(-1, -2)) # ij_plane
- assert_array_almost_equal(fftn(ij_plane1), swapaxes(y[0], -2, -1))
- assert_array_almost_equal(fftn(ij_plane2), swapaxes(y[1], -2, -1))
- assert_array_almost_equal(fftn(ij_plane3), swapaxes(y[2], -2, -1))
- y = fftn(x, axes=(-1, -3)) # ik_plane
- assert_array_almost_equal(fftn(ik_plane1),
- swapaxes(y[:, 0, :], -1, -2))
- assert_array_almost_equal(fftn(ik_plane2),
- swapaxes(y[:, 1, :], -1, -2))
- assert_array_almost_equal(fftn(ik_plane3),
- swapaxes(y[:, 2, :], -1, -2))
- y = fftn(x, axes=(-2, -3)) # jk_plane
- assert_array_almost_equal(fftn(jk_plane1),
- swapaxes(y[:, :, 0], -1, -2))
- assert_array_almost_equal(fftn(jk_plane2),
- swapaxes(y[:, :, 1], -1, -2))
- assert_array_almost_equal(fftn(jk_plane3),
- swapaxes(y[:, :, 2], -1, -2))
- y = fftn(x, axes=(-1,)) # i_line
- for i in range(3):
- for j in range(3):
- assert_array_almost_equal(fft(x[i, j, :]), y[i, j, :])
- y = fftn(x, axes=(-2,)) # j_line
- for i in range(3):
- for j in range(3):
- assert_array_almost_equal(fft(x[i, :, j]), y[i, :, j])
- y = fftn(x, axes=(0,)) # k_line
- for i in range(3):
- for j in range(3):
- assert_array_almost_equal(fft(x[:, i, j]), y[:, i, j])
- y = fftn(x, axes=()) # point
- assert_array_almost_equal(y, x)
- def test_shape_argument(self):
- small_x = [[1, 2, 3],
- [4, 5, 6]]
- large_x1 = [[1, 2, 3, 0],
- [4, 5, 6, 0],
- [0, 0, 0, 0],
- [0, 0, 0, 0]]
- y = fftn(small_x, shape=(4, 4))
- assert_array_almost_equal(y, fftn(large_x1))
- y = fftn(small_x, shape=(3, 4))
- assert_array_almost_equal(y, fftn(large_x1[:-1]))
- def test_shape_axes_argument(self):
- small_x = [[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]]
- large_x1 = array([[1, 2, 3, 0],
- [4, 5, 6, 0],
- [7, 8, 9, 0],
- [0, 0, 0, 0]])
- y = fftn(small_x, shape=(4, 4), axes=(-2, -1))
- assert_array_almost_equal(y, fftn(large_x1))
- y = fftn(small_x, shape=(4, 4), axes=(-1, -2))
- assert_array_almost_equal(y, swapaxes(
- fftn(swapaxes(large_x1, -1, -2)), -1, -2))
- def test_shape_axes_argument2(self):
- # Change shape of the last axis
- x = numpy.random.random((10, 5, 3, 7))
- y = fftn(x, axes=(-1,), shape=(8,))
- assert_array_almost_equal(y, fft(x, axis=-1, n=8))
- # Change shape of an arbitrary axis which is not the last one
- x = numpy.random.random((10, 5, 3, 7))
- y = fftn(x, axes=(-2,), shape=(8,))
- assert_array_almost_equal(y, fft(x, axis=-2, n=8))
- # Change shape of axes: cf #244, where shape and axes were mixed up
- x = numpy.random.random((4, 4, 2))
- y = fftn(x, axes=(-3, -2), shape=(8, 8))
- assert_array_almost_equal(y,
- numpy.fft.fftn(x, axes=(-3, -2), s=(8, 8)))
- def test_shape_argument_more(self):
- x = zeros((4, 4, 2))
- with assert_raises(ValueError,
- match="when given, axes and shape arguments"
- " have to be of the same length"):
- fftn(x, shape=(8, 8, 2, 1))
- def test_invalid_sizes(self):
- with assert_raises(ValueError,
- match="invalid number of data points"
- r" \(\[1 0\]\) specified"):
- fftn([[]])
- with assert_raises(ValueError,
- match="invalid number of data points"
- r" \(\[ 4 -3\]\) specified"):
- fftn([[1, 1], [2, 2]], (4, -3))
- class TestIfftn(object):
- dtype = None
- cdtype = None
- def setup_method(self):
- np.random.seed(1234)
- @pytest.mark.parametrize('dtype,cdtype,maxnlp',
- [(np.float64, np.complex128, 2000),
- (np.float32, np.complex64, 3500)])
- def test_definition(self, dtype, cdtype, maxnlp):
- x = np.array([[1, 2, 3],
- [4, 5, 6],
- [7, 8, 9]], dtype=dtype)
- y = ifftn(x)
- assert_equal(y.dtype, cdtype)
- assert_array_almost_equal_nulp(y, direct_idftn(x), maxnlp)
- x = random((20, 26))
- assert_array_almost_equal_nulp(ifftn(x), direct_idftn(x), maxnlp)
- x = random((5, 4, 3, 20))
- assert_array_almost_equal_nulp(ifftn(x), direct_idftn(x), maxnlp)
- @pytest.mark.parametrize('maxnlp', [2000, 3500])
- @pytest.mark.parametrize('size', [1, 2, 51, 32, 64, 92])
- def test_random_complex(self, maxnlp, size):
- x = random([size, size]) + 1j*random([size, size])
- assert_array_almost_equal_nulp(ifftn(fftn(x)), x, maxnlp)
- assert_array_almost_equal_nulp(fftn(ifftn(x)), x, maxnlp)
- def test_invalid_sizes(self):
- with assert_raises(ValueError,
- match="invalid number of data points"
- r" \(\[1 0\]\) specified"):
- ifftn([[]])
- with assert_raises(ValueError,
- match="invalid number of data points"
- r" \(\[ 4 -3\]\) specified"):
- ifftn([[1, 1], [2, 2]], (4, -3))
- class TestLongDoubleFailure(object):
- def setup_method(self):
- np.random.seed(1234)
- def test_complex(self):
- if np.dtype(np.longcomplex).itemsize == np.dtype(complex).itemsize:
- # longdouble == double; so fft is supported
- return
- x = np.random.randn(10).astype(np.longdouble) + \
- 1j * np.random.randn(10).astype(np.longdouble)
- for f in [fft, ifft]:
- try:
- f(x)
- raise AssertionError("Type {0} not supported but does not fail" %
- np.longcomplex)
- except ValueError:
- pass
- def test_real(self):
- if np.dtype(np.longdouble).itemsize == np.dtype(np.double).itemsize:
- # longdouble == double; so fft is supported
- return
- x = np.random.randn(10).astype(np.longcomplex)
- for f in [fft, ifft]:
- try:
- f(x)
- raise AssertionError("Type %r not supported but does not fail" %
- np.longcomplex)
- except ValueError:
- pass
- class FakeArray(object):
- def __init__(self, data):
- self._data = data
- self.__array_interface__ = data.__array_interface__
- class FakeArray2(object):
- def __init__(self, data):
- self._data = data
- def __array__(self):
- return self._data
- class TestOverwrite(object):
- """Check input overwrite behavior of the FFT functions."""
- real_dtypes = [np.float32, np.float64]
- dtypes = real_dtypes + [np.complex64, np.complex128]
- fftsizes = [8, 16, 32]
- def _check(self, x, routine, fftsize, axis, overwrite_x, should_overwrite):
- x2 = x.copy()
- for fake in [lambda x: x, FakeArray, FakeArray2]:
- routine(fake(x2), fftsize, axis, overwrite_x=overwrite_x)
- sig = "%s(%s%r, %r, axis=%r, overwrite_x=%r)" % (
- routine.__name__, x.dtype, x.shape, fftsize, axis, overwrite_x)
- if not should_overwrite:
- assert_equal(x2, x, err_msg="spurious overwrite in %s" % sig)
- def _check_1d(self, routine, dtype, shape, axis, overwritable_dtypes,
- fftsize, overwrite_x):
- np.random.seed(1234)
- if np.issubdtype(dtype, np.complexfloating):
- data = np.random.randn(*shape) + 1j*np.random.randn(*shape)
- else:
- data = np.random.randn(*shape)
- data = data.astype(dtype)
- should_overwrite = (overwrite_x
- and dtype in overwritable_dtypes
- and fftsize <= shape[axis]
- and (len(shape) == 1 or
- (axis % len(shape) == len(shape)-1
- and fftsize == shape[axis])))
- self._check(data, routine, fftsize, axis,
- overwrite_x=overwrite_x,
- should_overwrite=should_overwrite)
- @pytest.mark.parametrize('dtype', dtypes)
- @pytest.mark.parametrize('fftsize', fftsizes)
- @pytest.mark.parametrize('overwrite_x', [True, False])
- @pytest.mark.parametrize('shape,axes', [((16,), -1),
- ((16, 2), 0),
- ((2, 16), 1)])
- def test_fft_ifft(self, dtype, fftsize, overwrite_x, shape, axes):
- overwritable = (np.complex128, np.complex64)
- self._check_1d(fft, dtype, shape, axes, overwritable,
- fftsize, overwrite_x)
- self._check_1d(ifft, dtype, shape, axes, overwritable,
- fftsize, overwrite_x)
- @pytest.mark.parametrize('dtype', real_dtypes)
- @pytest.mark.parametrize('fftsize', fftsizes)
- @pytest.mark.parametrize('overwrite_x', [True, False])
- @pytest.mark.parametrize('shape,axes', [((16,), -1),
- ((16, 2), 0),
- ((2, 16), 1)])
- def test_rfft_irfft(self, dtype, fftsize, overwrite_x, shape, axes):
- overwritable = self.real_dtypes
- self._check_1d(irfft, dtype, shape, axes, overwritable,
- fftsize, overwrite_x)
- self._check_1d(rfft, dtype, shape, axes, overwritable,
- fftsize, overwrite_x)
- def _check_nd_one(self, routine, dtype, shape, axes, overwritable_dtypes,
- overwrite_x):
- np.random.seed(1234)
- if np.issubdtype(dtype, np.complexfloating):
- data = np.random.randn(*shape) + 1j*np.random.randn(*shape)
- else:
- data = np.random.randn(*shape)
- data = data.astype(dtype)
- def fftshape_iter(shp):
- if len(shp) <= 0:
- yield ()
- else:
- for j in (shp[0]//2, shp[0], shp[0]*2):
- for rest in fftshape_iter(shp[1:]):
- yield (j,) + rest
- if axes is None:
- part_shape = shape
- else:
- part_shape = tuple(np.take(shape, axes))
- for fftshape in fftshape_iter(part_shape):
- should_overwrite = (overwrite_x
- and data.ndim == 1
- and np.all([x < y for x, y in zip(fftshape,
- part_shape)])
- and dtype in overwritable_dtypes)
- self._check(data, routine, fftshape, axes,
- overwrite_x=overwrite_x,
- should_overwrite=should_overwrite)
- if data.ndim > 1:
- # check fortran order: it never overwrites
- self._check(data.T, routine, fftshape, axes,
- overwrite_x=overwrite_x,
- should_overwrite=False)
- @pytest.mark.parametrize('dtype', dtypes)
- @pytest.mark.parametrize('overwrite_x', [True, False])
- @pytest.mark.parametrize('shape,axes', [((16,), None),
- ((16,), (0,)),
- ((16, 2), (0,)),
- ((2, 16), (1,)),
- ((8, 16), None),
- ((8, 16), (0, 1)),
- ((8, 16, 2), (0, 1)),
- ((8, 16, 2), (1, 2)),
- ((8, 16, 2), (0,)),
- ((8, 16, 2), (1,)),
- ((8, 16, 2), (2,)),
- ((8, 16, 2), None),
- ((8, 16, 2), (0, 1, 2))])
- def test_fftn_ifftn(self, dtype, overwrite_x, shape, axes):
- overwritable = (np.complex128, np.complex64)
- self._check_nd_one(fftn, dtype, shape, axes, overwritable,
- overwrite_x)
- self._check_nd_one(ifftn, dtype, shape, axes, overwritable,
- overwrite_x)
|