Skip to content

Commit 4209d46

Browse files
authored
Add tridiagonal Reverse Cholesky (#167)
* Generalise QL * tridiagonal reverse cholesky * Update test_infql.jl * v0.7.5
1 parent d120f45 commit 4209d46

10 files changed

+126
-39
lines changed

Project.toml

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "InfiniteLinearAlgebra"
22
uuid = "cde9dba0-b1de-11e9-2c62-0bab9446c55c"
3-
version = "0.7.4"
3+
version = "0.7.5"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -16,17 +16,22 @@ MatrixFactorizations = "a3b82374-2e81-5b9e-98ce-41277c0e4c87"
1616
SemiseparableMatrices = "f8ebbe35-cbfb-4060-bf7f-b10e4670cf57"
1717

1818
[compat]
19-
Aqua = "0.6"
20-
ArrayLayouts = "1.0.12"
19+
Aqua = "0.8"
20+
ArrayLayouts = "1.9.2"
2121
BandedMatrices = "0.17.19, 1"
2222
BlockArrays = "0.16.14"
2323
BlockBandedMatrices = "0.12"
2424
FillArrays = "1"
2525
InfiniteArrays = "0.13"
2626
LazyArrays = "1.3"
27-
LazyBandedMatrices = "0.8.7, 0.9"
28-
MatrixFactorizations = "2.1"
27+
LazyBandedMatrices = "0.9"
28+
LinearAlgebra = "1"
29+
MatrixFactorizations = "2.2"
30+
Random = "1"
2931
SemiseparableMatrices = "0.3"
32+
SpecialFunctions = "2"
33+
StaticArrays = "1"
34+
Test = "1"
3035
julia = "1.9"
3136

3237
[extras]

src/InfiniteLinearAlgebra.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import ArrayLayouts: colsupport, rowsupport, triangularlayout, MatLdivVec, trian
1414
_bidiag_forwardsub!, mulreduce, RangeCumsum, _factorize, transposelayout, ldiv!, lmul!, mul, CNoPivot
1515
import BandedMatrices: BandedMatrix, _BandedMatrix, AbstractBandedMatrix, bandeddata, bandwidths, BandedColumns, bandedcolumns, BandedLayout,
1616
_default_banded_broadcast, banded_similar
17-
import FillArrays: AbstractFill, getindex_value, axes_print_matrix_row
17+
import FillArrays: AbstractFill, getindex_value, axes_print_matrix_row, AbstractFillMatrix, AbstractFillVector
1818
import InfiniteArrays: OneToInf, InfUnitRange, Infinity, PosInfinity, InfiniteCardinal, InfStepRange, AbstractInfUnitRange, InfAxes, InfRanges
1919
import LinearAlgebra: matprod, qr, AbstractTriangular, AbstractQ, adjoint, transpose, AdjOrTrans, copymutable
2020
import LazyArrays: applybroadcaststyle, CachedArray, CachedMatrix, CachedVector, DenseColumnMajor, FillLayout, ApplyMatrix, check_mul_axes, LazyArrayStyle,
2121
resizedata!, MemoryLayout, AbstractLazyLayout,
2222
factorize, sub_materialize, LazyLayout, LazyArrayStyle, layout_getindex,
2323
applylayout, ApplyLayout, PaddedLayout, CachedLayout, AbstractCachedVector, AbstractCachedMatrix, cacheddata, zero!, MulAddStyle, ApplyArray,
2424
LazyArray, LazyMatrix, LazyVector, paddeddata, arguments, resizedata!, simplifiable, simplify, LazyLayouts
25-
import MatrixFactorizations: ul, ul!, _ul, ql, ql!, _ql, QLPackedQ, getL, getR, getQ, getU, reflector!, reflectorApply!, QL, QR, QRPackedQ,
25+
import MatrixFactorizations: ul, ul!, ul_layout, ql, ql!, ql_layout, reversecholesky_layout, QLPackedQ, getL, getR, getQ, getU, reflector!, reflectorApply!, QL, QR, QRPackedQ,
2626
QRPackedQLayout, AdjQRPackedQLayout, QLPackedQLayout, AdjQLPackedQLayout, LayoutQ, copymutable_size
2727

2828
import BlockArrays: AbstractBlockVecOrMat, sizes_from_blocks, _length, BlockedUnitRange, blockcolsupport, BlockLayout, AbstractBlockLayout, BlockSlice
@@ -121,6 +121,7 @@ include("banded/hessenbergq.jl")
121121
include("banded/infbanded.jl")
122122
include("blockbanded/blockbanded.jl")
123123
include("banded/infqltoeplitz.jl")
124+
include("banded/infreversecholeskytoeplitz.jl")
124125
include("infql.jl")
125126
include("infqr.jl")
126127
include("inful.jl")

src/banded/infbanded.jl

+34-15
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ sub_materialize(_, V::SubArray{<:Any,1,<:AbstractMatrix,Tuple{InfBandCartesianIn
3434
_inf_banded_sub_materialize(MemoryLayout(parent(V)), V)
3535

3636
const TriToeplitz{T} = Tridiagonal{T,Fill{T,1,Tuple{OneToInf{Int}}}}
37-
const ConstRowMatrix{T} = ApplyMatrix{T,typeof(*),<:Tuple{<:AbstractVector,<:AbstractFill{<:Any,2,Tuple{OneTo{Int},OneToInf{Int}}}}}
37+
const ConstRowMatrix{T} = ApplyMatrix{T,typeof(*),<:Tuple{<:AbstractVector,<:AbstractFillMatrix{<:Any,Tuple{OneTo{Int},OneToInf{Int}}}}}
3838
const PertConstRowMatrix{T} = Hcat{T,<:Tuple{Array{T},<:ConstRowMatrix{T}}}
3939
const InfToeplitz{T} = BandedMatrix{T,<:ConstRowMatrix{T},OneToInf{Int}}
4040
const PertToeplitz{T} = BandedMatrix{T,<:PertConstRowMatrix{T},OneToInf{Int}}
@@ -337,10 +337,26 @@ for Typ in (:ConstRows, :PertConstRows)
337337
end
338338
end
339339

340+
"""
341+
TridiagonalToeplitzLayout
342+
343+
represents a matrix which is tridiagonal and toeplitz. Must support
344+
`subdiagonalconstant`, `diagonalconstant`, `supdiagonalconstant`.
345+
"""
340346
struct TridiagonalToeplitzLayout <: AbstractLazyBandedLayout end
341347
const BandedToeplitzLayout = BandedColumns{ConstRows}
342348
const PertToeplitzLayout = BandedColumns{PertConstRows}
343349
const PertTriangularToeplitzLayout{UPLO,UNIT} = TriangularLayout{UPLO,UNIT,BandedColumns{PertConstRows}}
350+
struct BidiagonalToeplitzLayout <: AbstractLazyBandedLayout end
351+
struct PertBidiagonalToeplitzLayout <: AbstractLazyBandedLayout end
352+
struct PertTridiagonalToeplitzLayout <: AbstractLazyBandedLayout end
353+
354+
const InfToeplitzLayouts = Union{TridiagonalToeplitzLayout, BandedToeplitzLayout, BidiagonalToeplitzLayout,
355+
PertToeplitzLayout, PertTriangularToeplitzLayout, PertBidiagonalToeplitzLayout, PertTridiagonalToeplitzLayout}
356+
357+
subdiagonalconstant(A) = getindex_value(subdiagonaldata(A))
358+
diagonalconstant(A) = getindex_value(diagonaldata(A))
359+
supdiagonalconstant(A) = getindex_value(supdiagonaldata(A))
344360

345361

346362
_BandedMatrix(::BandedToeplitzLayout, A::AbstractMatrix) =
@@ -428,18 +444,13 @@ _bandedfill_mul(M::MulAdd, ::Tuple{Any,InfAxes}, ::Tuple{InfAxes,InfAxes}) = App
428444
_bandedfill_mul(M::MulAdd, ::Tuple{InfAxes,InfAxes}, ::Tuple{InfAxes,Any}) = ApplyArray(*, M.A, M.B)
429445
_bandedfill_mul(M::MulAdd, ::Tuple{Any,InfAxes}, ::Tuple{InfAxes,Any}) = ApplyArray(*, M.A, M.B)
430446

431-
mulreduce(M::Mul{BandedToeplitzLayout, BandedToeplitzLayout}) = ApplyArray(M)
432-
mulreduce(M::Mul{BandedToeplitzLayout}) = ApplyArray(M)
433-
mulreduce(M::Mul{BandedToeplitzLayout,<:PaddedLayout}) = MulAdd(M)
434-
mulreduce(M::Mul{<:Any, BandedToeplitzLayout}) = ApplyArray(M)
435-
mulreduce(M::Mul{<:BandedColumns{<:AbstractFillLayout}, PertToeplitzLayout}) = ApplyArray(M)
436-
mulreduce(M::Mul{<:PertToeplitzLayout, <:BandedColumns{<:AbstractFillLayout}}) = ApplyArray(M)
437-
mulreduce(M::Mul{<:BandedColumns{<:AbstractFillLayout}, BandedToeplitzLayout}) = ApplyArray(M)
438-
mulreduce(M::Mul{BandedToeplitzLayout, <:BandedColumns{<:AbstractFillLayout}}) = ApplyArray(M)
439-
mulreduce(M::Mul{<:AbstractQLayout, BandedToeplitzLayout}) = ApplyArray(M)
440-
mulreduce(M::Mul{<:AbstractQLayout, PertToeplitzLayout}) = ApplyArray(M)
441-
mulreduce(M::Mul{<:DiagonalLayout, BandedToeplitzLayout}) = Lmul(M)
442-
mulreduce(M::Mul{BandedToeplitzLayout, <:DiagonalLayout}) = Rmul(M)
447+
mulreduce(M::Mul{<:InfToeplitzLayouts, <:InfToeplitzLayouts}) = ApplyArray(M)
448+
mulreduce(M::Mul{<:InfToeplitzLayouts}) = ApplyArray(M)
449+
mulreduce(M::Mul{<:InfToeplitzLayouts,<:PaddedLayout}) = MulAdd(M)
450+
mulreduce(M::Mul{<:Any, <:InfToeplitzLayouts}) = ApplyArray(M)
451+
mulreduce(M::Mul{<:AbstractQLayout, <:InfToeplitzLayouts}) = ApplyArray(M)
452+
mulreduce(M::Mul{<:DiagonalLayout, <:InfToeplitzLayouts}) = Lmul(M)
453+
mulreduce(M::Mul{<:InfToeplitzLayouts, <:DiagonalLayout}) = Rmul(M)
443454

444455

445456
function _bidiag_forwardsub!(M::Ldiv{<:Any,<:PaddedLayout})
@@ -491,8 +502,6 @@ for Typ in (:(LinearAlgebra.Tridiagonal{<:Any,<:InfFill}),
491502
end
492503
end
493504

494-
struct BidiagonalToeplitzLayout <: AbstractLazyBandedLayout end
495-
496505
for Typ in (:(LinearAlgebra.Bidiagonal{<:Any,<:InfFill}),
497506
:(LazyBandedMatrices.Bidiagonal{<:Any,<:InfFill,<:InfFill}))
498507
@eval begin
@@ -501,6 +510,9 @@ for Typ in (:(LinearAlgebra.Bidiagonal{<:Any,<:InfFill}),
501510
end
502511
end
503512

513+
*(A::LinearAlgebra.Bidiagonal{<:Any,<:InfFill}, B::LinearAlgebra.Bidiagonal{<:Any,<:InfFill}) =
514+
mul(A, B)
515+
504516
# fall back for Ldiv
505517
triangularlayout(::Type{<:TriangularLayout{UPLO,'N'}}, ::TridiagonalToeplitzLayout) where UPLO = BidiagonalToeplitzLayout()
506518
materialize!(L::MatLdivVec{BidiagonalToeplitzLayout,Lay}) where Lay = materialize!(Ldiv{BidiagonalLayout{FillLayout,FillLayout},Lay}(L.A, L.B))
@@ -518,3 +530,10 @@ copy(A::Transpose{T,<:BandedMatrix{T,<:Any,OneToInf{Int}}}) where T = transpose(
518530

519531
Base.typed_hcat(::Type{T}, A::BandedMatrix{<:Any,<:Any,OneToInf{Int}}, B::AbstractVecOrMat...) where T = Hcat{T}(A, B...)
520532

533+
534+
535+
###
536+
# SymTriPertToeplitz
537+
###
538+
539+
MemoryLayout(::Type{<:SymTriPertToeplitz}) = PertTridiagonalToeplitzLayout()

src/banded/infqltoeplitz.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ end
4141

4242

4343

44-
function ql(Op::TriToeplitz{T}; kwds...) where {T<:Real}
45-
Z, A, B = Op.dl.value, Op.d.value, Op.du.value
44+
function ql_layout(::TridiagonalToeplitzLayout, ::NTuple{2,OneToInf{Int}}, Op::AbstractMatrix{T}, args...; kwds...) where {T<:Real}
45+
Z, A, B = subdiagonalconstant(Op), diagonalconstant(Op), supdiagonalconstant(Op)
4646
d, e = tail_de([Z, A, B]; kwds...) # fixed point of QL but with two Qs, one that changes sign
4747
X = [Z A B; zero(T) d e]
4848
F = ql_X!(X)
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
function reversecholesky_layout(::TridiagonalToeplitzLayout, ::NTuple{2,OneToInf{Int}}, A, ::NoPivot; kwds...)
2+
# [a b = [α β * [α
3+
# b a ⋱ ⋱ ⋱] β α
4+
# ⋱ ⋱]
5+
# [a b' [a b' [1 b'inv(U)' ] [a - b'inv(U)'inv(U)*b [1
6+
# b A ] = b U*U'] = U ] I] inv(U)b U']
7+
8+
# since inv(U) = [inv(α) …] we have inv(U)*(b*e₁) = b/α
9+
# we also assume Toeplitz structure so that α^2 = a - b'inv(U)'inv(U)*b = a - b^2/α^2
10+
# Thus we have a Quadratic equation:
11+
#
12+
# α^4 - a*α^2 + b^2 = 0
13+
#
14+
# i.e. α^2 = (a ± sqrt(a^2 - 4b^2))/2.
15+
# We also have αβ = b.
16+
17+
a = diagonalconstant(A)
18+
b = supdiagonalconstant(A)
19+
@assert b == subdiagonalconstant(A)
20+
21+
α² = (a + sqrt(a^2 - 4b^2))/2
22+
# (a - sqrt(a^2 - 4b^2))/2 other branch gives non-invertible U
23+
24+
α = sqrt(α²)
25+
β = b/α
26+
27+
ReverseCholesky(Bidiagonal(Fill(α,∞), Fill(β,∞), :U), 'U', 0)
28+
end
29+
30+
function reversecholesky_layout(::PertTridiagonalToeplitzLayout, ::NTuple{2,OneToInf{Int}}, A, ::NoPivot; kwds...)
31+
a = diagonaldata(A)
32+
aₙ,a∞ = arguments(vcat, a)
33+
b = supdiagonaldata(A)
34+
bₙ,b∞ = arguments(vcat, b)
35+
U∞, = reversecholesky(SymTridiagonal(a∞, b∞))
36+
37+
n = max(length(aₙ), length(bₙ)+1)
38+
Aₙ = SymTridiagonal([aₙ; float(a∞[1:(n-length(aₙ))])], [bₙ; float(b∞[1:(n-length(bₙ)-1)])])
39+
α = U∞[1,1]
40+
b = getindex_value(b∞)
41+
Aₙ[end,end] -= b^2/α^2
42+
Uₙ, = reversecholesky(Aₙ)
43+
ReverseCholesky(Bidiagonal([Uₙ.dv; U∞.dv], [Uₙ.ev; U∞.ev], :U), 'U', 0)
44+
end

src/infql.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ function materialize!(M::MatLdivVec{<:TriangularLayout{'L','N',BandedColumns{Per
281281
b
282282
end
283283

284-
_ql(layout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...) = error("Not implemented")
284+
ql_layout(layout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...) = error("Not implemented")
285285

286286
_data_tail(::PaddedLayout, a) = paddeddata(a), zero(eltype(a))
287287
_data_tail(::AbstractFillLayout, a) = Vector{eltype(a)}(), getindex_value(a)
@@ -293,7 +293,7 @@ function _data_tail(::ApplyLayout{typeof(vcat)}, a)
293293
end
294294
_data_tail(a) = _data_tail(MemoryLayout(a), a)
295295

296-
function _ql(::SymTridiagonalLayout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...)
296+
function ql_layout(::Union{PertTridiagonalToeplitzLayout,SymTridiagonalLayout}, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...)
297297
T = eltype(A)
298298
d,d∞ = _data_tail(A.dv)
299299
ev,ev∞ = _data_tail(A.ev)
@@ -312,7 +312,7 @@ end
312312

313313
# TODO: This should be redesigned as ql(BandedMatrix(A))
314314
# But we need to support dispatch on axes
315-
function _ql(::TridiagonalLayout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...)
315+
function ql_layout(::TridiagonalLayout, ::NTuple{2,OneToInf{Int}}, A, args...; kwds...)
316316
T = eltype(A)
317317
d,d∞ = _data_tail(A.d)
318318
dl,dl∞ = _data_tail(A.dl)

src/inful.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function _ultailL1(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix)
3434
C*(V*Diagonal(inv.(λs))/V)
3535
end
3636

37-
function _ul(::TridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{false}; check::Bool = true)
37+
function ul_layout(::TridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{false}; check::Bool = true)
3838
C = getindex_value(subdiagonaldata(J))
3939
A = getindex_value(diagonaldata(J))
4040
B = getindex_value(supdiagonaldata(J))
@@ -43,15 +43,15 @@ function _ul(::TridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{false}; check
4343
UL(Tridiagonal(Fill(convert(typeof(L),C),∞), Fill(L,∞), Fill(U,∞)), OneToInf(), 0)
4444
end
4545

46-
function _ul(::TridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{true}; check::Bool = true)
46+
function ul_layout(::TridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{true}; check::Bool = true)
4747
C = getindex_value(subdiagonaldata(J))
4848
A = getindex_value(diagonaldata(J))
4949
B = getindex_value(supdiagonaldata(J))
5050
A^2 4B*C || error("Pivotting not implemented")
5151
ul(J, Val(false))
5252
end
5353

54-
function _ul(::BlockTridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{false}; check::Bool = true)
54+
function ul_layout(::BlockTridiagonalToeplitzLayout, J::AbstractMatrix, ::Val{false}; check::Bool = true)
5555
C = getindex_value(subdiagonaldata(blocks(J)))
5656
A = getindex_value(diagonaldata(blocks(J)))
5757
B = getindex_value(supdiagonaldata(blocks(J)))

test/runtests.jl

+2-6
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ import LazyBandedMatrices: BroadcastBandedBlockBandedLayout, BroadcastBandedLayo
1515

1616
using Aqua
1717
@testset "Project quality" begin
18-
Aqua.test_all(InfiniteLinearAlgebra, ambiguities=false, unbound_args=false, piracy=false,
19-
# Project.toml formatting issue on v1.6
20-
# Pkg issue: https://github.com/JuliaLang/Pkg.jl/issues/3481
21-
# Aqua workaround: https://github.com/JuliaTesting/Aqua.jl/issues/105#issuecomment-1551405866
22-
# we only check the formatting on more recent versions
23-
project_toml_formatting = VERSION>=v"1.7")
18+
Aqua.test_all(InfiniteLinearAlgebra, ambiguities=false, unbound_args=false, piracies=false)
2419
end
2520

2621
@testset "chop" begin
@@ -477,3 +472,4 @@ include("test_infql.jl")
477472
include("test_infqr.jl")
478473
include("test_inful.jl")
479474
include("test_infcholesky.jl")
475+
include("test_infreversecholesky.jl")

test/test_infql.jl

+9-3
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ using ArrayLayouts: TriangularLayout, UnknownLayout
220220
Aplain = LinearAlgebra.Tridiagonal([[1., 2.]; Fill(1.,∞)], [[1.,2.]; Fill(3.,∞)], [[1., 2.]; Fill(1.,∞)])
221221
Qsym, Lsym = ql(Asym, 1e-10)
222222
Qplain, Lplain = ql(Aplain, 1e-10)
223-
223+
224224
@test size(Qsym) == (ℵ₀, ℵ₀)
225225
@test size(Lsym) == (ℵ₀, ℵ₀)
226226
@test size(Qplain) == (ℵ₀, ℵ₀)
@@ -250,7 +250,7 @@ using ArrayLayouts: TriangularLayout, UnknownLayout
250250
A = im * LinearAlgebra.Tridiagonal([[1., 2.]; Fill(1.,∞)], [[1.,2.]; Fill(3.,∞)], [[1., 2.]; Fill(1.,∞)])
251251
Abanded = _BandedMatrix(conj.(Hcat(Vcat(1.,A.du),A.d,A.dl)'), ℵ₀, 1, 1)
252252
F = ql(Abanded)
253-
@test (F.Q[1:51,1:51]*F.L[1:51,1:51])[1:50,1:50] A[1:50,1:50]
253+
@test (F.Q[1:51,1:51]*F.L[1:51,1:51])[1:50,1:50] A[1:50,1:50]
254254
@test MemoryLayout(F.L.data) == LazyBandedLayout()
255255
@test bandwidths(F.L) == (2,0)
256256
end
@@ -273,9 +273,15 @@ using ArrayLayouts: TriangularLayout, UnknownLayout
273273
Vcat([[-1. 1.; 1. 1.]], Fill([-1. 1.; 1. 1.], ∞)),
274274
Vcat([[0. 0.; 1. 0.]], Fill([0. 0.; 1. 0.], ∞)))
275275

276-
A[1,1] = 2
276+
A[1,1] = 2
277277

278278
x = -0.95
279279
@test ql(A-x*I).L[1,1] isa Float64
280280
end
281+
282+
@testset "SymTridiagonal QL" begin
283+
A = SymTridiagonal(Fill(3, ∞), Fill(1, ∞))
284+
Q,L = ql(A)
285+
@test (Q*L)[1:10,1:10] A[1:10,1:10]
286+
end
281287
end

test/test_infreversecholesky.jl

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using InfiniteLinearAlgebra, MatrixFactorizations, ArrayLayouts, LinearAlgebra, Test
2+
3+
4+
5+
@testset "infreversecholesky" begin
6+
@testset "Tri Toeplitz" begin
7+
A = SymTridiagonal(Fill(3, ∞), Fill(1, ∞))
8+
U, = reversecholesky(A)
9+
@test (U*U')[1:10,1:10] A[1:10,1:10]
10+
end
11+
12+
@testset "Pert Tri Toeplitz" begin
13+
A = SymTridiagonal([[4,5, 6]; Fill(3, ∞)], [[2,3]; Fill(1, ∞)])
14+
@test reversecholesky(A).U[1:100,1:100] reversecholesky(A[1:1000,1:1000]).U[1:100,1:100]
15+
end
16+
end

0 commit comments

Comments
 (0)