Skip to content

Commit 32990fc

Browse files
Create blockcholesky.jl (#126)
* Create blockcholesky.jl * Add files via upload * overload cholesk! * Including the test file in REPL will do the test * Including test_cholesky.jl in runtests.jl * Added lower Cholesky factorization * Added PD check * Changed the function name and types * Added blockbanded case * Rearrange * Capable on both BlockArray and BlockBandedArray * Changes * Update Choleksy * tests pass * Support sparse block structure * Update blockcholesky.jl * Fix tests on 1.8, use ArrayLayouts.ldiv! * Speed up BlockKron construction * Update test_blockproduct.jl * increase cov Co-authored-by: Sheehan Olver <[email protected]>
1 parent 0551a95 commit 32990fc

File tree

8 files changed

+175
-11
lines changed

8 files changed

+175
-11
lines changed

Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "BlockArrays"
22
uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
3-
version = "0.16.17"
3+
version = "0.16.18"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -18,6 +18,7 @@ OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
1818
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1919
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2020
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
21+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2122

2223
[targets]
23-
test = ["Base64", "OffsetArrays", "SparseArrays", "StaticArrays", "Test"]
24+
test = ["Base64", "OffsetArrays", "SparseArrays", "StaticArrays", "Test", "Random"]

src/BlockArrays.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import Base: @propagate_inbounds, Array, to_indices, to_index,
2222
unsafe_indices, first, last, size, length, unsafe_length,
2323
unsafe_convert,
2424
getindex, ndims, show,
25-
step,
25+
step,
2626
broadcast, eltype, convert, similar,
2727
@_inline_meta, _maybetail, tail, @_propagate_inbounds_meta, reindex,
2828
RangeIndex, Int, Integer, Number,
2929
+, -, *, /, \, min, max, isless, in, copy, copyto!, axes, @deprecate,
30-
BroadcastStyle, checkbounds, throw_boundserror,
30+
BroadcastStyle, checkbounds, throw_boundserror,
3131
ones, zeros, intersect, Slice, resize!
3232
using Base: ReshapedArray, dataids
3333
import Base: AbstractArray
@@ -36,13 +36,13 @@ import Base: AbstractArray
3636
import Base: (:), IteratorSize, iterate, axes1, strides, isempty
3737
import Base.Broadcast: broadcasted, DefaultArrayStyle, AbstractArrayStyle, Broadcasted, broadcastable
3838
import LinearAlgebra: lmul!, rmul!, AbstractTriangular, HermOrSym, AdjOrTrans,
39-
StructuredMatrixStyle
39+
StructuredMatrixStyle, cholesky, cholesky!, cholcopy, RealHermSymComplexHerm
4040
import ArrayLayouts: _fill_lmul!, MatMulVecAdd, MatMulMatAdd, MatLmulVec, MatLdivVec,
41-
materialize!, MemoryLayout, sublayout, transposelayout, conjlayout,
41+
materialize!, MemoryLayout, sublayout, transposelayout, conjlayout,
4242
triangularlayout, triangulardata, _inv, _copyto!, axes_print_matrix_row,
4343
colsupport, rowsupport, sub_materialize
4444

45-
include("blockindices.jl")
45+
include("blockindices.jl")
4646
include("blockaxis.jl")
4747
include("abstractblockarray.jl")
4848
include("blockarray.jl")
@@ -51,6 +51,7 @@ include("views.jl")
5151
include("blocks.jl")
5252

5353
include("blockbroadcast.jl")
54+
include("blockcholesky.jl")
5455
include("blocklinalg.jl")
5556
include("blockproduct.jl")
5657
include("show.jl")
@@ -63,4 +64,5 @@ include("blockarrayinterface.jl")
6364
@deprecate setblock!(A::AbstractBlockArray{T,N}, v, I::Vararg{Integer, N}) where {T,N} (A[Block(I...)] = v)
6465

6566

67+
6668
end # module

src/blockcholesky.jl

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
2+
##########################################
3+
# Cholesky Factorization on BlockMatrices#
4+
##########################################
5+
6+
7+
function _diag_chol!(A::AbstractArray{T}, i::Int, uplo) where T<:Real
8+
Pii = view(A,Block(i,i))
9+
for k = Int(first(blockcolsupport(A,Block(i)))):i-1
10+
muladd!(-one(T), view(A,Block(k,i))', view(A,Block(k,i)), one(T), Pii)
11+
end
12+
return LAPACK.potrf!('U', Pii)
13+
end
14+
15+
16+
function _nondiag_chol!(A::AbstractArray{T}, i::Int, n::Int, ::Type{UpperTriangular}) where T<:Real
17+
for j = i+1:Int(last(blockrowsupport(A,Block(i))))
18+
Pij = view(A,Block(i,j))
19+
for k = Int(first(blockcolsupport(A,Block(j)))):i-1
20+
muladd!(-one(T), view(A,Block(k,i))', view(A,Block(k,j)), one(T), Pij)
21+
end
22+
# use ArrayLayouts.ldiv! to take advantage of layout
23+
ArrayLayouts.ldiv!(transpose(UpperTriangular(view(A,Block(i,i)))), Pij)
24+
end
25+
end
26+
27+
function _nondiag_chol!(A::AbstractArray{T}, i::Int, n::Int, ::Type{LowerTriangular}) where T<:Real
28+
for j = i+1:Int(last(blockrowsupport(A,Block(i))))
29+
Pij = view(A,Block(i,j))
30+
for k = Int(first(blockcolsupport(A,Block(j)))):i-1
31+
muladd!(-one(T), view(A,Block(k,i))', view(A,Block(k,j)), one(T), Pij)
32+
end
33+
ArrayLayouts.ldiv!(UpperTriangular(view(A,Block(i,i)))', Pij)
34+
end
35+
end
36+
37+
function _block_chol!(A::AbstractArray{T}, ::Type{UpperTriangular}) where T<:Real
38+
n = blocksize(A)[1]
39+
40+
@inbounds begin
41+
for i = 1:n
42+
_, info = _diag_chol!(A, i, UpperTriangular)
43+
44+
if !iszero(info)
45+
@assert info > 0
46+
if i == 1
47+
return UpperTriangular(A), info
48+
end
49+
info += sum(size(A[Block(l,l)])[1] for l=1:i-1)
50+
return UpperTriangular(A), info
51+
end
52+
53+
_nondiag_chol!(A, i, n, UpperTriangular)
54+
end
55+
end
56+
57+
return UpperTriangular(A), 0
58+
end
59+
60+
function _block_chol!(A::AbstractArray{T}, ::Type{LowerTriangular}) where T<:Real
61+
n = blocksize(A)[1]
62+
A = copy(transpose(A))
63+
64+
@inbounds begin
65+
for i = 1:n
66+
_, info = _diag_chol!(A, i, LowerTriangular)
67+
68+
if !iszero(info)
69+
@assert info > 0
70+
if i == 1
71+
return LowerTriangular(copy(transpose(A))), info
72+
end
73+
info += sum(size(A[Block(l,l)])[1] for l=1:i-1)
74+
return LowerTriangular(A), info
75+
end
76+
77+
_nondiag_chol!(A, i, n, LowerTriangular)
78+
end
79+
end
80+
81+
return LowerTriangular(transpose(A)), 0
82+
end
83+
84+
function ArrayLayouts._cholesky!(layout, ::NTuple{2,BlockedUnitRange}, A::RealHermSymComplexHerm, ::ArrayLayouts.CNoPivot; check::Bool = true)
85+
C, info = _block_chol!(A.data, A.uplo == 'U' ? UpperTriangular : LowerTriangular)
86+
check && LinearAlgebra.checkpositivedefinite(info)
87+
return Cholesky(C.data, A.uplo, info)
88+
end
89+

src/blocklinalg.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function _copyto!(_, ::AbstractBlockLayout, dest::AbstractMatrix, src::AbstractM
138138
return dest
139139
end
140140

141-
@inbounds for J = blockaxes(src,2),K = blockaxes(src,1)
141+
@inbounds for J = blockaxes(src,2),K = blockcolsupport(src,J)
142142
copyto!(view(dest,K,J), view(src,K,J))
143143
end
144144
dest

src/blockproduct.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ kron_viewblock(args, k::Integer, j::Integer) = args[1][k,j]*BlockKron(tail(args)
8989
viewblock(K::BlockKron{<:Any,1}, k::Block{1}) = kron_viewblock(K.args, Int(k))
9090
viewblock(K::BlockKron{<:Any,2}, kj::Block{2}) = kron_viewblock(K.args, Int.(kj.n)...)
9191

92+
# At the moment this only takes advantage of AbstractBlockLayout structure
93+
struct KronLayout <: AbstractBlockLayout end
94+
MemoryLayout(::Type{<:BlockKron}) = KronLayout()
95+
blockcolsupport(K::BlockKron, J) = Block.(colsupport(first(K.args), Int.(J)))
96+
blockrowsupport(K::BlockKron, J) = Block.(rowsupport(first(K.args), Int.(J)))
97+
9298
# const SubKron{T,M1,M2,R1,R2} = SubArray{T,2,<:BlockKron{T,M1,M2},<:Tuple{<:BlockSlice{R1},<:BlockSlice{R2}}}
9399

94100

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using BlockArrays, LinearAlgebra, Test
22

33

4+
45
include("test_blockindices.jl")
56
include("test_blockarrays.jl")
67
include("test_blockviews.jl")
@@ -12,3 +13,4 @@ include("test_blocklinalg.jl")
1213
include("test_blockproduct.jl")
1314
include("test_blockreduce.jl")
1415
include("test_blockdeque.jl")
16+
include("test_blockcholesky.jl")

test/test_blockcholesky.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using BlockArrays, Test, LinearAlgebra, Random
2+
3+
4+
Random.seed!(0)
5+
6+
@testset "Block cholesky" begin
7+
8+
# Generating random positive definite and symmetric matrices
9+
A = BlockArray{Float32}(rand(9,9)+100I, fill(3,3), fill(3,3)); A = Symmetric(A)
10+
B = BlockArray{Float32}(rand(55,55)+100I, 1:10, 1:10); B = Symmetric(B)
11+
C = BlockArray{Float32}(rand(9,9)+100I, fill(3,3), fill(3,3)); C = Symmetric(C, :L)
12+
D = BlockArray{Float32}(rand(55,55)+100I, 1:10, 1:10); D = Symmetric(D, :L)
13+
E = BlockArray{Float32}(rand(9,9)+100I, fill(3,3), fill(3,3)); E = Symmetric(E)
14+
D1 = copy(D); D1[1,1] = 0
15+
D2 = copy(D); D2[2,2] = 0
16+
E2 = copy(E); E2[2,2] = 0
17+
E5 = copy(E); E5[5,5] = 0
18+
E8 = copy(E); E8[8,8] = 0
19+
nsym = BlockArray{Float32}(randn(6,8), fill(2,3), fill(2,4))
20+
21+
A_T = Matrix(A)
22+
B_T = Matrix(B)
23+
C_T = Matrix(C)
24+
D_T = Matrix(D)
25+
26+
#Test on nonsymmetric matrix
27+
if VERSION < v"1.8-"
28+
@test_throws MethodError cholesky(nsym)
29+
else
30+
@test_throws DimensionMismatch cholesky(nsym)
31+
end
32+
33+
#Tests on A
34+
@test cholesky(A).U cholesky(A_T).U
35+
@test cholesky(A).U'cholesky(A).U A
36+
37+
#Tests on B
38+
@test cholesky(B).U cholesky(B_T).U
39+
@test cholesky(B).U'cholesky(B).U B
40+
41+
#Tests on C
42+
@test cholesky(C).L cholesky(C_T).L
43+
@test cholesky(C).L*cholesky(C).L' C
44+
45+
#Tests on D
46+
@test cholesky(D).L cholesky(D_T).L
47+
@test cholesky(D).L*cholesky(D).L' D
48+
49+
#Tests on non-PD matrices
50+
@test_throws PosDefException cholesky(D1)
51+
@test_throws PosDefException cholesky(D2)
52+
@test_throws PosDefException cholesky(E2)
53+
@test_throws PosDefException cholesky(E5)
54+
@test_throws PosDefException cholesky(E8)
55+
56+
@test cholesky(D1; check=false).info == 1
57+
@test cholesky(D2; check=false).info == 2
58+
@test cholesky(E2; check=false).info == 2
59+
@test cholesky(E5; check=false).info == 5
60+
@test cholesky(E8; check=false).info == 8
61+
end
62+

test/test_blockproduct.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,20 @@ using BlockArrays, Test
124124
= BlockKron(A,B)
125125
@test K ==== kron(A,B)
126126
@test blocksize(K) == blocksize(K̃) == size(A)
127+
@test BlockArrays.blockcolsupport(K, Block(1)) == BlockArrays.blockcolsupport(K̃, Block(1)) == Block.(BlockArrays.colsupport(A,1))
128+
@test BlockArrays.blockrowsupport(K, Block(1)) == BlockArrays.blockrowsupport(K̃, Block(1)) == Block.(BlockArrays.rowsupport(A,1))
127129
@test K[Block(1,1)] == K̃[Block(1),Block(1)] == A[1,1]*B
128130
@test K[Block(2,3)] == K̃[Block(2),Block(3)] == A[2,3]*B
129131
C = randn(2,5)
130132
= BlockKron(A,B,C)
131-
@test== blockkron(A,B,C) == kron(A,B,C)
133+
@test blockkron(A,B,C) kron(A,B,C)
132134
@test K̄[Block(1,1)][Block(1,1)] A[1,1]*B[1,1]*C
133135
@test K̄[Block(2,3)][Block(3,4)] A[2,3]*B[3,4]*C
134136

135137
@test blockkron(a,B) == kron(a,B)
136138
@test blockkron(A,b) == kron(A,b)
137-
@test blockkron(A,b,c) == kron(A,b,c)
138-
@test blockkron(A,b,C) == kron(A,b,C)
139+
@test blockkron(A,b,c) kron(A,b,c)
140+
@test blockkron(A,b,C) kron(A,b,C)
139141

140142
@test_throws MethodError BlockKron()
141143
@test_throws MethodError BlockKron(a)

0 commit comments

Comments
 (0)