Skip to content

Commit 0084985

Browse files
authored
Remove templating of types for cached vectors (#19)
* Remove templating of types for cached vectors * Update Project.toml * Add Laguerre * Update test_laguerre.jl * Update Project.toml * Update Project.toml * update op name * Update test_stieltjes.jl * Update test_lanczos.jl * Laguerre tests * increase coverage
1 parent d2f0766 commit 0084985

18 files changed

+220
-115
lines changed

Project.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ClassicalOrthogonalPolynomials"
22
uuid = "b30e2e7b-c4ee-47da-9d5f-2c5c27239acd"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.2.3"
4+
version = "0.3.0"
55

66
[deps]
77
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -26,19 +26,19 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2626
[compat]
2727
ArrayLayouts = "0.6.2"
2828
BandedMatrices = "0.16.5"
29-
BlockArrays = "0.14.1"
29+
BlockArrays = "0.14.1, 0.15"
3030
BlockBandedMatrices = "0.10"
3131
ContinuumArrays = "0.6"
3232
DomainSets = "0.4, 0.5"
3333
FFTW = "1.1"
3434
FastGaussQuadrature = "0.4.3"
3535
FastTransforms = "0.11, 0.12"
3636
FillArrays = "0.11"
37-
InfiniteArrays = "0.10"
38-
InfiniteLinearAlgebra = "0.5.2"
37+
InfiniteArrays = "0.10.3"
38+
InfiniteLinearAlgebra = "0.5.3"
3939
IntervalSets = "0.5"
40-
LazyArrays = "0.20.8"
41-
LazyBandedMatrices = "0.5"
40+
LazyArrays = "0.21"
41+
LazyBandedMatrices = "0.5.1"
4242
QuasiArrays = "0.4.6"
4343
SpecialFunctions = "0.10, 1"
4444
julia = "1.5"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ julia> chebyshevt.(0:5,0.1)
1818
0.9208
1919
0.48016
2020
```
21-
Other examples include `chebyshevu`, `legendrep`, `jacobip`, and `ultrasphericalp`.
21+
Other examples include `chebyshevu`, `legendrep`, `jacobip`, `ultrasphericalc`, `hermiteh` and `laguerrel`.
2222

2323
For expansion, it supports usafe as quasi-arrays where one one axes is continuous and the other axis is discrete (countably infinite), as implemented in [QuasiArrays.jl](https://github.com/JuliaApproximation/QuasiArrays.jl) and [ContinuumArrays.jl](https://github.com/JuliaApproximation/ContinuumArrays.jl).
2424
```julia

src/ClassicalOrthogonalPolynomials.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ import FastGaussQuadrature: jacobimoment
3939
import BlockArrays: blockedrange, _BlockedUnitRange, unblock, _BlockArray
4040
import BandedMatrices: bandwidths
4141

42-
export OrthogonalPolynomial, Normalized, orthonormalpolynomial, LanczosPolynomial, Hermite, Jacobi, Legendre, Chebyshev, ChebyshevT, ChebyshevU, ChebyshevInterval, Ultraspherical, Fourier,
43-
HermiteWeight, JacobiWeight, ChebyshevWeight, ChebyshevGrid, ChebyshevTWeight, ChebyshevUWeight, UltrasphericalWeight, LegendreWeight,
42+
export OrthogonalPolynomial, Normalized, orthonormalpolynomial, LanczosPolynomial,
43+
Hermite, Jacobi, Legendre, Chebyshev, ChebyshevT, ChebyshevU, ChebyshevInterval, Ultraspherical, Fourier, Laguerre,
44+
HermiteWeight, JacobiWeight, ChebyshevWeight, ChebyshevGrid, ChebyshevTWeight, ChebyshevUWeight, UltrasphericalWeight, LegendreWeight, LaguerreWeight,
4445
WeightedUltraspherical, WeightedChebyshev, WeightedChebyshevT, WeightedChebyshevU, WeightedJacobi,
45-
∞, Derivative, .., Inclusion, chebyshevt, chebyshevu, legendre, jacobi, legendrep, jacobip, ultrasphericalp, jacobimatrix, jacobiweight, legendreweight, chebyshevtweight, chebyshevuweight
46+
∞, Derivative, .., Inclusion,
47+
chebyshevt, chebyshevu, legendre, jacobi,
48+
legendrep, jacobip, ultrasphericalc, laguerrel,hermiteh,
49+
jacobimatrix, jacobiweight, legendreweight, chebyshevtweight, chebyshevuweight
4650

4751
if VERSION < v"1.6-"
4852
oneto(n) = Base.OneTo(n)
@@ -277,12 +281,14 @@ function \(wA::WeightedOrthogonalPolynomial, wB::WeightedOrthogonalPolynomial)
277281
A\B
278282
end
279283

284+
include("ratios.jl")
280285
include("normalized.jl")
281286
include("lanczos.jl")
282287
include("hermite.jl")
283288
include("jacobi.jl")
284289
include("chebyshev.jl")
285290
include("ultraspherical.jl")
291+
include("laguerre.jl")
286292
include("fourier.jl")
287293
include("stieltjes.jl")
288294

src/hermite.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""
2+
HermiteWeight()
3+
4+
is a quasi-vector representing `exp(-x^2)` on ℝ.
5+
"""
16
struct HermiteWeight{T} <: Weight{T} end
27

38
HermiteWeight() = HermiteWeight{Float64}()
@@ -16,6 +21,14 @@ orthogonalityweight(::Hermite{T}) where T = HermiteWeight{T}()
1621
==(::Hermite, ::Hermite) = true
1722
axes(::Hermite{T}) where T = (Inclusion(ℝ), oneto(∞))
1823

24+
"""
25+
hermiteh(n, z)
26+
27+
computes the `n`-th Hermite polynomial, orthogonal with
28+
respec to `exp(-x^2)`, at `z`.
29+
"""
30+
hermiteh(n::Integer, z::Number) = Base.unsafe_getindex(Hermite{typeof(z)}(), z, n+1)
31+
1932
# H_{n+1} = 2x H_n - 2n H_{n-1}
2033
# 1/2 * H_{n+1} + n H_{n-1} = x H_n
2134
# x*[H_0 H_1 H_2 …] = [H_0 H_1 H_2 …] * [0 1; 1/2 0 2; 1/2 0 3; …]

src/laguerre.jl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
LaguerreWeight(α)
3+
4+
is a quasi-vector representing `x^α * exp(-x)` on `0..Inf`.
5+
"""
6+
struct LaguerreWeight{T} <: Weight{T}
7+
α::T
8+
end
9+
10+
LaguerreWeight{T}() where T = LaguerreWeight{T}(zero(T))
11+
LaguerreWeight() = LaguerreWeight{Float64}()
12+
axes(::LaguerreWeight{T}) where T = (Inclusion(ℝ),)
13+
function getindex(w::LaguerreWeight, x::Number)
14+
x axes(w,1) || throw(BoundsError())
15+
x^w.α * exp(-x)
16+
end
17+
18+
sum(L::LaguerreWeight{T}) where T = gamma(L.α + 1)
19+
20+
struct Laguerre{T} <: OrthogonalPolynomial{T}
21+
α::T
22+
Laguerre{T}(α) where T = new{T}(convert(T, α))
23+
end
24+
Laguerre{T}() where T = Laguerre{T}(zero(T))
25+
Laguerre() = Laguerre{Float64}()
26+
Laguerre::T) where T = Laguerre{float(T)}(α)
27+
orthogonalityweight(L::Laguerre)= LaguerreWeight(L.α)
28+
29+
==(L1::Laguerre, L2::Laguerre) = L1.α == L2.α
30+
axes(::Laguerre{T}) where T = (Inclusion(HalfLine{T}()), oneto(∞))
31+
32+
"""
33+
laguerrel(n, α, z)
34+
35+
computes the `n`-th generalized Laguerre polynomial, orthogonal with
36+
respec to `x^α * exp(-x)`, at `z`.
37+
"""
38+
laguerrel(n::Integer, α, z::Number) = Base.unsafe_getindex(Laguerre{promote_type(typeof(α), typeof(z))}(α), z, n+1)
39+
40+
"""
41+
laguerrel(n, z)
42+
43+
computes the `n`-th Laguerre polynomial, orthogonal with
44+
respec to `exp(-x)`, at `z`.
45+
"""
46+
laguerrel(n::Integer, z::Number) = laguerrel(n, 0, z)
47+
48+
49+
# L_{n+1} = (-1/(n+1) x + (2n+α+1)/(n+1)) L_n - (n+α)/(n+1) L_{n-1}
50+
# - (n+α) L_{n-1} + (2n+α+1)* L_n -(n+1) L_{n+1} = x L_n
51+
# x*[L_0 L_1 L_2 …] = [L_0 L_1 L_2 …] * [(α+1) -(α+1); -1 (α+3) -(α+2);0 -2 (α+5) -(α+3); …]
52+
function jacobimatrix(L::Laguerre{T}) where T
53+
α = L.α
54+
Tridiagonal(-(1:∞), (α+1):2:∞, -+1:∞))
55+
end
56+
57+
recurrencecoefficients(L::Laguerre{T}) where T = ((-one(T)) ./ (1:∞), ((L.α+1):2:∞) ./ (1:∞), (L.α:∞) ./ (1:∞))
58+
59+
##########
60+
# Derivatives
61+
##########
62+
63+
@simplify function *(D::Derivative, L::Laguerre)
64+
T = promote_type(eltype(D),eltype(L))
65+
D = _BandedMatrix(Fill(-one(T),1,∞), ∞, -1,1)
66+
Laguerre(L.α+1)*D
67+
end

src/lanczos.jl

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,24 @@ end
2525
const PaddedVector{T} = CachedVector{T,Vector{T},Zeros{T,1,Tuple{OneToInf{Int}}}}
2626
const PaddedMatrix{T} = CachedMatrix{T,Matrix{T},Zeros{T,2,NTuple{2,OneToInf{Int}}}}
2727

28-
mutable struct LanczosData{T,XX,WW}
29-
X::XX
30-
W::WW
28+
mutable struct LanczosData{T}
29+
X
30+
W
3131
γ::PaddedVector{T}
3232
β::PaddedVector{T}
3333
R::UpperTriangular{T,PaddedMatrix{T}}
3434
ncols::Int
3535

36-
function LanczosData{T,XX,WW}(X, W, γ, β, R) where {T,XX,WW}
36+
function LanczosData{T}(X, W, γ, β, R) where {T}
3737
R[1,1] = 1;
3838
p0 = view(R,:,1);
3939
γ[1] = sqrt(dot(p0,W,p0))
4040
lmul!(inv(γ[1]), p0)
41-
new{T,XX,WW}(X, W, γ, β, R, 1)
41+
new{T}(X, W, γ, β, R, 1)
4242
end
4343
end
4444

45-
LanczosData(X::XX, W::WW, γ::AbstractVector{T}, β, R) where {T,XX,WW} = LanczosData{T,XX,WW}(X, W, γ, β, R)
45+
LanczosData(X, W, γ::AbstractVector{T}, β, R) where {T} = LanczosData{T}(X, W, γ, β, R)
4646
LanczosData(X::AbstractMatrix{T}, W::AbstractMatrix{T}) where T = LanczosData(X, W, zeros(T,∞), zeros(T,∞), UpperTriangular(zeros(T,∞,∞)))
4747

4848
function LanczosData(w::AbstractQuasiVector, P::AbstractQuasiMatrix)
@@ -63,8 +63,8 @@ function resizedata!(L::LanczosData, N)
6363
L
6464
end
6565

66-
struct LanczosConversion{T,XX,WW} <: LayoutMatrix{T}
67-
data::LanczosData{T,XX,WW}
66+
struct LanczosConversion{T} <: LayoutMatrix{T}
67+
data::LanczosData{T}
6868
end
6969

7070
size(::LanczosConversion) = (∞,∞)
@@ -115,12 +115,12 @@ function sub_paddeddata(::LanczosConversionLayout, S::SubArray{<:Any,1,<:Abstrac
115115
paddeddata(view(UpperTriangular(P.data.R.data.data), kr, j))
116116
end
117117

118-
# struct LanczosJacobiMatrix{T,XX,WW} <: AbstractBandedMatrix{T}
119-
# data::LanczosData{T,XX,WW}
118+
# struct LanczosJacobiMatrix{T} <: AbstractBandedMatrix{T}
119+
# data::LanczosData{T}
120120
# end
121121

122-
struct LanczosJacobiBand{T,XX,WW} <: LazyVector{T}
123-
data::LanczosData{T,XX,WW}
122+
struct LanczosJacobiBand{T} <: LazyVector{T}
123+
data::LanczosData{T}
124124
diag::Symbol
125125
end
126126

@@ -145,46 +145,11 @@ getindex(K::SubArray{<:Any,1,<:LanczosJacobiBand}, k::AbstractInfUnitRange{<:Int
145145

146146
copy(A::LanczosJacobiBand) = A # immutable
147147

148-
struct LanczosRecurrence{ABC,T,XX,WW} <: LazyVector{T}
149-
data::LanczosData{T,XX,WW}
150-
end
151-
152-
LanczosRecurrence{ABC}(data::LanczosData{T,XX,WW}) where {ABC,T,XX,WW} = LanczosRecurrence{ABC,T,XX,WW}(data)
153-
154-
size(P::LanczosRecurrence) = (∞,)
155-
156-
resizedata!(A::LanczosRecurrence, n) = resizedata!(A.data, n)
157-
158-
159-
160-
# Q[x,n] = (x/γ[n] - β[n-1]/γ[n]) * Q[x,n-1] - γ[n-1]/γ[n] * Q[x,n]
161-
162-
163-
function _lanczos_getindex(A::LanczosRecurrence{:A}, I)
164-
resizedata!(A, maximum(I)+1)
165-
inv.(A.data.γ.data[I .+ 1])
166-
end
167-
168-
function _lanczos_getindex(B::LanczosRecurrence{:B}, I)
169-
resizedata!(B, maximum(I)+1)
170-
B.data.β.data[I] ./ B.data.γ.data[I .+ 1]
171-
end
172-
173-
function _lanczos_getindex(C::LanczosRecurrence{:C}, I)
174-
resizedata!(C, maximum(I)+1)
175-
C.data.γ.data[I] ./ C.data.γ.data[I .+ 1]
176-
end
177-
178-
getindex(A::LanczosRecurrence, I::Integer) = _lanczos_getindex(A, I)
179-
getindex(A::LanczosRecurrence, I::AbstractVector) = _lanczos_getindex(A, I)
180-
getindex(K::LanczosRecurrence, k::InfRanges{<:Integer}) = view(K, k)
181-
getindex(K::SubArray{<:Any,1,<:LanczosRecurrence}, k::InfRanges{<:Integer}) = view(K, k)
182-
183148

184-
struct LanczosPolynomial{T,XX,WW,Weight,Basis} <: OrthogonalPolynomial{T}
149+
struct LanczosPolynomial{T,Weight,Basis} <: OrthogonalPolynomial{T}
185150
w::Weight # Weight of orthogonality
186151
P::Basis # Basis we use to represent the OPs
187-
data::LanczosData{T,XX,WW}
152+
data::LanczosData{T}
188153
end
189154

190155
==(A::LanczosPolynomial, B::LanczosPolynomial) = A.w == B.w
@@ -217,8 +182,8 @@ axes(Q::LanczosPolynomial) = (axes(Q.w,1),OneToInf())
217182

218183
_p0(Q::LanczosPolynomial) = inv(Q.data.γ[1])*_p0(Q.P)
219184

220-
recurrencecoefficients(Q::LanczosPolynomial) = LanczosRecurrence{:A}(Q.data),LanczosRecurrence{:B}(Q.data),LanczosRecurrence{:C}(Q.data)
221185
jacobimatrix(Q::LanczosPolynomial) = SymTridiagonal(LanczosJacobiBand(Q.data, :d), LanczosJacobiBand(Q.data, :du))
186+
recurrencecoefficients(Q::LanczosPolynomial) = normalized_recurrencecoefficients(Q)
222187

223188
Base.summary(io::IO, Q::LanczosPolynomial{T}) where T = print(io, "LanczosPolynomial{$T} with weight with singularities $(singularities(Q.w))")
224189
Base.show(io::IO, Q::LanczosPolynomial{T}) where T = summary(io, Q)

src/normalized.jl

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,26 @@
11
"""
2-
NormalizationConstant
2+
normalizationconstant
33
44
gives the normalization constants so that the jacobi matrix is symmetric,
55
that is, so we have orthonormal OPs:
66
7-
Q == P*NormalizationConstant(P)
7+
Q == P*normalizationconstant(P)
88
"""
9-
10-
11-
mutable struct NormalizationConstant{T, PP<:AbstractQuasiMatrix{T}} <: AbstractCachedVector{T}
12-
P::PP # OPs
13-
data::Vector{T}
14-
datasize::Tuple{Int}
15-
16-
NormalizationConstant{T, PP}(μ, P::PP) where {T,PP<:AbstractQuasiMatrix{T}} = new{T, PP}(P, T[μ], (1,))
17-
end
18-
19-
NormalizationConstant(μ, P::AbstractQuasiMatrix{T}) where T = NormalizationConstant{T,typeof(P)}(μ, P)
20-
NormalizationConstant(P::AbstractQuasiMatrix) = NormalizationConstant(inv(sqrt(sum(orthogonalityweight(P)))), P)
21-
22-
size(K::NormalizationConstant) = (ℵ₀,)
23-
24-
# How we populate the data
25-
# function _normalizationconstant_fill_data!(K::NormalizationConstant, J::Union{BandedMatrix,Symmetric{<:Any,BandedMatrix},Tridiagonal,SymTridiagonal}, inds)
26-
# dl, _, du = bands(J)
27-
# @inbounds for k in inds
28-
# K.data[k] = sqrt(du[k-1]/dl[k]) * K.data[k-1]
29-
# end
30-
# end
31-
32-
function _normalizationconstant_fill_data!(K::NormalizationConstant, J, inds)
33-
@inbounds for k in inds
34-
K.data[k] = sqrt(J[k,k-1]/J[k-1,k]) * K.data[k-1]
35-
end
9+
function normalizationconstant(μ, P::AbstractQuasiMatrix{T}) where T
10+
X = jacobimatrix(P)
11+
c,b = subdiagonaldata(X),supdiagonaldata(X)
12+
# hide array type to avoid crazy compilation
13+
Accumulate{T,1,typeof(*),Vector{T},AbstractVector{T}}(*, T[μ], Vcat(zero(T),sqrt.(c ./ b)), 1, (1,))
3614
end
3715

38-
39-
LazyArrays.cache_filldata!(K::NormalizationConstant, inds) = _normalizationconstant_fill_data!(K, jacobimatrix(K.P), inds)
16+
normalizationconstant(P::AbstractQuasiMatrix) = normalizationconstant(inv(sqrt(sum(orthogonalityweight(P)))), P)
4017

4118

4219
struct Normalized{T, OPs<:AbstractQuasiMatrix{T}, NL} <: OrthogonalPolynomial{T}
4320
P::OPs
4421
scaling::NL # Q = P * Diagonal(scaling)
4522
end
4623

47-
normalizationconstant(P) = NormalizationConstant(P)
4824
Normalized(P::AbstractQuasiMatrix{T}) where T = Normalized(P, normalizationconstant(P))
4925
Normalized(Q::Normalized) = Q
5026
normalized(P) = Normalized(P)
@@ -83,24 +59,26 @@ _p0(Q::Normalized) = Q.scaling[1]
8359
# q_{n+1}/h[n+1] = (A_n * x + B_n) * q_n/h[n] - C_n * p_{n-1}/h[n-1]
8460
# q_{n+1} = (h[n+1]/h[n] * A_n * x + h[n+1]/h[n] * B_n) * q_n - h[n+1]/h[n-1] * C_n * p_{n-1}
8561

86-
function recurrencecoefficients(Q::Normalized)
87-
X = jacobimatrix(Q.P)
88-
c,a,b = subdiagonaldata(X), diagonaldata(X), supdiagonaldata(X)
89-
inv.(sqrt.(b .* c)), -(a ./ sqrt.(b .* c)), Vcat(zero(eltype(Q)), sqrt.(b .* c) ./ sqrt.(b[2:end] .* c[2:end]))
62+
function normalized_recurrencecoefficients(Q::AbstractQuasiMatrix{T}) where T
63+
X = jacobimatrix(Q)
64+
a,b = diagonaldata(X), supdiagonaldata(X)
65+
inv.(b), -(a ./ b), Vcat(zero(T), b) ./ b
9066
end
9167

68+
recurrencecoefficients(Q::Normalized{T}) where T = normalized_recurrencecoefficients(Q)
69+
9270
# x * p[n] = c[n-1] * p[n-1] + a[n] * p[n] + b[n] * p[n+1]
9371
# x * q[n]/h[n] = c[n-1] * q[n-1]/h[n-1] + a[n] * q[n]/h[n] + b[n] * q[n+1]/h[n+1]
9472
# x * q[n+1] = c[n-1] * h[n]/h[n-1] * q[n-1] + a[n] * q[n] + b[n] * h[n]/h[n+1] * q[n+1]
9573

9674
# q_{n+1}/h[n+1] = (A_n * x + B_n) * q_n/h[n] - C_n * p_{n-1}/h[n-1]
9775
# q_{n+1} = (h[n+1]/h[n] * A_n * x + h[n+1]/h[n] * B_n) * q_n - h[n+1]/h[n-1] * C_n * p_{n-1}
9876

99-
function symtridagonalize(X)
77+
function symtridiagonalize(X)
10078
c,a,b = subdiagonaldata(X), diagonaldata(X), supdiagonaldata(X)
10179
SymTridiagonal(a, sqrt.(b .* c))
10280
end
103-
jacobimatrix(Q::Normalized) = symtridagonalize(jacobimatrix(Q.P))
81+
jacobimatrix(Q::Normalized) = symtridiagonalize(jacobimatrix(Q.P))
10482

10583
orthogonalityweight(Q::Normalized) = orthogonalityweight(Q.P)
10684
singularities(Q::Normalized) = singularities(Q.P)
@@ -163,14 +141,13 @@ end
163141
###
164142
# show
165143
###
166-
Base.array_summary(io::IO, C::NormalizationConstant{T}, inds) where T = print(io, "NormalizationConstant{$T}")
167144
show(io::IO, Q::Normalized) = print(io, "Normalized($(Q.P))")
168145
show(io::IO, ::MIME"text/plain", Q::Normalized) = show(io, Q)
169146

170147

171148

172149
struct OrthonormalWeighted{T, PP<:AbstractQuasiMatrix{T}} <: Basis{T}
173-
P::Normalized{T, PP, NormalizationConstant{T, PP}}
150+
P::Normalized{T, PP}
174151
end
175152

176153
function OrthonormalWeighted(P)

0 commit comments

Comments
 (0)