Skip to content

Commit eb2d8dd

Browse files
authored
Start PiecewiseInterlace (#26)
* Start PiecewiseInterlace * copy for LanczosConversion * tests pass
1 parent 87c766d commit eb2d8dd

File tree

7 files changed

+133
-17
lines changed

7 files changed

+133
-17
lines changed

src/ClassicalOrthogonalPolynomials.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ using ContinuumArrays, QuasiArrays, LazyArrays, FillArrays, BandedMatrices, Bloc
77
InfiniteLinearAlgebra, InfiniteArrays, LinearAlgebra, FastGaussQuadrature, FastTransforms, FFTW,
88
LazyBandedMatrices, HypergeometricFunctions
99

10-
import Base: @_inline_meta, axes, getindex, convert, prod, *, /, \, +, -,
10+
import Base: @_inline_meta, axes, getindex, unsafe_getindex, convert, prod, *, /, \, +, -,
1111
IndexStyle, IndexLinear, ==, OneTo, tail, similar, copyto!, copy,
1212
first, last, Slice, size, length, axes, IdentityUnitRange, sum, _sum, cumsum,
1313
to_indices, _maybetail, tail, getproperty, inv, show, isapprox, summary
@@ -18,7 +18,7 @@ import LazyArrays: MemoryLayout, Applied, ApplyStyle, flatten, _flatten, colsupp
1818
AbstractCachedVector, AbstractCachedMatrix, paddeddata, cache_filldata!
1919
import ArrayLayouts: MatMulVecAdd, materialize!, _fill_lmul!, sublayout, sub_materialize, lmul!, ldiv!, ldiv, transposelayout, triangulardata,
2020
subdiagonaldata, diagonaldata, supdiagonaldata
21-
import LazyBandedMatrices: SymTridiagonal, Bidiagonal, Tridiagonal, AbstractLazyBandedLayout
21+
import LazyBandedMatrices: SymTridiagonal, Bidiagonal, Tridiagonal, unitblocks, BlockRange1, AbstractLazyBandedLayout
2222
import LinearAlgebra: pinv, factorize, qr, adjoint, transpose, dot
2323
import BandedMatrices: AbstractBandedLayout, AbstractBandedMatrix, _BandedMatrix, bandeddata
2424
import FillArrays: AbstractFill, getindex_value, SquareEye
@@ -39,7 +39,7 @@ import FastTransforms: Λ, forwardrecurrence, forwardrecurrence!, _forwardrecurr
3939

4040
import FastGaussQuadrature: jacobimoment
4141

42-
import BlockArrays: blockedrange, _BlockedUnitRange, unblock, _BlockArray
42+
import BlockArrays: blockedrange, _BlockedUnitRange, unblock, _BlockArray, block, blockindex, BlockSlice
4343
import BandedMatrices: bandwidths
4444

4545
export OrthogonalPolynomial, Normalized, orthonormalpolynomial, LanczosPolynomial,
@@ -49,7 +49,7 @@ export OrthogonalPolynomial, Normalized, orthonormalpolynomial, LanczosPolynomia
4949
∞, Derivative, .., Inclusion,
5050
chebyshevt, chebyshevu, legendre, jacobi, ultraspherical,
5151
legendrep, jacobip, ultrasphericalc, laguerrel,hermiteh, normalizedjacobip,
52-
jacobimatrix, jacobiweight, legendreweight, chebyshevtweight, chebyshevuweight, Weighted
52+
jacobimatrix, jacobiweight, legendreweight, chebyshevtweight, chebyshevuweight, Weighted, PiecewiseInterlace
5353

5454

5555
import Base: oneto
@@ -61,7 +61,7 @@ include("interlace.jl")
6161
cardinality(::FullSpace{<:AbstractFloat}) = ℵ₁
6262
cardinality(::EuclideanDomain) = ℵ₁
6363

64-
transform_ldiv(A::AbstractQuasiArray{T}, f::AbstractQuasiArray{V}, ::Tuple{<:Any,InfiniteCardinal{0}}) where {T,V} =
64+
transform_ldiv(A::AbstractQuasiArray{T}, f::AbstractQuasiArray{V}, ::Tuple{<:Any,InfiniteCardinal{0}}) where {T,V} =
6565
adaptivetransform_ldiv(convert(AbstractQuasiArray{promote_type(T,V)}, A), f)
6666

6767
function chop!(c::AbstractVector, tol::Real)

src/clenshaw.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,16 @@ end
9595
# Clenshaw
9696
###
9797

98-
function getindex(f::Expansion{<:Any,<:OrthogonalPolynomial}, x::Number)
98+
function unsafe_getindex(f::Expansion{<:Any,<:OrthogonalPolynomial}, x::Number)
9999
P,c = arguments(f)
100100
_p0(P)*clenshaw(paddeddata(c), recurrencecoefficients(P)..., x)
101101
end
102102

103+
Base.@propagate_inbounds function getindex(f::Expansion{<:Any,<:OrthogonalPolynomial}, x::Number)
104+
@inbounds checkbounds(f, x)
105+
unsafe_getindex(f, x)
106+
end
107+
103108
getindex(f::Expansion{T,<:OrthogonalPolynomial}, x::AbstractVector{<:Number}) where T =
104109
copyto!(Vector{T}(undef, length(x)), view(f, x))
105110

src/interlace.jl

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,79 @@ function interlace!(v::AbstractVector,offset::Int)
9393
end
9494
v
9595
end
96+
97+
98+
abstract type AbstractInterlaceBasis{T} <: Basis{T} end
99+
copy(A::AbstractInterlaceBasis) = interlacebasis(A, map(copy, A.args))
100+
101+
"""
102+
PiecewiseInterlace(args...)
103+
104+
is an analogue of `Basis` that takes the union of the first axis,
105+
and the second axis is a blocked interlace of args.
106+
If there is overlap, it uses the first in order.
107+
"""
108+
struct PiecewiseInterlace{T, Args} <: AbstractInterlaceBasis{T}
109+
args::Args
110+
end
111+
112+
PiecewiseInterlace{T}(args...) where T = PiecewiseInterlace{T,typeof(args)}(args)
113+
PiecewiseInterlace(args...) = PiecewiseInterlace{mapreduce(eltype,promote_type,args)}(args...)
114+
PiecewiseInterlace{T}(args::AbstractVector) where T = PiecewiseInterlace{T,typeof(args)}(args)
115+
PiecewiseInterlace(args::AbstractVector) = PiecewiseInterlace{eltype(eltype(args))}(args)
116+
117+
interlacebasis(::PiecewiseInterlace, args...) = PiecewiseInterlace(args...)
118+
119+
120+
axes(A::PiecewiseInterlace) = (union(axes.(A.args,1)...), LazyBandedMatrices._block_vcat_axes(unitblocks.(axes.(A.args,2))...))
121+
122+
==(A::PiecewiseInterlace, B::PiecewiseInterlace) = all(A.args .== B.args)
123+
124+
125+
function QuasiArrays._getindex(::Type{IND}, A::PiecewiseInterlace{T}, (x,j)::IND) where {IND,T}
126+
Jj = findblockindex(axes(A,2), j)
127+
@boundscheck x in axes(A,1) || throw(BoundsError(A, (x,j)))
128+
J = Int(block(Jj))
129+
i = blockindex(Jj)
130+
x in axes(A.args[i],1) && return A.args[i][x, J]
131+
zero(T)
132+
end
133+
134+
function \(A::AbstractInterlaceBasis, B::AbstractInterlaceBasis)
135+
axes(A,1) == axes(B,1) || throw(DimensionMismatch())
136+
T = promote_type(eltype(A),eltype(B))
137+
A == B && return Eye{T}((axes(A,2),))
138+
BlockBroadcastArray{T}(Diagonal, unitblocks.((\).(A.args, B.args))...)
139+
end
140+
141+
@simplify function *(D::Derivative, S::AbstractInterlaceBasis)
142+
axes(D,2) == axes(S,1) || throw(DimensionMismatch())
143+
args = arguments.(Ref(ApplyLayout{typeof(*)}()), Derivative.(axes.(S.args,1)) .* S.args)
144+
all(length.(args) .== 2) || error("Not implemented")
145+
interlacebasis(S, map(first, args)...) * BlockBroadcastArray{promote_type(eltype(D),eltype(S))}(Diagonal, unitblocks.(last.(args))...)
146+
end
147+
148+
struct PiecewiseFactorization{T,FF,Ax} <: Factorization{T}
149+
factorizations::FF
150+
axes::Ax
151+
end
152+
153+
PiecewiseFactorization{T}(fac, ax) where T = PiecewiseFactorization{T,typeof(fac),typeof(ax)}(fac, ax)
154+
155+
function \(F::PiecewiseFactorization{T}, v::AbstractQuasiVector) where {T}
156+
BlockBroadcastArray{T}(vcat, unitblocks.((\).(F.factorizations, getindex.(Ref(v), F.axes)))...)
157+
end
158+
159+
function factorize(V::SubQuasiArray{T,2,<:AbstractInterlaceBasis,<:Tuple{Inclusion,BlockSlice{BlockRange1{OneTo{Int}}}}}) where T
160+
P = parent(V)
161+
_,jr = parentindices(V)
162+
N = Int(last(jr.block))
163+
PiecewiseFactorization{T}(factorize.(view.(P.args, :, Ref(Base.OneTo(N)))), axes.(P.args,1))
164+
end
165+
166+
function factorize(V::SubQuasiArray{<:Any,2,<:AbstractInterlaceBasis,<:Tuple{Inclusion,AbstractVector{Int}}})
167+
P = parent(V)
168+
_,jr = parentindices(V)
169+
J = findblock(axes(P,2),maximum(jr))
170+
ProjectionFactorization(factorize(P[:,Block.(OneTo(Int(J)))]), jr)
171+
end

src/lanczos.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ getindex(R::LanczosConversion, k::AbstractUnitRange, j::AbstractUnitRange) = _la
8787

8888
inv(R::LanczosConversion) = ApplyArray(inv, R)
8989

90-
9190
Base.BroadcastStyle(::Type{<:LanczosConversion}) = LazyArrays.LazyArrayStyle{2}()
9291

9392
struct LanczosConversionLayout <: AbstractLazyLayout end
@@ -157,6 +156,15 @@ struct LanczosPolynomial{T,Weight,Basis} <: OrthogonalPolynomial{T}
157156
data::LanczosData{T}
158157
end
159158

159+
function LanczosPolynomial(w_in::AbstractQuasiVector, P::AbstractQuasiMatrix)
160+
Q = normalize(P)
161+
wQ = weighted(Q)
162+
w = wQ * (wQ \ w_in) # expand weight in basis
163+
LanczosPolynomial(w, Q, LanczosData(w, Q))
164+
end
165+
166+
LanczosPolynomial(w::AbstractQuasiVector) = LanczosPolynomial(w, orthonormalpolynomial(singularities(w)))
167+
160168
==(A::LanczosPolynomial, B::LanczosPolynomial) = A.w == B.w
161169
==(::LanczosPolynomial, ::OrthogonalPolynomial) = false # TODO: fix
162170
==(::OrthogonalPolynomial, ::LanczosPolynomial) = false # TODO: fix
@@ -172,14 +180,6 @@ orthogonalpolynomial(w::AbstractQuasiVector) = OrthogonalPolynomial(w)
172180
orthogonalpolynomial(w::SubQuasiArray) = orthogonalpolynomial(parent(w))[parentindices(w)[1],:]
173181
orthonormalpolynomial(w::AbstractQuasiVector) = normalize(orthogonalpolynomial(w))
174182

175-
function LanczosPolynomial(w_in::AbstractQuasiVector, P::AbstractQuasiMatrix)
176-
Q = normalize(P)
177-
wQ = weighted(Q)
178-
w = wQ * (wQ \ w_in) # expand weight in basis
179-
LanczosPolynomial(w, Q, LanczosData(w, Q))
180-
end
181-
182-
LanczosPolynomial(w::AbstractQuasiVector) = LanczosPolynomial(w, orthonormalpolynomial(singularities(w)))
183183

184184

185185

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ include("test_ratios.jl")
3939
include("test_normalized.jl")
4040
include("test_lanczos.jl")
4141
include("test_stieltjes.jl")
42+
include("test_interlace.jl")
4243

4344
@testset "Auto-diff" begin
4445
U = Ultraspherical(1)

test/test_interlace.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using ClassicalOrthogonalPolynomials, BlockArrays, LazyBandedMatrices, Test
2+
import ClassicalOrthogonalPolynomials: PiecewiseInterlace
3+
4+
@testset "Piecewise" begin
5+
T1,T2 = chebyshevt((-1)..0), chebyshevt(0..1)
6+
U1,U2 = chebyshevu((-1)..0), chebyshevu(0..1)
7+
T = PiecewiseInterlace(T1, T2)
8+
U = PiecewiseInterlace(U1, U2)
9+
D = U \ (Derivative(axes(T,1))*T)
10+
C = U \ T
11+
12+
A = BlockVcat(T[-1,:]',
13+
BlockBroadcastArray(vcat,unitblocks(T1[end,:]),-unitblocks(T2[begin,:]))',
14+
D-C)
15+
N = 20
16+
M = BlockArray(A[Block.(1:N+1), Block.(1:N)])
17+
18+
u = M \ [exp(-1); zeros(size(M,1)-1)]
19+
x = axes(T,1)
20+
21+
F = factorize(T[:,Block.(Base.OneTo(N))])
22+
@test F \ exp.(x) (T \ exp.(x))[Block.(1:N)] u
23+
end

test/test_lanczos.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using ClassicalOrthogonalPolynomials, BandedMatrices, ArrayLayouts, Test
2-
import ClassicalOrthogonalPolynomials: recurrencecoefficients, PaddedLayout, orthogonalityweight, golubwelsch
1+
using ClassicalOrthogonalPolynomials, BandedMatrices, ArrayLayouts, QuasiArrays, ContinuumArrays, Test
2+
import ClassicalOrthogonalPolynomials: recurrencecoefficients, PaddedLayout, orthogonalityweight, golubwelsch, LanczosData
33

44
@testset "Lanczos" begin
55
@testset "Legendre" begin
@@ -247,4 +247,15 @@ import ClassicalOrthogonalPolynomials: recurrencecoefficients, PaddedLayout, ort
247247
Q = LanczosPolynomial(@. x^m*(1-x)^m*(2-x)^m)
248248
@test Q[0.1,:]'*(Q \exp.(x)) exp(0.1)
249249
end
250+
251+
@testset "1/sqrt(1-x^2) + δ₂" begin
252+
U = ChebyshevU()
253+
W = π/2*I + (Base.unsafe_getindex(U,2,:) * Base.unsafe_getindex(U,2,:)')
254+
X = jacobimatrix(U)
255+
dat = LanczosData(X, W);
256+
w = QuasiArrays.UnionVcat(ChebyshevUWeight(), DiracDelta(2))
257+
Q = LanczosPolynomial(w, U, dat);
258+
R = U \ Q;
259+
@test R[1:5,1:5] isa Matrix{Float64}
260+
end
250261
end

0 commit comments

Comments
 (0)