Skip to content

Commit 4b91f57

Browse files
committed
Optimizing planned transforms
1 parent ed05a6a commit 4b91f57

File tree

3 files changed

+90
-159
lines changed

3 files changed

+90
-159
lines changed

src/FastTransforms.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Compat: view
99
export cjt, icjt, jjt, plan_cjt, plan_icjt
1010
export leg2cheb, cheb2leg, leg2chebu, ultra2ultra, jac2jac
1111
export gaunt
12-
export paduatransform, ipaduatransform, paduapoints, paduaeval
12+
export paduatransform, ipaduatransform, paduapoints
1313
export plan_paduatransform, plan_ipaduatransform
1414

1515
# Other module methods and constants:

src/PaduaTransform.jl

Lines changed: 55 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,42 @@
11
"""
22
Pre-plan an Inverse Padua Transform.
33
"""
4-
immutable IPaduaTransformPlan{DCTPLAN}
5-
cfsmat::Matrix{Float64}
6-
tensorvals::Matrix{Float64}
7-
padvals::Vector{Float64}
8-
dctplan::DCTPLAN
4+
immutable IPaduaTransformPlan{IDCTPLAN,T}
5+
cfsmat::Matrix{T}
6+
padvals::Vector{T}
7+
idctplan::IDCTPLAN
98
end
109

11-
function plan_ipaduatransform(v::AbstractVector)
10+
function plan_ipaduatransform{T}(v::AbstractVector{T})
1211
N=length(v)
1312
n=Int(cld(-3+sqrt(1+8N),2))
1413
@assert N==div((n+1)*(n+2),2)
15-
IPaduaTransformPlan(zeros(Float64,n+2,n+1),Array(Float64,n+2,n+1),
16-
Array(Float64,N),FFTW.plan_r2r(Array(eltype(v),n+2,n+1),FFTW.REDFT00))
14+
IPaduaTransformPlan(Array{T}(n+2,n+1),Array{T}(N),
15+
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00))
1716
end
1817

1918
"""
2019
Inverse Padua Transform maps the 2D Chebyshev coefficients to the values of the interpolation polynomial at the Padua points.
2120
"""
22-
function ipaduatransform(P::IPaduaTransformPlan,v::AbstractVector)
21+
function ipaduatransform{T}(P::IPaduaTransformPlan,v::AbstractVector{T})
2322
cfsmat=trianglecfsmat(P,v)
24-
tensorvals=P.tensorvals
25-
cfsmat[:,2:end-1]=scale!(cfsmat[:,2:end-1],0.5)
26-
cfsmat[2:end-1,:]=scale!(cfsmat[2:end-1,:],0.5)
27-
tensorvals=P.dctplan*cfsmat
23+
n,m=size(cfsmat)
24+
scale!(view(cfsmat,:,2:m-1),0.5)
25+
scale!(view(cfsmat,2:n-1,:),0.5)
26+
tensorvals=P.idctplan*cfsmat
2827
paduavals=paduavec(P,tensorvals)
2928
return paduavals
3029
end
3130

32-
function ipaduatransform(v::AbstractVector)
33-
cfsmat=trianglecfsmat(v)
34-
n=size(cfsmat,2)-1
35-
tensorvals=Array(Float64,n+2,n+1)
36-
cfsmat[:,2:end-1]=scale!(cfsmat[:,2:end-1],0.5)
37-
cfsmat[2:end-1,:]=scale!(cfsmat[2:end-1,:],0.5)
38-
tensorvals= FFTW.r2r(cfsmat,FFTW.REDFT00)
39-
paduavals=paduavec(tensorvals)
40-
return paduavals
41-
end
4231
"""
4332
Creates (n+2)x(n+1) Chebyshev coefficient matrix from triangle coefficients.
4433
"""
4534
function trianglecfsmat(P::IPaduaTransformPlan,cfs::AbstractVector)
4635
N=length(cfs)
4736
n=Int(cld(-3+sqrt(1+8N),2))
48-
cfsmat=P.cfsmat
49-
m=1
50-
for d=1:n+1, k=1:d
51-
j=d-k+1
52-
cfsmat[k,j]=cfs[m]
53-
if m==N
54-
return cfsmat
55-
else
56-
m+=1
57-
end
58-
end
59-
return cfsmat
60-
end
61-
62-
function trianglecfsmat(cfs::AbstractVector)
63-
N=length(cfs)
64-
n=Int(cld(-3+sqrt(1+8N),2))
65-
@assert N==div((n+1)*(n+2),2)
66-
cfsmat=zeros(Float64,n+2,n+1)
37+
cfsmat=fill!(P.cfsmat,0)
6738
m=1
68-
for d=1:n+1, k=1:d
39+
@inbounds for d=1:n+1, k=1:d
6940
j=d-k+1
7041
cfsmat[k,j]=cfs[m]
7142
if m==N
@@ -81,123 +52,73 @@ end
8152
Vectorizes the function values at the Padua points.
8253
"""
8354
function paduavec(P::IPaduaTransformPlan,padmat::Matrix)
84-
n=size(padmat,2)-1
85-
padvals=P.padvals
86-
if iseven(n)>0
87-
d=div(n+2,2)
88-
m=0
89-
for i=1:n+1
90-
padvals[m+1:m+d]=padmat[1+mod(i,2):2:end-1+mod(i,2),i]
91-
m+=d
92-
end
93-
else
94-
padvals=padmat[1:2:end-1]
95-
end
96-
return padvals
97-
end
98-
99-
function paduavec(padmat::Matrix)
10055
n=size(padmat,2)-1
10156
N=div((n+1)*(n+2),2)
102-
padvals=Array(Float64,N)
10357
if iseven(n)>0
10458
d=div(n+2,2)
10559
m=0
106-
for i=1:n+1
107-
padvals[m+1:m+d]=padmat[1+mod(i,2):2:end-1+mod(i,2),i]
108-
m+=d
109-
end
60+
@inbounds for i=1:n+1
61+
P.padvals[m+1:m+d]=view(padmat,1+mod(i,2):2:N-1+mod(i,2),i)
62+
m+=d
63+
end
11064
else
111-
padvals=padmat[1:2:end-1]
65+
66+
@inbounds P.padvals[:]=view(padmat,1:2:N-1)
11267
end
113-
return padvals
68+
return P.padvals
11469
end
11570

11671
"""
11772
Pre-plan a Padua Transform.
11873
"""
119-
immutable PaduaTransformPlan{IDCTPLAN}
120-
vals::Matrix{Float64}
121-
tensorcfs::Matrix{Float64}
122-
retvec::Vector{Float64}
123-
idctplan::IDCTPLAN
74+
immutable PaduaTransformPlan{DCTPLAN,T}
75+
vals::Matrix{T}
76+
retvec::Vector{T}
77+
dctplan::DCTPLAN
12478
end
12579

126-
function plan_paduatransform(v::AbstractVector)
80+
function plan_paduatransform{T}(v::AbstractVector{T})
12781
N=length(v)
12882
n=Int(cld(-3+sqrt(1+8N),2))
12983
@assert N==div((n+1)*(n+2),2)
130-
PaduaTransformPlan(zeros(Float64,n+2,n+1),Array(Float64,n+2,n+1),
131-
zeros(Float64,N),FFTW.plan_r2r(Array(eltype(v),n+2,n+1),FFTW.REDFT00))
84+
PaduaTransformPlan(Array{T}(n+2,n+1),Array{T}(N),
85+
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00))
13286
end
13387

13488
"""
13589
Padua Transform maps from interpolant values at the Padua points to the 2D Chebyshev coefficients.
13690
"""
137-
function paduatransform(P::PaduaTransformPlan,v::AbstractVector)
91+
function paduatransform{T}(P::PaduaTransformPlan,v::AbstractVector{T})
13892
N=length(v)
13993
n=Int(cld(-3+sqrt(1+8N),2))
140-
tensorcfs=P.tensorcfs
14194
vals=paduavalsmat(P,v)
142-
tensorcfs=P.idctplan*vals
143-
tensorcfs=scale!(tensorcfs,2./(n*(n+1.)))
144-
tensorcfs[1,:]=scale!(tensorcfs[1,:],0.5)
145-
tensorcfs[:,1]=scale!(tensorcfs[:,1],0.5)
146-
tensorcfs[end,:]=scale!(tensorcfs[end,:],0.5)
147-
tensorcfs[:,end]=scale!(tensorcfs[:,end],0.5)
95+
tensorcfs=P.dctplan*vals
96+
m,l=size(tensorcfs)
97+
scale!(tensorcfs,T(2)/(n*(n+1)))
98+
scale!(view(tensorcfs,1,:),0.5)
99+
scale!(view(tensorcfs,:,1),0.5)
100+
scale!(view(tensorcfs,m,:),0.5)
101+
scale!(view(tensorcfs,:,l),0.5)
148102
cfs=trianglecfsvec(P,tensorcfs)
149103
return cfs
150104
end
151105

152-
function paduatransform(v::AbstractVector)
153-
N=length(v)
154-
n=Int(cld(-3+sqrt(1+8N),2))
155-
tensorcfs=Array(Float64,n+2,n+1)
156-
vals=paduavalsmat(v)
157-
tensorcfs=FFTW.r2r(vals,FFTW.REDFT00)
158-
tensorcfs=scale!(tensorcfs,2./(n*(n+1.)))
159-
tensorcfs[1,:]=scale!(tensorcfs[1,:],0.5)
160-
tensorcfs[:,1]=scale!(tensorcfs[:,1],0.5)
161-
tensorcfs[end,:]=scale!(tensorcfs[end,:],0.5)
162-
tensorcfs[:,end]=scale!(tensorcfs[:,end],0.5)
163-
cfsvec=trianglecfsvec(tensorcfs)
164-
return cfsvec
165-
end
166-
167106
"""
168107
Creates (n+2)x(n+1) matrix of interpolant values on the tensor grid at the (n+1)(n+2)/2 Padua points.
169108
"""
170109
function paduavalsmat(P::PaduaTransformPlan,v::AbstractVector)
171110
N=length(v)
172111
n=Int(cld(-3+sqrt(1+8N),2))
173-
vals=P.vals
174-
if iseven(n)>0
175-
d=div(n+2,2)
176-
m=0
177-
for i=1:n+1
178-
vals[1+mod(i,2):2:end-1+mod(i,2),i]=v[m+1:m+d]
179-
m+=d
180-
end
181-
else
182-
vals[1:2:end]=v
183-
end
184-
return vals
185-
end
186-
187-
function paduavalsmat(v::AbstractVector)
188-
N=length(v)
189-
n=Int(cld(-3+sqrt(1+8N),2))
190-
@assert N==div((n+1)*(n+2),2)
191-
vals=zeros(Float64,n+2,n+1)
112+
vals=fill!(P.vals,0.)
192113
if iseven(n)>0
193114
d=div(n+2,2)
194115
m=0
195-
for i=1:n+1
196-
vals[1+mod(i,2):2:end-1+mod(i,2),i]=v[m+1:m+d]
116+
@inbounds for i=1:n+1
117+
vals[1+mod(i,2):2:end-1+mod(i,2),i]=view(v,m+1:m+d)
197118
m+=d
198119
end
199120
else
200-
vals[1:2:end]=v
121+
@inbounds vals[1:2:end]=view(v,:)
201122
end
202123
return vals
203124
end
@@ -207,67 +128,43 @@ Creates length (n+1)(n+2)/2 vector from matrix of triangle Chebyshev coefficient
207128
"""
208129
function trianglecfsvec(P::PaduaTransformPlan,cfs::Matrix)
209130
m=size(cfs,2)
210-
ret=P.retvec
211131
l=1
212-
for d=1:m,k=1:d
132+
@inbounds for d=1:m,k=1:d
213133
j=d-k+1
214-
ret[l]=cfs[k,j]
134+
P.retvec[l]=cfs[k,j]
215135
l+=1
216136
end
217-
return ret
218-
end
219-
220-
function trianglecfsvec(cfs::Matrix)
221-
n,m=size(cfs)
222-
N=div(n*m,2)
223-
ret=Array(Float64,N)
224-
l=1
225-
for d=1:m,k=1:d
226-
j=d-k+1
227-
ret[l]=cfs[k,j]
228-
l+=1
229-
end
230-
return ret
137+
return P.retvec
231138
end
232139

233140
"""
234141
Returns coordinates of the (n+1)(n+2)/2 Padua points.
235142
"""
236-
function paduapoints(n::Integer)
143+
function paduapoints{T}(::Type{T},n::Integer)
237144
N=div((n+1)*(n+2),2)
238-
MM=Array(Float64,N,2)
145+
MM=Array(T,N,2)
239146
m=0
240147
delta=0
241148
NN=fld(n+2,2)
242-
for k=n:-1:0
149+
@inbounds for k=n:-1:0
243150
if isodd(n)>0
244151
delta=mod(k,2)
245152
end
246-
for j=NN+delta:-1:1
153+
@inbounds for j=NN+delta:-1:1
247154
m+=1
248-
MM[m,1]=sinpi(1.*k/n-0.5)
155+
MM[m,1]=sinpi(T(k)/n-T(0.5))
249156
if isodd(n-k)>0
250-
MM[m,2]=sinpi((2j-1.)/(n+1.)-0.5)
157+
MM[m,2]=sinpi((2j-one(T))/(n+1)-T(0.5))
251158
else
252-
MM[m,2]=sinpi((2j-2.)/(n+1.)-0.5)
159+
MM[m,2]=sinpi(T(2j-2)/(n+1)-T(0.5))
253160
end
254161
end
255162
end
256163
return MM
257164
end
258165

259-
"""
260-
Interpolates a 2d function at a given point using 2d Chebyshev series.
261-
"""
262-
function paduaeval(f::Function,x::Float64,y::Float64,m::Integer)
263-
M=div((m+1)*(m+2),2)
264-
pvals=Array(Float64,M)
265-
p=paduapoints(m)
266-
pvals=map(f,p[:,1],p[:,2])
267-
plan=plan_paduatransform(pvals)
268-
coeffs=paduatransform(plan,pvals)
269-
cfs_mat=trianglecfsmat(coeffs)
270-
cfs_mat=cfs_mat[1:end-1,:]
271-
f_x=sum([cfs_mat[k,j]*cos((j-1)*acos(x))*cos((k-1)*acos(y)) for k=1:m+1, j=1:m+1])
272-
return f_x
273-
end
166+
# v=collect(1.:6.)
167+
# P=plan_ipaduatransform(v)
168+
# @code_warntype ipaduatransform(P,v)
169+
# M=plan_paduatransform(v)
170+
# @code_warntype paduatransform(M,v)

test/runtests.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,40 @@ IPlan=plan_ipaduatransform(v)
228228
@time ipaduatransform(IPlan,v)
229229

230230
println("Accuracy of 2d function interpolation at a point")
231+
function trianglecfsmat{T}(cfs::AbstractVector{T})
232+
N=length(cfs)
233+
n=Int(cld(-3+sqrt(1+8N),2))
234+
@assert N==div((n+1)*(n+2),2)
235+
cfsmat=Array(T,n+2,n+1)
236+
cfsmat=fill!(cfsmat,0)
237+
m=1
238+
for d=1:n+1, k=1:d
239+
j=d-k+1
240+
cfsmat[k,j]=cfs[m]
241+
if m==N
242+
return cfsmat
243+
else
244+
m+=1
245+
end
246+
end
247+
return cfsmat
248+
end
249+
"""
250+
Interpolates a 2d function at a given point using 2d Chebyshev series.
251+
"""
252+
function paduaeval(f::Function,x::AbstractFloat,y::AbstractFloat,m::Integer)
253+
T=promote_type(typeof(x),typeof(y))
254+
M=div((m+1)*(m+2),2)
255+
pvals=Array(T,M)
256+
p=paduapoints(m)
257+
pvals=map!(f,p[:,1],p[:,2])
258+
plan=plan_paduatransform(pvals)
259+
coeffs=paduatransform(plan,pvals)
260+
cfs_mat=trianglecfsmat(coeffs)
261+
cfs_mat=view(cfs_mat,1:m+1,:)
262+
f_x=sum([cfs_mat[k,j]*cos((j-1)*acos(x))*cos((k-1)*acos(y)) for k=1:m+1, j=1:m+1])
263+
return f_x
264+
end
231265
f_xy = (x,y) -> x^2*y+x^3
232266
g_xy = (x,y) ->cos(exp(2*x+y))*sin(y)
233267
x=0.1;y=0.2

0 commit comments

Comments
 (0)