Skip to content

Commit 50ce3a4

Browse files
ioannisPApapadopoulosioannisPApapadopoulosdlfivefifty
authored
Jp/twoband (#64)
* Fix jacobimatrix (plus a test) * Add support for derivative of bubble functions * Fix tests on definition of TwoBand + add derivative and inner product of HalfWeighted{:ab}(TwoBand(\rho, 1,1,0)) * Type-stability and simplifications * Fix first failing test * Update test_twoband.jl * v0.3.2 Co-authored-by: ioannisPApapadopoulos <[email protected]> Co-authored-by: Sheehan Olver <[email protected]>
1 parent c5e5689 commit 50ce3a4

File tree

6 files changed

+126
-15
lines changed

6 files changed

+126
-15
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SemiclassicalOrthogonalPolynomials"
22
uuid = "291c01f3-23f6-4eb6-aeb0-063a639b53f2"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.3.1"
4+
version = "0.3.2"
55

66
[deps]
77
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"

src/SemiclassicalOrthogonalPolynomials.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ function getindex(P::SemiclassicalJacobiWeight, x::Real)
4747
end
4848

4949
function sum(P::SemiclassicalJacobiWeight{T}) where T
50-
(t,a,b,c) = map(big, map(float, (P.t,P.a,P.b,P.c)))
50+
# (t,a,b,c) = map(big, map(float, (P.t,P.a,P.b,P.c)))
51+
(t,a,b,c) = P.t, P.a, P.b, P.c
5152
return convert(T, t^c * beta(1+a,1+b) * _₂F₁general2(1+a,-c,2+a+b,1/t))
5253
end
5354

@@ -166,7 +167,7 @@ SemiclassicalJacobi(t, a, b, c, P::SemiclassicalJacobi) = SemiclassicalJacobi(t,
166167
SemiclassicalJacobi(t, a, b, c) = SemiclassicalJacobi(t, a, b, c, semiclassical_jacobimatrix(t, a, b, c))
167168
SemiclassicalJacobi{T}(t, a, b, c) where T = SemiclassicalJacobi(convert(T,t), convert(T,a), convert(T,b), convert(T,c))
168169

169-
WeightedSemiclassicalJacobi(t, a, b, c, P...) = SemiclassicalJacobiWeight(t, a, b, c) .* SemiclassicalJacobi(t, a, b, c, P...)
170+
WeightedSemiclassicalJacobi{T}(t, a, b, c, P...) where T = SemiclassicalJacobiWeight{T}(convert(T,t), convert(T,a), convert(T,b), convert(T,c)) .* SemiclassicalJacobi{T}(convert(T,t), convert(T,a), convert(T,b), convert(T,c), P...)
170171

171172

172173

@@ -360,6 +361,7 @@ end
360361

361362
\(A::SemiclassicalJacobi, w_B::WeightedSemiclassicalJacobi) = (SemiclassicalJacobiWeight(A.t,0,0,0) .* A) \ w_B
362363

364+
\(w_A::Weighted{<:Any,<:SemiclassicalJacobi}, w_B::Weighted{<:Any,<:SemiclassicalJacobi}) = convert(WeightedBasis, w_A) \ convert(WeightedBasis, w_B)
363365

364366
massmatrix(P::SemiclassicalJacobi) = Diagonal(Fill(sum(orthogonalityweight(P)),∞))
365367

@@ -416,6 +418,7 @@ convert(::Type{WeightedBasis}, Q::HalfWeighted{:bc,T,<:SemiclassicalJacobi}) whe
416418
convert(::Type{WeightedBasis}, Q::HalfWeighted{:ac,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, Q.P.a,zero(T),Q.P.c) .* Q.P
417419

418420

421+
include("twoband.jl")
419422
include("derivatives.jl")
420423

421424

@@ -473,7 +476,6 @@ function LazyArrays.cache_filldata!(P::SemiclassicalJacobiFamily, inds::Abstract
473476
P
474477
end
475478

476-
include("twoband.jl")
477479
include("lowering.jl")
478480

479481
end

src/derivatives.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,5 +215,4 @@ end
215215
t = P.t
216216
HQ = HalfWeighted{:bc}(SemiclassicalJacobi(t, P.a+1,P.b-1,P.c-1))
217217
HQ * divmul(HQ, D, HP)
218-
end
219-
218+
end

src/twoband.jl

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,15 @@ function sum(w::TwoBandWeight{T}) where T
3030
if 2w.a == 2w.b == -1 && 2w.c == 1
3131
convert(T,π)
3232
else
33-
error("not implemented")
34-
# 1/2 \[Pi] (-((\[Rho]^(1 + 2 b + 2 c)
35-
# Gamma[1 + b] Hypergeometric2F1Regularized[-a, 1/2 + c,
36-
# 3/2 + b + c, \[Rho]^2])/Gamma[1/2 - c]) + (
37-
# Gamma[1 + a] Hypergeometric2F1Regularized[-b, -(1/2) - a - b - c,
38-
# 1/2 - b - c, \[Rho]^2])/
39-
# Gamma[3/2 + a + b + c]) Sec[(b + c) \[Pi]]
33+
a,b,c,ρ = w.a,w.b,w.c,w.ρ
34+
convert(T,π)/2 * sec((b + c)*convert(T,π)) * (
35+
- ρ^(one(T) + 2b + 2c) * gamma(one(T) + b) * _₂F₁(-a, one(T)/2 + c, convert(T,3)/2 + b + c, ρ^2) / gamma(one(T)/2 - c)
36+
+ gamma(one(T) + a) * _₂F₁(-b, -one(T)/2 - a - b - c, one(T)/2 - b - c, ρ^2) / gamma(convert(T,3)/2 + a + b + c)
37+
)
4038
end
4139
end
4240

41+
4342
"""
4443
TwoBandJacobi(ρ, a, b, c)
4544
@@ -78,6 +77,8 @@ orthogonalityweight(Z::TwoBandJacobi) = TwoBandWeight(Z.ρ, Z.a, Z.b, Z.c)
7877
# end
7978
# end
8079

80+
weight(W::HalfWeighted{:ab,T,<:TwoBandJacobi}) where T = TwoBandWeight(W.P.ρ, W.P.a,W.P.b,zero(T))
81+
convert(::Type{WeightedBasis}, Q::HalfWeighted{:ab,T,<:TwoBandJacobi}) where T = TwoBandWeight(Q.P.ρ, Q.P.a,Q.P.b,zero(T)) .* Q.P
8182

8283
struct Interlace{T,AA,BB} <: LazyVector{T}
8384
a::AA
@@ -94,7 +95,10 @@ getindex(A::Interlace{T}, k::Int) where T = convert(T, isodd(k) ? A.a[(k+1)÷2]
9495
function jacobimatrix(R::TwoBandJacobi{T}) where T
9596
ρ = R.ρ
9697
L = R.P \ (SemiclassicalJacobiWeight(R.P.t,0,0,1) .* R.Q)
98+
# M = (L / L[1,1])' # equal to R.Q \ R.P
99+
97100
Tridiagonal(Interlace(L.dv/L[1,1], (ρ^2-1) * L.ev), Zeros{T}(∞), Interlace((1-ρ^2) * L.dv,L.ev/(-L[1,1])))
101+
# Tridiagonal(Interlace(L.dv/L[1,1], (1-ρ^2) * L.ev), Zeros{T}(∞), Interlace((1-ρ^2) * L.dv, L.ev/L[1,1]))
98102
end
99103

100104

@@ -140,3 +144,69 @@ end
140144
@assert axes(H,1) == axes(Q,1)
141145
Q * BandedMatrix(1 =>Fill(-A[1]*sum(w),∞))
142146
end
147+
148+
149+
##
150+
# Derivative of double weighted TwoBandJacobi
151+
##
152+
function divmul(R::TwoBandJacobi, D::Derivative, HP::HalfWeighted{:ab,<:Any,<:TwoBandJacobi})
153+
T = promote_type(eltype(R), eltype(HP))
154+
ρ=convert(T,R.ρ); t=inv(one(T)-ρ^2)
155+
a,b,c = R.a,R.b,R.c
156+
157+
Dₑ = -2*(one(T)-ρ^2) .* (R.Q \ (Derivative(axes(R.Q,1))*HalfWeighted{:ab}(HP.P.P)))
158+
D₀ = -2*(one(T)-ρ^2)^2 .* (Weighted(R.P) \ (Derivative(axes(R.P,1))*Weighted(HP.P.Q)))
159+
160+
(dₑ, dlₑ, d₀, dl₀) = Dₑ.data[1,:], Dₑ.data[2,:], D₀.data[1,:], D₀.data[2,:]
161+
BandedMatrix(-1=>Interlace(dₑ, -d₀), -3=>Interlace(-dlₑ, dl₀))
162+
end
163+
164+
@simplify function *(D::Derivative, HP::HalfWeighted{:ab,<:Any,<:TwoBandJacobi})
165+
P = HP.P
166+
ρ = P.ρ
167+
@assert P.a == 1 && P.b == 1 && P.c == 0
168+
169+
R = TwoBandJacobi(ρ, P.a-1,P.b-1,P.c)
170+
R * divmul(R, D, HP)
171+
end
172+
173+
###
174+
# L^2 inner product of double weighted TwoBandJacobi
175+
###
176+
@simplify function *(A::QuasiAdjoint{<:Any,<:HalfWeighted{:ab,<:Any,<:TwoBandJacobi}}, B::HalfWeighted{:ab,<:Any,<:TwoBandJacobi})
177+
T = promote_type(eltype(A), eltype(B))
178+
P = B.P
179+
a,b,c = P.a,P.b,P.c
180+
181+
@assert A.parent.P.a == a && A.parent.P.b == b && A.parent.P.c == c
182+
@assert a == 1 && b == 1 && c == 0
183+
184+
ρ = convert(T,P.ρ)
185+
t = inv(one(T)-ρ^2)
186+
Pₗ = SemiclassicalJacobi{T}(t,a-one(T),b-one(T),c-one(T)/2)
187+
Qₗ = SemiclassicalJacobi{T}(t,a-one(T),b-one(T),c+one(T)/2)
188+
189+
Lₑ = Pₗ \ HalfWeighted{:ab}(P.P)
190+
Lₒ = Weighted(Qₗ) \ Weighted(P.Q)
191+
192+
mₑ = (one(T)-ρ^2)^4*(1-ρ^2)^(one(T)/2)*sum(orthogonalityweight(Pₗ))
193+
mₒ = (one(T)-ρ^2)^4*(1-ρ^2)^(convert(T,3)/2)*sum(orthogonalityweight(Qₗ))
194+
195+
mₑ = Fill{T}(mₑ, ∞); mₒ = Fill{T}(mₒ, ∞)
196+
197+
# Sum of entries in each column squared.
198+
dₑ = mₑ.*((Lₑ .* Lₑ)' * Ones{T}(∞))
199+
d₀ = mₒ.*((Lₒ .* Lₒ)' * Ones{T}(∞))
200+
201+
# Sum of entries x entries in next column.
202+
dlₑ = mₑ.* (Lₑ[2:∞,:] .* Lₑ[2:∞,2:∞])' * Ones{T}(∞)
203+
dl₀ = mₒ.* (Lₒ[2:∞,:] .* Lₒ[2:∞,2:∞])' * Ones{T}(∞)
204+
205+
# Sum of entries and entries in second column over.
206+
dllₑ = mₑ.* (Lₑ[3:∞,:] .* Lₑ[3:∞,3:∞])' * Ones{T}(∞)
207+
dll₀ = mₒ.* (Lₒ[3:∞,:] .* Lₒ[3:∞,3:∞])' * Ones{T}(∞)
208+
209+
BandedMatrix(0=>Interlace(dₑ, d₀),
210+
-2=>Interlace(-dlₑ, -dl₀), 2=>Interlace(-dlₑ, -dl₀),
211+
-4=>Interlace(dllₑ, dll₀), 4=>Interlace(dllₑ, dll₀))
212+
end

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ end
365365
@test 2φ(2t-1)*Base.unsafe_getindex(P,t,n)/(Base.unsafe_getindex(P,t,n+1)) 1 atol=1E-3
366366

367367

368-
L1 = P \ WeightedSemiclassicalJacobi(t,0,0,1,P)
368+
L1 = P \ Weighted(SemiclassicalJacobi(t,0,0,1,P))
369369
@test L1[n+1,n]/L1[n,n] -1/(2φ(2t-1)) atol=1E-3
370370
end
371371

test/test_twoband.jl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using SemiclassicalOrthogonalPolynomials, ClassicalOrthogonalPolynomials, BandedMatrices, Test
1+
using SemiclassicalOrthogonalPolynomials, ClassicalOrthogonalPolynomials, BandedMatrices, LinearAlgebra, Test
22
import ClassicalOrthogonalPolynomials: orthogonalityweight, Weighted, associated, plotgrid
3+
import SemiclassicalOrthogonalPolynomials: Interlace, HalfWeighted, WeightedBasis
34

45
@testset "Two Band" begin
56
@testset "TwoBandWeight" begin
@@ -23,6 +24,10 @@ import ClassicalOrthogonalPolynomials: orthogonalityweight, Weighted, associated
2324
@test U T
2425
@test orthogonalityweight(T) == TwoBandWeight(ρ, -1/2, -1/2, 1/2)
2526

27+
R = TwoBandJacobi(ρ, 1, 1, 0)
28+
x=0.6; τ=(1-x^2)*R.P.t; n=10
29+
@test R[x, 1:n] Interlace((-1).^(2:n÷2+1).*R.P[τ, 1:n÷2], (-1).^(2:n÷2+1).*x.*R.Q[τ, 1:n÷2])[1:n]
30+
2631
# bug
2732
@test !issymmetric(jacobimatrix(T)[1:10,1:10])
2833
end
@@ -71,4 +76,39 @@ import ClassicalOrthogonalPolynomials: orthogonalityweight, Weighted, associated
7176
x = axes(Q,1)
7277
@test norm((Q[:,Base.OneTo(30)] \ Vp.(b*x))[1])  1E-13
7378
end
79+
80+
@testset "derivative half weighted twoband" begin
81+
ρ = 0.2
82+
R = TwoBandJacobi(ρ, 0, 0, 0)
83+
D = R \ Derivative(axes(R,1))*HalfWeighted{:ab}(TwoBandJacobi(ρ, 1, 1, 0))
84+
85+
@test (D.l, D.u) == (3, -1)
86+
@test D[1:5,1] [0.0, -0.33858064516128994, 0.0, -1.030932383768154, 0.0]
87+
@test D[1:5,2] [0.0, 0.0, -0.4609776443497252, 0.0, -0.34580926348402935]
88+
end
89+
90+
@testset "L2 inner product" begin
91+
ρ = 0.2
92+
HP = HalfWeighted{:ab}(TwoBandJacobi(ρ, 1, 1, 0))
93+
M = HP' * HP
94+
95+
@test (M.l, M.u) == (4, 4)
96+
97+
Mm = M[1:20, 1:20]
98+
@test Mm == Mm'
99+
100+
# The following is checked via QuadGK, e.g. 2*quadgk(x->HP[x,n]*HP[x,n], ρ, 1, rtol=1e-3)[1]
101+
@test diag(Mm[1:5, 1:5]) [0.0399723828825396, 0.01926644161200575, 0.028656015290810938, 0.014202710309357196, 0.02719735154820007]
102+
@test diag(Mm[2:6, 1:5]) [0, 0, 0, 0, 0]
103+
@test diag(Mm[3:7, 1:5]) [0.003417521501385307, -0.0013645130261003458, 0.0008788935542028268, -0.0005306108105399927, 0.0003587270849050795]
104+
@test diag(Mm[4:8, 1:5]) [0, 0, 0, 0, 0]
105+
@test diag(Mm[5:9, 1:5]) [-0.011436406405959944, -0.004811623256062165, -0.012192463544540394, -0.005436023256389608, -0.012469708623429861]
106+
end
107+
108+
@testset "halfweight" begin
109+
ρ = 0.5
110+
T = TwoBandJacobi(ρ, -1/2, -1/2, 1/2)
111+
@test HalfWeighted{:ab}(T)[0.6,1:10] convert(WeightedBasis, HalfWeighted{:ab}(T))[0.6,1:10] (1-0.6^2)^(-1/2) * (0.6^2-ρ^2)^(-1/2) * T[0.6,1:10]
112+
113+
end
74114
end

0 commit comments

Comments
 (0)