codekingpro/portable-devtools
114k
1import queue
2import threading
3
4import pytest
5
6import numpy as np
7from numpy.random import random
8from numpy.testing import IS_WASM, assert_allclose, assert_array_equal, assert_raises
9
10
11def fft1(x):
12 L = len(x)
13 phase = -2j * np.pi * (np.arange(L) / L)
14 phase = np.arange(L).reshape(-1, 1) * phase
15 return np.sum(x * np.exp(phase), axis=1)
16
17
18class TestFFTShift:
19
20 def test_fft_n(self):
21 assert_raises(ValueError, np.fft.fft, [1, 2, 3], 0)
22
23
24class TestFFT1D:
25
26 def test_identity(self):
27 maxlen = 512
28 x = random(maxlen) + 1j * random(maxlen)
29 xr = random(maxlen)
30 for i in range(1, maxlen):
31 assert_allclose(np.fft.ifft(np.fft.fft(x[0:i])), x[0:i],
32 atol=1e-12)
33 assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]), i),
34 xr[0:i], atol=1e-12)
35
36 @pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
37 def test_identity_long_short(self, dtype):
38 # Test with explicitly given number of points, both for n
39 # smaller and for n larger than the input size.
40 maxlen = 16
41 atol = 5 * np.spacing(np.array(1., dtype=dtype))
42 x = random(maxlen).astype(dtype) + 1j * random(maxlen).astype(dtype)
43 xx = np.concatenate([x, np.zeros_like(x)])
44 xr = random(maxlen).astype(dtype)
45 xxr = np.concatenate([xr, np.zeros_like(xr)])
46 for i in range(1, maxlen * 2):
47 check_c = np.fft.ifft(np.fft.fft(x, n=i), n=i)
48 assert check_c.real.dtype == dtype
49 assert_allclose(check_c, xx[0:i], atol=atol, rtol=0)
50 check_r = np.fft.irfft(np.fft.rfft(xr, n=i), n=i)
51 assert check_r.dtype == dtype
52 assert_allclose(check_r, xxr[0:i], atol=atol, rtol=0)
53
54 @pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
55 def test_identity_long_short_reversed(self, dtype):
56 # Also test explicitly given number of points in reversed order.
57 maxlen = 16
58 atol = 6 * np.spacing(np.array(1., dtype=dtype))
59 x = random(maxlen).astype(dtype) + 1j * random(maxlen).astype(dtype)
60 xx = np.concatenate([x, np.zeros_like(x)])
61 for i in range(1, maxlen * 2):
62 check_via_c = np.fft.fft(np.fft.ifft(x, n=i), n=i)
63 assert check_via_c.dtype == x.dtype
64 assert_allclose(check_via_c, xx[0:i], atol=atol, rtol=0)
65 # For irfft, we can neither recover the imaginary part of
66 # the first element, nor the imaginary part of the last
67 # element if npts is even. So, set to 0 for the comparison.
68 y = x.copy()
69 n = i // 2 + 1
70 y.imag[0] = 0
71 if i % 2 == 0:
72 y.imag[n - 1:] = 0
73 yy = np.concatenate([y, np.zeros_like(y)])
74 check_via_r = np.fft.rfft(np.fft.irfft(x, n=i), n=i)
75 assert check_via_r.dtype == x.dtype
76 assert_allclose(check_via_r, yy[0:n], atol=atol, rtol=0)
77
78 def test_fft(self):
79 x = random(30) + 1j * random(30)
80 assert_allclose(fft1(x), np.fft.fft(x), atol=1e-6)
81 assert_allclose(fft1(x), np.fft.fft(x, norm="backward"), atol=1e-6)
82 assert_allclose(fft1(x) / np.sqrt(30),
83 np.fft.fft(x, norm="ortho"), atol=1e-6)
84 assert_allclose(fft1(x) / 30.,
85 np.fft.fft(x, norm="forward"), atol=1e-6)
86
87 @pytest.mark.parametrize("axis", (0, 1))
88 @pytest.mark.parametrize("dtype", (complex, float))
89 @pytest.mark.parametrize("transpose", (True, False))
90 def test_fft_out_argument(self, dtype, transpose, axis):
91 def zeros_like(x):
92 if transpose:
93 return np.zeros_like(x.T).T
94 else:
95 return np.zeros_like(x)
96
97 # tests below only test the out parameter
98 if dtype is complex:
99 y = random((10, 20)) + 1j * random((10, 20))
100 fft, ifft = np.fft.fft, np.fft.ifft
101 else:
102 y = random((10, 20))
103 fft, ifft = np.fft.rfft, np.fft.irfft
104
105 expected = fft(y, axis=axis)
106 out = zeros_like(expected)
107 result = fft(y, out=out, axis=axis)
108 assert result is out
109 assert_array_equal(result, expected)
110
111 expected2 = ifft(expected, axis=axis)
112 out2 = out if dtype is complex else zeros_like(expected2)
113 result2 = ifft(out, out=out2, axis=axis)
114 assert result2 is out2
115 assert_array_equal(result2, expected2)
116
117 @pytest.mark.parametrize("axis", [0, 1])
118 def test_fft_inplace_out(self, axis):
119 # Test some weirder in-place combinations
120 y = random((20, 20)) + 1j * random((20, 20))
121 # Fully in-place.
122 y1 = y.copy()
123 expected1 = np.fft.fft(y1, axis=axis)
124 result1 = np.fft.fft(y1, axis=axis, out=y1)
125 assert result1 is y1
126 assert_array_equal(result1, expected1)
127 # In-place of part of the array; rest should be unchanged.
128 y2 = y.copy()
129 out2 = y2[:10] if axis == 0 else y2[:, :10]
130 expected2 = np.fft.fft(y2, n=10, axis=axis)
131 result2 = np.fft.fft(y2, n=10, axis=axis, out=out2)
132 assert result2 is out2
133 assert_array_equal(result2, expected2)
134 if axis == 0:
135 assert_array_equal(y2[10:], y[10:])
136 else:
137 assert_array_equal(y2[:, 10:], y[:, 10:])
138 # In-place of another part of the array.
139 y3 = y.copy()
140 y3_sel = y3[5:] if axis == 0 else y3[:, 5:]
141 out3 = y3[5:15] if axis == 0 else y3[:, 5:15]
142 expected3 = np.fft.fft(y3_sel, n=10, axis=axis)
143 result3 = np.fft.fft(y3_sel, n=10, axis=axis, out=out3)
144 assert result3 is out3
145 assert_array_equal(result3, expected3)
146 if axis == 0:
147 assert_array_equal(y3[:5], y[:5])
148 assert_array_equal(y3[15:], y[15:])
149 else:
150 assert_array_equal(y3[:, :5], y[:, :5])
151 assert_array_equal(y3[:, 15:], y[:, 15:])
152 # In-place with n > nin; rest should be unchanged.
153 y4 = y.copy()
154 y4_sel = y4[:10] if axis == 0 else y4[:, :10]
155 out4 = y4[:15] if axis == 0 else y4[:, :15]
156 expected4 = np.fft.fft(y4_sel, n=15, axis=axis)
157 result4 = np.fft.fft(y4_sel, n=15, axis=axis, out=out4)
158 assert result4 is out4
159 assert_array_equal(result4, expected4)
160 if axis == 0:
161 assert_array_equal(y4[15:], y[15:])
162 else:
163 assert_array_equal(y4[:, 15:], y[:, 15:])
164 # Overwrite in a transpose.
165 y5 = y.copy()
166 out5 = y5.T
167 result5 = np.fft.fft(y5, axis=axis, out=out5)
168 assert result5 is out5
169 assert_array_equal(result5, expected1)
170 # Reverse strides.
171 y6 = y.copy()
172 out6 = y6[::-1] if axis == 0 else y6[:, ::-1]
173 result6 = np.fft.fft(y6, axis=axis, out=out6)
174 assert result6 is out6
175 assert_array_equal(result6, expected1)
176
177 def test_fft_bad_out(self):
178 x = np.arange(30.)
179 with pytest.raises(TypeError, match="must be of ArrayType"):
180 np.fft.fft(x, out="")
181 with pytest.raises(ValueError, match="has wrong shape"):
182 np.fft.fft(x, out=np.zeros_like(x).reshape(5, -1))
183 with pytest.raises(TypeError, match="Cannot cast"):
184 np.fft.fft(x, out=np.zeros_like(x, dtype=float))
185
186 @pytest.mark.parametrize('norm', (None, 'backward', 'ortho', 'forward'))
187 def test_ifft(self, norm):
188 x = random(30) + 1j * random(30)
189 assert_allclose(
190 x, np.fft.ifft(np.fft.fft(x, norm=norm), norm=norm),
191 atol=1e-6)
192 # Ensure we get the correct error message
193 with pytest.raises(ValueError,
194 match='Invalid number of FFT data points'):
195 np.fft.ifft([], norm=norm)
196
197 def test_fft2(self):
198 x = random((30, 20)) + 1j * random((30, 20))
199 assert_allclose(np.fft.fft(np.fft.fft(x, axis=1), axis=0),
200 np.fft.fft2(x), atol=1e-6)
201 assert_allclose(np.fft.fft2(x),
202 np.fft.fft2(x, norm="backward"), atol=1e-6)
203 assert_allclose(np.fft.fft2(x) / np.sqrt(30 * 20),
204 np.fft.fft2(x, norm="ortho"), atol=1e-6)
205 assert_allclose(np.fft.fft2(x) / (30. * 20.),
206 np.fft.fft2(x, norm="forward"), atol=1e-6)
207
208 def test_ifft2(self):
209 x = random((30, 20)) + 1j * random((30, 20))
210 assert_allclose(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0),
211 np.fft.ifft2(x), atol=1e-6)
212 assert_allclose(np.fft.ifft2(x),
213 np.fft.ifft2(x, norm="backward"), atol=1e-6)
214 assert_allclose(np.fft.ifft2(x) * np.sqrt(30 * 20),
215 np.fft.ifft2(x, norm="ortho"), atol=1e-6)
216 assert_allclose(np.fft.ifft2(x) * (30. * 20.),
217 np.fft.ifft2(x, norm="forward"), atol=1e-6)
218
219 def test_fftn(self):
220 x = random((30, 20, 10)) + 1j * random((30, 20, 10))
221 assert_allclose(
222 np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0),
223 np.fft.fftn(x), atol=1e-6)
224 assert_allclose(np.fft.fftn(x),
225 np.fft.fftn(x, norm="backward"), atol=1e-6)
226 assert_allclose(np.fft.fftn(x) / np.sqrt(30 * 20 * 10),
227 np.fft.fftn(x, norm="ortho"), atol=1e-6)
228 assert_allclose(np.fft.fftn(x) / (30. * 20. * 10.),
229 np.fft.fftn(x, norm="forward"), atol=1e-6)
230
231 def test_ifftn(self):
232 x = random((30, 20, 10)) + 1j * random((30, 20, 10))
233 assert_allclose(
234 np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0),
235 np.fft.ifftn(x), atol=1e-6)
236 assert_allclose(np.fft.ifftn(x),
237 np.fft.ifftn(x, norm="backward"), atol=1e-6)
238 assert_allclose(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10),
239 np.fft.ifftn(x, norm="ortho"), atol=1e-6)
240 assert_allclose(np.fft.ifftn(x) * (30. * 20. * 10.),
241 np.fft.ifftn(x, norm="forward"), atol=1e-6)
242
243 def test_rfft(self):
244 x = random(30)
245 for n in [x.size, 2 * x.size]:
246 for norm in [None, 'backward', 'ortho', 'forward']:
247 assert_allclose(
248 np.fft.fft(x, n=n, norm=norm)[:(n // 2 + 1)],
249 np.fft.rfft(x, n=n, norm=norm), atol=1e-6)
250 assert_allclose(
251 np.fft.rfft(x, n=n),
252 np.fft.rfft(x, n=n, norm="backward"), atol=1e-6)
253 assert_allclose(
254 np.fft.rfft(x, n=n) / np.sqrt(n),
255 np.fft.rfft(x, n=n, norm="ortho"), atol=1e-6)
256 assert_allclose(
257 np.fft.rfft(x, n=n) / n,
258 np.fft.rfft(x, n=n, norm="forward"), atol=1e-6)
259
260 def test_rfft_even(self):
261 x = np.arange(8)
262 n = 4
263 y = np.fft.rfft(x, n)
264 assert_allclose(y, np.fft.fft(x[:n])[:n // 2 + 1], rtol=1e-14)
265
266 def test_rfft_odd(self):
267 x = np.array([1, 0, 2, 3, -3])
268 y = np.fft.rfft(x)
269 assert_allclose(y, np.fft.fft(x)[:3], rtol=1e-14)
270
271 def test_irfft(self):
272 x = random(30)
273 assert_allclose(x, np.fft.irfft(np.fft.rfft(x)), atol=1e-6)
274 assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="backward"),
275 norm="backward"), atol=1e-6)
276 assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="ortho"),
277 norm="ortho"), atol=1e-6)
278 assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="forward"),
279 norm="forward"), atol=1e-6)
280
281 def test_rfft2(self):
282 x = random((30, 20))
283 assert_allclose(np.fft.fft2(x)[:, :11], np.fft.rfft2(x), atol=1e-6)
284 assert_allclose(np.fft.rfft2(x),
285 np.fft.rfft2(x, norm="backward"), atol=1e-6)
286 assert_allclose(np.fft.rfft2(x) / np.sqrt(30 * 20),
287 np.fft.rfft2(x, norm="ortho"), atol=1e-6)
288 assert_allclose(np.fft.rfft2(x) / (30. * 20.),
289 np.fft.rfft2(x, norm="forward"), atol=1e-6)
290
291 def test_irfft2(self):
292 x = random((30, 20))
293 assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x)), atol=1e-6)
294 assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="backward"),
295 norm="backward"), atol=1e-6)
296 assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"),
297 norm="ortho"), atol=1e-6)
298 assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="forward"),
299 norm="forward"), atol=1e-6)
300
301 def test_rfftn(self):
302 x = random((30, 20, 10))
303 assert_allclose(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x), atol=1e-6)
304 assert_allclose(np.fft.rfftn(x),
305 np.fft.rfftn(x, norm="backward"), atol=1e-6)
306 assert_allclose(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10),
307 np.fft.rfftn(x, norm="ortho"), atol=1e-6)
308 assert_allclose(np.fft.rfftn(x) / (30. * 20. * 10.),
309 np.fft.rfftn(x, norm="forward"), atol=1e-6)
310 # Regression test for gh-27159
311 x = np.ones((2, 3))
312 result = np.fft.rfftn(x, axes=(0, 0, 1), s=(10, 20, 40))
313 assert result.shape == (10, 21)
314 expected = np.fft.fft(np.fft.fft(np.fft.rfft(x, axis=1, n=40),
315 axis=0, n=20), axis=0, n=10)
316 assert expected.shape == (10, 21)
317 assert_allclose(result, expected, atol=1e-6)
318
319 def test_irfftn(self):
320 x = random((30, 20, 10))
321 assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x)), atol=1e-6)
322 assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="backward"),
323 norm="backward"), atol=1e-6)
324 assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"),
325 norm="ortho"), atol=1e-6)
326 assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="forward"),
327 norm="forward"), atol=1e-6)
328
329 def test_hfft(self):
330 x = random(14) + 1j * random(14)
331 x_herm = np.concatenate((random(1), x, random(1)))
332 x = np.concatenate((x_herm, x[::-1].conj()))
333 assert_allclose(np.fft.fft(x), np.fft.hfft(x_herm), atol=1e-6)
334 assert_allclose(np.fft.hfft(x_herm),
335 np.fft.hfft(x_herm, norm="backward"), atol=1e-6)
336 assert_allclose(np.fft.hfft(x_herm) / np.sqrt(30),
337 np.fft.hfft(x_herm, norm="ortho"), atol=1e-6)
338 assert_allclose(np.fft.hfft(x_herm) / 30.,
339 np.fft.hfft(x_herm, norm="forward"), atol=1e-6)
340
341 def test_ihfft(self):
342 x = random(14) + 1j * random(14)
343 x_herm = np.concatenate((random(1), x, random(1)))
344 x = np.concatenate((x_herm, x[::-1].conj()))
345 assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm)), atol=1e-6)
346 assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
347 norm="backward"), norm="backward"), atol=1e-6)
348 assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
349 norm="ortho"), norm="ortho"), atol=1e-6)
350 assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
351 norm="forward"), norm="forward"), atol=1e-6)
352
353 @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
354 np.fft.rfftn, np.fft.irfftn])
355 def test_axes(self, op):
356 x = random((30, 20, 10))
357 axes = [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
358 for a in axes:
359 op_tr = op(np.transpose(x, a))
360 tr_op = np.transpose(op(x, axes=a), a)
361 assert_allclose(op_tr, tr_op, atol=1e-6)
362
363 @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
364 np.fft.fft2, np.fft.ifft2])
365 def test_s_negative_1(self, op):
366 x = np.arange(100).reshape(10, 10)
367 # should use the whole input array along the first axis
368 assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5)
369
370 @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
371 np.fft.rfftn, np.fft.irfftn])
372 def test_s_axes_none(self, op):
373 x = np.arange(100).reshape(10, 10)
374 with pytest.warns(match='`axes` should not be `None` if `s`'):
375 op(x, s=(-1, 5))
376
377 @pytest.mark.parametrize("op", [np.fft.fft2, np.fft.ifft2])
378 def test_s_axes_none_2D(self, op):
379 x = np.arange(100).reshape(10, 10)
380 with pytest.warns(match='`axes` should not be `None` if `s`'):
381 op(x, s=(-1, 5), axes=None)
382
383 @pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
384 np.fft.rfftn, np.fft.irfftn,
385 np.fft.fft2, np.fft.ifft2])
386 def test_s_contains_none(self, op):
387 x = random((30, 20, 10))
388 with pytest.warns(match='array containing `None` values to `s`'):
389 op(x, s=(10, None, 10), axes=(0, 1, 2))
390
391 def test_all_1d_norm_preserving(self):
392 # verify that round-trip transforms are norm-preserving
393 x = random(30)
394 x_norm = np.linalg.norm(x)
395 n = x.size * 2
396 func_pairs = [(np.fft.fft, np.fft.ifft),
397 (np.fft.rfft, np.fft.irfft),
398 # hfft: order so the first function takes x.size samples
399 # (necessary for comparison to x_norm above)
400 (np.fft.ihfft, np.fft.hfft),
401 ]
402 for forw, back in func_pairs:
403 for n in [x.size, 2 * x.size]:
404 for norm in [None, 'backward', 'ortho', 'forward']:
405 tmp = forw(x, n=n, norm=norm)
406 tmp = back(tmp, n=n, norm=norm)
407 assert_allclose(x_norm,
408 np.linalg.norm(tmp), atol=1e-6)
409
410 @pytest.mark.parametrize("axes", [(0, 1), (0, 2), None])
411 @pytest.mark.parametrize("dtype", (complex, float))
412 @pytest.mark.parametrize("transpose", (True, False))
413 def test_fftn_out_argument(self, dtype, transpose, axes):
414 def zeros_like(x):
415 if transpose:
416 return np.zeros_like(x.T).T
417 else:
418 return np.zeros_like(x)
419
420 # tests below only test the out parameter
421 if dtype is complex:
422 x = random((10, 5, 6)) + 1j * random((10, 5, 6))
423 fft, ifft = np.fft.fftn, np.fft.ifftn
424 else:
425 x = random((10, 5, 6))
426 fft, ifft = np.fft.rfftn, np.fft.irfftn
427
428 expected = fft(x, axes=axes)
429 out = zeros_like(expected)
430 result = fft(x, out=out, axes=axes)
431 assert result is out
432 assert_array_equal(result, expected)
433
434 expected2 = ifft(expected, axes=axes)
435 out2 = out if dtype is complex else zeros_like(expected2)
436 result2 = ifft(out, out=out2, axes=axes)
437 assert result2 is out2
438 assert_array_equal(result2, expected2)
439
440 @pytest.mark.parametrize("fft", [np.fft.fftn, np.fft.ifftn, np.fft.rfftn])
441 def test_fftn_out_and_s_interaction(self, fft):
442 # With s, shape varies, so generally one cannot pass in out.
443 if fft is np.fft.rfftn:
444 x = random((10, 5, 6))
445 else:
446 x = random((10, 5, 6)) + 1j * random((10, 5, 6))
447 with pytest.raises(ValueError, match="has wrong shape"):
448 fft(x, out=np.zeros_like(x), s=(3, 3, 3), axes=(0, 1, 2))
449 # Except on the first axis done (which is the last of axes).
450 s = (10, 5, 5)
451 expected = fft(x, s=s, axes=(0, 1, 2))
452 out = np.zeros_like(expected)
453 result = fft(x, s=s, axes=(0, 1, 2), out=out)
454 assert result is out
455 assert_array_equal(result, expected)
456
457 @pytest.mark.parametrize("s", [(9, 5, 5), (3, 3, 3)])
458 def test_irfftn_out_and_s_interaction(self, s):
459 # Since for irfftn, the output is real and thus cannot be used for
460 # intermediate steps, it should always work.
461 x = random((9, 5, 6, 2)) + 1j * random((9, 5, 6, 2))
462 expected = np.fft.irfftn(x, s=s, axes=(0, 1, 2))
463 out = np.zeros_like(expected)
464 result = np.fft.irfftn(x, s=s, axes=(0, 1, 2), out=out)
465 assert result is out
466 assert_array_equal(result, expected)
467
468
469@pytest.mark.parametrize(
470 "dtype",
471 [np.float32, np.float64, np.complex64, np.complex128])
472@pytest.mark.parametrize("order", ["F", 'non-contiguous'])
473@pytest.mark.parametrize(
474 "fft",
475 [np.fft.fft, np.fft.fft2, np.fft.fftn,
476 np.fft.ifft, np.fft.ifft2, np.fft.ifftn])
477def test_fft_with_order(dtype, order, fft):
478 # Check that FFT/IFFT produces identical results for C, Fortran and
479 # non contiguous arrays
480 rng = np.random.RandomState(42)
481 X = rng.rand(8, 7, 13).astype(dtype, copy=False)
482 # See discussion in pull/14178
483 _tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps
484 if order == 'F':
485 Y = np.asfortranarray(X)
486 else:
487 # Make a non contiguous array
488 Y = X[::-1]
489 X = np.ascontiguousarray(X[::-1])
490
491 if fft.__name__.endswith('fft'):
492 for axis in range(3):
493 X_res = fft(X, axis=axis)
494 Y_res = fft(Y, axis=axis)
495 assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
496 elif fft.__name__.endswith(('fft2', 'fftn')):
497 axes = [(0, 1), (1, 2), (0, 2)]
498 if fft.__name__.endswith('fftn'):
499 axes.extend([(0,), (1,), (2,), None])
500 for ax in axes:
501 X_res = fft(X, axes=ax)
502 Y_res = fft(Y, axes=ax)
503 assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
504 else:
505 raise ValueError
506
507
508@pytest.mark.parametrize("order", ["F", "C"])
509@pytest.mark.parametrize("n", [None, 7, 12])
510def test_fft_output_order(order, n):
511 rng = np.random.RandomState(42)
512 x = rng.rand(10)
513 x = np.asarray(x, dtype=np.complex64, order=order)
514 res = np.fft.fft(x, n=n)
515 assert res.flags.c_contiguous == x.flags.c_contiguous
516 assert res.flags.f_contiguous == x.flags.f_contiguous
517
518@pytest.mark.skipif(IS_WASM, reason="Cannot start thread")
519class TestFFTThreadSafe:
520 threads = 16
521 input_shape = (800, 200)
522
523 def _test_mtsame(self, func, *args):
524 def worker(args, q):
525 q.put(func(*args))
526
527 q = queue.Queue()
528 expected = func(*args)
529
530 # Spin off a bunch of threads to call the same function simultaneously
531 t = [threading.Thread(target=worker, args=(args, q))
532 for i in range(self.threads)]
533 [x.start() for x in t]
534
535 [x.join() for x in t]
536 # Make sure all threads returned the correct value
537 for i in range(self.threads):
538 assert_array_equal(q.get(timeout=5), expected,
539 'Function returned wrong value in multithreaded context')
540
541 def test_fft(self):
542 a = np.ones(self.input_shape) * 1 + 0j
543 self._test_mtsame(np.fft.fft, a)
544
545 def test_ifft(self):
546 a = np.ones(self.input_shape) * 1 + 0j
547 self._test_mtsame(np.fft.ifft, a)
548
549 def test_rfft(self):
550 a = np.ones(self.input_shape)
551 self._test_mtsame(np.fft.rfft, a)
552
553 def test_irfft(self):
554 a = np.ones(self.input_shape) * 1 + 0j
555 self._test_mtsame(np.fft.irfft, a)
556
557
558def test_irfft_with_n_1_regression():
559 # Regression test for gh-25661
560 x = np.arange(10)
561 np.fft.irfft(x, n=1)
562 np.fft.hfft(x, n=1)
563 np.fft.irfft(np.array([0], complex), n=10)
564
565
566def test_irfft_with_n_large_regression():
567 # Regression test for gh-25679
568 x = np.arange(5) * (1 + 1j)
569 result = np.fft.hfft(x, n=10)
570 expected = np.array([20., 9.91628173, -11.8819096, 7.1048486,
571 -6.62459848, 4., -3.37540152, -0.16057669,
572 1.8819096, -20.86055364])
573 assert_allclose(result, expected)
574
575
576@pytest.mark.parametrize("fft", [
577 np.fft.fft, np.fft.ifft, np.fft.rfft, np.fft.irfft
578])
579@pytest.mark.parametrize("data", [
580 np.array([False, True, False]),
581 np.arange(10, dtype=np.uint8),
582 np.arange(5, dtype=np.int16),
583])
584def test_fft_with_integer_or_bool_input(data, fft):
585 # Regression test for gh-25819
586 result = fft(data)
587 float_data = data.astype(np.result_type(data, 1.))
588 expected = fft(float_data)
589 assert_array_equal(result, expected)
590 