Skip to content

Commit f6d6fe2

Browse files
add nufft3
1 parent 4a7cc32 commit f6d6fe2

File tree

5 files changed

+132
-17
lines changed

5 files changed

+132
-17
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ then increment/decrement operators are used with linear complexity (and linear c
7777

7878
## Nonuniform fast Fourier transforms
7979

80-
The NUFFTs are implemented thanks to [Alex Townsend](https://github.com/ajt60gaibb). `nufft1` assumes uniform samples and noninteger frequencies, while `nufft2` assumes nonuniform samples and integer frequencies.
80+
The NUFFTs are implemented thanks to [Alex Townsend](https://github.com/ajt60gaibb):
81+
- `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.
8184
```julia
8285
julia> n = 10^4;
8386

@@ -101,6 +104,13 @@ julia> p2 = plan_nufft2(x, eps());
101104
julia> @time p2*c;
102105
0.001478 seconds (6 allocations: 156.484 KiB)
103106

107+
julia> nufft3(c, x, ω, eps());
108+
109+
julia> p3 = plan_nufft3(x, ω, eps());
110+
111+
julia> @time p3*c;
112+
0.058999 seconds (6 allocations: 156.484 KiB)
113+
104114
```
105115

106116
## The Padua Transform

docs/src/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ nufft1
6060
nufft2
6161
```
6262

63+
```@docs
64+
nufft3
65+
```
66+
6367
```@docs
6468
plan_nufft1
6569
```
@@ -68,6 +72,10 @@ plan_nufft1
6872
plan_nufft2
6973
```
7074

75+
```@docs
76+
plan_nufft3
77+
```
78+
7179
```@docs
7280
paduatransform
7381
```

src/FastTransforms.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export gaunt
2222
export paduatransform, ipaduatransform, paduatransform!, ipaduatransform!, paduapoints
2323
export plan_paduatransform!, plan_ipaduatransform!
2424

25-
export nufft, nufft1, nufft2
26-
export plan_nufft, plan_nufft1, plan_nufft2
25+
export nufft, nufft1, nufft2, nufft3
26+
export plan_nufft, plan_nufft1, plan_nufft2, plan_nufft3
2727

2828
export SlowSphericalHarmonicPlan, FastSphericalHarmonicPlan, ThinSphericalHarmonicPlan
2929
export sph2fourier, fourier2sph, plan_sph2fourier

src/nufft.jl

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ function plan_nufft1{T<:AbstractFloat}(ω::AbstractVector{T}, ϵ::T)
2626
t = AssignClosestEquispacedFFTpoint(ωdN)
2727
γ = PerturbationParameter(ωdN, AssignClosestEquispacedGridpoint(ωdN))
2828
K = FindK(γ, ϵ)
29-
U = constructU( ωdN, K)
30-
V = constructV( ωdN, K)
31-
p = plan_ifft!(V, 1)
29+
U = constructU(ωdN, K)
30+
V = constructV(linspace(zero(T), N-1, N), K)
31+
p = plan_bfft!(V, 1)
3232
temp = zeros(Complex{T}, N, K)
3333
temp2 = zeros(Complex{T}, N, K)
3434
Ones = ones(Complex{T}, K)
@@ -49,7 +49,7 @@ function plan_nufft2{T<:AbstractFloat}(x::AbstractVector{T}, ϵ::T)
4949
γ = PerturbationParameter(x, AssignClosestEquispacedGridpoint(x))
5050
K = FindK(γ, ϵ)
5151
U = constructU(x, K)
52-
V = constructV(x, K)
52+
V = constructV(linspace(zero(T), N-1, N), K)
5353
p = plan_fft!(U, 1)
5454
temp = zeros(Complex{T}, N, K)
5555
temp2 = zeros(Complex{T}, N, K)
@@ -58,6 +58,37 @@ function plan_nufft2{T<:AbstractFloat}(x::AbstractVector{T}, ϵ::T)
5858
NUFFTPlan{2, eltype(U), typeof(p)}(U, V, p, t, temp, temp2, Ones)
5959
end
6060

61+
doc"""
62+
Computes a nonuniform fast Fourier transform of type III:
63+
64+
```math
65+
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.
66+
```
67+
"""
68+
function plan_nufft3{T<:AbstractFloat}(x::AbstractVector{T}, ω::AbstractVector{T}, ϵ::T)
69+
N = length(x)
70+
s = AssignClosestEquispacedGridpoint(x)
71+
t = AssignClosestEquispacedFFTpoint(x)
72+
γ = PerturbationParameter(x, s)
73+
K = FindK(γ, ϵ)
74+
u = constructU(x, K)
75+
v = constructV(ω, K)
76+
77+
p = plan_nufft1(ω, ϵ)
78+
79+
D1 = Diagonal(1-(s-t+1)/N)
80+
D2 = Diagonal((s-t+1)/N)
81+
D3 = Diagonal(exp.(-2*im*T(π)*ω))
82+
U = hcat(D1*u, D2*u)
83+
V = hcat(v, D3*v)
84+
85+
temp = zeros(Complex{T}, N, 2K)
86+
temp2 = zeros(Complex{T}, N, 2K)
87+
Ones = ones(Complex{T}, 2K)
88+
89+
NUFFTPlan{3, eltype(U), typeof(p)}(U, V, p, t, temp, temp2, Ones)
90+
end
91+
6192
function (*){N,T,V}(p::NUFFTPlan{N,T}, x::AbstractVector{V})
6293
A_mul_B!(zeros(promote_type(T,V), length(x)), p, x)
6394
end
@@ -75,11 +106,44 @@ function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{1,T}, c::AbstractVe
75106
conj!(temp2)
76107
broadcast!(*, temp, V, temp2)
77108
A_mul_B!(y, temp, Ones)
78-
scale!(length(c), y)
79109

80110
y
81111
end
82112

113+
function Base.A_mul_B!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T})
114+
for J = 1:size(Y, 2)
115+
A_mul_B_col_J!(Y, P, C, J)
116+
end
117+
Y
118+
end
119+
120+
function A_mul_B_col_J!{T}(Y::Matrix{T}, P::NUFFTPlan{1,T}, C::Matrix{T}, J::Int)
121+
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
122+
123+
broadcast_col_J!(*, temp, C, U, J)
124+
conj!(temp)
125+
fill!(temp2, zero(T))
126+
recombine_rows!(temp, t, temp2)
127+
p*temp2
128+
conj!(temp2)
129+
broadcast!(*, temp, V, temp2)
130+
COLSHIFT = size(C, 1)*(J-1)
131+
A_mul_B!(Y, temp, Ones, 1+COLSHIFT, 1)
132+
133+
Y
134+
end
135+
136+
function broadcast_col_J!(f, temp::Matrix, C::Matrix, U::Matrix, J::Int)
137+
N = size(C, 1)
138+
COLSHIFT = N*(J-1)
139+
@inbounds for j = 1:size(temp, 2)
140+
for i = 1:N
141+
temp[i,j] = f(C[i+COLSHIFT],U[i,j])
142+
end
143+
end
144+
temp
145+
end
146+
83147
function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{2,T}, c::AbstractVector{T})
84148
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
85149

@@ -94,6 +158,18 @@ function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{2,T}, c::AbstractVe
94158
y
95159
end
96160

161+
function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{3,T}, c::AbstractVector{T})
162+
U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones
163+
164+
broadcast!(*, temp2, c, V)
165+
A_mul_B!(temp, p, temp2)
166+
reindex_temp!(temp, t, temp2)
167+
broadcast!(*, temp, U, temp2)
168+
A_mul_B!(y, temp, Ones)
169+
170+
y
171+
end
172+
97173
function reindex_temp!{T}(temp::Matrix{T}, t::Vector{Int}, temp2::Matrix{T})
98174
@inbounds for j = 1:size(temp, 2)
99175
for i = 1:size(temp, 1)
@@ -122,6 +198,14 @@ Pre-compute a nonuniform fast Fourier transform of type II.
122198
"""
123199
nufft2{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ϵ::T) = plan_nufft2(x, ϵ)*c
124200

201+
doc"""
202+
Pre-compute a nonuniform fast Fourier transform of type III.
203+
"""
204+
nufft3{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ω::AbstractVector{T}, ϵ::T) = plan_nufft3(x, ω, ϵ)*c
205+
206+
const nufft = nufft3
207+
const plan_nufft = plan_nufft3
208+
125209
FindK{T<:AbstractFloat}::T, ϵ::T) = Int(ceil(5*γ*exp(lambertw(log(10/ϵ)/γ/7))))
126210
AssignClosestEquispacedGridpoint{T<:AbstractFloat}(x::AbstractVector{T})::AbstractVector{T} = round.([Int], size(x, 1)*x)
127211
AssignClosestEquispacedFFTpoint{T<:AbstractFloat}(x::AbstractVector{T})::Array{Int,1} = mod.(round.([Int], size(x, 1)*x), size(x, 1)) + 1
@@ -130,18 +214,15 @@ PerturbationParameter{T<:AbstractFloat}(x::AbstractVector{T}, s_vec::AbstractVec
130214
function constructU{T<:AbstractFloat}(x::AbstractVector{T}, K::Int)
131215
# Construct a low rank approximation, using Chebyshev expansions
132216
# for AK = exp(-2*pi*1im*(x[j]-j/N)*k):
133-
N = size(x, 1)
134-
#(s_vec, t, γ) = FindAlgorithmicParameters( x )
135-
s_vec = AssignClosestEquispacedGridpoint(x)
136-
er = N*x - s_vec
217+
N = length(x)
218+
s = AssignClosestEquispacedGridpoint(x)
219+
er = N*x - s
137220
γ = norm(er, Inf)
138-
# colspace vectors:
139-
Diagonal(exp.(-im*(pi*er)))*ChebyshevP(K-1, er/γ)*Bessel_coeffs(K, γ)
221+
Diagonal(exp.(-im**er)))*ChebyshevP(K-1, er/γ)*Bessel_coeffs(K, γ)
140222
end
141223

142-
function constructV{T<:AbstractFloat}(x::AbstractVector{T}, K::Int)
143-
N = size(x, 1)
144-
complex(ChebyshevP(K-1, two(T)*collect(0:N-1)/N - ones(N) ))
224+
function constructV{T<:AbstractFloat}::AbstractVector{T}, K::Int)
225+
complex(ChebyshevP(K-1, ω*(two(T)/length(ω)) - 1))
145226
end
146227

147228
function Bessel_coeffs{T<:AbstractFloat}(K::Int, γ::T)

test/nuffttests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ using FastTransforms, Base.Test
2929
return output
3030
end
3131

32+
function nudft3{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ω::AbstractVector{T})
33+
# Nonuniform discrete Fourier transform of type III
34+
35+
N = size(x, 1)
36+
output = zeros(c)
37+
for j = 1:N
38+
output[j] = dot(exp.(2*T(π)*im*x[j]*ω), c)
39+
end
40+
41+
return output
42+
end
43+
3244
N = round.([Int],logspace(1,3,10))
3345

3446
for n in N, ϵ in (1e-4,1e-8,1e-12,eps(Float64))
@@ -43,5 +55,9 @@ using FastTransforms, Base.Test
4355
exact = nudft2(c, x)
4456
fast = nufft2(c, x, ϵ)
4557
@test norm(exact - fast, Inf) < 500*ϵ*n*norm(c)
58+
59+
exact = nudft3(c, x, ω)
60+
fast = nufft3(c, x, ω, ϵ)
61+
@test norm(exact - fast, Inf) < 500*ϵ*n*norm(c)
4662
end
4763
end

0 commit comments

Comments
 (0)