1
1
@enum Direction FFT_FORWARD FFT_BACKWARD
2
2
abstract type AbstractFFTType end
3
3
4
+ function alternatingSum (x:: AbstractVector{T} ) where T
5
+ y = x[1 ]
6
+ @turbo for i in 2 : length (x)
7
+ y += (x[i] * convert (T,(2 * (i % 2 ) - 1 )))
8
+ end
9
+ y
10
+ end
11
+
4
12
# Represents a Composite Cooley-Tukey FFT
5
13
struct CompositeFFT <: AbstractFFTType end
6
14
@@ -51,7 +59,7 @@ struct CallGraph{T<:Complex}
51
59
end
52
60
53
61
# Get the node in the graph at index i
54
- Base. getindex (g:: CallGraph{T} , i:: Int ) where {T<: Complex } = g. nodes[i]
62
+ Base. getindex (g:: CallGraph{T} , i:: Int ) where {T} = g. nodes[i]
55
63
56
64
# Get the left child of the node at index `i`
57
65
leftNode (g:: CallGraph , i:: Int ) = g[i+ g[i]. left]
@@ -60,7 +68,7 @@ leftNode(g::CallGraph, i::Int) = g[i+g[i].left]
60
68
rightNode (g:: CallGraph , i:: Int ) = g[i+ g[i]. right]
61
69
62
70
# Recursively instantiate a set of `CallGraphNode`s
63
- function CallGraphNode! (nodes:: Vector{CallGraphNode} , N:: Int , workspace:: Vector{Vector{T}} ):: Int where {T<: Complex }
71
+ function CallGraphNode! (nodes:: Vector{CallGraphNode} , N:: Int , workspace:: Vector{Vector{T}} ):: Int where {T}
64
72
facs = factor (N)
65
73
Ns = [first (x) for x in collect (facs) for _ in 1 : last (x)]
66
74
if length (Ns) == 1 || Ns[end ] == 2
@@ -90,21 +98,28 @@ function CallGraphNode!(nodes::Vector{CallGraphNode}, N::Int, workspace::Vector{
90
98
end
91
99
92
100
# Instantiate a CallGraph from a number `N`
93
- function CallGraph {T} (N:: Int ) where {T<: Complex }
101
+ function CallGraph {T} (N:: Int ) where {T}
94
102
nodes = CallGraphNode[]
95
103
workspace = Vector {Vector{T}} ()
96
104
CallGraphNode! (nodes, N, workspace)
97
105
CallGraph (nodes, workspace)
98
106
end
99
107
100
- function fft (x:: AbstractVector{T} ) where {T<: Complex }
108
+ function fft (x:: AbstractVector{T} ) where {T}
101
109
y = similar (x)
102
110
g = CallGraph {T} (length (x))
103
111
fft! (y, x, Val (FFT_FORWARD), g[1 ]. type, g, 1 )
104
112
y
105
113
end
106
114
107
- function fft (x:: AbstractMatrix{T} ) where {T<: Complex }
115
+ function fft (x:: AbstractVector{T} ) where {T <: Real }
116
+ y = similar (x, Complex{T})
117
+ g = CallGraph {Complex{T}} (length (x))
118
+ fft! (y, x, Val (FFT_FORWARD), g[1 ]. type, g, 1 )
119
+ y
120
+ end
121
+
122
+ function fft (x:: AbstractMatrix{T} ) where {T}
108
123
M,N = size (x)
109
124
y1 = similar (x)
110
125
y2 = similar (x)
@@ -121,14 +136,14 @@ function fft(x::AbstractMatrix{T}) where {T<:Complex}
121
136
y2
122
137
end
123
138
124
- function bfft (x:: AbstractVector{T} ) where {T<: Complex }
139
+ function bfft (x:: AbstractVector{T} ) where {T}
125
140
y = similar (x)
126
141
g = CallGraph {T} (length (x))
127
142
fft! (y, x, Val (FFT_BACKWARD), g[1 ]. type, g, 1 )
128
143
y
129
144
end
130
145
131
- function bfft (x:: AbstractMatrix{T} ) where {T<: Complex }
146
+ function bfft (x:: AbstractMatrix{T} ) where {T}
132
147
M,N = size (x)
133
148
y1 = similar (x)
134
149
y2 = similar (x)
@@ -147,24 +162,23 @@ end
147
162
148
163
fft! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{<:Direction} , :: AbstractFFTType , :: CallGraph{T} , :: Int ) where {T} = nothing
149
164
150
- function (g:: CallGraph{T} )(out:: AbstractVector{T} , in:: AbstractVector{T } , v:: Val{FFT_FORWARD} , t:: AbstractFFTType , idx:: Int ) where {T}
165
+ function (g:: CallGraph{T} )(out:: AbstractVector{T} , in:: AbstractVector{U } , v:: Val{FFT_FORWARD} , t:: AbstractFFTType , idx:: Int ) where {T,U }
151
166
fft! (out, in, v, t, g, idx)
152
167
end
153
168
154
- function (g:: CallGraph{T} )(out:: AbstractVector{T} , in:: AbstractVector{T } , v:: Val{FFT_BACKWARD} , t:: AbstractFFTType , idx:: Int ) where {T}
169
+ function (g:: CallGraph{T} )(out:: AbstractVector{T} , in:: AbstractVector{U } , v:: Val{FFT_BACKWARD} , t:: AbstractFFTType , idx:: Int ) where {T,U }
155
170
fft! (out, in, v, t, g, idx)
156
171
end
157
172
158
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_FORWARD} , :: CompositeFFT , g:: CallGraph{T} , idx:: Int ) where {T<: Complex }
173
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_FORWARD} , :: CompositeFFT , g:: CallGraph{T} , idx:: Int ) where {T,U }
159
174
N = length (out)
160
175
left = leftNode (g,idx)
161
176
right = rightNode (g,idx)
162
177
N1 = left. sz
163
178
N2 = right. sz
164
179
165
- inc = 2 * π/ N
166
- w1 = T (cos (inc), - sin (inc))
167
- wj1 = T (1 , 0 )
180
+ w1 = convert (T, cispi (- 2 / N))
181
+ wj1 = one (T)
168
182
tmp = g. workspace[idx]
169
183
for j1 in 1 : N1
170
184
wk2 = wj1;
@@ -181,16 +195,15 @@ function fft!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_FORWARD},
181
195
end
182
196
end
183
197
184
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_BACKWARD} , :: CompositeFFT , g:: CallGraph{T} , idx:: Int ) where {T<: Complex }
198
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_BACKWARD} , :: CompositeFFT , g:: CallGraph{T} , idx:: Int ) where {T,U }
185
199
N = length (out)
186
200
left = left (g,i)
187
201
right = right (g,i)
188
202
N1 = left. sz
189
203
N2 = right. sz
190
204
191
- inc = 2 * π/ N
192
- w1 = T (cos (inc), sin (inc))
193
- wj1 = T (1 , 0 )
205
+ w1 = convert (T, cispi (2 / N))
206
+ wj1 = one (T)
194
207
tmp = g. workspace[idx]
195
208
for j1 in 2 : N1
196
209
Complex< F,L> wk2 = wj1;
@@ -207,19 +220,19 @@ function fft!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_BACKWARD}
207
220
end
208
221
end
209
222
210
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_FORWARD} , :: Pow2FFT , :: CallGraph{T} , :: Int ) where {T<: Complex }
223
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_FORWARD} , :: Pow2FFT , :: CallGraph{T} , :: Int ) where {T,U }
211
224
fft_pow2! (out, in, Val (FFT_FORWARD))
212
225
end
213
226
214
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_BACKWARD} , :: Pow2FFT , :: CallGraph{T} , :: Int ) where {T<: Complex }
227
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_BACKWARD} , :: Pow2FFT , :: CallGraph{T} , :: Int ) where {T,U }
215
228
fft_pow2! (out, in, Val (FFT_BACKWARD))
216
229
end
217
230
218
231
"""
219
232
Power of 2 FFT in place, forward
220
233
221
234
"""
222
- function fft_pow2! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_FORWARD} ) where {T<: Complex }
235
+ function fft_pow2! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_FORWARD} ) where {T}
223
236
N = length (out)
224
237
if N == 1
225
238
out[1 ] = in[1 ]
@@ -228,9 +241,8 @@ function fft_pow2!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_FORW
228
241
fft_pow2! (@view (out[1 : (end ÷ 2 )]), @view (in[1 : 2 : end ]), Val (FFT_FORWARD))
229
242
fft_pow2! (@view (out[(end ÷ 2 + 1 ): end ]), @view (in[2 : 2 : end ]), Val (FFT_FORWARD))
230
243
231
- inc = 2 * π/ N
232
- w1 = T (cos (inc), - sin (inc));
233
- wj = T (1 ,0 )
244
+ w1 = convert (T, cispi (- 2 / N))
245
+ wj = one (T)
234
246
m = N ÷ 2
235
247
for j in 1 : m
236
248
out_j = out[j]
244
256
Power of 2 FFT in place, backward
245
257
246
258
"""
247
- function fft_pow2! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD} ) where {T<: Complex }
259
+ function fft_pow2! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD} ) where {T}
248
260
N = length (out)
249
261
if N == 1
250
262
out[1 ] = in[1 ]
@@ -253,9 +265,8 @@ function fft_pow2!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_BACK
253
265
fft_pow2! (@view (out[1 : (end ÷ 2 )]), @view (in[1 : 2 : end ]), Val (FFT_BACKWARD))
254
266
fft_pow2! (@view (out[(end ÷ 2 + 1 ): end ]), @view (in[2 : 2 : end ]), Val (FFT_BACKWARD))
255
267
256
- inc = 2 * π/ N
257
- w1 = T (cos (inc), sin (inc));
258
- wj = T (1 ,0 )
268
+ w1 = convert (T, cispi (2 / N))
269
+ wj = one (T)
259
270
m = N ÷ 2
260
271
for j in 1 : m
261
272
out_j = out[j]
@@ -265,16 +276,63 @@ function fft_pow2!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_BACK
265
276
end
266
277
end
267
278
268
- function fft_dft! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD} ) where {T<: Complex }
279
+ """
280
+ Power of 2 FFT in place, forward
281
+
282
+ """
283
+ function fft_pow2! (out:: AbstractVector{Complex{T}} , in:: AbstractVector{T} , :: Val{FFT_FORWARD} ) where {T<: Real }
269
284
N = length (out)
270
- inc = 2 * π/ N
271
- wn² = wn = w = T (cos (inc), sin (inc))
272
- wn_1 = T (1. , 0. )
285
+ if N == 1
286
+ out[1 ] = in[1 ]
287
+ return
288
+ end
289
+ fft_pow2! (@view (out[1 : (end ÷ 2 )]), @view (in[1 : 2 : end ]), Val (FFT_FORWARD))
290
+ fft_pow2! (@view (out[(end ÷ 2 + 1 ): end ]), @view (in[2 : 2 : end ]), Val (FFT_FORWARD))
273
291
274
- tmp = in[1 ]
275
- out .= tmp
292
+ w1 = convert (Complex{T}, cispi (- 2 / N))
293
+ wj = one (Complex{T})
294
+ m = N ÷ 2
295
+ @turbo for j in 2 : m
296
+ out[j] = out[j] + wj* out[j+ m]
297
+ wj *= w1
298
+ end
299
+ @turbo for j in 2 : m
300
+ out[m+ j] = conj (out[m- j+ 2 ])
301
+ end
302
+ end
303
+
304
+ """
305
+ Power of 2 FFT in place, backward
306
+
307
+ """
308
+ function fft_pow2! (out:: AbstractVector{Complex{T}} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD} ) where {T<: Real }
309
+ N = length (out)
310
+ if N == 1
311
+ out[1 ] = in[1 ]
312
+ return
313
+ end
314
+ fft_pow2! (@view (out[1 : (end ÷ 2 )]), @view (in[1 : 2 : end ]), Val (FFT_BACKWARD))
315
+ fft_pow2! (@view (out[(end ÷ 2 + 1 ): end ]), @view (in[2 : 2 : end ]), Val (FFT_BACKWARD))
316
+
317
+ w1 = convert (Complex{T}, cispi (2 / N))
318
+ wj = one (Complex{T})
319
+ m = N ÷ 2
320
+ @turbo for j in 2 : m
321
+ out[j] = out[j] + wj* out[j+ m]
322
+ out[m+ j] = conj (out[m- i+ 2 ])
323
+ wj *= w1
324
+ end
325
+ end
326
+
327
+ function fft_dft! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_FORWARD} ) where {T}
328
+ N = length (out)
329
+ wn² = wn = w = convert (T, cispi (- 2 / N))
330
+ wn_1 = one (T)
331
+
332
+ tmp = in[1 ];
333
+ out .= tmp;
276
334
tmp = sum (in)
277
- out[1 ] = tmp
335
+ out[1 ] = tmp;
278
336
279
337
wk = wn²;
280
338
for d in 2 : N
@@ -291,16 +349,15 @@ function fft_dft!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_BACKW
291
349
end
292
350
end
293
351
294
- function fft_dft! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_FORWARD } ) where {T<: Complex }
352
+ function fft_dft! (out:: AbstractVector{T} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD } ) where {T}
295
353
N = length (out)
296
- inc = 2 * π/ N
297
- wn² = wn = w = T (cos (inc), - sin (inc));
298
- wn_1 = T (1. , 0. );
354
+ wn² = wn = w = convert (T, cispi (2 / N))
355
+ wn_1 = one (T)
299
356
300
- tmp = in[1 ];
301
- out .= tmp;
357
+ tmp = in[1 ]
358
+ out .= tmp
302
359
tmp = sum (in)
303
- out[1 ] = tmp;
360
+ out[1 ] = tmp
304
361
305
362
wk = wn²;
306
363
for d in 2 : N
@@ -317,11 +374,61 @@ function fft_dft!(out::AbstractVector{T}, in::AbstractVector{T}, ::Val{FFT_FORWA
317
374
end
318
375
end
319
376
377
+ function fft_dft! (out:: AbstractVector{Complex{T}} , in:: AbstractVector{T} , :: Val{FFT_FORWARD} ) where {T<: Real }
378
+ N = length (out)
379
+ halfN = N÷ 2
380
+ wk = wkn = w = convert (Complex{T}, cispi (- 2 / N))
381
+
382
+ out[2 : N] .= in[1 ]
383
+ out[1 ] = sum (in)
384
+ iseven (N) && (out[halfN+ 1 ] = alternatingSum (in))
385
+
386
+ for d in 2 : halfN+ 1
387
+ tmp = in[1 ]
388
+ for k in 2 : N
389
+ tmp += wkn* in[k]
390
+ wkn *= wk
391
+ end
392
+ out[d] = tmp
393
+ wk *= w
394
+ wkn = wk
395
+ end
396
+ @turbo for i in 0 : halfN- 1
397
+ out[N- i] = conj (out[halfN- i])
398
+ end
399
+ end
400
+
401
+ function fft_dft! (out:: AbstractVector{Complex{T}} , in:: AbstractVector{T} , :: Val{FFT_BACKWARD} ) where {T<: Real }
402
+ N = length (out)
403
+ halfN = N÷ 2
404
+ wn² = wn = w = convert (Complex{T}, cispi (2 / N))
405
+ wn_1 = one (T)
406
+
407
+ out .= in[1 ]
408
+ out[1 ] = sum (in)
409
+ iseven (N) && (out[halfN+ 1 ] = alternatingSum (in))
410
+
411
+ wk = wn²;
412
+ for d in 2 : halfN
413
+ out[d] = in[d]* wk + out[d]
414
+ for k in (d+ 1 ): halfN
415
+ wk *= wn
416
+ out[d] = in[k]* wk + out[d]
417
+ out[k] = in[d]* wk + out[k]
418
+ end
419
+ wn_1 = wn
420
+ wn *= w
421
+ wn² *= (wn* wn_1)
422
+ wk = wn²
423
+ end
424
+ out[(N- halfN+ 2 ): end ] .= conj .(out[halfN: - 1 : 2 ])
425
+ end
426
+
320
427
321
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_FORWARD} , :: DFT , :: CallGraph{T} , :: Int ) where {T<: Complex }
428
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_FORWARD} , :: DFT , :: CallGraph{T} , :: Int ) where {T,U }
322
429
fft_dft! (out, in, Val (FFT_FORWARD))
323
430
end
324
431
325
- function fft! (out:: AbstractVector{T} , in:: AbstractVector{T } , :: Val{FFT_BACKWARD} , :: DFT , :: CallGraph{T} , :: Int ) where {T<: Complex }
432
+ function fft! (out:: AbstractVector{T} , in:: AbstractVector{U } , :: Val{FFT_BACKWARD} , :: DFT , :: CallGraph{T} , :: Int ) where {T,U }
326
433
fft_dft! (out, in, Val (FFT_BACKWARD))
327
434
end
0 commit comments