Skip to content

Commit f4625ff

Browse files
Merge pull request #22 from MikaelSlevinsky/add-nufft
Add nonuniform fast Fourier transforms
2 parents 66bc345 + 6a11c6a commit f4625ff

File tree

9 files changed

+717
-10
lines changed

9 files changed

+717
-10
lines changed

README.md

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,48 @@ is valid for the half-open square `(α,β) ∈ (-1/2,1/2]^2`. Therefore, the fas
7575
when the parameters are inside. If the parameters `(α,β)` are not exceptionally beyond the square,
7676
then increment/decrement operators are used with linear complexity (and linear conditioning) in the degree.
7777

78+
## Nonuniform fast Fourier transforms
79+
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;
83+
- `nufft3 ( = nufft)` assumes nonuniform samples and noninteger frequencies;
84+
- `inufft1` inverts an `nufft1`; and,
85+
- `inufft2` inverts an `nufft2`.
86+
87+
Here is an example:
88+
```julia
89+
julia> n = 10^4;
90+
91+
julia> c = complex(rand(n));
92+
93+
julia> ω = collect(0:n-1) + rand(n);
94+
95+
julia> nufft1(c, ω, eps());
96+
97+
julia> p1 = plan_nufft1(ω, eps());
98+
99+
julia> @time p1*c;
100+
0.002383 seconds (6 allocations: 156.484 KiB)
101+
102+
julia> x = (collect(0:n-1) + 3rand(n))/n;
103+
104+
julia> nufft2(c, x, eps());
105+
106+
julia> p2 = plan_nufft2(x, eps());
107+
108+
julia> @time p2*c;
109+
0.001478 seconds (6 allocations: 156.484 KiB)
110+
111+
julia> nufft3(c, x, ω, eps());
112+
113+
julia> p3 = plan_nufft3(x, ω, eps());
114+
115+
julia> @time p3*c;
116+
0.058999 seconds (6 allocations: 156.484 KiB)
117+
118+
```
119+
78120
## The Padua Transform
79121

80122
The Padua transform and its inverse are implemented thanks to [Michael Clarke](https://github.com/MikeAClarke). These are optimized methods designed for computing the bivariate Chebyshev coefficients by interpolating a bivariate function at the Padua points on `[-1,1]^2`.
@@ -87,7 +129,7 @@ julia> N = div((n+1)*(n+2),2);
87129
julia> v = rand(N); # The length of v is the number of Padua points
88130

89131
julia> @time norm(ipaduatransform(paduatransform(v))-v)
90-
0.006571 seconds (846 allocations: 1.746 MiB)
132+
0.006571 seconds (846 allocations: 1.746 MiB)
91133
3.123637691861415e-14
92134

93135
```
@@ -126,10 +168,12 @@ As with other fast transforms, `plan_sph2fourier` saves effort by caching the pr
126168

127169
[2] N. Hale and A. Townsend. <a href="http://dx.doi.org/10.1137/130932223">A fast, simple, and stable Chebyshev—Legendre transform using and asymptotic formula</a>, *SIAM J. Sci. Comput.*, **36**:A148—A167, 2014.
128170

129-
[3] J. Keiner. <a href="http://dx.doi.org/10.1137/070703065">Computing with expansions in Gegenbauer polynomials</a>, *SIAM J. Sci. Comput.*, **31**:2151—2171, 2009.
171+
[3] J. Keiner. <a href="http://dx.doi.org/10.1137/070703065">Computing with expansions in Gegenbauer polynomials</a>, *SIAM J. Sci. Comput.*, **31**:2151—2171, 2009.
172+
173+
[4] D. Ruiz—Antolín and A. Townsend. <a href="https://arxiv.org/abs/1701.04492">A nonuniform fast Fourier transform based on low rank approximation</a>, arXiv:1701.04492, 2017.
130174

131-
[4] R. M. Slevinsky. <a href="https://doi.org/10.1093/imanum/drw070">On the use of Hahn's asymptotic formula and stabilized recurrence for a fast, simple, and stable Chebyshev—Jacobi transform</a>, in press at *IMA J. Numer. Anal.*, 2017.
175+
[5] R. M. Slevinsky. <a href="https://doi.org/10.1093/imanum/drw070">On the use of Hahn's asymptotic formula and stabilized recurrence for a fast, simple, and stable Chebyshev—Jacobi transform</a>, in press at *IMA J. Numer. Anal.*, 2017.
132176

133-
[5] R. M. Slevinsky. <a href="https://arxiv.org/abs/1705.05448">Fast and backward stable transforms between spherical harmonic expansions and bivariate Fourier series</a>, arXiv:1705.05448, 2017.
177+
[6] R. M. Slevinsky. <a href="https://arxiv.org/abs/1705.05448">Fast and backward stable transforms between spherical harmonic expansions and bivariate Fourier series</a>, arXiv:1705.05448, 2017.
134178

135-
[6] A. Townsend, M. Webb, and S. Olver. <a href="https://doi.org/10.1090/mcom/3277">Fast polynomial transforms based on Toeplitz and Hankel matrices</a>, in press at *Math. Comp.*, 2017.
179+
[7] A. Townsend, M. Webb, and S. Olver. <a href="https://doi.org/10.1090/mcom/3277">Fast polynomial transforms based on Toeplitz and Hankel matrices</a>, in press at *Math. Comp.*, 2017.

docs/src/index.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,46 @@ plan_cjt
5252
plan_icjt
5353
```
5454

55+
```@docs
56+
nufft1
57+
```
58+
59+
```@docs
60+
nufft2
61+
```
62+
63+
```@docs
64+
nufft3
65+
```
66+
67+
```@docs
68+
inufft1
69+
```
70+
71+
```@docs
72+
inufft2
73+
```
74+
75+
```@docs
76+
plan_nufft1
77+
```
78+
79+
```@docs
80+
plan_nufft2
81+
```
82+
83+
```@docs
84+
plan_nufft3
85+
```
86+
87+
```@docs
88+
plan_inufft1
89+
```
90+
91+
```@docs
92+
plan_inufft2
93+
```
94+
5595
```@docs
5696
paduatransform
5797
```
@@ -112,6 +152,10 @@ FastTransforms.δ
112152
FastTransforms.Λ
113153
```
114154

155+
```@docs
156+
FastTransforms.lambertw
157+
```
158+
115159
```@docs
116160
FastTransforms.pochhammer
117161
```

src/FastTransforms.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ export normleg2cheb, cheb2normleg, normleg12cheb2, cheb22normleg1
1616
export plan_leg2cheb, plan_cheb2leg
1717
export plan_normleg2cheb, plan_cheb2normleg
1818
export plan_normleg12cheb2, plan_cheb22normleg1
19+
1920
export gaunt
21+
22+
export nufft, nufft1, nufft2, nufft3, inufft1, inufft2
23+
export plan_nufft, plan_nufft1, plan_nufft2, plan_nufft3, plan_inufft1, plan_inufft2
24+
2025
export paduatransform, ipaduatransform, paduatransform!, ipaduatransform!, paduapoints
2126
export plan_paduatransform!, plan_ipaduatransform!
2227

@@ -49,6 +54,8 @@ include("cheb2jac.jl")
4954
include("ChebyshevUltrasphericalPlan.jl")
5055
include("ultra2cheb.jl")
5156
include("cheb2ultra.jl")
57+
include("nufft.jl")
58+
include("inufft.jl")
5259

5360
include("cjt.jl")
5461

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

0 commit comments

Comments
 (0)