Skip to content

Commit ad21867

Browse files
add thin plan
1 parent e146c60 commit ad21867

File tree

10 files changed

+315
-171
lines changed

10 files changed

+315
-171
lines changed

src/FastTransforms.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export gaunt
1919
export paduatransform, ipaduatransform, paduatransform!, ipaduatransform!, paduapoints
2020
export plan_paduatransform!, plan_ipaduatransform!
2121

22+
export SlowSphericalHarmonicPlan, FastSphericalHarmonicPlan, ThinSphericalHarmonicPlan
23+
2224
# Other module methods and constants:
2325
#export ChebyshevJacobiPlan, jac2cheb, cheb2jac
2426
#export sqrtpi, pochhammer, stirlingseries, stirlingremainder, Aratio, Cratio, Anαβ
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
function zero_spurious_modes!(A::AbstractMatrix)
2+
M, N = size(A)
3+
n = N÷2
4+
@inbounds for j = 1:n
5+
@simd for i = M-j+1:M
6+
A[i,2j] = 0
7+
A[i,2j+1] = 0
8+
end
9+
end
10+
A
11+
end
12+
113
include("slowplan.jl")
214
include("Butterfly.jl")
315
include("fastplan.jl")
16+
include("thinplan.jl")

src/SphericalHarmonics/fastplan.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ end
1010

1111
function FastSphericalHarmonicPlan{T}(A::Matrix{T}, L::Int)
1212
M, N = size(A)
13+
@assert ispow2(M)
14+
@assert N == 2M-1
1315
n = (N+1)÷2
1416
RP = RotationPlan(T, n-1)
1517
a1 = A[:,1]
@@ -24,16 +26,17 @@ function FastSphericalHarmonicPlan{T}(A::Matrix{T}, L::Int)
2426
for j = 1:2:n-2
2527
A_mul_B!(Ce, RP.layers[j])
2628
BF[j] = orthogonalButterfly(Ce, L)
27-
#println("Level: ",j)
29+
println("Layer: ",j)
2830
end
2931
for j = 2:2:n-2
3032
A_mul_B!(Co, RP.layers[j])
3133
BF[j] = orthogonalButterfly(Co, L)
32-
#println("Level: ",j)
34+
println("Layer: ",j)
3335
end
3436
FastSphericalHarmonicPlan(RP, BF, p1, p2, p1inv, p2inv, B)
3537
end
3638

39+
FastSphericalHarmonicPlan(A::Matrix) = FastSphericalHarmonicPlan(A, round(Int, log2(size(A, 1)+1)-6))
3740

3841
function A_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
3942
RP, BF, p1, p2, B = FP.RP, FP.BF, FP.p1, FP.p2, FP.B
@@ -76,7 +79,7 @@ function At_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
7679
At_mul_B_col_J!(Y, BF[J-1], B, 2J)
7780
At_mul_B_col_J!(Y, BF[J-1], B, 2J+1)
7881
end
79-
Y
82+
zero_spurious_modes!(Y)
8083
end
8184

8285
Ac_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, FP, X)

src/SphericalHarmonics/slowplan.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function At_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
176176
A_mul_B_col_J!!(Y, p1inv, B, J)
177177
A_mul_B_col_J!!(Y, p1inv, B, J+1)
178178
end
179-
At_mul_B!(RP, Y)
179+
zero_spurious_modes!(At_mul_B!(RP, Y))
180180
end
181181

182182
Ac_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, SP, X)

src/SphericalHarmonics/thinplan.jl

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
const LAYERSKELETON = 64
2+
3+
checklayer(j::Int) = j÷LAYERSKELETON == j/LAYERSKELETON
4+
5+
immutable ThinSphericalHarmonicPlan{T}
6+
RP::RotationPlan{T}
7+
BF::Vector{Butterfly{T}}
8+
p1::NormalizedLegendreToChebyshevPlan{T}
9+
p2::NormalizedLegendre1ToChebyshev2Plan{T}
10+
p1inv::ChebyshevToNormalizedLegendrePlan{T}
11+
p2inv::Chebyshev2ToNormalizedLegendre1Plan{T}
12+
B::Matrix{T}
13+
end
14+
15+
function ThinSphericalHarmonicPlan{T}(A::Matrix{T}, L::Int)
16+
M, N = size(A)
17+
@assert ispow2(M)
18+
@assert N == 2M-1
19+
n = (N+1)÷2
20+
RP = RotationPlan(T, n-1)
21+
a1 = A[:,1]
22+
p1 = plan_normleg2cheb(a1)
23+
p2 = plan_normleg12cheb2(a1)
24+
p1inv = plan_cheb2normleg(a1)
25+
p2inv = plan_cheb22normleg1(a1)
26+
B = zeros(A)
27+
Ce = eye(T, M)
28+
Co = eye(T, M)
29+
BF = Vector{Butterfly{T}}(n-2)
30+
for j = 1:2:n-2
31+
A_mul_B!(Ce, RP.layers[j])
32+
checklayer(j+1) && (BF[j] = orthogonalButterfly(Ce, L);println("Layer: ",j))
33+
end
34+
for j = 2:2:n-2
35+
A_mul_B!(Co, RP.layers[j])
36+
checklayer(j) && (BF[j] = orthogonalButterfly(Co, L);println("Layer: ",j))
37+
end
38+
ThinSphericalHarmonicPlan(RP, BF, p1, p2, p1inv, p2inv, B)
39+
end
40+
41+
ThinSphericalHarmonicPlan(A::Matrix) = ThinSphericalHarmonicPlan(A, round(Int, log2(size(A, 1)+1)-6))
42+
43+
function A_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
44+
RP, BF, p1, p2, B = TP.RP, TP.BF, TP.p1, TP.p2, TP.B
45+
copy!(B, X)
46+
M, N = size(X)
47+
48+
for j = 3:2:N÷2
49+
if checklayer(j-1)
50+
A_mul_B_col_J!(Y, BF[j-1], B, 2j)
51+
A_mul_B_col_J!(Y, BF[j-1], B, 2j+1)
52+
else
53+
= round(Int, (j-1)÷LAYERSKELETON)*LAYERSKELETON
54+
A_mul_B_col_J!(RP, B, 2j, ℓ+1, j-1)
55+
A_mul_B_col_J!(RP, B, 2j+1, ℓ+1, j-1)
56+
if> LAYERSKELETON-2
57+
A_mul_B_col_J!(Y, BF[ℓ], B, 2j)
58+
A_mul_B_col_J!(Y, BF[ℓ], B, 2j+1)
59+
else
60+
copy!(Y, 1+M*(2j-1), B, 1+M*(2j-1), 2M)
61+
end
62+
end
63+
end
64+
65+
for j = 2:2:N÷2
66+
if checklayer(j)
67+
A_mul_B_col_J!(Y, BF[j-1], B, 2j)
68+
A_mul_B_col_J!(Y, BF[j-1], B, 2j+1)
69+
else
70+
= round(Int, j÷LAYERSKELETON)*LAYERSKELETON
71+
A_mul_B_col_J!(RP, B, 2j, ℓ, j-1)
72+
A_mul_B_col_J!(RP, B, 2j+1, ℓ, j-1)
73+
if> LAYERSKELETON-2
74+
A_mul_B_col_J!(Y, BF[ℓ-1], B, 2j)
75+
A_mul_B_col_J!(Y, BF[ℓ-1], B, 2j+1)
76+
else
77+
copy!(Y, 1+M*(2j-1), B, 1+M*(2j-1), 2M)
78+
end
79+
end
80+
end
81+
82+
copy!(Y, 1, X, 1, 3M)
83+
copy!(B, Y)
84+
fill!(Y, zero(eltype(Y)))
85+
86+
A_mul_B_col_J!!(Y, p1, B, 1)
87+
for J = 2:4:N
88+
A_mul_B_col_J!!(Y, p2, B, J)
89+
A_mul_B_col_J!!(Y, p2, B, J+1)
90+
end
91+
for J = 4:4:N
92+
A_mul_B_col_J!!(Y, p1, B, J)
93+
A_mul_B_col_J!!(Y, p1, B, J+1)
94+
end
95+
Y
96+
end
97+
98+
99+
function At_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
100+
RP, BF, p1inv, p2inv, B = TP.RP, TP.BF, TP.p1inv, TP.p2inv, TP.B
101+
copy!(B, X)
102+
M, N = size(X)
103+
A_mul_B_col_J!!(Y, p1inv, B, 1)
104+
for J = 2:4:N
105+
A_mul_B_col_J!!(Y, p2inv, B, J)
106+
A_mul_B_col_J!!(Y, p2inv, B, J+1)
107+
end
108+
for J = 4:4:N
109+
A_mul_B_col_J!!(Y, p1inv, B, J)
110+
A_mul_B_col_J!!(Y, p1inv, B, J+1)
111+
end
112+
113+
copy!(B, Y)
114+
fill!(Y, zero(eltype(Y)))
115+
copy!(Y, 1, B, 1, 3M)
116+
117+
for j = 3:2:N÷2
118+
if checklayer(j-1)
119+
At_mul_B_col_J!(Y, BF[j-1], B, 2j)
120+
At_mul_B_col_J!(Y, BF[j-1], B, 2j+1)
121+
else
122+
= round(Int, (j-1)÷LAYERSKELETON)*LAYERSKELETON
123+
if> LAYERSKELETON-2
124+
At_mul_B_col_J!(Y, BF[ℓ], B, 2j)
125+
At_mul_B_col_J!(Y, BF[ℓ], B, 2j+1)
126+
else
127+
copy!(Y, 1+M*(2j-1), B, 1+M*(2j-1), 2M)
128+
end
129+
At_mul_B_col_J!(RP, Y, 2j, ℓ+1, j-1)
130+
At_mul_B_col_J!(RP, Y, 2j+1, ℓ+1, j-1)
131+
end
132+
end
133+
134+
for j = 2:2:N÷2
135+
if checklayer(j)
136+
At_mul_B_col_J!(Y, BF[j-1], B, 2j)
137+
At_mul_B_col_J!(Y, BF[j-1], B, 2j+1)
138+
else
139+
= round(Int, j÷LAYERSKELETON)*LAYERSKELETON
140+
if> LAYERSKELETON-2
141+
At_mul_B_col_J!(Y, BF[ℓ-1], B, 2j)
142+
At_mul_B_col_J!(Y, BF[ℓ-1], B, 2j+1)
143+
else
144+
copy!(Y, 1+M*(2j-1), B, 1+M*(2j-1), 2M)
145+
end
146+
At_mul_B_col_J!(RP, Y, 2j, ℓ, j-1)
147+
At_mul_B_col_J!(RP, Y, 2j+1, ℓ, j-1)
148+
end
149+
end
150+
151+
zero_spurious_modes!(Y)
152+
end
153+
154+
Ac_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, TP, X)
155+
156+
allranks(TP::ThinSphericalHarmonicPlan) = mapreduce(i->allranks(TP.BF[i]),vcat,sort!([LAYERSKELETON-1:LAYERSKELETON:length(TP.BF);LAYERSKELETON:LAYERSKELETON:length(TP.BF)]))
157+
158+
159+
function A_mul_B_col_J!(P::RotationPlan, A::AbstractMatrix, J::Int, L1::Int, L2::Int)
160+
M, N = size(A)
161+
@inbounds for m = L2-1:-2:L1
162+
layer = P.layers[m+1]
163+
@simd for i = 1:length(layer)
164+
G = layer[i]
165+
a1, a2 = A[G.i1,J], A[G.i2,J]
166+
A[G.i1,J] = G.c*a1 + G.s*a2
167+
A[G.i2,J] = G.c*a2 - G.s*a1
168+
end
169+
end
170+
A
171+
end
172+
173+
function At_mul_B_col_J!(P::RotationPlan, A::AbstractMatrix, J::Int, L1::Int, L2::Int)
174+
M, N = size(A)
175+
@inbounds for m = L1:2:L2-1
176+
layer = P.layers[m+1]
177+
@simd for i = length(layer):-1:1
178+
G = layer[i]
179+
a1, a2 = A[G.i1,J], A[G.i2,J]
180+
A[G.i1,J] = G.c*a1 - G.s*a2
181+
A[G.i2,J] = G.c*a2 + G.s*a1
182+
end
183+
end
184+
A
185+
end

test/butterflytests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ for n in 7:N
7979
end
8080

8181

82-
N = 14
82+
N = 12
8383
A = Vector{Matrix{Complex{Float64}}}(N)
8484
B = Vector{Butterfly{Complex{Float64}}}(N)
8585
for n in 7:N

test/sphericalharmonictests.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using FastTransforms, Base.Test
2+
3+
function sphrand{T}(::Type{T}, m, n)
4+
A = zeros(T, m, 2n-1)
5+
for i = 1:m
6+
A[i,1] = rand(T)
7+
end
8+
for j = 1:n
9+
for i = 1:m-j
10+
A[i,2j] = rand(T)
11+
A[i,2j+1] = rand(T)
12+
end
13+
end
14+
A
15+
end
16+
17+
function sphrandn{T}(::Type{T}, m, n)
18+
A = zeros(T, m, 2n-1)
19+
for i = 1:m
20+
A[i,1] = randn(T)
21+
end
22+
for j = 1:n
23+
for i = 1:m-j
24+
A[i,2j] = randn(T)
25+
A[i,2j+1] = randn(T)
26+
end
27+
end
28+
A
29+
end
30+
31+
function normalizecolumns!(A::AbstractMatrix)
32+
m, n = size(A)
33+
@inbounds for j = 1:n
34+
nrm = zero(eltype(A))
35+
for i = 1:m
36+
nrm += abs2(A[i,j])
37+
end
38+
nrm = sqrt(nrm)
39+
for i = 1:m
40+
A[i,j] /= nrm
41+
end
42+
end
43+
A
44+
end
45+
46+
function maxcolnorm(A::AbstractMatrix)
47+
m, n = size(A)
48+
nrm = zeros(n)
49+
@inbounds for j = 1:n
50+
nrm[j] = 0
51+
for i = 1:m
52+
nrm[j] += abs2(A[i,j])
53+
end
54+
nrm[j] = sqrt(nrm[j])
55+
end
56+
norm(nrm, Inf)
57+
end
58+
59+
println("Testing slow plan")
60+
include("test_slowplan.jl")
61+
println("Testing fast plan")
62+
include("test_fastplan.jl")
63+
println("Testing thin plan")
64+
include("test_thinplan.jl")

0 commit comments

Comments
 (0)