Skip to content

Commit dc3e973

Browse files
Merge pull request #64 from daanhb/genericfft
Genericfft
2 parents c21bcbd + bfec169 commit dc3e973

File tree

2 files changed

+103
-69
lines changed

2 files changed

+103
-69
lines changed

src/fftBigFloat.jl

Lines changed: 102 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,59 @@
1-
const BigFloats = Union{BigFloat,Complex{BigFloat}}
1+
const AbstractFloats = Union{AbstractFloat,Complex{T} where T<:AbstractFloat}
22

33
if VERSION < v"0.7-"
4-
import Base.FFTW: fft, fft!, rfft, irfft, ifft, conv, dct, idct, dct!, idct!,
4+
import Base.FFTW: fft, fft!, rfft, irfft, ifft, ifft!, conv, dct, idct, dct!, idct!,
55
plan_fft!, plan_ifft!, plan_dct!, plan_idct!,
66
plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct
77
else
8-
import FFTW: fft, fft!, rfft, irfft, ifft, dct, idct, dct!, idct!,
9-
plan_fft!, plan_ifft!, plan_dct!, plan_idct!,
10-
plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct
8+
import FFTW: dct, dct!, idct, idct!,
9+
plan_fft!, plan_ifft!, plan_dct!, plan_idct!,
10+
plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct
1111
import DSP: conv
1212
end
1313

1414
# The following implements Bluestein's algorithm, following http://www.dsprelated.com/dspbooks/mdft/Bluestein_s_FFT_Algorithm.html
1515
# To add more types, add them in the union of the function's signature.
16-
function fft(x::Vector{T}) where T<:BigFloats
16+
17+
function generic_fft(x::Vector{T}) where T<:AbstractFloats
1718
n = length(x)
18-
ispow2(n) && return fft_pow2(x)
19+
ispow2(n) && return generic_fft_pow2(x)
1920
ks = range(zero(real(T)),stop=n-one(real(T)),length=n)
2021
Wks = exp.((-im).*convert(T,π).*ks.^2 ./ n)
2122
xq, wq = x.*Wks, conj([exp(-im*convert(T,π)*n);reverse(Wks);Wks[2:end]])
2223
return Wks.*conv(xq,wq)[n+1:2n]
2324
end
2425

2526

26-
function fft!(x::Vector{T}) where T<:BigFloats
27-
x[:] = fft(x)
27+
function generic_fft!(x::Vector{T}) where T<:AbstractFloats
28+
x[:] = generic_fft(x)
2829
return x
2930
end
3031

31-
# add rfft for BigFloat, by calling fft
32+
# add rfft for AbstractFloat, by calling fft
3233
# this creates ToeplitzMatrices.rfft, so avoids changing rfft
3334

34-
rfft(v::Vector{T}) where T<:BigFloats = fft(v)[1:div(length(v),2)+1]
35-
function irfft(v::Vector{T},n::Integer) where T<:BigFloats
35+
generic_rfft(v::Vector{T}) where T<:AbstractFloats = generic_fft(v)[1:div(length(v),2)+1]
36+
37+
function generic_irfft(v::Vector{T},n::Integer) where T<:AbstractFloats
3638
@assert n==2length(v)-1
37-
r = Vector{Complex{BigFloat}}(undef, n)
39+
r = Vector{Complex{real(T)}}(undef, n)
3840
r[1:length(v)]=v
3941
r[length(v)+1:end]=reverse(conj(v[2:end]))
40-
real(ifft(r))
42+
real(generic_ifft(r))
4143
end
4244

43-
ifft(x::Vector{T}) where {T<:BigFloats} = conj!(fft(conj(x)))/length(x)
44-
function ifft!(x::Vector{T}) where T<:BigFloats
45-
x[:] = ifft(x)
45+
generic_ifft(x::Vector{T}) where {T<:AbstractFloats} = conj!(generic_fft(conj(x)))/length(x)
46+
function generic_ifft!(x::Vector{T}) where T<:AbstractFloats
47+
x[:] = generic_ifft(x)
4648
return x
4749
end
4850

49-
function conv(u::StridedVector{T}, v::StridedVector{T}) where T<:BigFloats
51+
function conv(u::StridedVector{T}, v::StridedVector{T}) where T<:AbstractFloats
5052
nu,nv = length(u),length(v)
5153
n = nu + nv - 1
5254
np2 = nextpow(2,n)
5355
append!(u,zeros(T,np2-nu)),append!(v,zeros(T,np2-nv))
54-
y = ifft_pow2(fft_pow2(u).*fft_pow2(v))
56+
y = generic_ifft_pow2(generic_fft_pow2(u).*generic_fft_pow2(v))
5557
#TODO This would not handle Dual/ComplexDual numbers correctly
5658
y = T<:Real ? real(y[1:n]) : y[1:n]
5759
end
@@ -60,7 +62,7 @@ end
6062
# c_radix2.c in the GNU Scientific Library and four1 in the Numerical Recipes in C.
6163
# However, the trigonometric recurrence is improved for greater efficiency.
6264
# The algorithm starts with bit-reversal, then divides and conquers in-place.
63-
function fft_pow2!(x::Vector{T}) where T<:BigFloat
65+
function generic_fft_pow2!(x::Vector{T}) where T<:AbstractFloat
6466
n,big2=length(x),2one(T)
6567
nn,j=n÷2,1
6668
for i=1:2:n-1
@@ -96,97 +98,129 @@ function fft_pow2!(x::Vector{T}) where T<:BigFloat
9698
return x
9799
end
98100

99-
function fft_pow2(x::Vector{Complex{T}}) where T<:BigFloat
101+
function generic_fft_pow2(x::Vector{Complex{T}}) where T<:AbstractFloat
100102
y = interlace(real(x),imag(x))
101-
fft_pow2!(y)
103+
generic_fft_pow2!(y)
102104
return complex.(y[1:2:end],y[2:2:end])
103105
end
104-
fft_pow2(x::Vector{T}) where {T<:BigFloat} = fft_pow2(complex(x))
106+
generic_fft_pow2(x::Vector{T}) where {T<:AbstractFloat} = generic_fft_pow2(complex(x))
105107

106-
function ifft_pow2(x::Vector{Complex{T}}) where T<:BigFloat
108+
function generic_ifft_pow2(x::Vector{Complex{T}}) where T<:AbstractFloat
107109
y = interlace(real(x),-imag(x))
108-
fft_pow2!(y)
110+
generic_fft_pow2!(y)
109111
return complex.(y[1:2:end],-y[2:2:end])/length(x)
110112
end
111113

112-
113-
function dct(a::AbstractVector{Complex{BigFloat}})
114-
N = big(length(a))
115-
c = fft([a; flipdim(a,1)])
114+
function generic_dct(a::AbstractVector{Complex{T}}) where {T <: AbstractFloat}
115+
N = length(a)
116+
twoN = convert(T,2) * N
117+
c = generic_fft([a; flipdim(a,1)])
116118
d = c[1:N]
117-
d .*= exp.((-im*big(pi)).*(0:N-1)./(2*N))
118-
d[1] = d[1] / sqrt(big(2))
119-
lmul!(inv(sqrt(2N)), d)
119+
d .*= exp.((-im*convert(T, pi)).*(0:N-1)./twoN)
120+
d[1] = d[1] / sqrt(convert(T, 2))
121+
lmul!(inv(sqrt(twoN)), d)
120122
end
121123

122-
dct(a::AbstractArray{BigFloat}) = real(dct(complex(a)))
124+
generic_dct(a::AbstractArray{T}) where {T <: AbstractFloat} = real(generic_dct(complex(a)))
123125

124-
function idct(a::AbstractVector{Complex{BigFloat}})
125-
N = big(length(a))
126-
b = a * sqrt(2*N)
127-
b[1] = b[1] * sqrt(big(2))
128-
shift = exp.(-im * 2 * big(pi) * (N - big(1)/2) * (0:(2N-1)) / (2 * N))
126+
function generic_idct(a::AbstractVector{Complex{T}}) where {T <: AbstractFloat}
127+
N = length(a)
128+
twoN = convert(T,2)*N
129+
b = a * sqrt(twoN)
130+
b[1] = b[1] * sqrt(convert(T,2))
131+
shift = exp.(-im * 2 * convert(T, pi) * (N - convert(T,1)/2) * (0:(2N-1)) / twoN)
129132
b = [b; 0; -flipdim(b[2:end],1)] .* shift
130133
c = ifft(b)
131134
flipdim(c[1:N],1)
132135
end
133136

134-
idct(a::AbstractArray{BigFloat}) = real(idct(complex(a)))
137+
generic_idct(a::AbstractArray{T}) where {T <: AbstractFloat} = real(generic_idct(complex(a)))
135138

136-
dct!(a::AbstractArray{T}) where {T<:BigFloats} = (b = dct(a); a[:] = b)
137-
idct!(a::AbstractArray{T}) where {T<:BigFloats} = (b = idct(a); a[:] = b)
139+
generic_dct!(a::AbstractArray{T}) where {T<:AbstractFloats} = (b = generic_dct(a); a[:] = b)
140+
generic_idct!(a::AbstractArray{T}) where {T<:AbstractFloats} = (b = generic_idct(a); a[:] = b)
141+
142+
# These lines mimick the corresponding ones in FFTW/src/dct.jl, but with
143+
# AbstractFloat rather than fftwNumber.
144+
for f in (:dct, :dct!, :idct, :idct!)
145+
pf = Symbol("plan_", f)
146+
@eval begin
147+
$f(x::AbstractArray{<:AbstractFloats}) = $pf(x) * x
148+
$f(x::AbstractArray{<:AbstractFloats}, region) = $pf(x, region) * x
149+
end
150+
end
138151

139152
# dummy plans
140153
struct DummyFFTPlan{T,inplace} <: Plan{T} end
141154
struct DummyiFFTPlan{T,inplace} <: Plan{T} end
142-
struct DummyrFFTPlan{T,inplace} <: Plan{T} end
143-
struct DummyirFFTPlan{T,inplace} <: Plan{T} end
144155
struct DummyDCTPlan{T,inplace} <: Plan{T} end
145156
struct DummyiDCTPlan{T,inplace} <: Plan{T} end
157+
struct DummyrFFTPlan{T,inplace} <: Plan{T}
158+
n :: Integer
159+
end
160+
struct DummyirFFTPlan{T,inplace} <: Plan{T}
161+
n :: Integer
162+
end
146163

147164
for (Plan,iPlan) in ((:DummyFFTPlan,:DummyiFFTPlan),
148-
(:DummyrFFTPlan,:DummyirFFTPlan),
165+
# (:DummyrFFTPlan,:DummyirFFTPlan),
149166
(:DummyDCTPlan,:DummyiDCTPlan))
150167
@eval begin
151168
Base.inv(::$Plan{T,inplace}) where {T,inplace} = $iPlan{T,inplace}()
152169
Base.inv(::$iPlan{T,inplace}) where {T,inplace} = $Plan{T,inplace}()
153170
end
154171
end
155172

173+
# Specific for rfft and irfft:
174+
Base.inv(::DummyirFFTPlan{T,inplace}) where {T,inplace} = DummyrFFTPlan{T,Inplace}(p.n)
175+
Base.inv(::DummyrFFTPlan{T,inplace}) where {T,inplace} = DummyirFFTPlan{T,Inplace}(p.n)
156176

157-
for (Plan,ff,ff!) in ((:DummyFFTPlan,:fft,:fft!),
158-
(:DummyiFFTPlan,:ifft,:ifft!),
159-
(:DummyrFFTPlan,:rfft,:rfft!),
160-
(:DummyirFFTPlan,:irfft,:irfft!),
161-
(:DummyDCTPlan,:dct,:dct!),
162-
(:DummyiDCTPlan,:idct,:idct!))
177+
178+
for (Plan,ff,ff!) in ((:DummyFFTPlan,:generic_fft,:generic_fft!),
179+
(:DummyiFFTPlan,:generic_ifft,:generic_ifft!),
180+
(:DummyrFFTPlan,:generic_rfft,:generic_rfft!),
181+
# (:DummyirFFTPlan,:generic_irfft,:generic_irfft!),
182+
(:DummyDCTPlan,:generic_dct,:generic_dct!),
183+
(:DummyiDCTPlan,:generic_idct,:generic_idct!))
163184
@eval begin
164-
*(p::$Plan{T,true}, x::StridedArray{T,N}) where {T,N} = $ff!(x)
165-
*(p::$Plan{T,false}, x::StridedArray{T,N}) where {T,N} = $ff(x)
185+
*(p::$Plan{T,true}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = $ff!(x)
186+
*(p::$Plan{T,false}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = $ff(x)
166187
function LAmul!(C::StridedVector, p::$Plan, x::StridedVector)
167188
C[:] = $ff(x)
168189
C
169190
end
170191
end
171192
end
172193

194+
# Specific for irfft:
195+
*(p::DummyirFFTPlan{T,true}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = generic_irfft!(x, p.n)
196+
*(p::DummyirFFTPlan{T,false}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = generic_irfft(x, p.n)
197+
function LAmul!(C::StridedVector, p::DummyirFFTPlan, x::StridedVector)
198+
C[:] = generic_irfft(x, p.n)
199+
C
200+
end
173201

174-
175-
176-
plan_fft!(x::Vector{T}) where {T<:BigFloats} = DummyFFTPlan{Complex{BigFloat},true}()
177-
plan_ifft!(x::Vector{T}) where {T<:BigFloats} = DummyiFFTPlan{Complex{BigFloat},true}()
178-
179-
#plan_rfft!{T<:BigFloats}(x::Vector{T}) = DummyrFFTPlan{Complex{BigFloat},true}()
180-
#plan_irfft!{T<:BigFloats}(x::Vector{T},n::Integer) = DummyirFFTPlan{Complex{BigFloat},true}()
181-
plan_dct!(x::Vector{T}) where {T<:BigFloats} = DummyDCTPlan{T,true}()
182-
plan_idct!(x::Vector{T}) where {T<:BigFloats} = DummyiDCTPlan{T,true}()
183-
184-
plan_fft(x::Vector{T}) where {T<:BigFloats} = DummyFFTPlan{Complex{BigFloat},false}()
185-
plan_ifft(x::Vector{T}) where {T<:BigFloats} = DummyiFFTPlan{Complex{BigFloat},false}()
186-
plan_rfft(x::Vector{T}) where {T<:BigFloats} = DummyrFFTPlan{Complex{BigFloat},false}()
187-
plan_irfft(x::Vector{T},n::Integer) where {T<:BigFloats} = DummyirFFTPlan{Complex{BigFloat},false}()
188-
plan_dct(x::Vector{T}) where {T<:BigFloats} = DummyDCTPlan{T,false}()
189-
plan_idct(x::Vector{T}) where {T<:BigFloats} = DummyiDCTPlan{T,false}()
202+
# We override these for AbstractFloat, so that conversion from reals to
203+
# complex numbers works for any AbstractFloat (instead of only BlasFloat's)
204+
AbstractFFTs.complexfloat(x::StridedArray{Complex{<:AbstractFloat}}) = x
205+
AbstractFFTs.realfloat(x::StridedArray{<:Real}) = x
206+
# We override this one in order to avoid throwing an error that the type is
207+
# unsupported (as defined in AbstractFFTs)
208+
AbstractFFTs._fftfloat(::Type{T}) where {T <: AbstractFloat} = T
209+
210+
plan_fft!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyFFTPlan{Complex{real(T)},true}()
211+
plan_ifft!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiFFTPlan{Complex{real(T)},true}()
212+
213+
# plan_rfft!(x::StridedArray{T}) where {T <: AbstractFloat} = DummyrFFTPlan{Complex{real(T)},true}()
214+
# plan_irfft!(x::StridedArray{T},n::Integer) where {T <: AbstractFloat} = DummyirFFTPlan{Complex{real(T)},true}()
215+
plan_dct!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyDCTPlan{T,true}()
216+
plan_idct!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiDCTPlan{T,true}()
217+
218+
plan_fft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyFFTPlan{Complex{real(T)},false}()
219+
plan_ifft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiFFTPlan{Complex{real(T)},false}()
220+
plan_rfft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyrFFTPlan{Complex{real(T)},false}(length(x))
221+
plan_irfft(x::StridedArray{T}, n::Integer, region) where {T <: AbstractFloats} = DummyirFFTPlan{Complex{real(T)},false}(n)
222+
plan_dct(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyDCTPlan{T,false}()
223+
plan_idct(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiDCTPlan{T,false}()
190224

191225

192226
function interlace(a::Vector{S},b::Vector{V}) where {S<:Number,V<:Number}

test/fftBigFloattests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ end
1414
@test norm(ifft(fft(c))-c) < 200norm(c)eps(BigFloat)
1515

1616
p = plan_dct(c)
17-
@test norm(dct(c) - p*c) == 0
17+
@test norm(FastTransforms.generic_dct(c) - p*c) == 0
1818

1919
pi = plan_idct!(c)
2020
@test norm(pi*dct(c) - c) < 1000norm(c)*eps(BigFloat)

0 commit comments

Comments
 (0)