Skip to content

Commit 41fa0fd

Browse files
committed
adds NFCT interface to AbstractNFFTs and implementation to NFFT3 wrapper #85
1 parent d79020f commit 41fa0fd

File tree

4 files changed

+272
-15
lines changed

4 files changed

+272
-15
lines changed

AbstractNFFTs/src/AbstractNFFTs.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ using LinearAlgebra
55
using Printf
66

77
# interface
8-
export AnyNFFTPlan, AbstractNFFTPlan, AbstractNNFFTPlan,
9-
plan_nfft, mul!, size_in, size_out, nodes!
8+
export AnyNFFTPlan, AbstractNFFTPlan, AbstractNFCTPlan, AbstractNNFFTPlan,
9+
plan_nfft, plan_nfct, mul!, size_in, size_out, nodes!
1010

1111
# optional
1212
export apodization!, apodization_adjoint!, convolve!, convolve_adjoint!
1313

1414
# derived
15-
export nfft, nfft_adjoint, ndft, ndft_adjoint
15+
export nfft, nfft_adjoint, ndft, ndft_adjoint, nfct, nfct_transposed
1616

1717
# misc
1818
export TimingStats, accuracyParams, reltolToParams, paramsToReltol,

AbstractNFFTs/src/derived.jl

+102-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,32 @@ plan_nfft(Q::Type, x::AbstractMatrix, N::NTuple{D,Int}, rest...; kwargs...) wher
2424

2525
plan_nfft(Q::Type, x::AbstractVector, y::AbstractVector, rest...; kwargs...) where {D} =
2626
plan_nfft(Q, collect(reshape(x,1,length(x))), collect(reshape(y,1,length(x))), rest...; kwargs...)
27+
28+
##########################
29+
# plan_nfct constructors
30+
##########################
31+
32+
# The following automatically call the plan_nfft version for type Array
33+
34+
plan_nfct(x::AbstractArray, N::Union{Integer,NTuple{D,Int}}, args...; kargs...) where {D} =
35+
plan_nfct(Array, x, N, args...; kargs...)
36+
37+
plan_nfct(x::AbstractArray, y::AbstractArray, args...; kargs...) where {D} =
38+
plan_nfct(Array, x, y, args...; kargs...)
39+
40+
# The follow convert 1D parameters into the format required by the NFFT plan
41+
42+
plan_nfct(Q::Type, x::AbstractVector, N::Integer, rest...; kwargs...) where {D} =
43+
plan_nfct(Q, collect(reshape(x,1,length(x))), (N,), rest...; kwargs...)
44+
45+
plan_nfct(Q::Type, x::AbstractVector, N::NTuple{D,Int}, rest...; kwargs...) where {D} =
46+
plan_nfct(Q, collect(reshape(x,1,length(x))), N, rest...; kwargs...)
47+
48+
plan_nfct(Q::Type, x::AbstractMatrix, N::NTuple{D,Int}, rest...; kwargs...) where {D} =
49+
plan_nfct(Q, collect(x), N, rest...; kwargs...)
50+
51+
plan_nfct(Q::Type, x::AbstractVector, y::AbstractVector, rest...; kwargs...) where {D} =
52+
plan_nfct(Q, collect(reshape(x,1,length(x))), collect(reshape(y,1,length(x))), rest...; kwargs...)
2753

2854

2955
##########################
@@ -64,7 +90,7 @@ For a **directional** `D` dimensional plan `p` both `f` and `fHat` are `D`
6490
dimensional arrays, and the dimension specified in the plan creation is
6591
affected.
6692
"""
67-
function Base.:*(p::AnyNFFTPlan{T}, f::AbstractArray{Complex{U},D}; kargs...) where {T,U,D}
93+
function Base.:*(p::AbstractNFFTPlan{T}, f::AbstractArray{Complex{U},D}; kargs...) where {T,U,D}
6894
fHat = similar(f, Complex{T}, size_out(p))
6995
mul!(fHat, p, f; kargs...)
7096
return fHat
@@ -82,22 +108,94 @@ dimensional arrays, and the dimension specified in the plan creation is
82108
affected.
83109
"""
84110

85-
function Base.:*(p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}, fHat::AbstractArray{Complex{U},D}; kargs...) where {T,U,D}
111+
function Base.:*(p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat::AbstractArray{Complex{U},D}; kargs...) where {T,U,D}
86112
f = similar(fHat, Complex{T}, size_out(p))
87113
mul!(f, p, fHat; kargs...)
88114
return f
89115
end
90116

91117
# The following two methods are redundant but need to be defined because of a method ambiguity with Julia Base
92-
function Base.:*(p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}, fHat::AbstractVector{Complex{U}}; kargs...) where {T,U}
118+
function Base.:*(p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat::AbstractVector{Complex{U}}; kargs...) where {T,U}
93119
f = similar(fHat, Complex{T}, size_out(p))
94120
mul!(f, p, fHat; kargs...)
95121
return f
96122
end
97-
function Base.:*(p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}, fHat::AbstractArray{Complex{U},2}; kargs...) where {T,U}
123+
function Base.:*(p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat::AbstractArray{Complex{U},2}; kargs...) where {T,U}
98124
f = similar(fHat, Complex{T}, size_out(p))
99125
mul!(f, p, fHat; kargs...)
100126
return f
101127
end
102128

129+
##########################
130+
# Allocating nfct functions
131+
##########################
132+
133+
"""
134+
nfct(x, f::AbstractArray{T,D}, rest...; kwargs...)
135+
136+
calculates the NFCT of the array `f` for the nodes contained in the matrix `x`
137+
The output is a vector of length M=`size(nodes,2)`
138+
"""
139+
function nfct(x, f::AbstractArray{T,D}; kargs...) where {T,D}
140+
p = plan_nfct(x, size(f); kargs... )
141+
return p * f
142+
end
143+
144+
"""
145+
nfct_transposed(x, N, fHat::AbstractArray{T,D}, rest...; kwargs...)
146+
147+
calculates the transposed NFCT of the vector `fHat` for the nodes contained in the matrix `x`.
148+
The output is an array of size `N`
149+
"""
150+
function nfct_transposed(x, N, fHat::AbstractVector{T}; kargs...) where T
151+
p = plan_nfct(x, N; kargs...)
152+
return transpose(p) * fHat
153+
end
154+
103155

156+
"""
157+
*(p, f) -> fHat
158+
159+
For a **non**-directional `D` dimensional plan `p` this calculates the NFCT of a `D` dimensional array `f` of size `N`.
160+
`fHat` is a vector of length `M`.
161+
(`M` and `N` are defined in the plan creation)
162+
163+
For a **directional** `D` dimensional plan `p` both `f` and `fHat` are `D`
164+
dimensional arrays, and the dimension specified in the plan creation is
165+
affected.
166+
"""
167+
function Base.:*(p::AbstractNFCTPlan{T}, f::AbstractArray{U,D}; kargs...) where {T,U,D}
168+
fHat = similar(f, T, size_out(p))
169+
mul!(fHat, p, f; kargs...)
170+
return fHat
171+
end
172+
173+
"""
174+
*(p::Transpose{T,AbstractNFCTPlan{T}}, fHat) -> f
175+
176+
For a **non**-directional `D` dimensional plan `p` this calculates the adjoint NFCT of a length `M` vector `fHat`
177+
`f` is a `D` dimensional array of size `N`.
178+
(`M` and `N` are defined in the plan creation)
179+
180+
For a **directional** `D` dimensional plan `p` both `f` and `fHat` are `D`
181+
dimensional arrays, and the dimension specified in the plan creation is
182+
affected.
183+
"""
184+
185+
function Base.:*(p::Transpose{T,<:AbstractNFCTPlan{T}}, fHat::AbstractArray{U,D}; kargs...) where {T,U,D}
186+
f = similar(fHat, T, size_out(p))
187+
mul!(f, p, fHat; kargs...)
188+
return f
189+
end
190+
191+
# The following two methods are redundant but need to be defined because of a method ambiguity with Julia Base
192+
function Base.:*(p::Transpose{T,<:AbstractNFCTPlan{T}}, fHat::AbstractVector{U}; kargs...) where {T,U}
193+
f = similar(fHat, T, size_out(p))
194+
mul!(f, p, fHat; kargs...)
195+
return f
196+
end
197+
function Base.:*(p::Transpose{T,<:AbstractNFCTPlan{T}}, fHat::AbstractArray{U,2}; kargs...) where {T,U}
198+
f = similar(fHat, T, size_out(p))
199+
mul!(f, p, fHat; kargs...)
200+
return f
201+
end

AbstractNFFTs/src/interface.jl

+73-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ Abstract type for an NFFT plan.
1818
"""
1919
abstract type AbstractNFFTPlan{T,D,R} <: AnyNFFTPlan{T,D,R} end
2020

21+
"""
22+
AbstractNFCTPlan{T,D,R}
23+
24+
Abstract type for an NFCT plan.
25+
* T is the element type (Float32/Float64)
26+
* D is the number of dimensions of the input array.
27+
* R is the number of dimensions of the output array.
28+
"""
29+
abstract type AbstractNFCTPlan{T,D,R} <: AnyNFFTPlan{T,D,R} end
30+
2131
"""
2232
AbstractNNFFTPlan{T,D,R}
2333
@@ -32,16 +42,38 @@ abstract type AbstractNNFFTPlan{T,D,R} <: AnyNFFTPlan{T,D,R} end
3242
# Function needed to make AnyNFFTPlan an operator
3343
#####################
3444

35-
Base.eltype(p::AnyNFFTPlan{T}) where T = Complex{T}
45+
Base.eltype(p::AbstractNFFTPlan{T}) where T = Complex{T}
46+
Base.eltype(p::AbstractNNFFTPlan{T}) where T = Complex{T}
47+
Base.eltype(p::AbstractNFCTPlan{T}) where T = T
48+
3649
Base.size(p::AnyNFFTPlan) = (prod(size_out(p)), prod(size_in(p)))
37-
Base.size(p::Adjoint{Complex{T}, U}) where {T, U<:AnyNFFTPlan{T}} =
50+
51+
Base.size(p::Adjoint{Complex{T}, U}) where {T, U<:AbstractNFFTPlan{T}} =
52+
(prod(size_in(p.parent)), prod(size_out(p.parent)))
53+
54+
Base.size(p::Adjoint{Complex{T}, U}) where {T, U<:AbstractNNFFTPlan{T}} =
3855
(prod(size_in(p.parent)), prod(size_out(p.parent)))
3956

40-
LinearAlgebra.adjoint(p::AnyNFFTPlan{T,D,R}) where {T,D,R} =
57+
Base.size(p::Transpose{T, U}) where {T, U<:AbstractNFCTPlan{T}} =
58+
(prod(size_in(p.parent)), prod(size_out(p.parent)))
59+
60+
LinearAlgebra.adjoint(p::AbstractNFFTPlan{T,D,R}) where {T,D,R} =
4161
Adjoint{Complex{T}, typeof(p)}(p)
4262

43-
size_in(p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}) where {T} = size_out(p.parent)
44-
size_out(p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}) where {T} = size_in(p.parent)
63+
LinearAlgebra.adjoint(p::AbstractNNFFTPlan{T,D,R}) where {T,D,R} =
64+
Adjoint{Complex{T}, typeof(p)}(p)
65+
66+
LinearAlgebra.transpose(p::AbstractNFCTPlan{T,D,R}) where {T,D,R} =
67+
Transpose{T, typeof(p)}(p)
68+
69+
size_in(p::Adjoint{Complex{T},<:AbstractNFFTPlan{T,D,R}}) where {T,D,R} = size_out(p.parent)
70+
size_out(p::Adjoint{Complex{T},<:AbstractNFFTPlan{T,D,R}}) where {T,D,R} = size_in(p.parent)
71+
72+
size_in(p::Adjoint{Complex{T},<:AbstractNNFFTPlan{T,D,R}}) where {T,D,R} = size_out(p.parent)
73+
size_out(p::Adjoint{Complex{T},<:AbstractNNFFTPlan{T,D,R}}) where {T,D,R} = size_in(p.parent)
74+
75+
size_in(p::Transpose{T,<:AbstractNFCTPlan{T,D,R}}) where {T,D,R} = size_out(p.parent)
76+
size_out(p::Transpose{T,<:AbstractNFCTPlan{T,D,R}}) where {T,D,R} = size_in(p.parent)
4577

4678
#####################
4779
# define interface
@@ -58,14 +90,32 @@ Both `f` and `fHat` must be complex arrays of element type `Complex{T}`.
5890
"""
5991
@mustimplement LinearAlgebra.mul!( fHat::AbstractArray, p::AbstractNFFTPlan{T}, f::AbstractArray) where {T}
6092

93+
"""
94+
mul!(fHat, p, f) -> fHat
95+
96+
Inplace NFCT transforming the `D` dimensional array `f` to the `R` dimensional array `fHat`.
97+
The transformation is applied along `D-R+1` dimensions specified in the plan `p`.
98+
Both `f` and `fHat` must be complex arrays of element type `Complex{T}`.
99+
"""
100+
@mustimplement LinearAlgebra.mul!( fHat::AbstractArray, p::AbstractNFCTPlan{T}, f::AbstractArray) where {T}
101+
61102
"""
62103
mul!(f, p, fHat) -> f
63104
64105
Inplace adjoint NFFT transforming the `R` dimensional array `fHat` to the `D` dimensional array `f`.
65106
The transformation is applied along `D-R+1` dimensions specified in the plan `p`.
66107
Both `f` and `fHat` must be complex arrays of element type `Complex{T}`.
67108
"""
68-
@mustimplement LinearAlgebra.mul!(f::AbstractArray, p::Adjoint{Complex{T},<:AnyNFFTPlan{T}}, fHat::AbstractArray) where {T}
109+
@mustimplement LinearAlgebra.mul!(f::AbstractArray, p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat::AbstractArray) where {T}
110+
111+
"""
112+
mul!(f, p, fHat) -> f
113+
114+
Inplace transposed NFCT transforming the `R` dimensional array `fHat` to the `D` dimensional array `f`.
115+
The transformation is applied along `D-R+1` dimensions specified in the plan `p`.
116+
Both `f` and `fHat` must be arrays of element type `T`.
117+
"""
118+
@mustimplement LinearAlgebra.mul!(f::AbstractArray, p::Transpose{T,<:AbstractNFCTPlan{T}}, fHat::AbstractArray) where {T}
69119

70120
"""
71121
size_in(p)
@@ -75,6 +125,14 @@ Note that this will be the output array for an adjoint NFFT.
75125
"""
76126
@mustimplement size_in(p::AbstractNFFTPlan{T,D,R}) where {T,D,R}
77127

128+
"""
129+
size_in(p)
130+
131+
Size of the input array for an NFCT operation. The returned tuple has `D` entries.
132+
Note that this will be the output array for a transposed NFCT.
133+
"""
134+
@mustimplement size_in(p::AbstractNFCTPlan{T,D,R}) where {T,D,R}
135+
78136
"""
79137
size_out(p)
80138
@@ -83,12 +141,21 @@ Note that this will be the input array for an adjoint NFFT.
83141
"""
84142
@mustimplement size_out(p::AbstractNFFTPlan{T,D,R}) where {T,D,R}
85143

144+
"""
145+
size_out(p)
146+
147+
Size of the output array for an NFCT operation. The returned tuple has `R` entries.
148+
Note that this will be the input array for a transposed NFCT.
149+
"""
150+
@mustimplement size_out(p::AbstractNFCTPlan{T,D,R}) where {T,D,R}
151+
86152
"""
87153
nodes!(p, x) -> p
88154
89155
Change nodes `x` in the plan `p` operation and return the plan.
90156
"""
91157
@mustimplement nodes!(p::AbstractNFFTPlan{T}, x::Matrix{T}) where {T}
158+
@mustimplement nodes!(p::AbstractNFCTPlan{T}, x::Matrix{T}) where {T}
92159

93160

94161
## Optional Interface ##

0 commit comments

Comments
 (0)