Skip to content

Commit 710dfec

Browse files
committed
Support ApproxFun's (unfortunate...) reverse lexigraphical order
1 parent fa62130 commit 710dfec

File tree

2 files changed

+68
-37
lines changed

2 files changed

+68
-37
lines changed

src/PaduaTransform.jl

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
"""
22
Pre-plan an Inverse Padua Transform.
33
"""
4-
immutable IPaduaTransformPlan{IDCTPLAN,T}
4+
# lex indicates if its lexigraphical (i.e., x, y) or reverse (y, x)
5+
immutable IPaduaTransformPlan{lex,IDCTPLAN,T}
56
cfsmat::Matrix{T}
67
padvals::Vector{T}
78
idctplan::IDCTPLAN
89
end
910

10-
function plan_ipaduatransform{T}(::Type{T},N::Integer)
11+
IPaduaTransformPlan{T,lex}(cfsmat::Matrix{T},padvals::Vector{T},idctplan,::Type{Val{lex}}) =
12+
IPaduaTransformPlan{lex,typeof(idctplan),T}(cfsmat,padvals,idctplan)
13+
14+
function plan_ipaduatransform{T}(::Type{T},N::Integer,lex)
1115
n=Int(cld(-3+sqrt(1+8N),2))
1216
if N div((n+1)*(n+2),2)
1317
error("Padua transforms can only be applied to vectors of length (n+1)*(n+2)/2.")
1418
end
1519
IPaduaTransformPlan(Array{T}(n+2,n+1),Array{T}(N),
16-
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00))
20+
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00),lex)
1721
end
1822

19-
plan_ipaduatransform{T}(v::AbstractVector{T}) = plan_ipaduatransform(eltype(v),length(v))
23+
24+
plan_ipaduatransform{T}(::Type{T},N::Integer) = plan_ipaduatransform(T,N,Val{true})
25+
26+
plan_ipaduatransform{T}(v::AbstractVector{T},lex...) = plan_ipaduatransform(eltype(v),length(v),lex...)
2027

2128
"""
2229
Inverse Padua Transform maps the 2D Chebyshev coefficients to the values of the interpolation polynomial at the Padua points.
@@ -31,12 +38,12 @@ function *{T}(P::IPaduaTransformPlan,v::AbstractVector{T})
3138
return paduavals
3239
end
3340

34-
ipaduatransform(v::AbstractVector) = plan_ipaduatransform(v)*v
41+
ipaduatransform(v::AbstractVector,lex...) = plan_ipaduatransform(v,lex...)*v
3542

3643
"""
3744
Creates (n+2)x(n+1) Chebyshev coefficient matrix from triangle coefficients.
3845
"""
39-
function trianglecfsmat(P::IPaduaTransformPlan,cfs::AbstractVector)
46+
function trianglecfsmat(P::IPaduaTransformPlan{true},cfs::AbstractVector)
4047
N=length(cfs)
4148
n=Int(cld(-3+sqrt(1+8N),2))
4249
cfsmat=fill!(P.cfsmat,0)
@@ -55,6 +62,25 @@ function trianglecfsmat(P::IPaduaTransformPlan,cfs::AbstractVector)
5562
return cfsmat
5663
end
5764

65+
function trianglecfsmat(P::IPaduaTransformPlan{false},cfs::AbstractVector)
66+
N=length(cfs)
67+
n=Int(cld(-3+sqrt(1+8N),2))
68+
cfsmat=fill!(P.cfsmat,0)
69+
m=1
70+
for d=1:n+1
71+
@inbounds for k=d:-1:1
72+
j=d-k+1
73+
cfsmat[k,j]=cfs[m]
74+
if m==N
75+
return cfsmat
76+
else
77+
m+=1
78+
end
79+
end
80+
end
81+
return cfsmat
82+
end
83+
5884
"""
5985
Vectorizes the function values at the Padua points.
6086
"""
@@ -77,22 +103,26 @@ end
77103
"""
78104
Pre-plan a Padua Transform.
79105
"""
80-
immutable PaduaTransformPlan{DCTPLAN,T}
106+
immutable PaduaTransformPlan{lex,DCTPLAN,T}
81107
vals::Matrix{T}
82108
retvec::Vector{T}
83109
dctplan::DCTPLAN
84110
end
85111

86-
function plan_paduatransform{T}(::Type{T},N::Integer)
112+
PaduaTransformPlan{T,lex}(vals::Matrix{T},retvec::Vector{T},dctplan,::Type{Val{lex}}) =
113+
PaduaTransformPlan{lex,typeof(dctplan),T}(vals,retvec,dctplan)
114+
115+
function plan_paduatransform{T}(::Type{T},N::Integer,lex)
87116
n=Int(cld(-3+sqrt(1+8N),2))
88117
if N  ((n+1)*(n+2))÷2
89118
error("Padua transforms can only be applied to vectors of length (n+1)*(n+2)/2.")
90119
end
91120
PaduaTransformPlan(Array{T}(n+2,n+1),Array{T}(N),
92-
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00))
121+
FFTW.plan_r2r!(Array{T}(n+2,n+1),FFTW.REDFT00),lex)
93122
end
94123

95-
plan_paduatransform{T}(v::AbstractVector{T}) = plan_paduatransform(eltype(v),length(v))
124+
plan_paduatransform{T}(::Type{T},N::Integer) = plan_paduatransform(T,N,Val{true})
125+
plan_paduatransform{T}(v::AbstractVector{T},lex...) = plan_paduatransform(eltype(v),length(v),lex...)
96126

97127
"""
98128
Padua Transform maps from interpolant values at the Padua points to the 2D Chebyshev coefficients.
@@ -112,7 +142,7 @@ function *{T}(P::PaduaTransformPlan,v::AbstractVector{T})
112142
return cfs
113143
end
114144

115-
paduatransform(v::AbstractVector) = plan_paduatransform(v)*v
145+
paduatransform(v::AbstractVector,lex...) = plan_paduatransform(v,lex...)*v
116146

117147
"""
118148
Creates (n+2)x(n+1) matrix of interpolant values on the tensor grid at the (n+1)(n+2)/2 Padua points.
@@ -137,7 +167,7 @@ end
137167
"""
138168
Creates length (n+1)(n+2)/2 vector from matrix of triangle Chebyshev coefficients.
139169
"""
140-
function trianglecfsvec(P::PaduaTransformPlan,cfs::Matrix)
170+
function trianglecfsvec(P::PaduaTransformPlan{true},cfs::Matrix)
141171
m=size(cfs,2)
142172
l=1
143173
for d=1:m
@@ -150,6 +180,19 @@ function trianglecfsvec(P::PaduaTransformPlan,cfs::Matrix)
150180
return P.retvec
151181
end
152182

183+
function trianglecfsvec(P::PaduaTransformPlan{false},cfs::Matrix)
184+
m=size(cfs,2)
185+
l=1
186+
for d=1:m
187+
@inbounds for k=d:-1:1
188+
j=d-k+1
189+
P.retvec[l]=cfs[k,j]
190+
l+=1
191+
end
192+
end
193+
return P.retvec
194+
end
195+
153196
"""
154197
Returns coordinates of the (n+1)(n+2)/2 Padua points.
155198
"""

test/runtests.jl

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -223,37 +223,19 @@ println("Testing runtimes for (I)Padua Transforms")
223223
@time IPl*v
224224

225225
println("Accuracy of 2d function interpolation at a point")
226-
function trianglecfsmat{T}(cfs::AbstractVector{T})
227-
N=length(cfs)
228-
n=Int(cld(-3+sqrt(1+8N),2))
229-
@assert N==div((n+1)*(n+2),2)
230-
cfsmat=Array(T,n+2,n+1)
231-
cfsmat=fill!(cfsmat,0)
232-
m=1
233-
for d=1:n+1
234-
@inbounds for k=1:d
235-
j=d-k+1
236-
cfsmat[k,j]=cfs[m]
237-
if m==N
238-
return cfsmat
239-
else
240-
m+=1
241-
end
242-
end
243-
end
244-
return cfsmat
245-
end
226+
246227
"""
247228
Interpolates a 2d function at a given point using 2d Chebyshev series.
248229
"""
249-
function paduaeval(f::Function,x::AbstractFloat,y::AbstractFloat,m::Integer)
230+
function paduaeval(f::Function,x::AbstractFloat,y::AbstractFloat,m::Integer,lex)
250231
T=promote_type(typeof(x),typeof(y))
251232
M=div((m+1)*(m+2),2)
252233
pvals=Array(T,M)
253234
p=paduapoints(T,m)
254235
map!(f,pvals,p[:,1],p[:,2])
255-
coeffs=paduatransform(pvals)
256-
cfs_mat=trianglecfsmat(coeffs)
236+
coeffs=paduatransform(pvals,lex)
237+
plan=plan_ipaduatransform(pvals,lex)
238+
cfs_mat=FastTransforms.trianglecfsmat(plan,coeffs)
257239
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])
258240
return f_x
259241
end
@@ -262,7 +244,13 @@ g_xy = (x,y) ->cos(exp(2*x+y))*sin(y)
262244
x=0.1;y=0.2
263245
m=130
264246
l=80
265-
f_m=paduaeval(f_xy,x,y,m)
266-
g_l=paduaeval(g_xy,x,y,l)
247+
f_m=paduaeval(f_xy,x,y,m,Val{true})
248+
g_l=paduaeval(g_xy,x,y,l,Val{true})
249+
@test_approx_eq f_xy(x,y) f_m
250+
@test_approx_eq g_xy(x,y) g_l
251+
252+
253+
f_m=paduaeval(f_xy,x,y,m,Val{false})
254+
g_l=paduaeval(g_xy,x,y,l,Val{false})
267255
@test_approx_eq f_xy(x,y) f_m
268256
@test_approx_eq g_xy(x,y) g_l

0 commit comments

Comments
 (0)