@@ -146,10 +146,10 @@ function semiclassical_jacobimatrix(t, a, b, c)
146146 iszero (c) && return jacobimatrix (P)
147147 if isone (c)
148148 return cholesky_jacobimatrix (x-> (t- x),P)
149- elseif isone (c÷ 2 )
149+ elseif isone (c/ 2 )
150150 return qr_jacobimatrix (x-> (t- x),P)
151151 elseif isinteger (c) && c ≥ 0 # reduce other integer c cases to hierarchy
152- return SemiclassicalJacobi .(t, a, b, 0 : c )[end ]. X
152+ return SemiclassicalJacobi .(t, a, b, 0 : Int (c) )[end ]. X
153153 else # if c is not an integer, use Lanczos for now
154154 x = axes (P,1 )
155155 return jacobimatrix (LanczosPolynomial (@. (x^ a * (1 - x)^ b * (t- x)^ c), jacobi (b, a, UnitInterval {T} ())))
@@ -170,11 +170,11 @@ function semiclassical_jacobimatrix(Q::SemiclassicalJacobi, a, b, c)
170170 return Q. X
171171 end
172172
173- if isone (Δa÷ 2 ) && iszero (Δb) && iszero (Δc) # raising by 2
173+ if isone (Δa/ 2 ) && iszero (Δb) && iszero (Δc) # raising by 2
174174 qr_jacobimatrix (Q. X,Q)
175- elseif iszero (Δa) && isone (Δb÷ 2 ) && iszero (Δc)
175+ elseif iszero (Δa) && isone (Δb/ 2 ) && iszero (Δc)
176176 qr_jacobimatrix (I- Q. X,Q)
177- elseif iszero (Δa) && iszero (Δb) && isone (Δc÷ 2 )
177+ elseif iszero (Δa) && iszero (Δb) && isone (Δc/ 2 )
178178 qr_jacobimatrix (Q. t* I- Q. X,Q)
179179 elseif isone (Δa) && iszero (Δb) && iszero (Δc) # raising by 1
180180 cholesky_jacobimatrix (Q. X,Q)
@@ -188,7 +188,7 @@ function semiclassical_jacobimatrix(Q::SemiclassicalJacobi, a, b, c)
188188 semiclassical_jacobimatrix (SemiclassicalJacobi (Q. t, Q. a, Q. b+ 1 , Q. c, Q), a, b, c)
189189 elseif c > Q. c
190190 semiclassical_jacobimatrix (SemiclassicalJacobi (Q. t, Q. a, Q. b, Q. c+ 1 , Q), a, b, c)
191- # TODO : Implement lowering via QL or via inverting R
191+ # TODO : Implement lowering via QL/reverse Cholesky or via inverting R
192192 # elseif b < Q.b # iterative lowering by 1
193193 # semiclassical_jacobimatrix(SemiclassicalJacobi(Q.t, Q.a, Q.b-1, Q.c, Q), a, b, c)
194194 # elseif c < Q.c
@@ -208,6 +208,7 @@ LanczosPolynomial(P::SemiclassicalJacobi{T}) where T =
208208
209209gives either a mapped `Jacobi` or `LanczosPolynomial` version of `P`.
210210"""
211+ # TODO : Use ConvertedOPs for integer special cases?
211212toclassical (P:: SemiclassicalJacobi{T} ) where T = iszero (P. c) ? Normalized (jacobi (P. b, P. a, UnitInterval {T} ())) : LanczosPolynomial (P)
212213
213214copy (P:: SemiclassicalJacobi ) = P
@@ -224,8 +225,6 @@ function summary(io::IO, P::SemiclassicalJacobi)
224225 print (io, " SemiclassicalJacobi with weight x^$a * (1-x)^$b * ($t -x)^$c " )
225226end
226227
227-
228-
229228jacobimatrix (P:: SemiclassicalJacobi ) = P. X
230229
231230"""
@@ -260,40 +259,51 @@ function semijacobi_ldiv(P::SemiclassicalJacobi, Q)
260259 (P \ R) * _p0 (R̃) * (R̃ \ Q)
261260end
262261
262+ # returns conversion operator from SemiclassicalJacobi P to SemiclassicalJacobi Q in a single step via decomposition.
263+ function semijacobi_ldiv_direct (Q:: SemiclassicalJacobi , P:: SemiclassicalJacobi )
264+ (Q == P) && return SymTridiagonal (Ones (∞),Zeros (∞))
265+ Δa = Q. a- P. a
266+ Δb = Q. b- P. b
267+ Δc = Q. c- P. c
268+ M = Diagonal (Ones (∞))
269+ if iseven (Δa) && iseven (Δb) && iseven (Δc)
270+ M = qr (P. X^ (Δa÷ 2 )* (I- P. X)^ (Δb÷ 2 )* (Q. t* I- P. X)^ (Δc÷ 2 )). R
271+ return ApplyArray (* , Diagonal (sign .(view (M,band (0 ))).* Fill (abs .(1 / M[1 ]),∞)), M) # match normalization choice P_0(x) = 1
272+ elseif isone (Δa) && iszero (Δb) && iszero (Δc) # special case (Δa,Δb,Δc) = (1,0,0)
273+ M = cholesky (P. X). U
274+ return ApplyArray (* , Diagonal (Fill (1 / M[1 ],∞)), M) # match normalization choice P_0(x) = 1
275+ elseif iszero (Δa) && isone (Δb) && iszero (Δc) # special case (Δa,Δb,Δc) = (0,1,0)
276+ M = cholesky (I- P. X). U
277+ return ApplyArray (* , Diagonal (Fill (1 / M[1 ],∞)), M) # match normalization choice P_0(x) = 1
278+ elseif iszero (Δa) && iszero (Δb) && isone (Δc) # special case (Δa,Δb,Δc) = (0,0,1)
279+ M = cholesky (Q. t* I- P. X). U
280+ return ApplyArray (* , Diagonal (Fill (1 / M[1 ],∞)), M) # match normalization choice P_0(x) = 1
281+ elseif isinteger (Δa) && isinteger (Δb) && isinteger (Δc)
282+ M = cholesky (Symmetric (P. X^ (Δa)* (I- P. X)^ (Δb)* (Q. t* I- P. X)^ (Δc))). U
283+ return ApplyArray (* , Diagonal (Fill (1 / M[1 ],∞)), M) # match normalization choice P_0(x) = 1
284+ else
285+ error (" Implement" )
286+ end
287+ end
288+
263289# returns conversion operator from SemiclassicalJacobi P to SemiclassicalJacobi Q.
264290function semijacobi_ldiv (Q:: SemiclassicalJacobi , P:: SemiclassicalJacobi )
265291 @assert Q. t ≈ P. t
266- # For polynomial modifications, use Cholesky/QR. Use Lanzos otherwise.
267- M = Diagonal (Ones (∞))
268- (Q == P) && return M
292+ (Q == P) && return SymTridiagonal (Ones (∞),Zeros (∞))
269293 Δa = Q. a- P. a
270294 Δb = Q. b- P. b
271295 Δc = Q. c- P. c
272- if iseven (Δa) && iseven (Δb) && iseven (Δc)
273- if ! iszero (Δa)
274- M = ApplyArray (* ,M,P. X^ (Δa÷ 2 ))
275- end
276- if ! iszero (Δb)
277- M = ApplyArray (* ,M,(I- P. X)^ (Δb÷ 2 ))
278- end
279- if ! iszero (Δc)
280- M = ApplyArray (* ,M,(Q. t* I- P. X)^ (Δc÷ 2 ))
281- end
282- M = qr (M). R
283- return ApplyArray (* , Diagonal (sign .(view (M,band (0 ))).* Fill (abs .(1 / M[1 ]),∞)), M) # match our normalization choice P_0(x) = 1
284- elseif isinteger (Δa) && isinteger (Δb) && isinteger (Δc)
285- if ! iszero (Δa)
286- M = ApplyArray (* ,M,P. X^ (Δa))
287- end
288- if ! iszero (Δb)
289- M = ApplyArray (* ,M,(I- P. X)^ (Δb))
290- end
291- if ! iszero (Δc)
292- M = ApplyArray (* ,M,(Q. t* I- P. X)^ (Δc))
296+ if isinteger (Δa) && isinteger (Δb) && isinteger (Δc) # (Δa,Δb,Δc) are integers -> use QR/Cholesky iteratively
297+ if ((isone (Δa)|| isone (Δa/ 2 )) && iszero (Δb) && iszero (Δc)) || (iszero (Δa) && (isone (Δb)|| isone (Δb/ 2 )) && iszero (Δc)) || (iszero (Δa) && iszero (Δb) && (isone (Δc)|| isone (Δc/ 2 )))
298+ M = semijacobi_ldiv_direct (Q, P)
299+ elseif Δa > 0 # iterative modification by 1
300+ M = ApplyArray (* ,semijacobi_ldiv_direct (Q, SemiclassicalJacobi (Q. t, Q. a- 1 - iseven (Δa), Q. b, Q. c)),semijacobi_ldiv (SemiclassicalJacobi (Q. t, Q. a- 1 - iseven (Δa), Q. b, Q. c), P))
301+ elseif Δb > 0
302+ M = ApplyArray (* ,semijacobi_ldiv_direct (Q, SemiclassicalJacobi (Q. t, Q. a, Q. b- 1 - iseven (Δb), Q. c)),semijacobi_ldiv (SemiclassicalJacobi (Q. t, Q. a, Q. b- 1 - iseven (Δb), Q. c), P))
303+ elseif Δc > 0
304+ M = ApplyArray (* ,semijacobi_ldiv_direct (Q, SemiclassicalJacobi (Q. t, Q. a, Q. b, Q. c- 1 - iseven (Δc))),semijacobi_ldiv (SemiclassicalJacobi (Q. t, Q. a, Q. b, Q. c- 1 - iseven (Δc)), P))
293305 end
294- M = cholesky (Symmetric (M)). U
295- return ApplyArray (* , Diagonal (Fill (1 / M[1 ],∞)), M) # match our normalization choice P_0(x) = 1
296- else # fallback option for non-integer weight modification
306+ else # fallback to Lancos
297307 R = SemiclassicalJacobi (P. t, mod (P. a,- 1 ), mod (P. b,- 1 ), mod (P. c,- 1 ))
298308 R̃ = toclassical (R)
299309 return (P \ R) * _p0 (R̃) * (R̃ \ Q)
@@ -338,8 +348,14 @@ function \(w_A::WeightedSemiclassicalJacobi, w_B::WeightedSemiclassicalJacobi)
338348 wA,A = w_A. args
339349 wB,B = w_B. args
340350 @assert wA. t == wB. t == A. t == B. t
341-
342- if wA. a == wB. a && wA. b == wB. b && wA. c == wB. c
351+ Δa = B. a- A. a
352+ Δb = B. b- A. b
353+ Δc = B. c- A. c
354+
355+ if (wA. a == A. a) && (wA. b == A. b) && (wA. c == A. c) && (wB. a == B. a) && (wB. b == B. b) && (wB. c == B. c) && isinteger (A. a) && isinteger (A. b) && isinteger (A. c) && isinteger (B. a) && isinteger (B. b) && isinteger (B. c)
356+ k = (A \ SemiclassicalJacobiWeight (A. t,Δa,Δb,Δc))[1 ]
357+ return (ApplyArray (* ,Diagonal (Fill (k,∞)),(B \ A)))'
358+ elseif wA. a == wB. a && wA. b == wB. b && wA. c == wB. c # fallback to Christoffel–Darboux
343359 A \ B
344360 elseif wA. a+ 1 == wB. a && wA. b == wB. b && wA. c == wB. c
345361 @assert A. a+ 1 == B. a && A. b == B. b && A. c == B. c
@@ -383,29 +399,30 @@ massmatrix(P::SemiclassicalJacobi) = Diagonal(Fill(sum(orthogonalityweight(P)),
383399end
384400
385401function ldiv (Q:: SemiclassicalJacobi , f:: AbstractQuasiVector )
386- if iszero (Q. a) && iszero (Q. b) && Q. c == - one (eltype (Q. t))
387- # TODO : due to a stdlib error this won't work with bigfloat as is
388- T = typeof (Q. t)
402+ T = typeof (Q. t)
403+ if iszero (Q. a) && iszero (Q. b) && isone (- Q. c) # (0,0,-1) special case
389404 R = legendre (zero (T).. one (T))
390405 B = neg1c_tolegendre (Q. t)
391406 return (B \ (R \ f))
407+ elseif isinteger (Q. a) && isinteger (Q. b) && isinteger (Q. c) # (a,b,c) are integers -> use QR/Cholesky
408+ R̃ = Normalized (jacobi (Q. b, Q. a, UnitInterval {T} ()))
409+ return (Q \ SemiclassicalJacobi (Q. t, Q. a, Q. b, 0 )) * _p0 (R̃) * (R̃ \ f)
410+ else # fallback to Lanzcos
411+ R̃ = toclassical (SemiclassicalJacobi (Q. t, mod (Q. a,- 1 ), mod (Q. b,- 1 ), mod (Q. c,- 1 )))
412+ return (Q \ R̃) * (R̃ \ f)
392413 end
393- R = SemiclassicalJacobi (Q. t, mod (Q. a,- 1 ), mod (Q. b,- 1 ), mod (Q. c,- 1 ))
394- R̃ = toclassical (R)
395- return (Q \ R̃) * (R̃ \ f)
396414end
397415function ldiv (Qn:: SubQuasiArray{<:Any,2,<:SemiclassicalJacobi,<:Tuple{<:Inclusion,<:Any}} , C:: AbstractQuasiArray )
398416 _,jr = parentindices (Qn)
399417 Q = parent (Qn)
400418 if iszero (Q. a) && iszero (Q. b) && Q. c == - one (eltype (Q. t))
401- # TODO : due to a stdlib error this won't work with bigfloat as is
402419 T = typeof (Q. t)
403420 R = legendre (zero (T).. one (T))
404421 B = neg1c_tolegendre (Q. t)
405422 return (B[jr,jr] \ (R[:,jr] \ C))
406423 end
407- R = SemiclassicalJacobi (Q . t, mod (Q . a, - 1 ), mod (Q . b, - 1 ), mod (Q . c, - 1 ))
408- R̃ = toclassical (R )
424+
425+ R̃ = toclassical (SemiclassicalJacobi (Q . t, mod (Q . a, - 1 ), mod (Q . b, - 1 ), mod (Q . c, - 1 )) )
409426 (Q \ R̃)[jr,jr] * (R̃[:,jr] \ C)
410427end
411428
0 commit comments