Skip to content

Commit 71ff423

Browse files
authored
Support for cumsum with ChebyshevT (#53)
* Support for cumsum with ChebyshevT * BigFloat with Ultraspherical * Support ContinuumArrays v0.9 * increase coverage
1 parent e9a6e3b commit 71ff423

10 files changed

+92
-28
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ ArrayLayouts = "0.7"
2929
BandedMatrices = "0.16.5"
3030
BlockArrays = "0.15, 0.16"
3131
BlockBandedMatrices = "0.10"
32-
ContinuumArrays = "0.8.5"
32+
ContinuumArrays = "0.8.5, 0.9"
3333
DomainSets = "0.5"
3434
FFTW = "1.1"
3535
FastGaussQuadrature = "0.4.3"

examples/ultrasphericalspectralmethod.jl

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ClassicalOrthogonalPolynomials, Plots, Test
2+
import ArrayLayouts: diagonal
23

34
###
45
# We can solve ODEs like the Airy equation
@@ -14,8 +15,27 @@ C = Ultraspherical(2)
1415
x = axes(T,1)
1516
D = Derivative(x)
1617

17-
c = [T[[begin,end],:]; C \ (D^2 * T - x .* T)] \ [airyai(-1); airyai(1); zeros(∞)]
18+
c = [T[[begin,end],:]; C \ ((D^2 - diagonal(x))*T)] \ [airyai(-1); airyai(1); zeros(∞)]
1819
u = T*c
1920

2021
@test u[0.0] airyai(0.0)
21-
plot(u)
22+
plot(u)
23+
24+
25+
##
26+
# Lee & Greengard
27+
# ε*u'' - x*u' + u = 0, u(-1) = 1, u(1) = 2
28+
##
29+
30+
T = ChebyshevT()
31+
C = Ultraspherical(2)
32+
x = axes(T,1)
33+
D = Derivative(x)
34+
35+
ε = 1/100
36+
A = [T[[begin,end],:]; C \ ((ε*D^2 - x .* D + I) * T)]
37+
c = A \ [1; 2; zeros(∞)]
38+
u = T*c
39+
plot(u)
40+
41+
C \*D^2 - x .* D + I)

src/ClassicalOrthogonalPolynomials.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ using ContinuumArrays, QuasiArrays, LazyArrays, FillArrays, BandedMatrices, Bloc
77

88
import Base: @_inline_meta, axes, getindex, convert, prod, *, /, \, +, -,
99
IndexStyle, IndexLinear, ==, OneTo, tail, similar, copyto!, copy,
10-
first, last, Slice, size, length, axes, IdentityUnitRange, sum, _sum,
10+
first, last, Slice, size, length, axes, IdentityUnitRange, sum, _sum, cumsum,
1111
to_indices, _maybetail, tail, getproperty, inv, show, isapprox, summary
1212
import Base.Broadcast: materialize, BroadcastStyle, broadcasted
1313
import LazyArrays: MemoryLayout, Applied, ApplyStyle, flatten, _flatten, colsupport, adjointlayout,
@@ -19,7 +19,7 @@ import ArrayLayouts: MatMulVecAdd, materialize!, _fill_lmul!, sublayout, sub_mat
1919
import LazyBandedMatrices: SymTridiagonal, Bidiagonal, Tridiagonal, AbstractLazyBandedLayout
2020
import LinearAlgebra: pinv, factorize, qr, adjoint, transpose, dot
2121
import BandedMatrices: AbstractBandedLayout, AbstractBandedMatrix, _BandedMatrix, bandeddata
22-
import FillArrays: AbstractFill, getindex_value
22+
import FillArrays: AbstractFill, getindex_value, SquareEye
2323

2424
import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclusion, SubQuasiArray,
2525
QuasiDiagonal, MulQuasiArray, MulQuasiMatrix, MulQuasiVector, QuasiMatMulMat,

src/classical/chebyshev.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ end
158158
# Conversion
159159
#####
160160

161+
\(::Chebyshev{kind,T}, ::Chebyshev{kind,V}) where {kind,T,V} = SquareEye{promote_type(T,V)}(ℵ₀)
162+
161163
function \(U::ChebyshevU, C::ChebyshevT)
162164
T = promote_type(eltype(U), eltype(C))
163165
_BandedMatrix(Vcat(-Ones{T}(1,∞)/2,
@@ -218,6 +220,8 @@ function \(A::ChebyshevT, B::Legendre)
218220
end, 1:∞, (1:∞)'))
219221
end
220222

223+
\(A::AbstractJacobi, B::Chebyshev) = ApplyArray(inv,B \ A)
224+
221225

222226
function \(A::Jacobi, B::WeightedBasis{<:Any,<:JacobiWeight,<:Chebyshev})
223227
w, T = B.args
@@ -253,6 +257,13 @@ function _sum(A::WeightedBasis{T,<:ChebyshevWeight,<:Chebyshev}, dims) where T
253257
Hcat(convert(T, π), Zeros{T}(1,∞))
254258
end
255259

260+
function cumsum(T::ChebyshevT{V}; dims::Integer) where V
261+
@assert dims == 1
262+
Σ = _BandedMatrix(Vcat(-one(V) ./ (-2:2:∞)', Zeros{V}(1,∞), Hcat(one(V), one(V) ./ (4:2:∞)')), ℵ₀, 0, 2)
263+
ApplyQuasiArray(*, T, Vcat((-1).^(0:∞)'* Σ, Σ))
264+
end
265+
266+
cumsum(f::Expansion{<:Any,<:ChebyshevT}) = cumsum(f.args[1]; dims=1) * f.args[2]
256267

257268
####
258269
# algebra

src/classical/jacobi.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,4 +516,6 @@ function _sum(P::Legendre{T}, dims) where T
516516
end
517517

518518
_sum(p::SubQuasiArray{T,1,Legendre{T},<:Tuple{Inclusion,Int}}, ::Colon) where T = parentindices(p)[2] == 1 ? convert(T, 2) : zero(T)
519+
_sum(P::AbstractJacobi{T}, dims) where T = 2 * (Legendre{T}() \ P)[1:1,:]
520+
519521

src/classical/ultraspherical.jl

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ function jacobimatrix(P::Ultraspherical{T}) where T
7373
end
7474

7575
# These return vectors A[k], B[k], C[k] are from DLMF. Cause of MikaelSlevinsky we need an extra entry in C ... for now.
76-
function recurrencecoefficients(C::Ultraspherical)
77-
λ = C.λ
76+
function recurrencecoefficients(C::Ultraspherical{T}) where T
77+
λ = convert(T,C.λ)
7878
n = 0:
7979
(2(n .+ λ) ./ (n .+ 1), Zeros{typeof(λ)}(∞), (n .+ (2λ-1)) ./ (n .+ 1))
8080
end
@@ -91,28 +91,29 @@ end
9191
@simplify function *(D::Derivative{<:Any,<:ChebyshevInterval}, S::Legendre)
9292
T = promote_type(eltype(D),eltype(S))
9393
A = _BandedMatrix(Ones{T}(1,∞), ℵ₀, -1,1)
94-
ApplyQuasiMatrix(*, Ultraspherical{T}(3/2), A)
94+
ApplyQuasiMatrix(*, Ultraspherical{T}(convert(T,3)/2), A)
9595
end
9696

9797

9898
# Ultraspherical(λ+1)\(D*Ultraspherical(λ))
9999
@simplify function *(D::Derivative{<:Any,<:ChebyshevInterval}, S::Ultraspherical)
100-
A = _BandedMatrix(Fill(2S.λ,1,∞), ℵ₀, -1,1)
101-
ApplyQuasiMatrix(*, Ultraspherical{eltype(S)}(S.λ+1), A)
100+
T = promote_type(eltype(D),eltype(S))
101+
A = _BandedMatrix(Fill(2convert(T,S.λ),1,∞), ℵ₀, -1,1)
102+
ApplyQuasiMatrix(*, Ultraspherical{T}(S.λ+1), A)
102103
end
103104

104105
# Ultraspherical(λ-1)\ (D*wUltraspherical(λ))
105106
@simplify function *(D::Derivative{<:Any,<:AbstractInterval}, WS::Weighted{<:Any,<:Ultraspherical})
106107
S = WS.P
107108
λ = S.λ
108-
T = eltype(WS)
109+
T = promote_type(eltype(D),eltype(WS))
109110
if λ == 1
110-
A = _BandedMatrix((-(1:∞))', ℵ₀, 1,-1)
111-
ApplyQuasiMatrix(*, ChebyshevTWeight{T}() .* ChebyshevT{T}(), A)
111+
A = _BandedMatrix((-(one(T):∞))', ℵ₀, 1,-1)
112+
ApplyQuasiMatrix(*, Weighted(ChebyshevT{T}()), A)
112113
else
113114
n = (0:∞)
114115
A = _BandedMatrix((-one(T)/(2*-1)) * ((n.+1) .* (n .+ (2λ-1))))', ℵ₀, 1,-1)
115-
ApplyQuasiMatrix(*, WeightedUltraspherical{T}-1), A)
116+
ApplyQuasiMatrix(*, Weighted(Ultraspherical{T}-1)), A)
116117
end
117118
end
118119

@@ -160,30 +161,32 @@ end
160161
\(T::Chebyshev, C::Ultraspherical) = inv(C \ T)
161162

162163
function \(C2::Ultraspherical{<:Any,<:Integer}, C1::Ultraspherical{<:Any,<:Integer})
163-
λ = C1.λ
164164
T = promote_type(eltype(C2), eltype(C1))
165-
if C2.λ == λ+1
166-
_BandedMatrix( Vcat(-./ ((0:∞) .+ λ))', Zeros(1,∞), (λ ./ ((0:∞) .+ λ))'), ℵ₀, 0, 2)
167-
elseif C2.λ == λ
165+
λ_Int = C1.λ
166+
λ = convert(T,λ_Int)
167+
if C2.λ == λ_Int+1
168+
_BandedMatrix( Vcat(-./ ((0:∞) .+ λ))', Zeros{T}(1,∞), (λ ./ ((0:∞) .+ λ))'), ℵ₀, 0, 2)
169+
elseif C2.λ == λ_Int
168170
Eye{T}(∞)
169-
elseif C2.λ > λ
170-
(C2 \ Ultraspherical(λ+1)) * (Ultraspherical(λ+1)\C1)
171+
elseif C2.λ > λ_Int
172+
(C2 \ Ultraspherical(λ_Int+1)) * (Ultraspherical(λ_Int+1)\C1)
171173
else
172174
error("Not implemented")
173175
end
174176
end
175177

176178
function \(C2::Ultraspherical, C1::Ultraspherical)
177-
λ = C1.λ
178179
T = promote_type(eltype(C2), eltype(C1))
180+
λ_Int = C1.λ
181+
λ = convert(T,λ_Int)
179182
if C2.λ == λ+1
180-
_BandedMatrix( Vcat(-./ ((0:∞) .+ λ))', Zeros(1,∞), (λ ./ ((0:∞) .+ λ))'), ℵ₀, 0, 2)
181-
elseif C2.λ == λ
183+
_BandedMatrix( Vcat(-./ ((0:∞) .+ λ))', Zeros{T}(1,∞), (λ ./ ((0:∞) .+ λ))'), ℵ₀, 0, 2)
184+
elseif C2.λ == λ_Int
182185
Eye{T}(∞)
183-
elseif isinteger(C2.λ-λ) && C2.λ > λ
184-
Cm = Ultraspherical{T}(λ+1)
186+
elseif isinteger(C2.λ-λ_Int) && C2.λ > λ_Int
187+
Cm = Ultraspherical{T}(λ_Int+1)
185188
(C2 \ Cm) * (Cm \ C1)
186-
elseif isinteger(C2.λ-λ)
189+
elseif isinteger(C2.λ-λ_Int)
187190
inv(C1 \ C2)
188191
else
189192
error("Not implemented")
@@ -193,13 +196,14 @@ end
193196
function \(w_A::WeightedUltraspherical, w_B::WeightedUltraspherical)
194197
wA,A = w_A.args
195198
wB,B = w_B.args
199+
T = promote_type(eltype(w_A),eltype(w_B))
196200

197201
if wA == wB
198202
A \ B
199203
elseif B.λ == A.λ+1 && wB.λ == wA.λ+1 # Lower
200-
λ = A.λ
204+
λ = convert(T,A.λ)
201205
_BandedMatrix(Vcat(((2λ:∞) .* ((2λ+1):∞) ./ (4λ .*+1:∞)))',
202-
Zeros(1,∞),
206+
Zeros{T}(1,∞),
203207
(-(1:∞) .* (2:∞) ./ (4λ .*+1:∞)))'), ℵ₀, 2,0)
204208
else
205209
error("not implemented for $A and $wB")

src/lanczos.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ struct LanczosLayout <: AbstractBasisLayout end
232232
MemoryLayout(::Type{<:LanczosPolynomial}) = LanczosLayout()
233233
arguments(::ApplyLayout{typeof(*)}, Q::LanczosPolynomial) = Q.P, LanczosConversion(Q.data)
234234
copy(L::Ldiv{LanczosLayout,Lay}) where Lay<:AbstractLazyLayout = copy(Ldiv{ApplyLayout{typeof(*)},Lay}(L.A,L.B))
235+
copy(L::Ldiv{LanczosLayout,Lay}) where Lay<:BroadcastLayout = copy(Ldiv{ApplyLayout{typeof(*)},Lay}(L.A,L.B))
235236
copy(L::Ldiv{LanczosLayout,ApplyLayout{typeof(*)}}) = copy(Ldiv{ApplyLayout{typeof(*)},ApplyLayout{typeof(*)}}(L.A,L.B))
236237
copy(L::Ldiv{LanczosLayout,ApplyLayout{typeof(*)},<:Any,<:AbstractQuasiVector}) = copy(Ldiv{ApplyLayout{typeof(*)},ApplyLayout{typeof(*)}}(L.A,L.B))
237238
LazyArrays._mul_arguments(Q::LanczosPolynomial) = arguments(ApplyLayout{typeof(*)}(), Q)

src/normalized.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ function copy(L::Ldiv{WeightedOPLayout,WeightedOPLayout})
182182
convert(WeightedOrthogonalPolynomial, L.A) \ convert(WeightedOrthogonalPolynomial, L.B)
183183
end
184184

185+
copy(L::Ldiv{WeightedOPLayout,<:BroadcastLayout}) = convert(WeightedOrthogonalPolynomial, L.A) \ L.B
185186
copy(L::Ldiv{WeightedOPLayout,<:AbstractLazyLayout}) = convert(WeightedOrthogonalPolynomial, L.A) \ L.B
186187
copy(L::Ldiv{WeightedOPLayout,<:AbstractBasisLayout}) = convert(WeightedOrthogonalPolynomial, L.A) \ L.B
187188
copy(L::Ldiv{<:AbstractLazyLayout,WeightedOPLayout}) = L.A \ convert(WeightedOrthogonalPolynomial, L.B)

test/test_chebyshev.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,18 @@ import ContinuumArrays: MappedWeightedBasisLayout, Map
245245
x = Inclusion(0..1)
246246
@test sum(wT[2x .- 1, :]; dims=1)[1,1:10] ==/2; zeros(9)]
247247
@test sum(wT[2x .- 1, :] * [[1,2,3]; zeros(∞)]) == π/2
248+
249+
T = Chebyshev()
250+
x = axes(T,1)
251+
@test sum(T * (T \ exp.(x))) - inv(ℯ)
252+
end
253+
254+
@testset "cumsum" begin
255+
T = ChebyshevT()
256+
x = axes(T,1)
257+
@test (T \ cumsum(T; dims=1)) * (T \ exp.(x)) T \ (exp.(x) .- exp(-1))
258+
f = T * (T \ exp.(x))
259+
@test T \ cumsum(f) T \ (exp.(x) .- exp(-1))
248260
end
249261

250262
@testset "algebra" begin

test/test_ultraspherical.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,17 @@ import LazyArrays: rowsupport, colsupport
118118
@test Ultraspherical(1/2) \ (JacobiWeight(0,0) .* Jacobi(0,0)) isa Diagonal
119119
@test (JacobiWeight(0,0) .* Jacobi(0,0)) \ Ultraspherical(1/2) isa Diagonal
120120
end
121+
122+
@testset "BigFloat" begin
123+
U = Ultraspherical{BigFloat}(1)
124+
T = ChebyshevT{BigFloat}()
125+
x = axes(U,1)
126+
D = Derivative(x)
127+
128+
@test Weighted(T) \ (D * Weighted(U)) isa BandedMatrix{BigFloat}
129+
130+
= Ultraspherical{BigFloat}(3)
131+
c = [1; 2; 3; zeros(BigFloat,∞)]
132+
@test C³[big(1)/10,:]'*(C³ \ U) * c U[big(1)/10,:]'c
133+
end
121134
end

0 commit comments

Comments
 (0)