Skip to content

Commit 91de5e3

Browse files
add inufft1 and inufft2
1 parent f6d6fe2 commit 91de5e3

File tree

6 files changed

+159
-33
lines changed

6 files changed

+159
-33
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ then increment/decrement operators are used with linear complexity (and linear c
7979

8080
The NUFFTs are implemented thanks to [Alex Townsend](https://github.com/ajt60gaibb):
8181
- `nufft1` assumes uniform samples and noninteger frequencies;
82-
- `nufft2` assumes nonuniform samples and integer frequencies; and,
83-
- `nufft3 ( = nufft)` assumes nonuniform samples and noninteger frequencies.
82+
- `nufft2` assumes nonuniform samples and integer frequencies;
83+
- `nufft3 ( = nufft)` assumes nonuniform samples and noninteger frequencies;
84+
- `inufft1` inverts an `nufft1`; and,
85+
- `inufft2` inverts an `nufft2`.
86+
Here is an example:
8487
```julia
8588
julia> n = 10^4;
8689

docs/src/index.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ nufft2
6464
nufft3
6565
```
6666

67+
```@docs
68+
inufft1
69+
```
70+
71+
```@docs
72+
inufft2
73+
```
74+
6775
```@docs
6876
plan_nufft1
6977
```
@@ -76,6 +84,14 @@ plan_nufft2
7684
plan_nufft3
7785
```
7886

87+
```@docs
88+
plan_inufft1
89+
```
90+
91+
```@docs
92+
plan_inufft2
93+
```
94+
7995
```@docs
8096
paduatransform
8197
```

src/FastTransforms.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ export plan_normleg12cheb2, plan_cheb22normleg1
1919

2020
export gaunt
2121

22+
export nufft, nufft1, nufft2, nufft3, inufft1, inufft2
23+
export plan_nufft, plan_nufft1, plan_nufft2, plan_nufft3, plan_inufft1, plan_inufft2
24+
2225
export paduatransform, ipaduatransform, paduatransform!, ipaduatransform!, paduapoints
2326
export plan_paduatransform!, plan_ipaduatransform!
2427

25-
export nufft, nufft1, nufft2, nufft3
26-
export plan_nufft, plan_nufft1, plan_nufft2, plan_nufft3
27-
2828
export SlowSphericalHarmonicPlan, FastSphericalHarmonicPlan, ThinSphericalHarmonicPlan
2929
export sph2fourier, fourier2sph, plan_sph2fourier
3030
export sphones, sphzeros, sphrand, sphrandn, sphevaluate
@@ -55,6 +55,7 @@ include("ChebyshevUltrasphericalPlan.jl")
5555
include("ultra2cheb.jl")
5656
include("cheb2ultra.jl")
5757
include("nufft.jl")
58+
include("inufft.jl")
5859

5960
include("cjt.jl")
6061

src/inufft.jl

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
doc"""
2+
Pre-computes an inverse nonuniform fast Fourier transform of type `N`.
3+
4+
For best performance, choose the right number of threads by `FFTW.set_num_threads(4)`, for example.
5+
"""
6+
immutable iNUFFTPlan{N,T,S,PT} <: Base.DFT.Plan{T}
7+
pt::PT
8+
TP::Toeplitz{T}
9+
ϵ::S
10+
end
11+
12+
doc"""
13+
Pre-computes an inverse nonuniform fast Fourier transform of type I.
14+
"""
15+
function plan_inufft1{T<:AbstractFloat}::AbstractVector{T}, ϵ::T)
16+
N = length(ω)
17+
p = plan_nufft1(ω, ϵ)
18+
pt = plan_nufft2/N, ϵ)
19+
c = p*ones(Complex{T}, N)
20+
r = conj(c)
21+
avg = (r[1]+c[1])/2
22+
r[1] = avg
23+
c[1] = avg
24+
TP = Toeplitz(c, r)
25+
26+
iNUFFTPlan{1, eltype(TP), typeof(ϵ), typeof(pt)}(pt, TP, ϵ)
27+
end
28+
29+
doc"""
30+
Pre-computes an inverse nonuniform fast Fourier transform of type II.
31+
"""
32+
function plan_inufft2{T<:AbstractFloat}(x::AbstractVector{T}, ϵ::T)
33+
N = length(x)
34+
pt = plan_nufft1(N*x, ϵ)
35+
r = pt*ones(Complex{T}, N)
36+
c = conj(r)
37+
avg = (r[1]+c[1])/2
38+
r[1] = avg
39+
c[1] = avg
40+
TP = Toeplitz(c, r)
41+
42+
iNUFFTPlan{2, eltype(TP), typeof(ϵ), typeof(pt)}(pt, TP, ϵ)
43+
end
44+
45+
function (*){N,T,V}(p::iNUFFTPlan{N,T}, x::AbstractVector{V})
46+
A_mul_B!(zeros(promote_type(T,V), length(x)), p, x)
47+
end
48+
49+
function Base.A_mul_B!{T}(c::AbstractVector{T}, P::iNUFFTPlan{1,T}, f::AbstractVector{T})
50+
pt, TP, ϵ = P.pt, P.TP, P.ϵ
51+
cg(TP, c, f, 50, 100ϵ)
52+
conj!(A_mul_B!(c, pt, conj!(c)))
53+
end
54+
55+
function Base.A_mul_B!{T}(c::AbstractVector{T}, P::iNUFFTPlan{2,T}, f::AbstractVector{T})
56+
pt, TP, ϵ = P.pt, P.TP, P.ϵ
57+
cg(TP, c, conj!(pt*conj!(f)), 50, 100ϵ)
58+
conj!(f)
59+
c
60+
end
61+
62+
doc"""
63+
Computes an inverse nonuniform fast Fourier transform of type I.
64+
"""
65+
inufft1{T<:AbstractFloat}(c::AbstractVector, ω::AbstractVector{T}, ϵ::T) = plan_inufft1(ω, ϵ)*c
66+
67+
doc"""
68+
Computes an inverse nonuniform fast Fourier transform of type II.
69+
"""
70+
inufft2{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ϵ::T) = plan_inufft2(x, ϵ)*c
71+
72+
function cg{T}(A::ToeplitzMatrices.AbstractToeplitz{T}, x::AbstractVector{T}, b::AbstractVector{T}, max_it::Integer, tol::Real)
73+
n = length(b)
74+
n1, n2 = size(A)
75+
n == n1 == n2 || throw(DimensionMismatch(""))
76+
nrmb = norm(b)
77+
if nrmb == 0 nrmb = one(typeof(nrmb)) end
78+
copy!(x, b)
79+
r = zero(x)
80+
p = zero(x)
81+
Ap = zero(x)
82+
# r = b - A*x
83+
copy!(r, b)
84+
A_mul_B!(-one(T), A, x, one(T), r)
85+
copy!(p, r)
86+
nrm2 = rr
87+
for k = 1:max_it
88+
# Ap = A*p
89+
A_mul_B!(one(T), A, p, zero(T), Ap)
90+
α = nrm2/(pAp)
91+
@inbounds @simd for l = 1:n
92+
x[l] += α*p[l]
93+
r[l] -= α*Ap[l]
94+
end
95+
nrm2new = rr
96+
cst = nrm2new/nrm2
97+
@inbounds @simd for l = 1:n
98+
p[l] = muladd(cst, p[l], r[l])
99+
end
100+
nrm2 = nrm2new
101+
if sqrt(abs(nrm2)) tol*nrmb break end
102+
end
103+
return x
104+
end

src/nufft.jl

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
doc"""
2-
Pre-compute a nonuniform fast Fourier transform of type `N`.
2+
Pre-computes a nonuniform fast Fourier transform of type `N`.
33
44
For best performance, choose the right number of threads by `FFTW.set_num_threads(4)`, for example.
55
"""
@@ -14,7 +14,7 @@ immutable NUFFTPlan{N,T,FFT} <: Base.DFT.Plan{T}
1414
end
1515

1616
doc"""
17-
Computes a nonuniform fast Fourier transform of type I:
17+
Pre-computes a nonuniform fast Fourier transform of type I:
1818
1919
```math
2020
f_j = \sum_{k=1}^N c_k e^{-2\pi{\rm i} (j-1)/N \omega_k},\quad{\rm for}\quad 1 \le j \le N.
@@ -37,7 +37,7 @@ function plan_nufft1{T<:AbstractFloat}(ω::AbstractVector{T}, ϵ::T)
3737
end
3838

3939
doc"""
40-
Computes a nonuniform fast Fourier transform of type II:
40+
Pre-computes a nonuniform fast Fourier transform of type II:
4141
4242
```math
4343
f_j = \sum_{k=1}^N c_k e^{-2\pi{\rm i} x_j (k-1)},\quad{\rm for}\quad 1 \le j \le N.
@@ -59,7 +59,6 @@ function plan_nufft2{T<:AbstractFloat}(x::AbstractVector{T}, ϵ::T)
5959
end
6060

6161
doc"""
62-
Computes a nonuniform fast Fourier transform of type III:
6362
6463
```math
6564
f_j = \sum_{k=1}^N c_k e^{-2\pi{\rm i} x_j \omega_k},\quad{\rm for}\quad 1 \le j \le N.
@@ -93,21 +92,19 @@ function (*){N,T,V}(p::NUFFTPlan{N,T}, x::AbstractVector{V})
9392
A_mul_B!(zeros(promote_type(T,V), length(x)), p, x)
9493
end
9594

96-
function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{1,T}, c::AbstractVector{T})
95+
function Base.A_mul_B!{T}(f::AbstractVector{T}, P::NUFFTPlan{1,T}, c::AbstractVector{T})
9796
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
9897

99-
# (V.*(N*conj(ifft(In[:,t]*conj(Diagonal(c)*U),1))))*ones(K)
100-
10198
broadcast!(*, temp, c, U)
10299
conj!(temp)
103100
fill!(temp2, zero(T))
104101
recombine_rows!(temp, t, temp2)
105102
p*temp2
106103
conj!(temp2)
107104
broadcast!(*, temp, V, temp2)
108-
A_mul_B!(y, temp, Ones)
105+
A_mul_B!(f, temp, Ones)
109106

110-
y
107+
f
111108
end
112109

113110
function Base.A_mul_B!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T})
@@ -117,7 +114,7 @@ function Base.A_mul_B!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T})
117114
Y
118115
end
119116

120-
function A_mul_B_col_J!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T}, J::Int)
117+
function A_mul_B_col_J!{T}(F::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T}, J::Int)
121118
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
122119

123120
broadcast_col_J!(*, temp, C, U, J)
@@ -128,9 +125,9 @@ function A_mul_B_col_J!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T}, J::Int
128125
conj!(temp2)
129126
broadcast!(*, temp, V, temp2)
130127
COLSHIFT = size(C, 1)*(J-1)
131-
A_mul_B!(Y, temp, Ones, 1+COLSHIFT, 1)
128+
A_mul_B!(F, temp, Ones, 1+COLSHIFT, 1)
132129

133-
Y
130+
F
134131
end
135132

136133
function broadcast_col_J!(f, temp::Matrix, C::Matrix, U::Matrix, J::Int)
@@ -144,30 +141,28 @@ function broadcast_col_J!(f, temp::Matrix, C::Matrix, U::Matrix, J::Int)
144141
temp
145142
end
146143

147-
function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{2,T}, c::AbstractVector{T})
144+
function Base.A_mul_B!{T}(f::AbstractVector{T}, P::NUFFTPlan{2,T}, c::AbstractVector{T})
148145
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
149146

150-
# (U.*(fft(Diagonal(c)*V,1)[t+1,:]))*ones(K)
151-
152147
broadcast!(*, temp, c, V)
153148
p*temp
154149
reindex_temp!(temp, t, temp2)
155150
broadcast!(*, temp, U, temp2)
156-
A_mul_B!(y, temp, Ones)
151+
A_mul_B!(f, temp, Ones)
157152

158-
y
153+
f
159154
end
160155

161-
function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{3,T}, c::AbstractVector{T})
156+
function Base.A_mul_B!{T}(f::AbstractVector{T}, P::NUFFTPlan{3,T}, c::AbstractVector{T})
162157
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
163158

164159
broadcast!(*, temp2, c, V)
165160
A_mul_B!(temp, p, temp2)
166161
reindex_temp!(temp, t, temp2)
167162
broadcast!(*, temp, U, temp2)
168-
A_mul_B!(y, temp, Ones)
163+
A_mul_B!(f, temp, Ones)
169164

170-
y
165+
f
171166
end
172167

173168
function reindex_temp!{T}(temp::Matrix{T}, t::Vector{Int}, temp2::Matrix{T})
@@ -189,17 +184,17 @@ function recombine_rows!{T}(temp::Matrix{T}, t::Vector{Int}, temp2::Matrix{T})
189184
end
190185

191186
doc"""
192-
Pre-compute a nonuniform fast Fourier transform of type I.
187+
Computes a nonuniform fast Fourier transform of type I.
193188
"""
194189
nufft1{T<:AbstractFloat}(c::AbstractVector, ω::AbstractVector{T}, ϵ::T) = plan_nufft1(ω, ϵ)*c
195190

196191
doc"""
197-
Pre-compute a nonuniform fast Fourier transform of type II.
192+
Computes a nonuniform fast Fourier transform of type II.
198193
"""
199194
nufft2{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ϵ::T) = plan_nufft2(x, ϵ)*c
200195

201196
doc"""
202-
Pre-compute a nonuniform fast Fourier transform of type III.
197+
Computes a nonuniform fast Fourier transform of type III.
203198
"""
204199
nufft3{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ω::AbstractVector{T}, ϵ::T) = plan_nufft3(x, ω, ϵ)*c
205200

test/nuffttests.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,26 @@ using FastTransforms, Base.Test
4545

4646
for n in N, ϵ in (1e-4,1e-8,1e-12,eps(Float64))
4747
c = complex(rand(n))
48+
err_bnd = 500*ϵ*n*norm(c)
4849

49-
ω = collect(0:n-1) + rand(n)
50+
ω = collect(0:n-1) + 0.25*rand(n)
5051
exact = nudft1(c, ω)
5152
fast = nufft1(c, ω, ϵ)
52-
@test norm(exact - fast, Inf) < 500*ϵ*n*norm(c)
53+
@test norm(exact - fast, Inf) < err_bnd
5354

54-
x = (collect(0:n-1) + 3rand(n))/n
55+
d = inufft1(fast, ω, ϵ)
56+
@test norm(c - d, Inf) < err_bnd
57+
58+
x = (collect(0:n-1) + 0.25*rand(n))/n
5559
exact = nudft2(c, x)
5660
fast = nufft2(c, x, ϵ)
57-
@test norm(exact - fast, Inf) < 500*ϵ*n*norm(c)
61+
@test norm(exact - fast, Inf) < err_bnd
62+
63+
d = inufft2(fast, x, ϵ)
64+
@test norm(c - d, Inf) < err_bnd
5865

5966
exact = nudft3(c, x, ω)
6067
fast = nufft3(c, x, ω, ϵ)
61-
@test norm(exact - fast, Inf) < 500*ϵ*n*norm(c)
68+
@test norm(exact - fast, Inf) < err_bnd
6269
end
6370
end

0 commit comments

Comments
 (0)