Static code analysis and corrections

This commit is contained in:
Kristjan Komlosi
2019-07-17 16:06:09 +02:00
parent 674692c2fc
commit 21bfae9fbc
10086 changed files with 2102103 additions and 51 deletions
@@ -0,0 +1,13 @@
CC = gcc
LD = gcc
fftw_single: fftw_dct.c
$(CC) -W -Wall -DDCT_TEST_USE_SINGLE $< -o $@ -lfftw3f
fftw_double: fftw_dct.c
$(CC) -W -Wall $< -o $@ -lfftw3
clean:
rm -f fftw_single
rm -f fftw_double
rm -f *.o
@@ -0,0 +1,138 @@
#include <stdlib.h>
#include <stdio.h>
#include <fftw3.h>
#ifdef DCT_TEST_USE_SINGLE
typedef float float_prec;
#define PF "%.7f"
#define FFTW_PLAN fftwf_plan
#define FFTW_MALLOC fftwf_malloc
#define FFTW_FREE fftwf_free
#define FFTW_PLAN_CREATE fftwf_plan_r2r_1d
#define FFTW_EXECUTE fftwf_execute
#define FFTW_DESTROY_PLAN fftwf_destroy_plan
#define FFTW_CLEANUP fftwf_cleanup
#else
typedef double float_prec;
#define PF "%.18f"
#define FFTW_PLAN fftw_plan
#define FFTW_MALLOC fftw_malloc
#define FFTW_FREE fftw_free
#define FFTW_PLAN_CREATE fftw_plan_r2r_1d
#define FFTW_EXECUTE fftw_execute
#define FFTW_DESTROY_PLAN fftw_destroy_plan
#define FFTW_CLEANUP fftw_cleanup
#endif
enum type {
DCT_I = 1,
DCT_II = 2,
DCT_III = 3,
DCT_IV = 4,
DST_I = 5,
DST_II = 6,
DST_III = 7,
DST_IV = 8,
};
int gen(int type, int sz)
{
float_prec *a, *b;
FFTW_PLAN p;
int i, tp;
a = FFTW_MALLOC(sizeof(*a) * sz);
if (a == NULL) {
fprintf(stderr, "failure\n");
exit(EXIT_FAILURE);
}
b = FFTW_MALLOC(sizeof(*b) * sz);
if (b == NULL) {
fprintf(stderr, "failure\n");
exit(EXIT_FAILURE);
}
switch(type) {
case DCT_I:
tp = FFTW_REDFT00;
break;
case DCT_II:
tp = FFTW_REDFT10;
break;
case DCT_III:
tp = FFTW_REDFT01;
break;
case DCT_IV:
tp = FFTW_REDFT11;
break;
case DST_I:
tp = FFTW_RODFT00;
break;
case DST_II:
tp = FFTW_RODFT10;
break;
case DST_III:
tp = FFTW_RODFT01;
break;
case DST_IV:
tp = FFTW_RODFT11;
break;
default:
fprintf(stderr, "unknown type\n");
exit(EXIT_FAILURE);
}
switch(type) {
case DCT_I:
case DCT_II:
case DCT_III:
case DCT_IV:
for(i=0; i < sz; ++i) {
a[i] = i;
}
break;
case DST_I:
case DST_II:
case DST_III:
case DST_IV:
/* TODO: what should we do for dst's?*/
for(i=0; i < sz; ++i) {
a[i] = i;
}
break;
default:
fprintf(stderr, "unknown type\n");
exit(EXIT_FAILURE);
}
p = FFTW_PLAN_CREATE(sz, a, b, tp, FFTW_ESTIMATE);
FFTW_EXECUTE(p);
FFTW_DESTROY_PLAN(p);
for(i=0; i < sz; ++i) {
printf(PF"\n", b[i]);
}
FFTW_FREE(b);
FFTW_FREE(a);
return 0;
}
int main(int argc, char* argv[])
{
int n, tp;
if (argc < 3) {
fprintf(stderr, "missing argument: program type n\n");
exit(EXIT_FAILURE);
}
tp = atoi(argv[1]);
n = atoi(argv[2]);
gen(tp, n);
FFTW_CLEANUP();
return 0;
}
@@ -0,0 +1,59 @@
from __future__ import division, print_function, absolute_import
from subprocess import Popen, PIPE, STDOUT
import numpy as np
SZ = [2, 3, 4, 8, 12, 15, 16, 17, 32, 64, 128, 256, 512, 1024]
def gen_data(dt):
arrays = {}
if dt == np.double:
pg = './fftw_double'
elif dt == np.float32:
pg = './fftw_single'
else:
raise ValueError("unknown: %s" % dt)
# Generate test data using FFTW for reference
for type in [1, 2, 3, 4, 5, 6, 7, 8]:
arrays[type] = {}
for sz in SZ:
a = Popen([pg, str(type), str(sz)], stdout=PIPE, stderr=STDOUT)
st = [i.strip() for i in a.stdout.readlines()]
arrays[type][sz] = np.fromstring(",".join(st), sep=',', dtype=dt)
return arrays
# generate single precision data
data = gen_data(np.float32)
filename = 'fftw_single_ref'
# Save ref data into npz format
d = {'sizes': SZ}
for type in [1, 2, 3, 4]:
for sz in SZ:
d['dct_%d_%d' % (type, sz)] = data[type][sz]
d['sizes'] = SZ
for type in [5, 6, 7, 8]:
for sz in SZ:
d['dst_%d_%d' % (type-4, sz)] = data[type][sz]
np.savez(filename, **d)
# generate double precision data
data = gen_data(np.float64)
filename = 'fftw_double_ref'
# Save ref data into npz format
d = {'sizes': SZ}
for type in [1, 2, 3, 4]:
for sz in SZ:
d['dct_%d_%d' % (type, sz)] = data[type][sz]
d['sizes'] = SZ
for type in [5, 6, 7, 8]:
for sz in SZ:
d['dst_%d_%d' % (type-4, sz)] = data[type][sz]
np.savez(filename, **d)
@@ -0,0 +1,21 @@
x0 = linspace(0, 10, 11);
x1 = linspace(0, 10, 15);
x2 = linspace(0, 10, 16);
x3 = linspace(0, 10, 17);
x4 = randn(32, 1);
x5 = randn(64, 1);
x6 = randn(128, 1);
x7 = randn(256, 1);
y0 = dct(x0);
y1 = dct(x1);
y2 = dct(x2);
y3 = dct(x3);
y4 = dct(x4);
y5 = dct(x5);
y6 = dct(x6);
y7 = dct(x7);
save('test.mat', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', ...
'y0', 'y1', 'y2', 'y3', 'y4', 'y5', 'y6', 'y7');
@@ -0,0 +1,8 @@
from __future__ import division, print_function, absolute_import
import numpy as np
from scipy.io import loadmat
m = loadmat('test.mat', squeeze_me=True, struct_as_record=True,
mat_dtype=True)
np.savez('test.npz', **m)
@@ -0,0 +1,972 @@
# 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)
@@ -0,0 +1,416 @@
# 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(<level>)'
Run tests if fftpack is not installed:
python tests/test_helper.py [<level>]
"""
from pytest import raises as assert_raises
from numpy.testing import assert_array_almost_equal, assert_equal, assert_
from scipy.fftpack import fftshift,ifftshift,fftfreq,rfftfreq
from scipy.fftpack.helper import (next_fast_len,
_init_nd_shape_and_axes,
_init_nd_shape_and_axes_sorted)
from numpy import pi, random
import numpy as np
class TestFFTShift(object):
def test_definition(self):
x = [0,1,2,3,4,-4,-3,-2,-1]
y = [-4,-3,-2,-1,0,1,2,3,4]
assert_array_almost_equal(fftshift(x),y)
assert_array_almost_equal(ifftshift(y),x)
x = [0,1,2,3,4,-5,-4,-3,-2,-1]
y = [-5,-4,-3,-2,-1,0,1,2,3,4]
assert_array_almost_equal(fftshift(x),y)
assert_array_almost_equal(ifftshift(y),x)
def test_inverse(self):
for n in [1,4,9,100,211]:
x = random.random((n,))
assert_array_almost_equal(ifftshift(fftshift(x)),x)
class TestFFTFreq(object):
def test_definition(self):
x = [0,1,2,3,4,-4,-3,-2,-1]
assert_array_almost_equal(9*fftfreq(9),x)
assert_array_almost_equal(9*pi*fftfreq(9,pi),x)
x = [0,1,2,3,4,-5,-4,-3,-2,-1]
assert_array_almost_equal(10*fftfreq(10),x)
assert_array_almost_equal(10*pi*fftfreq(10,pi),x)
class TestRFFTFreq(object):
def test_definition(self):
x = [0,1,1,2,2,3,3,4,4]
assert_array_almost_equal(9*rfftfreq(9),x)
assert_array_almost_equal(9*pi*rfftfreq(9,pi),x)
x = [0,1,1,2,2,3,3,4,4,5]
assert_array_almost_equal(10*rfftfreq(10),x)
assert_array_almost_equal(10*pi*rfftfreq(10,pi),x)
class TestNextOptLen(object):
def test_next_opt_len(self):
random.seed(1234)
def nums():
for j in range(1, 1000):
yield j
yield 2**5 * 3**5 * 4**5 + 1
for n in nums():
m = next_fast_len(n)
msg = "n=%d, m=%d" % (n, m)
assert_(m >= n, msg)
# check regularity
k = m
for d in [2, 3, 5]:
while True:
a, b = divmod(k, d)
if b == 0:
k = a
else:
break
assert_equal(k, 1, err_msg=msg)
def test_np_integers(self):
ITYPES = [np.int16, np.int32, np.int64, np.uint16, np.uint32, np.uint64]
for ityp in ITYPES:
x = ityp(12345)
testN = next_fast_len(x)
assert_equal(testN, next_fast_len(int(x)))
def test_next_opt_len_strict(self):
hams = {
1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 8, 8: 8, 14: 15, 15: 15,
16: 16, 17: 18, 1021: 1024, 1536: 1536, 51200000: 51200000,
510183360: 510183360, 510183360 + 1: 512000000,
511000000: 512000000,
854296875: 854296875, 854296875 + 1: 859963392,
196608000000: 196608000000, 196608000000 + 1: 196830000000,
8789062500000: 8789062500000, 8789062500000 + 1: 8796093022208,
206391214080000: 206391214080000,
206391214080000 + 1: 206624260800000,
470184984576000: 470184984576000,
470184984576000 + 1: 470715894135000,
7222041363087360: 7222041363087360,
7222041363087360 + 1: 7230196133913600,
# power of 5 5**23
11920928955078125: 11920928955078125,
11920928955078125 - 1: 11920928955078125,
# power of 3 3**34
16677181699666569: 16677181699666569,
16677181699666569 - 1: 16677181699666569,
# power of 2 2**54
18014398509481984: 18014398509481984,
18014398509481984 - 1: 18014398509481984,
# above this, int(ceil(n)) == int(ceil(n+1))
19200000000000000: 19200000000000000,
19200000000000000 + 1: 19221679687500000,
288230376151711744: 288230376151711744,
288230376151711744 + 1: 288325195312500000,
288325195312500000 - 1: 288325195312500000,
288325195312500000: 288325195312500000,
288325195312500000 + 1: 288555831593533440,
# power of 3 3**83
3990838394187339929534246675572349035227 - 1:
3990838394187339929534246675572349035227,
3990838394187339929534246675572349035227:
3990838394187339929534246675572349035227,
# power of 2 2**135
43556142965880123323311949751266331066368 - 1:
43556142965880123323311949751266331066368,
43556142965880123323311949751266331066368:
43556142965880123323311949751266331066368,
# power of 5 5**57
6938893903907228377647697925567626953125 - 1:
6938893903907228377647697925567626953125,
6938893903907228377647697925567626953125:
6938893903907228377647697925567626953125,
# http://www.drdobbs.com/228700538
# 2**96 * 3**1 * 5**13
290142196707511001929482240000000000000 - 1:
290142196707511001929482240000000000000,
290142196707511001929482240000000000000:
290142196707511001929482240000000000000,
290142196707511001929482240000000000000 + 1:
290237644800000000000000000000000000000,
# 2**36 * 3**69 * 5**7
4479571262811807241115438439905203543080960000000 - 1:
4479571262811807241115438439905203543080960000000,
4479571262811807241115438439905203543080960000000:
4479571262811807241115438439905203543080960000000,
4479571262811807241115438439905203543080960000000 + 1:
4480327901140333639941336854183943340032000000000,
# 2**37 * 3**44 * 5**42
30774090693237851027531250000000000000000000000000000000000000 - 1:
30774090693237851027531250000000000000000000000000000000000000,
30774090693237851027531250000000000000000000000000000000000000:
30774090693237851027531250000000000000000000000000000000000000,
30774090693237851027531250000000000000000000000000000000000000 + 1:
30778180617309082445871527002041377406962596539492679680000000,
}
for x, y in hams.items():
assert_equal(next_fast_len(x), y)
class Test_init_nd_shape_and_axes(object):
def test_py_0d_defaults(self):
x = 4
shape = None
axes = None
shape_expected = np.array([])
axes_expected = np.array([])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_0d_defaults(self):
x = np.array(7.)
shape = None
axes = None
shape_expected = np.array([])
axes_expected = np.array([])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_py_1d_defaults(self):
x = [1, 2, 3]
shape = None
axes = None
shape_expected = np.array([3])
axes_expected = np.array([0])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_1d_defaults(self):
x = np.arange(0, 1, .1)
shape = None
axes = None
shape_expected = np.array([10])
axes_expected = np.array([0])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_py_2d_defaults(self):
x = [[1, 2, 3, 4],
[5, 6, 7, 8]]
shape = None
axes = None
shape_expected = np.array([2, 4])
axes_expected = np.array([0, 1])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_2d_defaults(self):
x = np.arange(0, 1, .1).reshape(5, 2)
shape = None
axes = None
shape_expected = np.array([5, 2])
axes_expected = np.array([0, 1])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_defaults(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = None
axes = None
shape_expected = np.array([6, 2, 5, 3, 4])
axes_expected = np.array([0, 1, 2, 3, 4])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_set_shape(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = [10, -1, -1, 1, 4]
axes = None
shape_expected = np.array([10, 2, 5, 1, 4])
axes_expected = np.array([0, 1, 2, 3, 4])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_set_axes(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = None
axes = [4, 1, 2]
shape_expected = np.array([4, 2, 5])
axes_expected = np.array([4, 1, 2])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_set_axes_sorted(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = None
axes = [4, 1, 2]
shape_expected = np.array([2, 5, 4])
axes_expected = np.array([1, 2, 4])
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_set_shape_axes(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = [10, -1, 2]
axes = [1, 0, 3]
shape_expected = np.array([10, 6, 2])
axes_expected = np.array([1, 0, 3])
shape_res, axes_res = _init_nd_shape_and_axes(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_np_5d_set_shape_axes_sorted(self):
x = np.zeros([6, 2, 5, 3, 4])
shape = [10, -1, 2]
axes = [1, 0, 3]
shape_expected = np.array([6, 10, 2])
axes_expected = np.array([0, 1, 3])
shape_res, axes_res = _init_nd_shape_and_axes_sorted(x, shape, axes)
assert_equal(shape_res, shape_expected)
assert_equal(axes_res, axes_expected)
def test_errors(self):
with assert_raises(ValueError,
match="when given, axes values must be a scalar"
" or vector"):
_init_nd_shape_and_axes([0], shape=None, axes=[[1, 2], [3, 4]])
with assert_raises(ValueError,
match="when given, axes values must be integers"):
_init_nd_shape_and_axes([0], shape=None, axes=[1., 2., 3., 4.])
with assert_raises(ValueError,
match="axes exceeds dimensionality of input"):
_init_nd_shape_and_axes([0], shape=None, axes=[1])
with assert_raises(ValueError,
match="axes exceeds dimensionality of input"):
_init_nd_shape_and_axes([0], shape=None, axes=[-2])
with assert_raises(ValueError,
match="all axes must be unique"):
_init_nd_shape_and_axes([0], shape=None, axes=[0, 0])
with assert_raises(ValueError,
match="when given, shape values must be a scalar "
"or vector"):
_init_nd_shape_and_axes([0], shape=[[1, 2], [3, 4]], axes=None)
with assert_raises(ValueError,
match="when given, shape values must be integers"):
_init_nd_shape_and_axes([0], shape=[1., 2., 3., 4.], axes=None)
with assert_raises(ValueError,
match="when given, axes and shape arguments"
" have to be of the same length"):
_init_nd_shape_and_axes(np.zeros([1, 1, 1, 1]),
shape=[1, 2, 3], axes=[1])
with assert_raises(ValueError,
match="invalid number of data points"
r" \(\[0\]\) specified"):
_init_nd_shape_and_axes([0], shape=[0], axes=None)
with assert_raises(ValueError,
match="invalid number of data points"
r" \(\[-2\]\) specified"):
_init_nd_shape_and_axes([0], shape=-2, axes=None)
@@ -0,0 +1,33 @@
"""Test possibility of patching fftpack with pyfftw.
No module source outside of scipy.fftpack should contain an import of
the form `from scipy.fftpack import ...`, so that a simple replacement
of scipy.fftpack by the corresponding fftw interface completely swaps
the two FFT implementations.
Because this simply inspects source files, we only need to run the test
on one version of Python.
"""
import sys
if sys.version_info >= (3, 4):
from pathlib import Path
import re
import tokenize
from numpy.testing import assert_
import scipy
class TestFFTPackImport(object):
def test_fftpack_import(self):
base = Path(scipy.__file__).parent
regexp = r"\s*from.+\.fftpack import .*\n"
for path in base.rglob("*.py"):
if base / "fftpack" in path.parents:
continue
# use tokenize to auto-detect encoding on systems where no
# default encoding is defined (e.g. LANG='C')
with tokenize.open(str(path)) as file:
assert_(all(not re.fullmatch(regexp, line)
for line in file),
"{0} contains an import from fftpack".format(path))
@@ -0,0 +1,382 @@
# 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(<level>)'
Run tests if fftpack is not installed:
python tests/test_pseudo_diffs.py [<level>]
"""
from numpy.testing import (assert_equal, assert_almost_equal,
assert_array_almost_equal)
from scipy.fftpack import (diff, fft, ifft, tilbert, itilbert, hilbert,
ihilbert, shift, fftfreq, cs_diff, sc_diff,
ss_diff, cc_diff)
import numpy as np
from numpy import arange, sin, cos, pi, exp, tanh, sum, sign
from numpy.random import random
def direct_diff(x,k=1,period=None):
fx = fft(x)
n = len(fx)
if period is None:
period = 2*pi
w = fftfreq(n)*2j*pi/period*n
if k < 0:
w = 1 / w**k
w[0] = 0.0
else:
w = w**k
if n > 2000:
w[250:n-250] = 0.0
return ifft(w*fx).real
def direct_tilbert(x,h=1,period=None):
fx = fft(x)
n = len(fx)
if period is None:
period = 2*pi
w = fftfreq(n)*h*2*pi/period*n
w[0] = 1
w = 1j/tanh(w)
w[0] = 0j
return ifft(w*fx)
def direct_itilbert(x,h=1,period=None):
fx = fft(x)
n = len(fx)
if period is None:
period = 2*pi
w = fftfreq(n)*h*2*pi/period*n
w = -1j*tanh(w)
return ifft(w*fx)
def direct_hilbert(x):
fx = fft(x)
n = len(fx)
w = fftfreq(n)*n
w = 1j*sign(w)
return ifft(w*fx)
def direct_ihilbert(x):
return -direct_hilbert(x)
def direct_shift(x,a,period=None):
n = len(x)
if period is None:
k = fftfreq(n)*1j*n
else:
k = fftfreq(n)*2j*pi/period*n
return ifft(fft(x)*exp(k*a)).real
class TestDiff(object):
def test_definition(self):
for n in [16,17,64,127,32]:
x = arange(n)*2*pi/n
assert_array_almost_equal(diff(sin(x)),direct_diff(sin(x)))
assert_array_almost_equal(diff(sin(x),2),direct_diff(sin(x),2))
assert_array_almost_equal(diff(sin(x),3),direct_diff(sin(x),3))
assert_array_almost_equal(diff(sin(x),4),direct_diff(sin(x),4))
assert_array_almost_equal(diff(sin(x),5),direct_diff(sin(x),5))
assert_array_almost_equal(diff(sin(2*x),3),direct_diff(sin(2*x),3))
assert_array_almost_equal(diff(sin(2*x),4),direct_diff(sin(2*x),4))
assert_array_almost_equal(diff(cos(x)),direct_diff(cos(x)))
assert_array_almost_equal(diff(cos(x),2),direct_diff(cos(x),2))
assert_array_almost_equal(diff(cos(x),3),direct_diff(cos(x),3))
assert_array_almost_equal(diff(cos(x),4),direct_diff(cos(x),4))
assert_array_almost_equal(diff(cos(2*x)),direct_diff(cos(2*x)))
assert_array_almost_equal(diff(sin(x*n/8)),direct_diff(sin(x*n/8)))
assert_array_almost_equal(diff(cos(x*n/8)),direct_diff(cos(x*n/8)))
for k in range(5):
assert_array_almost_equal(diff(sin(4*x),k),direct_diff(sin(4*x),k))
assert_array_almost_equal(diff(cos(4*x),k),direct_diff(cos(4*x),k))
def test_period(self):
for n in [17,64]:
x = arange(n)/float(n)
assert_array_almost_equal(diff(sin(2*pi*x),period=1),
2*pi*cos(2*pi*x))
assert_array_almost_equal(diff(sin(2*pi*x),3,period=1),
-(2*pi)**3*cos(2*pi*x))
def test_sin(self):
for n in [32,64,77]:
x = arange(n)*2*pi/n
assert_array_almost_equal(diff(sin(x)),cos(x))
assert_array_almost_equal(diff(cos(x)),-sin(x))
assert_array_almost_equal(diff(sin(x),2),-sin(x))
assert_array_almost_equal(diff(sin(x),4),sin(x))
assert_array_almost_equal(diff(sin(4*x)),4*cos(4*x))
assert_array_almost_equal(diff(sin(sin(x))),cos(x)*cos(sin(x)))
def test_expr(self):
for n in [64,77,100,128,256,512,1024,2048,4096,8192][:5]:
x = arange(n)*2*pi/n
f = sin(x)*cos(4*x)+exp(sin(3*x))
df = cos(x)*cos(4*x)-4*sin(x)*sin(4*x)+3*cos(3*x)*exp(sin(3*x))
ddf = -17*sin(x)*cos(4*x)-8*cos(x)*sin(4*x)\
- 9*sin(3*x)*exp(sin(3*x))+9*cos(3*x)**2*exp(sin(3*x))
d1 = diff(f)
assert_array_almost_equal(d1,df)
assert_array_almost_equal(diff(df),ddf)
assert_array_almost_equal(diff(f,2),ddf)
assert_array_almost_equal(diff(ddf,-1),df)
def test_expr_large(self):
for n in [2048,4096]:
x = arange(n)*2*pi/n
f = sin(x)*cos(4*x)+exp(sin(3*x))
df = cos(x)*cos(4*x)-4*sin(x)*sin(4*x)+3*cos(3*x)*exp(sin(3*x))
ddf = -17*sin(x)*cos(4*x)-8*cos(x)*sin(4*x)\
- 9*sin(3*x)*exp(sin(3*x))+9*cos(3*x)**2*exp(sin(3*x))
assert_array_almost_equal(diff(f),df)
assert_array_almost_equal(diff(df),ddf)
assert_array_almost_equal(diff(ddf,-1),df)
assert_array_almost_equal(diff(f,2),ddf)
def test_int(self):
n = 64
x = arange(n)*2*pi/n
assert_array_almost_equal(diff(sin(x),-1),-cos(x))
assert_array_almost_equal(diff(sin(x),-2),-sin(x))
assert_array_almost_equal(diff(sin(x),-4),sin(x))
assert_array_almost_equal(diff(2*cos(2*x),-1),sin(2*x))
def test_random_even(self):
for k in [0,2,4,6]:
for n in [60,32,64,56,55]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
# zeroing Nyquist mode:
f = diff(diff(f,1),-1)
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(diff(diff(f,k),-k),f)
assert_array_almost_equal(diff(diff(f,-k),k),f)
def test_random_odd(self):
for k in [0,1,2,3,4,5,6]:
for n in [33,65,55]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(diff(diff(f,k),-k),f)
assert_array_almost_equal(diff(diff(f,-k),k),f)
def test_zero_nyquist(self):
for k in [0,1,2,3,4,5,6]:
for n in [32,33,64,56,55]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
# zeroing Nyquist mode:
f = diff(diff(f,1),-1)
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(diff(diff(f,k),-k),f)
assert_array_almost_equal(diff(diff(f,-k),k),f)
class TestTilbert(object):
def test_definition(self):
for h in [0.1,0.5,1,5.5,10]:
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
y = tilbert(sin(x),h)
y1 = direct_tilbert(sin(x),h)
assert_array_almost_equal(y,y1)
assert_array_almost_equal(tilbert(sin(x),h),
direct_tilbert(sin(x),h))
assert_array_almost_equal(tilbert(sin(2*x),h),
direct_tilbert(sin(2*x),h))
def test_random_even(self):
for h in [0.1,0.5,1,5.5,10]:
for n in [32,64,56]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(direct_tilbert(direct_itilbert(f,h),h),f)
def test_random_odd(self):
for h in [0.1,0.5,1,5.5,10]:
for n in [33,65,55]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(itilbert(tilbert(f,h),h),f)
assert_array_almost_equal(tilbert(itilbert(f,h),h),f)
class TestITilbert(object):
def test_definition(self):
for h in [0.1,0.5,1,5.5,10]:
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
y = itilbert(sin(x),h)
y1 = direct_itilbert(sin(x),h)
assert_array_almost_equal(y,y1)
assert_array_almost_equal(itilbert(sin(x),h),
direct_itilbert(sin(x),h))
assert_array_almost_equal(itilbert(sin(2*x),h),
direct_itilbert(sin(2*x),h))
class TestHilbert(object):
def test_definition(self):
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
y = hilbert(sin(x))
y1 = direct_hilbert(sin(x))
assert_array_almost_equal(y,y1)
assert_array_almost_equal(hilbert(sin(2*x)),
direct_hilbert(sin(2*x)))
def test_tilbert_relation(self):
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
f = sin(x)+cos(2*x)*sin(x)
y = hilbert(f)
y1 = direct_hilbert(f)
assert_array_almost_equal(y,y1)
y2 = tilbert(f,h=10)
assert_array_almost_equal(y,y2)
def test_random_odd(self):
for n in [33,65,55]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(ihilbert(hilbert(f)),f)
assert_array_almost_equal(hilbert(ihilbert(f)),f)
def test_random_even(self):
for n in [32,64,56]:
f = random((n,))
af = sum(f,axis=0)/n
f = f-af
# zeroing Nyquist mode:
f = diff(diff(f,1),-1)
assert_almost_equal(sum(f,axis=0),0.0)
assert_array_almost_equal(direct_hilbert(direct_ihilbert(f)),f)
assert_array_almost_equal(hilbert(ihilbert(f)),f)
class TestIHilbert(object):
def test_definition(self):
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
y = ihilbert(sin(x))
y1 = direct_ihilbert(sin(x))
assert_array_almost_equal(y,y1)
assert_array_almost_equal(ihilbert(sin(2*x)),
direct_ihilbert(sin(2*x)))
def test_itilbert_relation(self):
for n in [16,17,64,127]:
x = arange(n)*2*pi/n
f = sin(x)+cos(2*x)*sin(x)
y = ihilbert(f)
y1 = direct_ihilbert(f)
assert_array_almost_equal(y,y1)
y2 = itilbert(f,h=10)
assert_array_almost_equal(y,y2)
class TestShift(object):
def test_definition(self):
for n in [18,17,64,127,32,2048,256]:
x = arange(n)*2*pi/n
for a in [0.1,3]:
assert_array_almost_equal(shift(sin(x),a),direct_shift(sin(x),a))
assert_array_almost_equal(shift(sin(x),a),sin(x+a))
assert_array_almost_equal(shift(cos(x),a),cos(x+a))
assert_array_almost_equal(shift(cos(2*x)+sin(x),a),
cos(2*(x+a))+sin(x+a))
assert_array_almost_equal(shift(exp(sin(x)),a),exp(sin(x+a)))
assert_array_almost_equal(shift(sin(x),2*pi),sin(x))
assert_array_almost_equal(shift(sin(x),pi),-sin(x))
assert_array_almost_equal(shift(sin(x),pi/2),cos(x))
class TestOverwrite(object):
"""Check input overwrite behavior """
real_dtypes = [np.float32, np.float64]
dtypes = real_dtypes + [np.complex64, np.complex128]
def _check(self, x, routine, *args, **kwargs):
x2 = x.copy()
routine(x2, *args, **kwargs)
sig = routine.__name__
if args:
sig += repr(args)
if kwargs:
sig += repr(kwargs)
assert_equal(x2, x, err_msg="spurious overwrite in %s" % sig)
def _check_1d(self, routine, dtype, shape, *args, **kwargs):
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)
self._check(data, routine, *args, **kwargs)
def test_diff(self):
for dtype in self.dtypes:
self._check_1d(diff, dtype, (16,))
def test_tilbert(self):
for dtype in self.dtypes:
self._check_1d(tilbert, dtype, (16,), 1.6)
def test_itilbert(self):
for dtype in self.dtypes:
self._check_1d(itilbert, dtype, (16,), 1.6)
def test_hilbert(self):
for dtype in self.dtypes:
self._check_1d(hilbert, dtype, (16,))
def test_cs_diff(self):
for dtype in self.dtypes:
self._check_1d(cs_diff, dtype, (16,), 1.0, 4.0)
def test_sc_diff(self):
for dtype in self.dtypes:
self._check_1d(sc_diff, dtype, (16,), 1.0, 4.0)
def test_ss_diff(self):
for dtype in self.dtypes:
self._check_1d(ss_diff, dtype, (16,), 1.0, 4.0)
def test_cc_diff(self):
for dtype in self.dtypes:
self._check_1d(cc_diff, dtype, (16,), 1.0, 4.0)
def test_shift(self):
for dtype in self.dtypes:
self._check_1d(shift, dtype, (16,), 1.0)
@@ -0,0 +1,829 @@
from __future__ import division, print_function, absolute_import
from os.path import join, dirname
import numpy as np
from numpy.testing import assert_array_almost_equal, assert_equal
import pytest
from pytest import raises as assert_raises
from scipy.fftpack.realtransforms import (
dct, idct, dst, idst, dctn, idctn, dstn, idstn)
# Matlab reference data
MDATA = np.load(join(dirname(__file__), 'test.npz'))
X = [MDATA['x%d' % i] for i in range(8)]
Y = [MDATA['y%d' % i] for i in range(8)]
# FFTW reference data: the data are organized as follows:
# * SIZES is an array containing all available sizes
# * for every type (1, 2, 3, 4) and every size, the array dct_type_size
# contains the output of the DCT applied to the input np.linspace(0, size-1,
# size)
FFTWDATA_DOUBLE = np.load(join(dirname(__file__), 'fftw_double_ref.npz'))
FFTWDATA_SINGLE = np.load(join(dirname(__file__), 'fftw_single_ref.npz'))
FFTWDATA_SIZES = FFTWDATA_DOUBLE['sizes']
def fftw_dct_ref(type, size, dt):
x = np.linspace(0, size-1, size).astype(dt)
dt = np.result_type(np.float32, dt)
if dt == np.double:
data = FFTWDATA_DOUBLE
elif dt == np.float32:
data = FFTWDATA_SINGLE
else:
raise ValueError()
y = (data['dct_%d_%d' % (type, size)]).astype(dt)
return x, y, dt
def fftw_dst_ref(type, size, dt):
x = np.linspace(0, size-1, size).astype(dt)
dt = np.result_type(np.float32, dt)
if dt == np.double:
data = FFTWDATA_DOUBLE
elif dt == np.float32:
data = FFTWDATA_SINGLE
else:
raise ValueError()
y = (data['dst_%d_%d' % (type, size)]).astype(dt)
return x, y, dt
def dct_2d_ref(x, **kwargs):
"""Calculate reference values for testing dct2."""
x = np.array(x, copy=True)
for row in range(x.shape[0]):
x[row, :] = dct(x[row, :], **kwargs)
for col in range(x.shape[1]):
x[:, col] = dct(x[:, col], **kwargs)
return x
def idct_2d_ref(x, **kwargs):
"""Calculate reference values for testing idct2."""
x = np.array(x, copy=True)
for row in range(x.shape[0]):
x[row, :] = idct(x[row, :], **kwargs)
for col in range(x.shape[1]):
x[:, col] = idct(x[:, col], **kwargs)
return x
def dst_2d_ref(x, **kwargs):
"""Calculate reference values for testing dst2."""
x = np.array(x, copy=True)
for row in range(x.shape[0]):
x[row, :] = dst(x[row, :], **kwargs)
for col in range(x.shape[1]):
x[:, col] = dst(x[:, col], **kwargs)
return x
def idst_2d_ref(x, **kwargs):
"""Calculate reference values for testing idst2."""
x = np.array(x, copy=True)
for row in range(x.shape[0]):
x[row, :] = idst(x[row, :], **kwargs)
for col in range(x.shape[1]):
x[:, col] = idst(x[:, col], **kwargs)
return x
def naive_dct1(x, norm=None):
"""Calculate textbook definition version of DCT-I."""
x = np.array(x, copy=True)
N = len(x)
M = N-1
y = np.zeros(N)
m0, m = 1, 2
if norm == 'ortho':
m0 = np.sqrt(1.0/M)
m = np.sqrt(2.0/M)
for k in range(N):
for n in range(1, N-1):
y[k] += m*x[n]*np.cos(np.pi*n*k/M)
y[k] += m0 * x[0]
y[k] += m0 * x[N-1] * (1 if k % 2 == 0 else -1)
if norm == 'ortho':
y[0] *= 1/np.sqrt(2)
y[N-1] *= 1/np.sqrt(2)
return y
def naive_dst1(x, norm=None):
"""Calculate textbook definition version of DST-I."""
x = np.array(x, copy=True)
N = len(x)
M = N+1
y = np.zeros(N)
for k in range(N):
for n in range(N):
y[k] += 2*x[n]*np.sin(np.pi*(n+1.0)*(k+1.0)/M)
if norm == 'ortho':
y *= np.sqrt(0.5/M)
return y
def naive_dct4(x, norm=None):
"""Calculate textbook definition version of DCT-IV."""
x = np.array(x, copy=True)
N = len(x)
y = np.zeros(N)
for k in range(N):
for n in range(N):
y[k] += x[n]*np.cos(np.pi*(n+0.5)*(k+0.5)/(N))
if norm == 'ortho':
y *= np.sqrt(2.0/N)
else:
y *= 2
return y
def naive_dst4(x, norm=None):
"""Calculate textbook definition version of DST-IV."""
x = np.array(x, copy=True)
N = len(x)
y = np.zeros(N)
for k in range(N):
for n in range(N):
y[k] += x[n]*np.sin(np.pi*(n+0.5)*(k+0.5)/(N))
if norm == 'ortho':
y *= np.sqrt(2.0/N)
else:
y *= 2
return y
class TestComplex(object):
def test_dct_complex64(self):
y = dct(1j*np.arange(5, dtype=np.complex64))
x = 1j*dct(np.arange(5))
assert_array_almost_equal(x, y)
def test_dct_complex(self):
y = dct(np.arange(5)*1j)
x = 1j*dct(np.arange(5))
assert_array_almost_equal(x, y)
def test_idct_complex(self):
y = idct(np.arange(5)*1j)
x = 1j*idct(np.arange(5))
assert_array_almost_equal(x, y)
def test_dst_complex64(self):
y = dst(np.arange(5, dtype=np.complex64)*1j)
x = 1j*dst(np.arange(5))
assert_array_almost_equal(x, y)
def test_dst_complex(self):
y = dst(np.arange(5)*1j)
x = 1j*dst(np.arange(5))
assert_array_almost_equal(x, y)
def test_idst_complex(self):
y = idst(np.arange(5)*1j)
x = 1j*idst(np.arange(5))
assert_array_almost_equal(x, y)
class _TestDCTBase(object):
def setup_method(self):
self.rdt = None
self.dec = 14
self.type = None
def test_definition(self):
for i in FFTWDATA_SIZES:
x, yr, dt = fftw_dct_ref(self.type, i, self.rdt)
y = dct(x, type=self.type)
assert_equal(y.dtype, dt)
# XXX: we divide by np.max(y) because the tests fail otherwise. We
# should really use something like assert_array_approx_equal. The
# difference is due to fftw using a better algorithm w.r.t error
# propagation compared to the ones from fftpack.
assert_array_almost_equal(y / np.max(y), yr / np.max(y), decimal=self.dec,
err_msg="Size %d failed" % i)
def test_axis(self):
nt = 2
for i in [7, 8, 9, 16, 32, 64]:
x = np.random.randn(nt, i)
y = dct(x, type=self.type)
for j in range(nt):
assert_array_almost_equal(y[j], dct(x[j], type=self.type),
decimal=self.dec)
x = x.T
y = dct(x, axis=0, type=self.type)
for j in range(nt):
assert_array_almost_equal(y[:,j], dct(x[:,j], type=self.type),
decimal=self.dec)
class _TestDCTIBase(_TestDCTBase):
def test_definition_ortho(self):
# Test orthornomal mode.
for i in range(len(X)):
x = np.array(X[i], dtype=self.rdt)
dt = np.result_type(np.float32, self.rdt)
y = dct(x, norm='ortho', type=1)
y2 = naive_dct1(x, norm='ortho')
assert_equal(y.dtype, dt)
assert_array_almost_equal(y / np.max(y), y2 / np.max(y), decimal=self.dec)
class _TestDCTIIBase(_TestDCTBase):
def test_definition_matlab(self):
# Test correspondence with matlab (orthornomal mode).
for i in range(len(X)):
dt = np.result_type(np.float32, self.rdt)
x = np.array(X[i], dtype=dt)
yr = Y[i]
y = dct(x, norm="ortho", type=2)
assert_equal(y.dtype, dt)
assert_array_almost_equal(y, yr, decimal=self.dec)
class _TestDCTIIIBase(_TestDCTBase):
def test_definition_ortho(self):
# Test orthornomal mode.
for i in range(len(X)):
x = np.array(X[i], dtype=self.rdt)
dt = np.result_type(np.float32, self.rdt)
y = dct(x, norm='ortho', type=2)
xi = dct(y, norm="ortho", type=3)
assert_equal(xi.dtype, dt)
assert_array_almost_equal(xi, x, decimal=self.dec)
class _TestDCTIVBase(_TestDCTBase):
def test_definition_ortho(self):
# Test orthornomal mode.
for i in range(len(X)):
x = np.array(X[i], dtype=self.rdt)
dt = np.result_type(np.float32, self.rdt)
y = dct(x, norm='ortho', type=4)
y2 = naive_dct4(x, norm='ortho')
assert_equal(y.dtype, dt)
assert_array_almost_equal(y / np.max(y), y2 / np.max(y), decimal=self.dec)
class TestDCTIDouble(_TestDCTIBase):
def setup_method(self):
self.rdt = np.double
self.dec = 10
self.type = 1
class TestDCTIFloat(_TestDCTIBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 4
self.type = 1
class TestDCTIInt(_TestDCTIBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 1
class TestDCTIIDouble(_TestDCTIIBase):
def setup_method(self):
self.rdt = np.double
self.dec = 10
self.type = 2
class TestDCTIIFloat(_TestDCTIIBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 2
class TestDCTIIInt(_TestDCTIIBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 2
class TestDCTIIIDouble(_TestDCTIIIBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 3
class TestDCTIIIFloat(_TestDCTIIIBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 3
class TestDCTIIIInt(_TestDCTIIIBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 3
class TestDCTIVDouble(_TestDCTIVBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 3
class TestDCTIVFloat(_TestDCTIVBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 3
class TestDCTIVInt(_TestDCTIVBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 3
class _TestIDCTBase(object):
def setup_method(self):
self.rdt = None
self.dec = 14
self.type = None
def test_definition(self):
for i in FFTWDATA_SIZES:
xr, yr, dt = fftw_dct_ref(self.type, i, self.rdt)
x = idct(yr, type=self.type)
if self.type == 1:
x /= 2 * (i-1)
else:
x /= 2 * i
assert_equal(x.dtype, dt)
# XXX: we divide by np.max(y) because the tests fail otherwise. We
# should really use something like assert_array_approx_equal. The
# difference is due to fftw using a better algorithm w.r.t error
# propagation compared to the ones from fftpack.
assert_array_almost_equal(x / np.max(x), xr / np.max(x), decimal=self.dec,
err_msg="Size %d failed" % i)
class TestIDCTIDouble(_TestIDCTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 10
self.type = 1
class TestIDCTIFloat(_TestIDCTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 4
self.type = 1
class TestIDCTIInt(_TestIDCTBase):
def setup_method(self):
self.rdt = int
self.dec = 4
self.type = 1
class TestIDCTIIDouble(_TestIDCTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 10
self.type = 2
class TestIDCTIIFloat(_TestIDCTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 2
class TestIDCTIIInt(_TestIDCTBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 2
class TestIDCTIIIDouble(_TestIDCTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 3
class TestIDCTIIIFloat(_TestIDCTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 3
class TestIDCTIIIInt(_TestIDCTBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 3
class TestIDCTIVDouble(_TestIDCTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 4
class TestIDCTIVFloat(_TestIDCTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 5
self.type = 4
class TestIDCTIVInt(_TestIDCTBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 4
class _TestDSTBase(object):
def setup_method(self):
self.rdt = None # dtype
self.dec = None # number of decimals to match
self.type = None # dst type
def test_definition(self):
for i in FFTWDATA_SIZES:
xr, yr, dt = fftw_dst_ref(self.type, i, self.rdt)
y = dst(xr, type=self.type)
assert_equal(y.dtype, dt)
# XXX: we divide by np.max(y) because the tests fail otherwise. We
# should really use something like assert_array_approx_equal. The
# difference is due to fftw using a better algorithm w.r.t error
# propagation compared to the ones from fftpack.
assert_array_almost_equal(y / np.max(y), yr / np.max(y), decimal=self.dec,
err_msg="Size %d failed" % i)
class _TestDSTIBase(_TestDSTBase):
def test_definition_ortho(self):
# Test orthornomal mode.
for i in range(len(X)):
x = np.array(X[i], dtype=self.rdt)
dt = np.result_type(np.float32, self.rdt)
y = dst(x, norm='ortho', type=1)
y2 = naive_dst1(x, norm='ortho')
assert_equal(y.dtype, dt)
assert_array_almost_equal(y / np.max(y), y2 / np.max(y), decimal=self.dec)
class _TestDSTIVBase(_TestDSTBase):
def test_definition_ortho(self):
# Test orthornomal mode.
for i in range(len(X)):
x = np.array(X[i], dtype=self.rdt)
dt = np.result_type(np.float32, self.rdt)
y = dst(x, norm='ortho', type=4)
y2 = naive_dst4(x, norm='ortho')
assert_equal(y.dtype, dt)
assert_array_almost_equal(y, y2, decimal=self.dec)
class TestDSTIDouble(_TestDSTIBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 1
class TestDSTIFloat(_TestDSTIBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 4
self.type = 1
class TestDSTIInt(_TestDSTIBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 1
class TestDSTIIDouble(_TestDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 2
class TestDSTIIFloat(_TestDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 6
self.type = 2
class TestDSTIIInt(_TestDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 6
self.type = 2
class TestDSTIIIDouble(_TestDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 3
class TestDSTIIIFloat(_TestDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 7
self.type = 3
class TestDSTIIIInt(_TestDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 7
self.type = 3
class TestDSTIVDouble(_TestDSTIVBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 4
class TestDSTIVFloat(_TestDSTIVBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 4
self.type = 4
class TestDSTIVInt(_TestDSTIVBase):
def setup_method(self):
self.rdt = int
self.dec = 5
self.type = 4
class _TestIDSTBase(object):
def setup_method(self):
self.rdt = None
self.dec = None
self.type = None
def test_definition(self):
for i in FFTWDATA_SIZES:
xr, yr, dt = fftw_dst_ref(self.type, i, self.rdt)
x = idst(yr, type=self.type)
if self.type == 1:
x /= 2 * (i+1)
else:
x /= 2 * i
assert_equal(x.dtype, dt)
# XXX: we divide by np.max(x) because the tests fail otherwise. We
# should really use something like assert_array_approx_equal. The
# difference is due to fftw using a better algorithm w.r.t error
# propagation compared to the ones from fftpack.
assert_array_almost_equal(x / np.max(x), xr / np.max(x), decimal=self.dec,
err_msg="Size %d failed" % i)
class TestIDSTIDouble(_TestIDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 1
class TestIDSTIFloat(_TestIDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 4
self.type = 1
class TestIDSTIInt(_TestIDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 4
self.type = 1
class TestIDSTIIDouble(_TestIDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 2
class TestIDSTIIFloat(_TestIDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 6
self.type = 2
class TestIDSTIIInt(_TestIDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 6
self.type = 2
class TestIDSTIIIDouble(_TestIDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 14
self.type = 3
class TestIDSTIIIFloat(_TestIDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 6
self.type = 3
class TestIDSTIIIInt(_TestIDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 6
self.type = 3
class TestIDSTIVDouble(_TestIDSTBase):
def setup_method(self):
self.rdt = np.double
self.dec = 12
self.type = 4
class TestIDSTIVFloat(_TestIDSTBase):
def setup_method(self):
self.rdt = np.float32
self.dec = 6
self.type = 4
class TestIDSTIVnt(_TestIDSTBase):
def setup_method(self):
self.rdt = int
self.dec = 6
self.type = 4
class TestOverwrite(object):
"""Check input overwrite behavior."""
real_dtypes = [np.float32, np.float64]
def _check(self, x, routine, type, fftsize, axis, norm, overwrite_x,
should_overwrite, **kw):
x2 = x.copy()
routine(x2, type, fftsize, axis, norm, 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):
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)
for type in [1, 2, 3, 4]:
for overwrite_x in [True, False]:
for norm in [None, 'ortho']:
should_overwrite = (overwrite_x
and dtype in overwritable_dtypes
and (len(shape) == 1 or
(axis % len(shape) == len(shape)-1
)))
self._check(data, routine, type, None, axis, norm,
overwrite_x, should_overwrite)
def test_dct(self):
overwritable = self.real_dtypes
for dtype in self.real_dtypes:
self._check_1d(dct, dtype, (16,), -1, overwritable)
self._check_1d(dct, dtype, (16, 2), 0, overwritable)
self._check_1d(dct, dtype, (2, 16), 1, overwritable)
def test_idct(self):
overwritable = self.real_dtypes
for dtype in self.real_dtypes:
self._check_1d(idct, dtype, (16,), -1, overwritable)
self._check_1d(idct, dtype, (16, 2), 0, overwritable)
self._check_1d(idct, dtype, (2, 16), 1, overwritable)
def test_dst(self):
overwritable = self.real_dtypes
for dtype in self.real_dtypes:
self._check_1d(dst, dtype, (16,), -1, overwritable)
self._check_1d(dst, dtype, (16, 2), 0, overwritable)
self._check_1d(dst, dtype, (2, 16), 1, overwritable)
def test_idst(self):
overwritable = self.real_dtypes
for dtype in self.real_dtypes:
self._check_1d(idst, dtype, (16,), -1, overwritable)
self._check_1d(idst, dtype, (16, 2), 0, overwritable)
self._check_1d(idst, dtype, (2, 16), 1, overwritable)
class Test_DCTN_IDCTN(object):
dec = 14
dct_type = [1, 2, 3, 4]
norms = [None, 'ortho']
rstate = np.random.RandomState(1234)
shape = (32, 16)
data = rstate.randn(*shape)
@pytest.mark.parametrize('fforward,finverse', [(dctn, idctn),
(dstn, idstn)])
@pytest.mark.parametrize('axes', [None,
1, (1,), [1],
0, (0,), [0],
(0, 1), [0, 1],
(-2, -1), [-2, -1]])
@pytest.mark.parametrize('dct_type', dct_type)
@pytest.mark.parametrize('norm', ['ortho'])
def test_axes_round_trip(self, fforward, finverse, axes, dct_type, norm):
tmp = fforward(self.data, type=dct_type, axes=axes, norm=norm)
tmp = finverse(tmp, type=dct_type, axes=axes, norm=norm)
assert_array_almost_equal(self.data, tmp, decimal=12)
@pytest.mark.parametrize('fforward,fforward_ref', [(dctn, dct_2d_ref),
(dstn, dst_2d_ref)])
@pytest.mark.parametrize('dct_type', dct_type)
@pytest.mark.parametrize('norm', norms)
def test_dctn_vs_2d_reference(self, fforward, fforward_ref,
dct_type, norm):
y1 = fforward(self.data, type=dct_type, axes=None, norm=norm)
y2 = fforward_ref(self.data, type=dct_type, norm=norm)
assert_array_almost_equal(y1, y2, decimal=11)
@pytest.mark.parametrize('finverse,finverse_ref', [(idctn, idct_2d_ref),
(idstn, idst_2d_ref)])
@pytest.mark.parametrize('dct_type', dct_type)
@pytest.mark.parametrize('norm', [None, 'ortho'])
def test_idctn_vs_2d_reference(self, finverse, finverse_ref,
dct_type, norm):
fdata = dctn(self.data, type=dct_type, norm=norm)
y1 = finverse(fdata, type=dct_type, norm=norm)
y2 = finverse_ref(fdata, type=dct_type, norm=norm)
assert_array_almost_equal(y1, y2, decimal=11)
@pytest.mark.parametrize('fforward,finverse', [(dctn, idctn),
(dstn, idstn)])
def test_axes_and_shape(self, fforward, finverse):
with assert_raises(ValueError,
match="when given, axes and shape arguments"
" have to be of the same length"):
fforward(self.data, shape=self.data.shape[0], axes=(0, 1))
with assert_raises(ValueError,
match="when given, axes and shape arguments"
" have to be of the same length"):
fforward(self.data, shape=self.data.shape[0], axes=None)
with assert_raises(ValueError,
match="when given, axes and shape arguments"
" have to be of the same length"):
fforward(self.data, shape=self.data.shape, axes=0)
@pytest.mark.parametrize('fforward', [dctn, dstn])
def test_shape(self, fforward):
tmp = fforward(self.data, shape=(128, 128), axes=None)
assert_equal(tmp.shape, (128, 128))
@pytest.mark.parametrize('fforward,finverse', [(dctn, idctn),
(dstn, idstn)])
@pytest.mark.parametrize('axes', [1, (1,), [1],
0, (0,), [0]])
def test_shape_is_none_with_axes(self, fforward, finverse, axes):
tmp = fforward(self.data, shape=None, axes=axes, norm='ortho')
tmp = finverse(tmp, shape=None, axes=axes, norm='ortho')
assert_array_almost_equal(self.data, tmp, decimal=self.dec)