|
1 |
| -function nufft1_plan{T<:AbstractFloat}( x::AbstractVector{T}, ϵ::T ) |
2 |
| - |
3 |
| -t_idx = AssignClosestEquispacedFFTpoint( x ) |
4 |
| -γ = PerturbationParameter( x, AssignClosestEquispacedGridpoint( x ) ) |
5 |
| -K = FindK(γ, ϵ) |
6 |
| -u = constructU(x, K) |
7 |
| -v = constructV(x, K) |
8 |
| -p( c ) = (u.*(fft(Diagonal(c)*v,1)[t_idx,:]))*ones(K) |
| 1 | +doc""" |
| 2 | +Pre-compute a 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 NUFFTPlan{N,T,FFT} <: Base.DFT.Plan{T} |
| 7 | + U::Matrix{T} |
| 8 | + V::Matrix{T} |
| 9 | + p::FFT |
| 10 | + t::Vector{Int} |
| 11 | + temp::Matrix{T} |
| 12 | + temp2::Matrix{T} |
| 13 | + Ones::Vector{T} |
9 | 14 | end
|
10 | 15 |
|
11 |
| -function nufft2_plan{T<:AbstractFloat}( ω::AbstractVector{T}, ϵ::T ) |
| 16 | +doc""" |
| 17 | +Computes a nonuniform fast Fourier transform of type I: |
| 18 | +
|
| 19 | +```math |
| 20 | +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. |
| 21 | +``` |
| 22 | +""" |
| 23 | +function plan_nufft1{T<:AbstractFloat}(ω::AbstractVector{T}, ϵ::T) |
| 24 | + N = length(ω) |
| 25 | + ωdN = ω/N |
| 26 | + t = AssignClosestEquispacedFFTpoint(ωdN) |
| 27 | + γ = PerturbationParameter(ωdN, AssignClosestEquispacedGridpoint(ωdN)) |
| 28 | + K = FindK(γ, ϵ) |
| 29 | + U = constructU( ωdN, K) |
| 30 | + V = constructV( ωdN, K) |
| 31 | + p = plan_ifft!(V, 1) |
| 32 | + temp = zeros(Complex{T}, N, K) |
| 33 | + temp2 = zeros(Complex{T}, N, K) |
| 34 | + Ones = ones(Complex{T}, K) |
12 | 35 |
|
13 |
| -N = size(ω, 1) |
14 |
| -t_idx = AssignClosestEquispacedFFTpoint( ω/N ) |
15 |
| -γ = PerturbationParameter( ω/N, AssignClosestEquispacedGridpoint( ω/N ) ) |
16 |
| -K = FindK(γ, ϵ) |
17 |
| -u = constructU( ω/N, K) |
18 |
| -v = constructV( ω/N, K) |
19 |
| -In = speye(Complex{T}, N, N) |
20 |
| -p( c ) = (v.*(N*conj(ifft(In[:,t_idx]*conj(Diagonal(c)*u),1))))*ones(K) |
| 36 | + NUFFTPlan{1, eltype(U), typeof(p)}(U, V, p, t, temp, temp2, Ones) |
21 | 37 | end
|
22 | 38 |
|
23 |
| -nufft_plan{T<:AbstractFloat}( x::AbstractVector{T}, ϵ::T ) = nufft1_plan( x, ϵ ) |
24 |
| -nufft{T<:AbstractFloat}( c::AbstractVector, x::AbstractVector{T}, ϵ::T ) = nufft_plan(x, ϵ)(c) |
25 |
| -nufft1{T<:AbstractFloat}( c::AbstractVector, x::AbstractVector{T}, ϵ::T ) = nufft1_plan(x, ϵ)(c) |
26 |
| -nufft2{T<:AbstractFloat}( c::AbstractVector, ω::AbstractVector{T}, ϵ::T ) = nufft2_plan(ω, ϵ)(c) |
| 39 | +doc""" |
| 40 | +Computes a nonuniform fast Fourier transform of type II: |
27 | 41 |
|
28 |
| -FindK{T<:AbstractFloat}(γ::T, ϵ::T) = Int( ceil(5.0*γ.*exp(lambertw(log(10.0/ϵ)./γ/7.0))) ) |
29 |
| -AssignClosestEquispacedGridpoint{T<:AbstractFloat}( x::AbstractVector{T} )::AbstractVector{T} = round(size(x,1)*x) |
30 |
| -AssignClosestEquispacedFFTpoint{T<:AbstractFloat}( x::AbstractVector{T} )::Array{Int64,1} = mod(round(Int64, size(x,1)*x), size(x,1)) + 1 |
31 |
| -PerturbationParameter{T<:AbstractFloat}( x::AbstractVector{T}, s_vec::AbstractVector{T} )::AbstractFloat = norm( size(x,1)*x - s_vec, Inf) |
| 42 | +```math |
| 43 | +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. |
| 44 | +``` |
| 45 | +""" |
| 46 | +function plan_nufft2{T<:AbstractFloat}(x::AbstractVector{T}, ϵ::T) |
| 47 | + N = length(x) |
| 48 | + t = AssignClosestEquispacedFFTpoint(x) |
| 49 | + γ = PerturbationParameter(x, AssignClosestEquispacedGridpoint(x)) |
| 50 | + K = FindK(γ, ϵ) |
| 51 | + U = constructU(x, K) |
| 52 | + V = constructV(x, K) |
| 53 | + p = plan_fft!(U, 1) |
| 54 | + temp = zeros(Complex{T}, N, K) |
| 55 | + temp2 = zeros(Complex{T}, N, K) |
| 56 | + Ones = ones(Complex{T}, K) |
| 57 | + |
| 58 | + NUFFTPlan{2, eltype(U), typeof(p)}(U, V, p, t, temp, temp2, Ones) |
| 59 | +end |
32 | 60 |
|
33 |
| -function constructU{T<:AbstractFloat}(x::AbstractVector{T}, K::Int64) |
34 |
| -# Construct a low rank approximation, using Chebyshev expansions |
35 |
| -# for AK = exp(-2*pi*1im*(x[j]-j/N)*k): |
| 61 | +function (*){N,T,V}(p::NUFFTPlan{N,T}, x::AbstractVector{V}) |
| 62 | + A_mul_B!(zeros(promote_type(T,V), length(x)), p, x) |
| 63 | +end |
36 | 64 |
|
37 |
| -N = size(x, 1) |
38 |
| -#(s_vec, t_idx, γ) = FindAlgorithmicParameters( x ) |
39 |
| -s_vec = AssignClosestEquispacedGridpoint( x ) |
40 |
| -er = N*x - s_vec |
41 |
| -γ = norm( er, Inf ) |
| 65 | +function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{1,T}, c::AbstractVector{T}) |
| 66 | + U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones |
42 | 67 |
|
43 |
| -# colspace vectors: |
44 |
| -u = Diagonal(exp(-1im*pi*er))*ChebyshevP(K-1, er/γ)*Bessel_coeffs(K, γ) |
45 |
| -end |
| 68 | + # (V.*(N*conj(ifft(In[:,t]*conj(Diagonal(c)*U),1))))*ones(K) |
46 | 69 |
|
47 |
| -function constructV{T<:AbstractFloat}(x::AbstractVector{T}, K::Int64) |
| 70 | + broadcast!(*, temp, c, U) |
| 71 | + conj!(temp) |
| 72 | + fill!(temp2, zero(T)) |
| 73 | + recombine_rows!(temp, t, temp2) |
| 74 | + p*temp2 |
| 75 | + conj!(temp2) |
| 76 | + broadcast!(*, temp, V, temp2) |
| 77 | + A_mul_B!(y, temp, Ones) |
| 78 | + scale!(length(c), y) |
48 | 79 |
|
49 |
| -N = size(x, 1) |
50 |
| -v = complex(ChebyshevP(K-1, 2.0*collect(0:N-1)/N - ones(N) )) |
| 80 | + y |
51 | 81 | end
|
52 | 82 |
|
53 |
| -function Bessel_coeffs{T<:AbstractFloat}(K::Int64, γ::T)::Array{Complex{T},2} |
54 |
| -# Calculate the Chebyshev coefficients of exp(-2*pi*1im*x*y) on [-gam,gam]x[0,1] |
| 83 | +function Base.A_mul_B!{T}(y::AbstractVector{T}, P::NUFFTPlan{2,T}, c::AbstractVector{T}) |
| 84 | + U, V, p, t, temp, temp2, Ones = P.U, P.V, P.p, P.t, P.temp, P.temp2, P.Ones |
| 85 | + |
| 86 | + # (U.*(fft(Diagonal(c)*V,1)[t+1,:]))*ones(K) |
| 87 | + |
| 88 | + broadcast!(*, temp, c, V) |
| 89 | + p*temp |
| 90 | + reindex_temp!(temp, t, temp2) |
| 91 | + broadcast!(*, temp, U, temp2) |
| 92 | + A_mul_B!(y, temp, Ones) |
| 93 | + |
| 94 | + y |
| 95 | +end |
55 | 96 |
|
56 |
| -cfs = complex(zeros( K, K )) |
57 |
| -arg = -γ*pi/2.0 |
58 |
| -for p = 0:K-1 |
59 |
| - for q = mod(p,2):2:K-1 |
60 |
| - cfs[p+1,q+1] = 4.0*(1im)^q*besselj((p+q)/2,arg).*besselj((q-p)/2,arg) |
61 |
| - end |
| 97 | +function reindex_temp!{T}(temp::Matrix{T}, t::Vector{Int}, temp2::Matrix{T}) |
| 98 | + @inbounds for j = 1:size(temp, 2) |
| 99 | + for i = 1:size(temp, 1) |
| 100 | + temp2[i, j] = temp[t[i], j] |
| 101 | + end |
| 102 | + end |
| 103 | + temp2 |
62 | 104 | end
|
63 |
| -cfs[1,:] = cfs[1,:]/2.0 |
64 |
| -cfs[:,1] = cfs[:,1]/2.0 |
65 |
| -return cfs |
| 105 | + |
| 106 | +function recombine_rows!{T}(temp::Matrix{T}, t::Vector{Int}, temp2::Matrix{T}) |
| 107 | + @inbounds for j = 1:size(temp, 2) |
| 108 | + for i = 1:size(temp, 1) |
| 109 | + temp2[t[i], j] += temp[i, j] |
| 110 | + end |
| 111 | + end |
| 112 | + temp2 |
66 | 113 | end
|
67 | 114 |
|
68 |
| -function ChebyshevP{T<:AbstractFloat}(n::Int64, x::AbstractVector{T})::AbstractArray{T} |
69 |
| -# Evaluate Chebyshev polynomials of degree 0,...,n at x: |
| 115 | +doc""" |
| 116 | +Pre-compute a nonuniform fast Fourier transform of type I. |
| 117 | +""" |
| 118 | +nufft1{T<:AbstractFloat}(c::AbstractVector, ω::AbstractVector{T}, ϵ::T) = plan_nufft1(ω, ϵ)*c |
| 119 | + |
| 120 | +doc""" |
| 121 | +Pre-compute a nonuniform fast Fourier transform of type II. |
| 122 | +""" |
| 123 | +nufft2{T<:AbstractFloat}(c::AbstractVector, x::AbstractVector{T}, ϵ::T) = plan_nufft2(x, ϵ)*c |
| 124 | + |
| 125 | +FindK{T<:AbstractFloat}(γ::T, ϵ::T) = Int(ceil(5*γ*exp(lambertw(log(10/ϵ)/γ/7)))) |
| 126 | +AssignClosestEquispacedGridpoint{T<:AbstractFloat}(x::AbstractVector{T})::AbstractVector{T} = round.([Int], size(x, 1)*x) |
| 127 | +AssignClosestEquispacedFFTpoint{T<:AbstractFloat}(x::AbstractVector{T})::Array{Int,1} = mod.(round.([Int], size(x, 1)*x), size(x, 1)) + 1 |
| 128 | +PerturbationParameter{T<:AbstractFloat}(x::AbstractVector{T}, s_vec::AbstractVector{T})::AbstractFloat = norm(size(x, 1)*x - s_vec, Inf) |
70 | 129 |
|
71 |
| -N = size(x, 1) |
72 |
| -Tcheb = Array{T}(N, n+1) |
| 130 | +function constructU{T<:AbstractFloat}(x::AbstractVector{T}, K::Int) |
| 131 | + # Construct a low rank approximation, using Chebyshev expansions |
| 132 | + # 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 |
| 137 | + γ = norm(er, Inf) |
| 138 | + # colspace vectors: |
| 139 | + Diagonal(exp.(-im*(pi*er)))*ChebyshevP(K-1, er/γ)*Bessel_coeffs(K, γ) |
| 140 | +end |
73 | 141 |
|
74 |
| -# T_0(x) = 1.0 |
75 |
| -One = convert(eltype(x),1.0) |
76 |
| -@inbounds for j = 1:N |
77 |
| - Tcheb[j, 1] = One |
| 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) )) |
78 | 145 | end
|
79 |
| -# T_1(x) = x |
80 |
| -if ( n > 0 ) |
81 |
| - @inbounds for j = 1:N |
82 |
| - Tcheb[j, 2] = x[j] |
83 |
| - end |
| 146 | + |
| 147 | +function Bessel_coeffs{T<:AbstractFloat}(K::Int, γ::T) |
| 148 | + # Calculate the Chebyshev coefficients of exp(-2*pi*1im*x*y) on [-gam,gam]x[0,1] |
| 149 | + cfs = zeros(Complex{T}, K, K) |
| 150 | + arg = -γ*π/two(T) |
| 151 | + for p = 0:K-1 |
| 152 | + for q = mod(p,2):2:K-1 |
| 153 | + cfs[p+1,q+1] = 4*(1im)^q*besselj((p+q)/2,arg).*besselj((q-p)/2,arg) |
| 154 | + end |
| 155 | + end |
| 156 | + cfs[1,:] = cfs[1,:]/two(T) |
| 157 | + cfs[:,1] = cfs[:,1]/two(T) |
| 158 | + return cfs |
84 | 159 | end
|
85 |
| -# 3-term recurrence relation: |
86 |
| -twoX = 2x |
87 |
| -@inbounds for k = 2:n |
88 |
| - @inbounds for j = 1:N |
89 |
| - Tcheb[j, k+1] = twoX[j]*Tcheb[j, k] - Tcheb[j, k-1] |
90 |
| - end |
| 160 | + |
| 161 | +function ChebyshevP{T<:AbstractFloat}(n::Int, x::AbstractVector{T}) |
| 162 | + # Evaluate Chebyshev polynomials of degree 0,...,n at x: |
| 163 | + N = size(x, 1) |
| 164 | + Tcheb = Matrix{T}(N, n+1) |
| 165 | + |
| 166 | + # T_0(x) = 1.0 |
| 167 | + One = convert(eltype(x),1.0) |
| 168 | + @inbounds for j = 1:N |
| 169 | + Tcheb[j, 1] = One |
| 170 | + end |
| 171 | + # T_1(x) = x |
| 172 | + if ( n > 0 ) |
| 173 | + @inbounds for j = 1:N |
| 174 | + Tcheb[j, 2] = x[j] |
| 175 | + end |
| 176 | + end |
| 177 | + # 3-term recurrence relation: |
| 178 | + twoX = 2x |
| 179 | + @inbounds for k = 2:n |
| 180 | + @simd for j = 1:N |
| 181 | + Tcheb[j, k+1] = twoX[j]*Tcheb[j, k] - Tcheb[j, k-1] |
| 182 | + end |
| 183 | + end |
| 184 | + return Tcheb |
91 | 185 | end
|
92 |
| -return Tcheb |
93 |
| -end |
|
0 commit comments