Skip to content

Commit 9d95a7c

Browse files
committed
Thin/Wide QR, Actually call QR
1 parent c849531 commit 9d95a7c

File tree

4 files changed

+164
-79
lines changed

4 files changed

+164
-79
lines changed

src/BlockBandedMatrices.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import LazyArrays: AbstractStridedLayout, ColumnMajor, @lazymul, MatMulMatAdd, M
2626
triangularlayout, UpperTriangularLayout, TriangularLayout, MatMulVec, MatLdivVec,
2727
triangulardata, subarraylayout, _copyto!, @lazyldiv, @lazylmul,
2828
ArrayMulArrayStyle, AbstractColumnMajor, DenseColumnMajor, ColumnMajor,
29-
DiagonalLayout, MatMulMat, apply!
29+
DiagonalLayout, MatMulMat, apply!, materialize!
3030

3131
import BlockArrays: BlockSizes, nblocks, blocksize, blockcheckbounds, global2blockindex,
3232
Block, BlockSlice, getblock, unblock, setblock!, globalrange,

src/blockskylineqr.jl

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,38 @@ _apply_ql!(::AbstractColumnMajor, ::AbstractStridedLayout, ::AbstractStridedLayo
1313
apply_ql!(A, τ, B) = _apply_ql!(MemoryLayout(A), MemoryLayout(τ), MemoryLayout(B), A, τ, B)
1414

1515
function qr!(A::BlockBandedMatrix)
16-
bs = BlockSizes((cumulsizes(blocksizes(A),1),))
17-
τ = PseudoBlockVector{Float64}(undef, bs)
1816
l,u = blockbandwidths(A)
19-
N,M = nblocks(A)
20-
for K = 1:N
21-
KR = Block.(K:min(K+l,N))
17+
M,N = nblocks(A)
18+
bs = M < N ? BlockSizes((cumulsizes(blocksizes(A),1),)) : BlockSizes((cumulsizes(blocksizes(A),2),))
19+
τ = PseudoBlockVector{Float64}(undef, bs)
20+
for K = 1:min(N,M)
21+
KR = Block.(K:min(K+l,M))
2222
V = view(A,KR,Block(K))
2323
t = view(τ,Block(K))
2424
qrf!(V,t)
25-
for J = K+1:min(K+u,M)
25+
for J = K+1:min(K+u,N)
2626
apply_qr!(V, t, view(A,KR,Block(J)))
2727
end
2828
end
2929
QR(A,τ.blocks)
3030
end
3131

3232
function ql!(A::BlockBandedMatrix)
33-
bs = BlockSizes((cumulsizes(blocksizes(A),1),))
34-
τ = PseudoBlockVector{Float64}(undef, bs)
3533
l,u = blockbandwidths(A)
36-
N,M = nblocks(A)
37-
for K = N:-1:1
38-
KR = Block.(max(K-u,1):K)
34+
M,N = nblocks(A)
35+
36+
bs = if M < N
37+
throw(ArgumentError("Wide block-QL not implented"))
38+
else
39+
BlockSizes((cumulsizes(blocksizes(A),2),))
40+
end
41+
τ = PseudoBlockVector{Float64}(undef, bs)
42+
43+
for K = N:-1:max(N - M + 1,1)
44+
μ = M+K-N
45+
KR = Block.(max(K-u,1):μ)
3946
V = view(A,KR,Block(K))
40-
t = view(τ,Block(K))
47+
t = view(τ,Block(K-N+min(M,N)))
4148
qlf!(V,t)
4249
for J = K-1:-1:max(K-l,1)
4350
apply_ql!(V, t, view(A,KR,Block(J)))
@@ -58,7 +65,7 @@ function lmul!(adjQ::Adjoint{<:Any,<:QRPackedQ{<:Any,<:BlockSkylineMatrix}}, Bin
5865
bs = BlockSizes((cumulsizes(blocksizes(A),1),))
5966
τ = PseudoBlockArray(Q.τ, bs)
6067
B = PseudoBlockArray(Bin, bs)
61-
for K = 1:N
68+
for K = 1:min(N,M)
6269
KR = Block.(K:min(K+l,N))
6370
V = view(A,KR,Block(K))
6471
t = view(τ,Block(K))
@@ -87,14 +94,23 @@ end
8794

8895
# avoid LinearALgebra Strided obsession
8996

97+
for Typ in (:StridedVector, :StridedMatrix, :AbstractVector, :AbstractMatrix)
98+
@eval function ldiv!(A::QR{<:Any,<:BlockSkylineMatrix}, B::$Typ)
99+
lmul!(adjoint(A.Q), B)
100+
apply!(\, UpperTriangular(A.factors), B)
101+
end
102+
end
103+
104+
105+
90106
function ldiv!(A::QL{<:Any,<:BlockSkylineMatrix}, B::AbstractVector)
91107
lmul!(adjoint(A.Q), B)
92-
B .= Ldiv(LowerTriangular(A.factors), B)
108+
apply!(\, LowerTriangular(A.factors), B)
93109
end
94110

95111
function ldiv!(A::QL{<:Any,<:BlockSkylineMatrix}, B::AbstractMatrix)
96112
lmul!(adjoint(A.Q), B)
97-
B .= Ldiv(LowerTriangular(A.factors), B)
113+
apply!(\, LowerTriangular(A.factors), B)
98114
end
99115

100116
\(A::AbstractBlockBandedMatrix, b::AbstractVecOrMat) = qr(A)\b # use QR because LU would be a _mess_ to implement

src/triblockbanded.jl

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,25 @@ function _matchingblocks_triangular_mul!(::Val{'L'}, UNIT, A, dest)
8282
dest
8383
end
8484

85-
@inline function _copyto!(::AbstractStridedLayout, dest::AbstractVector{T},
86-
M::MatMulVec{<:TriangularLayout{UPLO,UNIT,<:AbstractBlockBandedLayout},
85+
@inline function materialize!(M::MatMulVec{<:TriangularLayout{UPLO,UNIT,<:AbstractBlockBandedLayout},
8786
<:AbstractStridedLayout,T,T}) where {UPLO,UNIT,T<:BlasFloat}
8887
U,x = M.args
89-
@boundscheck size(U,1) == size(dest,1) || throw(BoundsError())
88+
@boundscheck size(U,1) == size(x,1) || throw(BoundsError())
9089
if hasmatchingblocks(U)
91-
x dest || copyto!(dest, x)
92-
_matchingblocks_triangular_mul!(Val(UPLO), Val(UNIT), triangulardata(U), dest)
90+
_matchingblocks_triangular_mul!(Val(UPLO), Val(UNIT), triangulardata(U), x)
9391
else # use default
94-
if x dest
95-
materialize!(MulAdd(MemoryLayout(dest), BandedBlockBandedColumnMajor(), MemoryLayout(x),
96-
one(T), U, copy(x), zero(T), dest))
97-
else
98-
materialize!(MulAdd(MemoryLayout(dest), BandedBlockBandedColumnMajor(), MemoryLayout(x),
99-
one(T), U, x, zero(T), dest))
100-
end
92+
materialize!(MulAdd(MemoryLayout(dest), BandedBlockBandedColumnMajor(), MemoryLayout(x),
93+
one(T), U, copy(x), zero(T), dest))
10194
end
10295
end
10396

10497

10598

106-
@inline function _copyto!(::AbstractStridedLayout, dest::AbstractVector{T},
107-
M::MatLdivVec{<:TriangularLayout{'U',UNIT,<:AbstractBlockBandedLayout},
108-
<:AbstractStridedLayout}) where {T,UNIT}
109-
U,x = M.args
110-
x dest || copyto!(dest, x)
99+
@inline function materialize!(M::MatLdivVec{<:TriangularLayout{'U',UNIT,<:AbstractBlockBandedLayout},
100+
<:AbstractStridedLayout}) where UNIT
101+
U,dest = M.args
102+
T = eltype(dest)
103+
111104
A = triangulardata(U)
112105
@assert hasmatchingblocks(A)
113106

@@ -122,7 +115,7 @@ end
122115
for K = N:-1:1
123116
b_2 = view(b, Block(K))
124117
= _triangular_matrix(Val('U'), Val(UNIT), view(A, Block(K,K)))
125-
b_2 .= Ldiv(Ũ, b_2)
118+
apply!(\, Ũ, b_2)
126119

127120
if K  2
128121
KR = blockcolstart(A, K):Block(K-1)
@@ -135,11 +128,10 @@ end
135128
dest
136129
end
137130

138-
@inline function _copyto!(::AbstractStridedLayout, dest::AbstractVector{T},
139-
M::MatLdivVec{<:TriangularLayout{'L',UNIT,<:AbstractBlockBandedLayout},
140-
<:AbstractStridedLayout}) where {UNIT,T}
141-
L,x = M.args
142-
x dest || copyto!(dest, x)
131+
@inline function materialize!(M::MatLdivVec{<:TriangularLayout{'L',UNIT,<:AbstractBlockBandedLayout},
132+
<:AbstractStridedLayout}) where UNIT
133+
L,dest = M.args
134+
T = eltype(dest)
143135
A = triangulardata(L)
144136
@assert hasmatchingblocks(A)
145137

test/test_blockskylineqr.jl

Lines changed: 117 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,126 @@
11
using BlockBandedMatrices, LinearAlgebra, MatrixFactorizations
22

3-
@testset "BlockBandedMatrix QR" begin
4-
N = 5
5-
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N), (2,1))
6-
A.data .= randn.()
7-
8-
F = qr(A)
9-
@test F.factors qr(Matrix(A)).factors
10-
@test F.τ LinearAlgebra.qrfactUnblocked!(Matrix(A)).τ
11-
12-
Q,R = F
13-
Q̃,R̃ = qr(Matrix(A))
14-
@test R
15-
@test Q
16-
17-
b = randn(size(A,1))
18-
@test Q'b 'b
19-
@test Q*b *b
20-
21-
@test F\b ldiv!(F, copy(b)) Matrix(A)\b A\b
22-
end
3+
@testset "BlockBandedMatrix QR/QL" begin
4+
@testset "Square QR" begin
5+
N = 5
6+
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N), (2,1))
7+
A.data .= randn.()
8+
9+
F = qr(A)
10+
@test F.factors qr(Matrix(A)).factors
11+
@test F.τ LinearAlgebra.qrfactUnblocked!(Matrix(A)).τ
12+
13+
Q,R = F
14+
Q̃,R̃ = qr(Matrix(A))
15+
@test R
16+
@test Q
17+
18+
b = randn(size(A,1))
19+
@test Q'b 'b
20+
@test Q*b *b
21+
22+
@test F\b ldiv!(F, copy(b)) Matrix(A)\b A\b
23+
end
24+
25+
@testset "Thin QR" begin
26+
N = 5
27+
A = BlockBandedMatrix{Float64}(undef, (1:N+1,1:N), (2,1))
28+
A.data .= randn.()
29+
30+
F = qr(A)
31+
@test F.factors qr(Matrix(A)).factors
32+
@test F.τ LinearAlgebra.qrfactUnblocked!(Matrix(A)).τ
33+
34+
Q,R = F
35+
Q̃,R̃ = qr(Matrix(A))
36+
@test R
37+
@test Q
38+
39+
b = randn(size(A,1))
40+
@test Q'b 'b
41+
@test Q*b *b
42+
43+
@test_broken F\b ldiv!(F, copy(b))[1:15] Matrix(A)\b A\b
44+
end
45+
46+
@testset "Wide QR" begin
47+
N = 5
48+
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N+1), (2,1))
49+
A.data .= randn.()
50+
51+
F = qr(A)
52+
@test F.factors qr(Matrix(A)).factors
53+
@test F.τ LinearAlgebra.qrfactUnblocked!(Matrix(A)).τ
54+
55+
Q,R = F
56+
Q̃,R̃ = qr(Matrix(A))
57+
@test R
58+
@test Q
59+
60+
b = randn(size(A,1))
61+
@test Q'b 'b
62+
@test Q*b *b
63+
64+
@test_throws DimensionMismatch ldiv!(F, copy(b))
65+
66+
@test_broken F\b ldiv!(F, copy(b)) Matrix(A)\b A\b
67+
end
2368

24-
@testset "BlockBandedMatrix QL" begin
25-
N = 5
26-
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N), (2,1))
27-
A.data .= randn.()
28-
29-
F = ql(A)
30-
@test F.factors ql(Matrix(A)).factors
31-
@test F.τ MatrixFactorizations.qlfactUnblocked!(Matrix(A)).τ
32-
33-
Q,L = F
34-
Q̃,L̃ = ql(Matrix(A))
35-
@test L
36-
@test Q
37-
38-
b = randn(size(A,1))
39-
@test Q'b 'b
40-
@test Q*b *b
41-
42-
b = randn(size(A,1))
43-
@test F\b ldiv!(F, copy(b)) Matrix(A)\b A\b
69+
@testset "Square QL" begin
70+
N = 5
71+
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N), (2,1))
72+
A.data .= randn.()
73+
74+
F = ql(A)
75+
@test F.factors ql(Matrix(A)).factors
76+
@test F.τ MatrixFactorizations.qlfactUnblocked!(Matrix(A)).τ
77+
78+
Q,L = F
79+
Q̃,L̃ = ql(Matrix(A))
80+
@test L
81+
@test Q
82+
83+
b = randn(size(A,1))
84+
@test Q'b 'b
85+
@test Q*b *b
86+
87+
b = randn(size(A,1))
88+
@test F\b ldiv!(F, copy(b)) Matrix(A)\b A\b
89+
end
90+
91+
@testset "Thin QL" begin
92+
N = 5
93+
A = BlockBandedMatrix{Float64}(undef, (1:N+1,1:N), (2,1))
94+
A.data .= randn.()
95+
96+
# F = ql(A)
97+
# @test F.factors ≈ ql(Matrix(A)).factors
98+
# @test F.τ ≈ MatrixFactorizations.qlfactUnblocked!(Matrix(A)).τ
99+
100+
# Q,L = F
101+
# Q̃,L̃ = ql(Matrix(A))
102+
# @test L ≈ L̃
103+
# @test Q ≈ Q̃
104+
105+
# b = randn(size(A,1))
106+
# @test Q'b ≈ Q̃'b
107+
# @test Q*b ≈ Q̃*b
108+
109+
# b = randn(size(A,1))
110+
# @test F\b ≈ ldiv!(F, copy(b)) ≈ Matrix(A)\b ≈ A\b
111+
end
112+
113+
@testset "Wide QL" begin
114+
N = 5
115+
A = BlockBandedMatrix{Float64}(undef, (1:N,1:N+1), (2,1))
116+
A.data .= randn.()
117+
118+
@test_throws ArgumentError ql(A)
119+
end
44120
end
45121

46122

123+
47124
# N = 500;
48125
# A = BlockBandedMatrix{Float64}(undef, (1:N,1:N), (2,1));
49126
# A.data .= randn.();

0 commit comments

Comments
 (0)