Skip to content

Commit c7c1b9e

Browse files
authored
SemiclassicalJacobiFamily for a range of SemiclassicalJacobi (#45)
* Fix typo in SemiclassicalJacobi{T} constructor * v0.2.1 * Add SemiclassicalJacobiFamily * SemiclassicalJacobi{T} family * D * x^a * (1-x)^b * ab half-weighted * two-weighted derivatives done! * Update test_derivative.jl * Update runtests.jl * divmul to avoid recomputation of SemiclassicalJacobi * Add divmul * more divmul * fix em code * Update derivatives.jl * fix bugs
1 parent 021ea85 commit c7c1b9e

File tree

6 files changed

+403
-52
lines changed

6 files changed

+403
-52
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.2.0"
4+
version = "0.2.1"
55

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

examples/equilibriummeasure.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import SemiclassicalOrthogonalPolynomials: Weighted
44
import ClassicalOrthogonalPolynomials: associated, affine
55

66
Base.floatmin(::Type{Dual{T,V,N}}) where {T,V,N} = Dual{T,V,N}(floatmin(V))
7+
Base.big(d::Dual{T,V,N}) where {T,V,N} = Dual{T}(big(d.value), ForwardDiff.Partials(map(big,d.partials.values)))
78

8-
9-
####
9+
####
1010
#
1111
# We first do a single interval.
1212
# Equilibrium measures for a symmetric potential
@@ -61,7 +61,6 @@ for _ = 1:10
6161
end
6262

6363
plot(equilibrium(b))
64-
ClassicalOrthogonalPolynomials.plotgrid(equilibrium(b))
6564

6665

6766
#####
@@ -99,8 +98,8 @@ function equilibriumcoefficients(P,a,b)
9998
end
10099
function equilibriumendpointvalues(ab::SVector{2})
101100
a,b = ab
102-
P = TwoBandJacobi(a/b, -1/2, -1/2, 1/2)
103-
P[[a/b,1],:] * equilibriumcoefficients(P,a,b)
101+
P = TwoBandJacobi(a/b, -one(a)/2, -one(a)/2, one(a)/2)
102+
Vector(P[[a/b,1],:] * equilibriumcoefficients(P,a,b))
104103
end
105104

106105
function equilibrium(ab)
@@ -109,7 +108,7 @@ function equilibrium(ab)
109108
Weighted(P) * equilibriumcoefficients(P,a,b)
110109
end
111110

112-
(a,b) = ab = SVector(2.,3.)
111+
ab = SVector(2.,3.)
113112
ab -= jacobian(equilibriumendpointvalues,ab) \ equilibriumendpointvalues(ab)
114113

115114

src/SemiclassicalOrthogonalPolynomials.jl

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function getindex(P::SemiclassicalJacobiWeight, x::Real)
4646
end
4747

4848
function sum(P::SemiclassicalJacobiWeight{T}) where T
49-
(t,a,b,c) = BigFloat.((P.t,P.a,P.b,P.c))
49+
(t,a,b,c) = map(big, map(float, (P.t,P.a,P.b,P.c)))
5050
return convert(T, t^c * beta(1+a,1+b) * _₂F₁general2(1+a,-c,2+a+b,1/t))
5151
end
5252

@@ -163,7 +163,7 @@ end
163163

164164
SemiclassicalJacobi(t, a, b, c, P::SemiclassicalJacobi) = SemiclassicalJacobi(t, a, b, c, semiclassical_jacobimatrix(P, a, b, c))
165165
SemiclassicalJacobi(t, a, b, c) = SemiclassicalJacobi(t, a, b, c, semiclassical_jacobimatrix(t, a, b, c))
166-
SemiclassicalJacobi{T}(t, a, b, c) where T = SemiclassicalJacobi(convert(T,t), convert(T,a), convert(T,b), convert(T,b))
166+
SemiclassicalJacobi{T}(t, a, b, c) where T = SemiclassicalJacobi(convert(T,t), convert(T,a), convert(T,b), convert(T,c))
167167

168168
WeightedSemiclassicalJacobi(t, a, b, c, P...) = SemiclassicalJacobiWeight(t, a, b, c) .* SemiclassicalJacobi(t, a, b, c, P...)
169169

@@ -399,35 +399,66 @@ convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:a,T,<:Semiclassic
399399
convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:b,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, zero(T),Q.P.b,zero(T)) .* Q.P
400400
convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:c,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, zero(T),zero(T),Q.P.c) .* Q.P
401401

402+
convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:ab,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, Q.P.a,Q.P.b,zero(T)) .* Q.P
403+
convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:bc,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, zero(T),Q.P.b,Q.P.c) .* Q.P
404+
convert(::Type{WeightedOrthogonalPolynomial}, Q::HalfWeighted{:ac,T,<:SemiclassicalJacobi}) where T = SemiclassicalJacobiWeight(Q.P.t, Q.P.a,zero(T),Q.P.c) .* Q.P
405+
406+
402407
include("derivatives.jl")
403408

404409

405410
###
406411
# Hierarchy
412+
#
413+
# here we build the operators lazily
407414
###
408415

409-
function Base.broadcasted(::Type{SemiclassicalJacobi}, t::Number, ar::AbstractUnitRange, b::Number, c::Number)
410-
Ps = [SemiclassicalJacobi(t, first(ar), b, c)]
411-
for a in ar[2:end]
412-
push!(Ps, SemiclassicalJacobi(t, a, b, c, Ps[end]))
413-
end
414-
Ps
416+
mutable struct SemiclassicalJacobiFamily{T, A, B, C} <: AbstractCachedVector{SemiclassicalJacobi{T}}
417+
data::Vector{SemiclassicalJacobi{T}}
418+
t::T
419+
a::A
420+
b::B
421+
c::C
422+
datasize::Tuple{Int}
415423
end
416424

417-
function Base.broadcasted(::Type{SemiclassicalJacobi}, t::Number, a::Number, br::AbstractUnitRange, c::Number)
418-
Ps = [SemiclassicalJacobi(t, a, first(br), c)]
419-
for b in br[2:end]
420-
push!(Ps, SemiclassicalJacobi(t, a, b, c, Ps[end]))
421-
end
422-
Ps
425+
size(P::SemiclassicalJacobiFamily) = (max(length(P.a), length(P.b), length(P.c)),)
426+
427+
_checkrangesizes() = ()
428+
_checkrangesizes(a::Number, b...) = _checkrangesizes(b...)
429+
_checkrangesizes(a, b...) = (length(a), _checkrangesizes(b...)...)
430+
431+
_isequal() = true
432+
_isequal(a) = true
433+
_isequal(a,b,c...) = a == b && _isequal(b,c...)
434+
435+
checkrangesizes(a...) = _isequal(_checkrangesizes(a...)...) || throw(DimensionMismatch())
436+
437+
function SemiclassicalJacobiFamily{T}(data::Vector, t, a, b, c) where T
438+
checkrangesizes(a, b, c)
439+
SemiclassicalJacobiFamily{T,typeof(a),typeof(b),typeof(c)}(data, t, a, b, c, (length(data),))
423440
end
424441

425-
function Base.broadcasted(::Type{SemiclassicalJacobi}, t::Number, a::Number, b::Number, cr::AbstractUnitRange)
426-
Ps = [SemiclassicalJacobi(t, a, b, first(cr))]
427-
for c in cr[2:end]
428-
push!(Ps, SemiclassicalJacobi(t, a, b, c, Ps[end]))
442+
SemiclassicalJacobiFamily(t, a, b, c) = SemiclassicalJacobiFamily{float(promote_type(typeof(t),eltype(a),eltype(b),eltype(c)))}(t, a, b, c)
443+
SemiclassicalJacobiFamily{T}(t, a, b, c) where T = SemiclassicalJacobiFamily{T}([SemiclassicalJacobi{T}(t, first(a), first(b), first(c))], t, a, b, c)
444+
445+
Base.broadcasted(::Type{SemiclassicalJacobi}, t::Number, a::Number, b::Number, c::Number) = SemiclassicalJacobi(t, a, b, c)
446+
Base.broadcasted(::Type{SemiclassicalJacobi{T}}, t::Number, a::Number, b::Number, c::Number) where T = SemiclassicalJacobi{T}(t, a, b, c)
447+
Base.broadcasted(::Type{SemiclassicalJacobi}, t::Number, a::Union{AbstractUnitRange,Number}, b::Union{AbstractUnitRange,Number}, c::Union{AbstractUnitRange,Number}) =
448+
SemiclassicalJacobiFamily(t, a, b, c)
449+
Base.broadcasted(::Type{SemiclassicalJacobi{T}}, t::Number, a::Union{AbstractUnitRange,Number}, b::Union{AbstractUnitRange,Number}, c::Union{AbstractUnitRange,Number}) where T =
450+
SemiclassicalJacobiFamily{T}(t, a, b, c)
451+
452+
453+
_broadcast_getindex(a,k) = a[k]
454+
_broadcast_getindex(a::Number,k) = a
455+
456+
function LazyArrays.cache_filldata!(P::SemiclassicalJacobiFamily, inds::AbstractUnitRange)
457+
t,a,b,c = P.t,P.a,P.b,P.c
458+
for k in inds
459+
P.data[k] = SemiclassicalJacobi(t, _broadcast_getindex(a,k), _broadcast_getindex(b,k), _broadcast_getindex(c,k), P.data[k-1])
429460
end
430-
Ps
461+
P
431462
end
432463

433464
include("twoband.jl")

src/derivatives.jl

Lines changed: 138 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,66 @@ function LazyArrays.cache_filldata!(K::MulAddAccumulate, inds)
2828
end
2929
end
3030

31-
@simplify function *(D::Derivative, P::SemiclassicalJacobi)
32-
Q = SemiclassicalJacobi(P.t, P.a+1,P.b+1,P.c+1,P)
31+
"""
32+
divmul(A, B, C)
33+
34+
is equivalent to A \\ (B*C)
35+
"""
36+
function divmul(Q::SemiclassicalJacobi, D::Derivative, P::SemiclassicalJacobi)
3337
A,B,_ = recurrencecoefficients(P)
3438
α,β,_ = recurrencecoefficients(Q)
3539

3640
d = AccumulateAbstractVector(*, A ./ Vcat(1,α))
3741
v1 = AccumulateAbstractVector(+, B ./ A)
3842
v2 = MulAddAccumulate(Vcat(0,0,α[2:∞]) ./ α, Vcat(0./ α) ./ α);
3943
v3 = AccumulateAbstractVector(*, Vcat(A[1]A[2], A[3:∞] ./ α))
40-
Q * (_BandedMatrix(Vcat(((1:∞) .* d)', (((1:∞) .* (v1 .+ B[2:end]./A[2:end]) .- (2:∞) .*.* v2 .+ β ./ α)) .* v3)'), ∞, 2,-1))'
44+
_BandedMatrix(Vcat(((1:∞) .* d)', (((1:∞) .* (v1 .+ B[2:end]./A[2:end]) .- (2:∞) .*.* v2 .+ β ./ α)) .* v3)'), ∞, 2,-1)'
45+
end
46+
47+
@simplify function *(D::Derivative, P::SemiclassicalJacobi)
48+
Q = SemiclassicalJacobi(P.t, P.a+1,P.b+1,P.c+1,P)
49+
Q * divmul(Q, D, P)
50+
end
51+
52+
53+
54+
55+
function divmul(wP::Weighted{<:Any,<:SemiclassicalJacobi}, D::Derivative, wQ::Weighted{<:Any,<:SemiclassicalJacobi})
56+
Q,P = wQ.P,wP.P
57+
((-sum(orthogonalityweight(Q))/sum(orthogonalityweight(P))) * (Q \ (D * P))')
4158
end
4259

4360
@simplify function *(D::Derivative, wQ::Weighted{<:Any,<:SemiclassicalJacobi})
44-
Q = wQ.P
45-
P = SemiclassicalJacobi(Q.t, Q.a-1,Q.b-1,Q.c-1)
46-
Weighted(P) * ((-sum(orthogonalityweight(Q))/sum(orthogonalityweight(P))) * (Q \ (D * P))')
61+
wP = Weighted(SemiclassicalJacobi(wQ.P.t, wQ.P.a-1,wQ.P.b-1,wQ.P.c-1))
62+
wP * divmul(wP, D, wQ)
4763
end
4864

49-
@simplify function *(D::Derivative, HP::HalfWeighted{:a,<:Any,<:SemiclassicalJacobi})
65+
66+
##
67+
# One-Weighted
68+
##
69+
70+
function divmul(HQ::HalfWeighted{:a,<:Any,<:SemiclassicalJacobi}, D::Derivative, HP::HalfWeighted{:a,<:Any,<:SemiclassicalJacobi})
71+
Q = HQ.P
5072
P = HP.P
51-
Q = SemiclassicalJacobi(P.t, P.a-1, P.b+1, P.c+1)
73+
t = P.t
5274
a = Q.a
5375
A,B,C = recurrencecoefficients(P)
5476
α,β,γ = recurrencecoefficients(Q)
5577
d = AccumulateAbstractVector(*, A ./ α)
5678
v1 = MulAddAccumulate(Vcat(0,0,α[2:∞] ./ α), Vcat(0,β))
5779
v2 = MulAddAccumulate(Vcat(0,0,A[2:∞] ./ α), Vcat(0,B[1], B[2:end] .* d))
5880

59-
HalfWeighted{:a}(Q) * _BandedMatrix(
81+
_BandedMatrix(
6082
Vcat(
6183
((a:∞) .* v2 .- ((a+1):∞) .* Vcat(1,v1[2:end] .* d))',
6284
(((a+1):∞) .* Vcat(1,d))'), ℵ₀, 0,1)
6385
end
6486

65-
@simplify function *(D::Derivative, HP::HalfWeighted{:b,<:Any,<:SemiclassicalJacobi})
87+
function divmul(HQ::HalfWeighted{:b,<:Any,<:SemiclassicalJacobi}, D::Derivative, HP::HalfWeighted{:b,<:Any,<:SemiclassicalJacobi})
88+
Q = HQ.P
6689
P = HP.P
67-
Q = SemiclassicalJacobi(P.t, P.a+1, P.b-1, P.c+1)
90+
t = P.t
6891
b = Q.b
6992
A,B,C = recurrencecoefficients(P)
7093
α,β,γ = recurrencecoefficients(Q)
@@ -73,26 +96,124 @@ end
7396
v1 = MulAddAccumulate(Vcat(0,0,α[2:∞] ./ α), Vcat(0,β))
7497
v2 = MulAddAccumulate(Vcat(0,0,A[2:∞] ./ α), Vcat(0,B[1], B[2:end] .* d))
7598

76-
HalfWeighted{:b}(Q) * _BandedMatrix(
99+
_BandedMatrix(
77100
Vcat(
78101
(-(b:∞) .* v2 .+ ((b+1):∞) .* Vcat(1,v1[2:end] .* d) .+ Vcat(0,(1:∞) .* d2))',
79102
(-((b+1):∞) .* Vcat(1,d))'), ℵ₀, 0,1)
80103
end
81104

82-
@simplify function *(D::Derivative, HP::HalfWeighted{:c,<:Any,<:SemiclassicalJacobi})
105+
function divmul(HQ::HalfWeighted{:c,<:Any,<:SemiclassicalJacobi}, D::Derivative, HP::HalfWeighted{:c,<:Any,<:SemiclassicalJacobi})
106+
Q = HQ.P
83107
P = HP.P
84108
t = P.t
85-
Q = SemiclassicalJacobi(t, P.a+1, P.b+1, P.c-1)
86109
c = Q.c
87110
A,B,C = recurrencecoefficients(P)
88111
α,β,γ = recurrencecoefficients(Q)
89112
d = AccumulateAbstractVector(*, A ./ α)
90113
d2 = AccumulateAbstractVector(*, A ./ Vcat(1,α))
91114
v1 = MulAddAccumulate(Vcat(0,0,α[2:∞] ./ α), Vcat(0,β))
92115
v2 = MulAddAccumulate(Vcat(0,0,A[2:∞] ./ α), Vcat(0,B[1], B[2:end] .* d))
93-
94-
HalfWeighted{:c}(Q) * _BandedMatrix(
116+
_BandedMatrix(
95117
Vcat(
96118
(-(c:∞) .* v2 .+ ((c+1):∞) .* Vcat(1,v1[2:end] .* d) .+ Vcat(0,(t:t:∞) .* d2))',
97119
(-((c+1):∞) .* Vcat(1,d))'), ℵ₀, 0,1)
98-
end
120+
end
121+
122+
@simplify function *(D::Derivative, HP::HalfWeighted{:a,<:Any,<:SemiclassicalJacobi})
123+
P = HP.P
124+
t = P.t
125+
HQ = HalfWeighted{:a}(SemiclassicalJacobi(t, P.a-1, P.b+1, P.c+1))
126+
HQ * divmul(HQ, D, HP)
127+
end
128+
129+
@simplify function *(D::Derivative, HP::HalfWeighted{:b,<:Any,<:SemiclassicalJacobi})
130+
P = HP.P
131+
t = P.t
132+
HQ = HalfWeighted{:b}(SemiclassicalJacobi(t, P.a+1, P.b-1, P.c+1))
133+
HQ * divmul(HQ, D, HP)
134+
end
135+
136+
@simplify function *(D::Derivative, HP::HalfWeighted{:c,<:Any,<:SemiclassicalJacobi})
137+
P = HP.P
138+
t = P.t
139+
HQ = HalfWeighted{:c}(SemiclassicalJacobi(t, P.a+1, P.b+1, P.c-1))
140+
HQ * divmul(HQ, D, HP)
141+
end
142+
143+
##
144+
# Double-Weighted
145+
##
146+
147+
function divmul(HQ::HalfWeighted{:ab}, D::Derivative, HP::HalfWeighted{:ab})
148+
Q = HQ.P
149+
P = HP.P
150+
A,B,_ = recurrencecoefficients(P)
151+
α,β,_ = recurrencecoefficients(Q)
152+
a,b = Q.a,Q.b
153+
154+
d = AccumulateAbstractVector(*, Vcat(1,A) ./ α)
155+
e = AccumulateAbstractVector(*, Vcat(1,A ./ α))
156+
f = MulAddAccumulate(Vcat(0,0,A[2:end] ./ α[2:end]), Vcat(0, (B./ α) .* e))
157+
g = cumsum./ α)
158+
_BandedMatrix(Vcat((((a+1):∞) .* e .- ((b+a+1):∞).*f .+ ((a+b+2):∞) .* e .* g )',
159+
(-((a+b+2):∞) .* d)'),ℵ₀,1,0)
160+
end
161+
162+
163+
function divmul(HQ::HalfWeighted{:bc}, D::Derivative, HP::HalfWeighted{:bc})
164+
Q = HQ.P
165+
P = HP.P
166+
t = P.t
167+
A,B,_ = recurrencecoefficients(P)
168+
α,β,_ = recurrencecoefficients(Q)
169+
b,c = Q.b,Q.c
170+
171+
d = AccumulateAbstractVector(*, Vcat(1,A) ./ α)
172+
e = AccumulateAbstractVector(*, Vcat(1,A ./ α))
173+
f = MulAddAccumulate(Vcat(0,0,A[2:end] ./ α[2:end]), Vcat(0, (B./ α) .* e))
174+
g = cumsum./ α)
175+
_BandedMatrix(Vcat((-((t+1)* (0:∞) .+ (t*(b+1) + c+1)) .* e .+ ((c+b+1):∞).*f .- ((b+c+2):∞) .* e .* g )',
176+
(((b+c+2):∞) .* d)'),ℵ₀,1,0)
177+
end
178+
179+
function divmul(HQ::HalfWeighted{:ac}, D::Derivative, HP::HalfWeighted{:ac})
180+
Q = HQ.P
181+
P = HP.P
182+
t = P.t
183+
A,B,_ = recurrencecoefficients(P)
184+
α,β,_ = recurrencecoefficients(Q)
185+
a,c = Q.a,Q.c
186+
187+
d = AccumulateAbstractVector(*, Vcat(1,A) ./ α)
188+
e = AccumulateAbstractVector(*, Vcat(1,A ./ α))
189+
f = MulAddAccumulate(Vcat(0,0,A[2:end] ./ α[2:end]), Vcat(0, (B./ α) .* e))
190+
g = cumsum./ α)
191+
_BandedMatrix(Vcat((t* ((a+1):∞) .* e .- ((c+a+1):∞).*f .+ ((a+c+2):∞) .* e .* g )',
192+
(-((a+c+2):∞) .* d)'),ℵ₀,1,0)
193+
end
194+
195+
196+
197+
@simplify function *(D::Derivative, HP::HalfWeighted{:ab,<:Any,<:SemiclassicalJacobi})
198+
P = HP.P
199+
t = P.t
200+
HQ = HalfWeighted{:ab}(SemiclassicalJacobi(t, P.a-1,P.b-1,P.c+1))
201+
HQ * divmul(HQ, D, HP)
202+
end
203+
204+
205+
@simplify function *(D::Derivative, HP::HalfWeighted{:ac,<:Any,<:SemiclassicalJacobi})
206+
P = HP.P
207+
t = P.t
208+
HQ = HalfWeighted{:ac}(SemiclassicalJacobi(t, P.a-1,P.b+1,P.c-1))
209+
HQ * divmul(HQ, D, HP)
210+
end
211+
212+
213+
@simplify function *(D::Derivative, HP::HalfWeighted{:bc,<:Any,<:SemiclassicalJacobi})
214+
P = HP.P
215+
t = P.t
216+
HQ = HalfWeighted{:bc}(SemiclassicalJacobi(t, P.a+1,P.b-1,P.c-1))
217+
HQ * divmul(HQ, D, HP)
218+
end
219+

0 commit comments

Comments
 (0)