Skip to content

Commit 09778d2

Browse files
clarify the different A_mul_B!'s, work on SHT API and docs
1 parent fe1d94a commit 09778d2

16 files changed

+187
-108
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,16 @@ julia> @time norm(ipaduatransform(paduatransform(v))-v)
9696

9797
Let `F` be a matrix of spherical harmonic expansion coefficients arranged by increasing order in absolute value, alternating between negative and positive orders. Then `sph2fourier` converts the representation into a bivariate Fourier series, and `fourier2sph` converts it back.
9898
```julia
99-
julia> F = rand(Float64, 251, 501); FastTransforms.zero_spurious_modes!(F);
99+
julia> F = sphrandn(Float64, 256, 256);
100100

101101
julia> G = sph2fourier(F);
102102

103103
julia> H = fourier2sph(G);
104104

105105
julia> norm(F-H)
106-
7.422366861016818e-14
106+
4.950645831278297e-14
107107

108-
julia> F = rand(Float64, 1024, 2047); FastTransforms.zero_spurious_modes!(F);
108+
julia> F = sphrandn(Float64, 1024, 1024);
109109

110110
julia> G = sph2fourier(F; sketch = :none);
111111
Pre-computing thin plan...100%|██████████████████████████████████████████████████| Time: 0:00:04
@@ -114,7 +114,7 @@ julia> H = fourier2sph(G; sketch = :none);
114114
Pre-computing thin plan...100%|██████████████████████████████████████████████████| Time: 0:00:04
115115

116116
julia> norm(F-H)
117-
1.5062262753260893e-12
117+
1.1510623098225283e-12
118118

119119
```
120120

docs/src/index.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,15 @@
44

55
In numerical analysis, it is customary to expand a function in a basis:
66
```math
7-
f(x) = \sum_{\ell = 0}^{n} f_{\ell} \phi_{\ell}(x).
7+
f(x) \sim \sum_{\ell=0}^{\infty} f_{\ell} \phi_{\ell}(x).
88
```
9-
Orthogonal polynomials are examples of convenient bases for sufficiently smooth functions. To perform some operation, it may be necessary to convert our representation to one in a new basis, say, ``\{\psi_m(x)\}_{m\ge0}``.
10-
11-
If each function ``\phi_{\ell}`` is expanded in the basis ``\psi_m``, such as:
12-
```math
13-
\phi_{\ell}(x) \sim \sum_{m=0}^{\infty} c_{m,\ell}\psi_{m}(x),
14-
```
15-
then our original function has the alternative representation:
16-
```math
17-
f(x) \sim \sum_{m = 0}^{\infty} g_m \psi_m(x),
18-
```
19-
where ``g_m`` are defined by the sum:
9+
It may be more convenient to transform our representation to one in a new basis, say, ``\{\psi_m(x)\}_{m\ge0}``:
2010
```math
21-
g_m = \sum_{\ell = 0}^{n} c_{m,\ell} f_{\ell}.
11+
f(x) \sim \sum_{m=0}^{\infty} g_m \psi_m(x).
2212
```
13+
In many cases of interest, both representations are of finite length ``n`` and we seek a fast method (faster than ``\mathcal{O}(n^2)``) to transform the original coefficients ``f_{\ell}`` to the new coefficients ``g_m``.
2314

24-
This is the classical connection problem. In many cases of interest, the both representations are finite and we seek a fast method (faster than ``\mathcal{O}(n^2)``) to transform the coefficients ``f_{\ell}`` to ``g_m``. These are the fast transforms.
15+
A similar problem arises when we wish to evaluate ``f`` at a set of points ``\{x_m\}_{m=0}^n``. We wish to transform coefficients of ``f`` to values at the set of points in fewer than ``\mathcal{O}(n^2)`` operations.
2516

2617
## Fast Transforms
2718

@@ -99,6 +90,10 @@ gaunt
9990
paduapoints
10091
```
10192

93+
```@docs
94+
sphevaluate
95+
```
96+
10297
## Internal Methods
10398

10499
```@docs

src/FastTransforms.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ module FastTransforms
33

44
using Base, ToeplitzMatrices, HierarchicalMatrices, LowRankApprox, ProgressMeter, Compat
55

6-
import Base: *, \, size, view, A_mul_B!, At_mul_B!, Ac_mul_B!
6+
import Base: *, \, size, view
77
import Base: getindex, setindex!, Factorization, length
88
import Base.LinAlg: BlasFloat, BlasInt
99
import HierarchicalMatrices: HierarchicalMatrix, unsafe_broadcasttimes!
10+
import HierarchicalMatrices: A_mul_B!, At_mul_B!, Ac_mul_B!
1011
import LowRankApprox: ColPerm
1112

1213
export cjt, icjt, jjt, plan_cjt, plan_icjt
@@ -21,6 +22,7 @@ export plan_paduatransform!, plan_ipaduatransform!
2122

2223
export SlowSphericalHarmonicPlan, FastSphericalHarmonicPlan, ThinSphericalHarmonicPlan
2324
export sph2fourier, fourier2sph, plan_sph2fourier
25+
export sphones, sphzeros, sphrand, sphrandn, sphevaluate
2426

2527
# Other module methods and constants:
2628
#export ChebyshevJacobiPlan, jac2cheb, cheb2jac

src/SphericalHarmonics/Butterfly.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function A_mul_B!{T}(y::AbstractVecOrMat{T}, A::IDPackedV{T}, P::ColumnPermutati
166166
k, n = size(A)
167167
At_mul_B!(P, x, jstart)
168168
copy!(y, istart, x, jstart, k)
169-
HierarchicalMatrices.A_mul_B!(y, A.T, x, istart, jstart+k)
169+
A_mul_B!(y, A.T, x, istart, jstart+k)
170170
A_mul_B!(P, x, jstart)
171171
y
172172
end
@@ -176,7 +176,7 @@ for f! in (:At_mul_B!, :Ac_mul_B!)
176176
function $f!{T}(y::AbstractVecOrMat{T}, A::IDPackedV{T}, P::ColumnPermutation, x::AbstractVecOrMat{T}, istart::Int, jstart::Int)
177177
k, n = size(A)
178178
copy!(y, istart, x, jstart, k)
179-
HierarchicalMatrices.$f!(y, A.T, x, istart+k, jstart)
179+
$f!(y, A.T, x, istart+k, jstart)
180180
A_mul_B!(P, y, istart)
181181
y
182182
end
@@ -185,9 +185,9 @@ end
185185

186186
### A_mul_B!, At_mul_B!, and Ac_mul_B! for a Butterfly factorization.
187187

188-
A_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = A_mul_B_col_J!(u, B, b, 1)
189-
At_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = At_mul_B_col_J!(u, B, b, 1)
190-
Ac_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = Ac_mul_B_col_J!(u, B, b, 1)
188+
Base.A_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = A_mul_B_col_J!(u, B, b, 1)
189+
Base.At_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = At_mul_B_col_J!(u, B, b, 1)
190+
Base.Ac_mul_B!{T}(u::Vector{T}, B::Butterfly{T}, b::Vector{T}) = Ac_mul_B_col_J!(u, B, b, 1)
191191

192192
function A_mul_B_col_J!{T}(u::VecOrMat{T}, B::Butterfly{T}, b::VecOrMat{T}, J::Int)
193193
L = length(B.factors) - 1
@@ -237,7 +237,7 @@ function A_mul_B_col_J!{T}(u::VecOrMat{T}, B::Butterfly{T}, b::VecOrMat{T}, J::I
237237
for i = 1:tL
238238
ml = mu+1
239239
mu += size(columns[i], 1)
240-
HierarchicalMatrices.A_mul_B!(u, columns[i], temp1, ml+COLSHIFT, inds[i])
240+
A_mul_B!(u, columns[i], temp1, ml+COLSHIFT, inds[i])
241241
end
242242

243243
u
@@ -267,7 +267,7 @@ for f! in (:At_mul_B!,:Ac_mul_B!)
267267
for i = 1:tL
268268
ml = mu+1
269269
mu += size(columns[i], 1)
270-
HierarchicalMatrices.$f!(temp1, columns[i], b, inds[i], ml+COLSHIFT)
270+
$f!(temp1, columns[i], b, inds[i], ml+COLSHIFT)
271271
end
272272

273273
ii, jj = tL, 1

src/SphericalHarmonics/SphericalHarmonics.jl

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
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-
131
@compat abstract type SphericalHarmonicPlan{T} end
142

153
function *(P::SphericalHarmonicPlan, X::AbstractMatrix)
@@ -20,6 +8,7 @@ function \(P::SphericalHarmonicPlan, X::AbstractMatrix)
208
At_mul_B!(zero(X), P, X)
219
end
2210

11+
include("sphfunctions.jl")
2312
include("slowplan.jl")
2413
include("Butterfly.jl")
2514
include("fastplan.jl")

src/SphericalHarmonics/fastplan.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ end
3838

3939
FastSphericalHarmonicPlan(A::Matrix; opts...) = FastSphericalHarmonicPlan(A, round(Int, log2(size(A, 1)+1)-6); opts...)
4040

41-
function A_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
41+
function Base.A_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
4242
RP, BF, p1, p2, B = FP.RP, FP.BF, FP.p1, FP.p2, FP.B
4343
fill!(B, zero(eltype(B)))
4444
M, N = size(X)
@@ -60,7 +60,7 @@ function A_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
6060
Y
6161
end
6262

63-
function At_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
63+
function Base.At_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
6464
RP, BF, p1inv, p2inv, B = FP.RP, FP.BF, FP.p1inv, FP.p2inv, FP.B
6565
copy!(B, X)
6666
M, N = size(X)
@@ -82,6 +82,6 @@ function At_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix)
8282
zero_spurious_modes!(Y)
8383
end
8484

85-
Ac_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, FP, X)
85+
Base.Ac_mul_B!(Y::Matrix, FP::FastSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, FP, X)
8686

8787
allranks(FP::FastSphericalHarmonicPlan) = mapreduce(allranks,vcat,FP.BF)

src/SphericalHarmonics/slowplan.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Base.LinAlg: Givens, AbstractRotation
22

3+
### These three A_mul_B! should be in Base, but for the time being they do not add methods to Base.A_mul_B!; they add methods to the internal A_mul_B!.
4+
35
function A_mul_B!{T<:Real}(G::Givens{T}, A::AbstractVecOrMat)
46
m, n = size(A, 1), size(A, 2)
57
if G.i2 > m
@@ -56,14 +58,14 @@ end
5658
@inline length(P::Pnmp2toPlm) = length(P.rotations)
5759
@inline getindex(P::Pnmp2toPlm, i::Int) = P.rotations[i]
5860

59-
function A_mul_B!(C::Pnmp2toPlm,A::AbstractVecOrMat)
61+
function Base.A_mul_B!(C::Pnmp2toPlm,A::AbstractVecOrMat)
6062
@inbounds for i = 1:length(C)
6163
A_mul_B!(C.rotations[i], A)
6264
end
6365
A
6466
end
6567

66-
function A_mul_B!(A::AbstractMatrix, C::Pnmp2toPlm)
68+
function Base.A_mul_B!(A::AbstractMatrix, C::Pnmp2toPlm)
6769
@inbounds for i = length(C):-1:1
6870
A_mul_B!(A, C.rotations[i])
6971
end
@@ -83,7 +85,7 @@ function RotationPlan{T}(::Type{T}, n::Int)
8385
RotationPlan(layers)
8486
end
8587

86-
function A_mul_B!(P::RotationPlan, A::AbstractMatrix)
88+
function Base.A_mul_B!(P::RotationPlan, A::AbstractMatrix)
8789
M, N = size(A)
8890
@inbounds for m = N÷2-2:-1:0
8991
layer = P.layers[m+1]
@@ -102,7 +104,7 @@ function A_mul_B!(P::RotationPlan, A::AbstractMatrix)
102104
A
103105
end
104106

105-
function At_mul_B!(P::RotationPlan, A::AbstractMatrix)
107+
function Base.At_mul_B!(P::RotationPlan, A::AbstractMatrix)
106108
M, N = size(A)
107109
@inbounds for m = 0:N÷2-2
108110
layer = P.layers[m+1]
@@ -121,7 +123,7 @@ function At_mul_B!(P::RotationPlan, A::AbstractMatrix)
121123
A
122124
end
123125

124-
Ac_mul_B!(P::RotationPlan, A::AbstractMatrix) = At_mul_B!(P, A)
126+
Base.Ac_mul_B!(P::RotationPlan, A::AbstractMatrix) = At_mul_B!(P, A)
125127

126128

127129
immutable SlowSphericalHarmonicPlan{T} <: SphericalHarmonicPlan{T}
@@ -145,7 +147,7 @@ function SlowSphericalHarmonicPlan{T}(A::Matrix{T})
145147
SlowSphericalHarmonicPlan(RP, p1, p2, p1inv, p2inv, B)
146148
end
147149

148-
function A_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
150+
function Base.A_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
149151
RP, p1, p2, B = SP.RP, SP.p1, SP.p2, SP.B
150152
copy!(B, X)
151153
A_mul_B!(RP, B)
@@ -162,7 +164,7 @@ function A_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
162164
Y
163165
end
164166

165-
function At_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
167+
function Base.At_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
166168
RP, p1inv, p2inv, B = SP.RP, SP.p1inv, SP.p2inv, SP.B
167169
copy!(B, X)
168170
M, N = size(X)
@@ -178,4 +180,4 @@ function At_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix)
178180
zero_spurious_modes!(At_mul_B!(RP, Y))
179181
end
180182

181-
Ac_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, SP, X)
183+
Base.Ac_mul_B!(Y::Matrix, SP::SlowSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, SP, X)

test/sphericalharmonictestfunctions.jl renamed to src/SphericalHarmonics/sphfunctions.jl

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
function sphrand{T}(::Type{T}, m, n)
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+
13+
function sphrand{T}(::Type{T}, m::Int, n::Int)
214
A = zeros(T, m, 2n-1)
315
for i = 1:m
416
A[i,1] = rand(T)
@@ -12,7 +24,7 @@ function sphrand{T}(::Type{T}, m, n)
1224
A
1325
end
1426

15-
function sphrandn{T}(::Type{T}, m, n)
27+
function sphrandn{T}(::Type{T}, m::Int, n::Int)
1628
A = zeros(T, m, 2n-1)
1729
for i = 1:m
1830
A[i,1] = randn(T)
@@ -26,6 +38,22 @@ function sphrandn{T}(::Type{T}, m, n)
2638
A
2739
end
2840

41+
function sphones{T}(::Type{T}, m::Int, n::Int)
42+
A = zeros(T, m, 2n-1)
43+
for i = 1:m
44+
A[i,1] = one(T)
45+
end
46+
for j = 1:n
47+
for i = 1:m-j
48+
A[i,2j] = one(T)
49+
A[i,2j+1] = one(T)
50+
end
51+
end
52+
A
53+
end
54+
55+
sphzeros{T}(::Type{T}, m::Int, n::Int) = zeros(T, m, 2n-1)
56+
2957
function normalizecolumns!(A::AbstractMatrix)
3058
m, n = size(A)
3159
@inbounds for j = 1:n
@@ -54,7 +82,14 @@ function maxcolnorm(A::AbstractMatrix)
5482
norm(nrm, Inf)
5583
end
5684

57-
function sphevaluatepi::Number,L::Integer,M::Integer)
85+
doc"""
86+
Pointwise evaluation of spherical harmonic ``Y_{\ell}^m(\theta,\varphi)``.
87+
"""
88+
sphevaluate(θ, φ, L, M) = sphevaluatepi/π, φ/π, L, M)
89+
90+
sphevaluatepi::Number, φ::Number, L::Integer, M::Integer) = sphevaluatepi(θ,L,M)*sphevaluatepi(φ,M)
91+
92+
function sphevaluatepi::Number, L::Integer, M::Integer)
5893
ret = one(θ)/sqrt(two(θ))
5994
if M < 0 M = -M end
6095
c, s = cospi(θ), sinpi(θ)
@@ -76,3 +111,5 @@ function sphevaluatepi(θ::Number,L::Integer,M::Integer)
76111
return ret
77112
end
78113
end
114+
115+
sphevaluatepi::Number, M::Integer) = complex(cospi(M*φ),sinpi(M*φ))/sqrt(two(φ)*π)

src/SphericalHarmonics/thinplan.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ end
4242

4343
ThinSphericalHarmonicPlan(A::Matrix; opts...) = ThinSphericalHarmonicPlan(A, round(Int, log2(size(A, 1)+1)-6); opts...)
4444

45-
function A_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
45+
function Base.A_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
4646
RP, BF, p1, p2, B = TP.RP, TP.BF, TP.p1, TP.p2, TP.B
4747
copy!(B, X)
4848
M, N = size(X)
@@ -98,7 +98,7 @@ function A_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
9898
end
9999

100100

101-
function At_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
101+
function Base.At_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
102102
RP, BF, p1inv, p2inv, B = TP.RP, TP.BF, TP.p1inv, TP.p2inv, TP.B
103103
copy!(B, X)
104104
M, N = size(X)
@@ -153,7 +153,7 @@ function At_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix)
153153
zero_spurious_modes!(Y)
154154
end
155155

156-
Ac_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, TP, X)
156+
Base.Ac_mul_B!(Y::Matrix, TP::ThinSphericalHarmonicPlan, X::Matrix) = At_mul_B!(Y, TP, X)
157157

158158
allranks(TP::ThinSphericalHarmonicPlan) = mapreduce(i->allranks(TP.BF[i]),vcat,sort!([LAYERSKELETON-1:LAYERSKELETON:length(TP.BF);LAYERSKELETON:LAYERSKELETON:length(TP.BF)]))
159159

0 commit comments

Comments
 (0)