Skip to content

Commit c7ebc7a

Browse files
authored
Adaptive Cholesky (#76)
* Start adaptive Cholesky * ∞ cholesky works * adaptive cholesky works * Speed up Cholesky solve * Update test_infcholesky.jl * test pass * update Project * Update Project.toml
1 parent 85debaa commit c7ebc7a

File tree

9 files changed

+148
-12
lines changed

9 files changed

+148
-12
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
matrix:
1212
version:
1313
- '1.5'
14-
- '^1.6.0-0'
14+
- '1'
1515
os:
1616
- ubuntu-latest
1717
- macOS-latest

Project.toml

Lines changed: 5 additions & 5 deletions
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.5.5"
3+
version = "0.5.6"
44

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

1818
[compat]
19-
ArrayLayouts = "0.6"
20-
BandedMatrices = "0.16"
21-
BlockArrays = "0.14.5, 0.15"
19+
ArrayLayouts = "0.7"
20+
BandedMatrices = "0.16.9"
21+
BlockArrays = "0.15"
2222
BlockBandedMatrices = "0.10"
2323
FillArrays = "0.11"
2424
InfiniteArrays = "0.10.6"
25-
LazyArrays = "0.20.2, 0.21"
25+
LazyArrays = "0.21"
2626
LazyBandedMatrices = "0.5"
2727
MatrixFactorizations = "0.8"
2828
SemiseparableMatrices = "0.2.3"

src/InfiniteLinearAlgebra.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import Base.Broadcast: BroadcastStyle, Broadcasted, broadcasted
99

1010
import ArrayLayouts: colsupport, rowsupport, triangularlayout, MatLdivVec, triangulardata, TriangularLayout, TridiagonalLayout,
1111
sublayout, _qr, __qr, MatLmulVec, MatLmulMat, AbstractQLayout, materialize!, diagonaldata, subdiagonaldata, supdiagonaldata,
12-
_bidiag_forwardsub!, mulreduce, RangeCumsum, _factorize
12+
_bidiag_forwardsub!, mulreduce, RangeCumsum, _factorize, transposelayout, ldiv!, lmul!, mul
1313
import BandedMatrices: BandedMatrix, _BandedMatrix, AbstractBandedMatrix, bandeddata, bandwidths, BandedColumns, bandedcolumns,
1414
_default_banded_broadcast, banded_similar
1515
import FillArrays: AbstractFill, getindex_value, axes_print_matrix_row
1616
import InfiniteArrays: OneToInf, InfUnitRange, Infinity, PosInfinity, InfiniteCardinal, InfStepRange, AbstractInfUnitRange, InfAxes, InfRanges
17-
import LinearAlgebra: lmul!, ldiv!, matprod, qr, AbstractTriangular, AbstractQ, adjoint, transpose
17+
import LinearAlgebra: matprod, qr, AbstractTriangular, AbstractQ, adjoint, transpose, AdjOrTrans
1818
import LazyArrays: applybroadcaststyle, CachedArray, CachedMatrix, CachedVector, DenseColumnMajor, FillLayout, ApplyMatrix, check_mul_axes, ApplyStyle, LazyArrayApplyStyle, LazyArrayStyle,
1919
resizedata!, MemoryLayout,
2020
factorize, sub_materialize, LazyLayout, LazyArrayStyle, layout_getindex,
@@ -25,7 +25,7 @@ import MatrixFactorizations: ul, ul!, _ul, ql, ql!, _ql, QLPackedQ, getL, getR,
2525

2626
import BlockArrays: AbstractBlockVecOrMat, sizes_from_blocks, _length, BlockedUnitRange, blockcolsupport, BlockLayout, AbstractBlockLayout, BlockSlice
2727

28-
import BandedMatrices: BandedMatrix, bandwidths, AbstractBandedLayout, _banded_qr!, _banded_qr, _BandedMatrix
28+
import BandedMatrices: BandedMatrix, bandwidths, AbstractBandedLayout, _banded_qr!, _banded_qr, _BandedMatrix, banded_chol!
2929

3030
import LazyBandedMatrices: ApplyBandedLayout, BroadcastBandedLayout, _krontrav_axes, _block_interlace_axes, LazyBandedLayout,AbstractLazyBandedLayout
3131

@@ -66,6 +66,7 @@ include("banded/infqltoeplitz.jl")
6666
include("infql.jl")
6767
include("infqr.jl")
6868
include("inful.jl")
69+
include("infcholesky.jl")
6970

7071

7172
end # module

src/banded/infqltoeplitz.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ struct ProductQ{T,QQ<:Tuple} <: AbstractQ{T}
8888
Qs::QQ
8989
end
9090

91+
ArrayLayouts.@layoutmatrix ProductQ
92+
ArrayLayouts.@_layoutlmul ProductQ
93+
9194
ProductQ(Qs::AbstractMatrix...) = ProductQ{mapreduce(eltype,promote_type,Qs),typeof(Qs)}(Qs)
9295

9396
adjoint(Q::ProductQ) = ProductQ(reverse(map(adjoint,Q.Qs))...)
@@ -109,8 +112,7 @@ function _productq_mul(A::ProductQ{T}, x::AbstractVector{S}) where {T,S}
109112
lmul!(A, Base.copymutable(convert(AbstractVector{TS},x)))
110113
end
111114

112-
(*)(A::ProductQ, x::AbstractVector) = _productq_mul(A, x)
113-
(*)(A::ProductQ, x::LazyVector) = _productq_mul(A, x)
115+
mul(A::ProductQ, x::AbstractVector) = _productq_mul(A, x)
114116

115117

116118
# LQ where Q is a product of orthogonal operations

src/infcholesky.jl

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
2+
mutable struct AdaptiveCholeskyFactors{T,DM<:AbstractMatrix{T},M<:AbstractMatrix{T}} <: LayoutMatrix{T}
3+
data::CachedMatrix{T,DM,M}
4+
ncols::Int
5+
end
6+
7+
size(U::AdaptiveCholeskyFactors) = size(U.data.array)
8+
bandwidths(A::AdaptiveCholeskyFactors) = (0,bandwidth(A.data,2))
9+
AdaptiveCholeskyFactors(A::Symmetric) = AdaptiveCholeskyFactors(cache(parent(A)),0)
10+
MemoryLayout(::Type{AdaptiveCholeskyFactors{T,DM,M}}) where {T,DM,M} = AdaptiveLayout{typeof(MemoryLayout(DM))}()
11+
12+
13+
function partialcholesky!(F::AdaptiveCholeskyFactors{T,<:BandedMatrix}, n::Int) where T
14+
if n > F.ncols
15+
_,u = bandwidths(F.data.array)
16+
resizedata!(F.data,n+u,n+u);
17+
ncols = F.ncols
18+
kr = ncols+1:n
19+
factors = view(F.data.data,kr,kr)
20+
banded_chol!(factors, UpperTriangular)
21+
# multiply remaining columns
22+
U1 = UpperTriangular(view(F.data.data,n-u+1:n,n-u+1:n))
23+
B = view(F.data.data,n-u+1:n,n+1:n+u)
24+
ldiv!(U1',B)
25+
muladd!(-one(T),B',B,one(T),view(F.data.data,n+1:n+u,n+1:n+u))
26+
F.ncols = n
27+
end
28+
F
29+
end
30+
31+
function getindex(F::AdaptiveCholeskyFactors, k::Int, j::Int)
32+
partialcholesky!(F, max(k,j))
33+
F.data.data[k,j]
34+
end
35+
36+
37+
adaptivecholesky(A) = Cholesky(AdaptiveCholeskyFactors(A), :U, 0)
38+
39+
40+
ArrayLayouts._cholesky(::SymmetricLayout{<:AbstractBandedLayout}, ::NTuple{2,OneToInf{Int}}, A) = adaptivecholesky(A)
41+
42+
function colsupport(F::AdaptiveCholeskyFactors, j)
43+
partialcholesky!(F, maximum(j)+bandwidth(F,2))
44+
colsupport(F.data.data, j)
45+
end
46+
47+
function rowsupport(F::AdaptiveCholeskyFactors, j)
48+
partialcholesky!(F, maximum(j)+bandwidth(F,2))
49+
rowsupport(F.data.data, j)
50+
end
51+
52+
colsupport(F::AdjOrTrans{<:Any,<:AdaptiveCholeskyFactors}, j) = rowsupport(parent(F), j)
53+
rowsupport(F::AdjOrTrans{<:Any,<:AdaptiveCholeskyFactors}, j) = colsupport(parent(F), j)
54+
55+
function materialize!(M::MatLdivVec{<:TriangularLayout{'L','N',<:AdaptiveLayout},<:PaddedLayout})
56+
A,B = M.A,M.B
57+
T = eltype(M)
58+
COLGROWTH = 1000 # rate to grow columns
59+
tol = floatmin(real(T))
60+
61+
require_one_based_indexing(B)
62+
mA, nA = size(A)
63+
mB = length(B)
64+
if mA != mB
65+
throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)"))
66+
end
67+
sB = B.datasize[1]
68+
l,_ = bandwidths(A)
69+
70+
jr = 1:min(COLGROWTH,nA)
71+
72+
P = parent(parent(A))
73+
74+
@inbounds begin
75+
while first(jr) < nA
76+
j = first(jr)
77+
cs = colsupport(A, last(jr))
78+
cs_max = maximum(cs)
79+
kr = j:cs_max
80+
resizedata!(B, min(cs_max,mB))
81+
if (j > sB && maximum(abs,view(B.data,j:last(colsupport(P,j)))) tol)
82+
break
83+
end
84+
partialcholesky!(P, min(cs_max,nA))
85+
U_N = UpperTriangular(view(P.data.data, jr, jr))
86+
ldiv!(U_N', view(B.data, jr))
87+
jr1 = last(jr)-l+1:last(jr)
88+
jr2 = last(jr)+1:last(jr)+l
89+
muladd!(-one(T), view(P.data.data, jr1,jr2)', view(B.data,jr1), one(T), view(B.data,jr2))
90+
jr = last(jr)+1:min(last(jr)+COLGROWTH,nA)
91+
end
92+
end
93+
B
94+
end
95+
96+
function ldiv!(R::UpperTriangular{<:Any,<:AdaptiveCholeskyFactors}, B::CachedVector{<:Any,<:Any,<:Zeros{<:Any,1}})
97+
n = B.datasize[1]
98+
partialcholesky!(parent(R), n)
99+
ldiv!(UpperTriangular(view(parent(R).data.data,oneto(n),oneto(n))), view(B.data,oneto(n)))
100+
B
101+
end

src/infqr.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mutable struct AdaptiveQRData{T,DM<:AbstractMatrix{T},M<:AbstractMatrix{T}}
55
ncols::Int
66
end
77

8-
function AdaptiveQRData(::AbstractBandedLayout, A::AbstractMatrix{T}) where T
8+
function AdaptiveQRData(::Union{SymmetricLayout{<:AbstractBandedLayout},AbstractBandedLayout}, A::AbstractMatrix{T}) where T
99
l,u = bandwidths(A)
1010
data = BandedMatrix{T}(undef,(2l+u+1,0),(l,l+u)) # pad super
1111
AdaptiveQRData(CachedArray(data,A), Vector{T}(), 0)
@@ -94,6 +94,7 @@ end
9494
struct AdaptiveLayout{M} <: MemoryLayout end
9595
MemoryLayout(::Type{AdaptiveQRFactors{T,DM,M}}) where {T,DM,M} = AdaptiveLayout{typeof(MemoryLayout(DM))}()
9696
triangularlayout(::Type{Tri}, ::ML) where {Tri, ML<:AdaptiveLayout} = Tri{ML}()
97+
transposelayout(A::AdaptiveLayout{ML}) where ML = AdaptiveLayout{typeof(transposelayout(ML()))}()
9798

9899
size(F::AdaptiveQRFactors) = size(F.data.data)
99100
axes(F::AdaptiveQRFactors) = axes(F.data.data)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,4 @@ include("test_hessenbergq.jl")
489489
include("test_infql.jl")
490490
include("test_infqr.jl")
491491
include("test_inful.jl")
492+
include("test_infcholesky.jl")

test/test_infcholesky.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using InfiniteLinearAlgebra, LinearAlgebra, BandedMatrices, ArrayLayouts, Test
2+
3+
@testset "infinite-cholesky" begin
4+
S = Symmetric(BandedMatrix(0 => 1:∞, 1=> Ones(∞)))
5+
b = [1; zeros(∞)]
6+
@test cholesky(S) \ b qr(S) \ b S \ b
7+
8+
# go past adaptive
9+
b = [randn(10_000); zeros(∞)]
10+
@test cholesky(S) \ b qr(S) \ b S \ b
11+
12+
@testset "singularly perturbed" begin
13+
ε = 0.0001
14+
S = Symmetric(BandedMatrix(0 => 2 .+ ε*(1:∞), 1=> -Ones(∞)))
15+
b = [1; zeros(∞)]
16+
@test cholesky(S) \ b S \ b
17+
end
18+
19+
@testset "long bandwidths" begin
20+
S = Symmetric(BandedMatrix(0 => 1:∞, 50=> Ones(∞)))
21+
b = [1; zeros(∞)]
22+
@test cholesky(S) \ b qr(S) \ b S \ b
23+
end
24+
end

test/test_infqr.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ import SemiseparableMatrices: AlmostBandedLayout, VcatAlmostBandedLayout
148148
b = [[1,2,3]; zeros(∞)]
149149
@test A \ b == [ones(3); zeros(∞)]
150150
end
151+
152+
@testset "Symmetric" begin
153+
A = Symmetric(BandedMatrix(0 => 1:∞, 1=> Ones(∞)))
154+
= BandedMatrix(0 => 1:∞, 1=> Ones(∞), -1=> Ones(∞))
155+
@test qr(A).R[1:10,1:10] qr(Ã).R[1:10,1:10]
156+
end
151157
end
152158

153159
@testset "almost-banded" begin

0 commit comments

Comments
 (0)