Skip to content

Commit 33a2bbd

Browse files
authored
Increase support for padded QR (#381)
* Increase support for padded QR * Move over BlockVec * Move over blockvec * Work around padded data being a Blocked Array * Update padded.jl * increase coverage * Update paddedtests.jl * Update paddedtests.jl * increase coverage * Update padded.jl
1 parent 137bef2 commit 33a2bbd

File tree

7 files changed

+180
-23
lines changed

7 files changed

+180
-23
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "LazyArrays"
22
uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02"
3-
version = "2.7"
3+
version = "2.8"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -23,7 +23,7 @@ LazyArraysStaticArraysExt = "StaticArrays"
2323

2424
[compat]
2525
Aqua = "0.8"
26-
ArrayLayouts = "1.10.1"
26+
ArrayLayouts = "1.12"
2727
BandedMatrices = "1.6.2"
2828
Base64 = "1"
2929
BlockArrays = "1.0"

ext/LazyArraysBlockArraysExt.jl

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ using BlockArrays
44
using LazyArrays
55
using LazyArrays.ArrayLayouts
66
using LazyArrays.FillArrays
7+
using LazyArrays.LinearAlgebra
78
import LazyArrays: resizedata!, paddeddata, paddeddata_axes, arguments, call,
89
LazyArrayStyle, CachedVector, AbstractPaddedLayout, PaddedLayout, PaddedRows, PaddedColumns, BroadcastLayout,
910
AbstractCachedMatrix, AbstractCachedArray, setindex, applybroadcaststyle,
10-
ApplyLayout, cache_layout
11+
ApplyLayout, cache_layout, applied_eltype, applylayout, applied_ndims, broadcast_deblock
1112
import ArrayLayouts: sub_materialize
12-
import Base: getindex, BroadcastStyle, broadcasted, OneTo
13-
import BlockArrays: AbstractBlockStyle, AbstractBlockedUnitRange, blockcolsupport, blockrowsupport, BlockSlice, BlockIndexRange, AbstractBlockLayout
13+
import Base: getindex, setindex!, BroadcastStyle, broadcasted, OneTo, axes, size, view, resize!
14+
import BlockArrays: AbstractBlockStyle, AbstractBlockedUnitRange, blockcolsupport, blockrowsupport, BlockSlice, BlockIndexRange, AbstractBlockLayout, blockvec
1415

1516
BlockArrays._broadcaststyle(S::LazyArrays.LazyArrayStyle{1}) = S
1617

@@ -233,5 +234,33 @@ function arguments(lay::ApplyLayout{typeof(hcat)}, V::SubArray{<:Any,2,<:Any,<:T
233234
end
234235

235236

237+
####
238+
# BlockVec
239+
####
240+
const BlockVec{T, M<:AbstractMatrix{T}} = ApplyVector{T, typeof(blockvec), <:Tuple{M}}
241+
242+
BlockVec{T}(M::AbstractMatrix{T}) where T = ApplyVector{T}(blockvec, M)
243+
BlockVec(M::AbstractMatrix{T}) where T = BlockVec{T}(M)
244+
axes(b::BlockVec) = (blockedrange(Fill(size(b.args[1])...)),)
245+
size(b::BlockVec) = (length(b.args[1]),)
246+
applied_eltype(::typeof(blockvec), A) = eltype(A)
247+
applied_ndims(::typeof(blockvec), A) = 1
248+
249+
view(b::BlockVec, K::Block{1}) = view(b.args[1], :, Int(K))
250+
Base.@propagate_inbounds getindex(b::BlockVec, k::Int) = b.args[1][k]
251+
Base.@propagate_inbounds setindex!(b::BlockVec, v, k::Int) = setindex!(b.args[1], v, k)
252+
253+
_resize!(A::AbstractMatrix, m, n) = A[1:m, 1:n]
254+
_resize!(At::Transpose, m, n) = transpose(transpose(At)[1:n, 1:m])
255+
_resize!(Ac::Adjoint, m, n) = (Ac')[1:n, 1:m]'
256+
resize!(b::BlockVec, K::Block{1}) = BlockVec(_resize!(b.args[1], size(b.args[1],1), Int(K)))
257+
258+
applylayout(::Type{typeof(blockvec)}, ::AbstractPaddedLayout) = PaddedColumns{ApplyLayout{typeof(blockvec)}}()
259+
paddeddata(b::BlockVec) = BlockVec(paddeddata(b.args[1]))
260+
261+
# work around case where padded data is blocked
262+
broadcast_deblock(op, A, B::BlockedArray) = broadcast(op, A, B.blocks)
263+
broadcast_deblock(op, A::BlockedArray, B) = broadcast(op, A.blocks, B)
264+
broadcast_deblock(op, A::BlockedArray, B::BlockedArray) = broadcast(op, A.blocks, B.blocks)
236265

237266
end

src/LazyArrays.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import ArrayLayouts: AbstractQLayout, Dot, Dotu, Ldiv, Lmul, MatMulMatAdd, MatMu
4040
sublayout, symmetriclayout, symtridiagonallayout, transposelayout, triangulardata,
4141
triangularlayout, tridiagonallayout, zero!, transtype, OnesLayout,
4242
diagonaldata, subdiagonaldata, supdiagonaldata, MemoryLayout, MatLmulVec, MatLmulMat,
43-
AdjQRCompactWYQLayout
43+
AdjQRCompactWYQLayout, QRCompactWYQLayout, MatLmulMat, MatRmulMat
4444

4545
import FillArrays: AbstractFill, getindex_value
4646

src/linalg/mul.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ _mul(A,B,C...) = lazymaterialize(*,A,B,C...)
162162
_mul_colsupport(j) = j
163163
_mul_colsupport(j, Z::Number, Y...) = _mul_colsupport(j, Y...) # scalar mul doesn't do anything
164164
_mul_colsupport(j, Z::AbstractArray, Y...) = _mul_colsupport(colsupport(Z,j), Y...)
165+
_mul_colsupport(j, Z::AbstractQ, Y...) = _mul_colsupport(colsupport(Z,j), Y...)
165166

166167
colsupport(B::Applied{<:Any,typeof(*)}, j) = _mul_colsupport(j, reverse(B.args)...)
167168
colsupport(B::MulArray, j) = _mul_colsupport(j, reverse(B.args)...)
@@ -247,6 +248,7 @@ _vec_mul_arguments(args, (kr,jr)::Tuple{AbstractVector,Number}) =
247248

248249
# this is a row-vector view
249250
_transposeifnumber(a::AbstractArray{<:Number}) = transpose(a)
251+
_transposeifnumber(a::AbstractQ{<:Number}) = transpose(a)
250252
_transposeifnumber(a) = permutedims(a)
251253

252254
_vec_mul_arguments(args, (kr,jr)::Tuple{Number,AbstractVector}) =

src/padded.jl

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ _hvcat_paddeddata(N, A, B::Zeros...) = A
8181
paddeddata(A::ApplyMatrix{<:Any,typeof(hvcat)}) = _hvcat_paddeddata(A.args...)
8282

8383

84+
paddeddata(A::Array) = A # support padded interface for strided arrays
8485

8586

8687
#####
8788
# conversion
8889
#####
8990

9091
cache_layout(::AbstractPaddedLayout, O::AbstractArray) = CachedArray(copy(paddeddata(O)), Zeros{eltype(O)}(axes(O)))
92+
cache_layout(::AbstractPaddedLayout, O::CachedArray) = CachedArray(copy(O.data), O.array, O.datasize)
9193

9294

9395
#####
@@ -252,48 +254,51 @@ end
252254

253255
makearray(a::Number, ::Tuple{Any}) = [a]
254256
makearray(a::Number, ::Tuple{Any,Any}) = [a ;;]
257+
makearray(a::AbstractVector, ::Tuple{Any,Any}) = reshape(a, :, 1)
255258
makearray(a, _) = convert(Array, a)
256259

260+
broadcast_deblock(op, A, B) = broadcast(op, A, B)
261+
257262
function layout_broadcasted(_, ::AbstractPaddedLayout, op, A::Union{Ref,Number}, B::AbstractArray)
258263
b = paddeddata(B)
259264
m = length(b)
260265
zB = Zeros{eltype(B)}(size(B)...)
261-
CachedArray(makearray(broadcast(op, A, b), size(B)), broadcast(op, A, zB))
266+
CachedArray(makearray(broadcast_deblock(op, A, b), size(B)), broadcast(op, A, zB))
262267
end
263268

264269
function layout_broadcasted(::AbstractPaddedLayout, _, op, A::AbstractArray, B::Union{Ref,Number})
265270
a = paddeddata(A)
266271
n = length(a)
267272
zA = Zeros{eltype(A)}(size(A)...)
268-
CachedArray(makearray(broadcast(op, a, B), size(A)), broadcast(op, zA, B))
273+
CachedArray(makearray(broadcast_deblock(op, a, B), size(A)), broadcast(op, zA, B))
269274
end
270275

271276
function layout_broadcasted(_, ::AbstractPaddedLayout, op, A::AbstractVector, B::AbstractVector)
272277
b = paddeddata(B)
273278
m = length(b)
274279
zB = Zeros{eltype(B)}(size(B)...)
275-
CachedArray(makearray(broadcast(op, view(A,1:m), b), size(B)), broadcast(op, A, zB))
280+
CachedArray(makearray(broadcast_deblock(op, view(A,1:m), b), size(B)), broadcast(op, A, zB))
276281
end
277282

278283
function layout_broadcasted(::AbstractPaddedLayout, _, op, A::AbstractVector, B::AbstractVector)
279284
a = paddeddata(A)
280285
n = length(a)
281286
zA = Zeros{eltype(A)}(size(A)...)
282-
CachedArray(makearray(broadcast(op, a, view(B,1:n)), size(A)), broadcast(op, zA, B))
287+
CachedArray(makearray(broadcast_deblock(op, a, view(B,1:n)), size(A)), broadcast(op, zA, B))
283288
end
284289

285290
function layout_broadcasted(_, ::AbstractPaddedLayout, op, A::AbstractVector, B::AbstractMatrix)
286291
b = paddeddata(B)
287292
m = size(b,1)
288293
zB = Zeros{eltype(B)}(size(B)...)
289-
CachedArray(makearray(broadcast(op, view(A,1:m), b), size(B)), broadcast(op, A, zB))
294+
CachedArray(makearray(broadcast_deblock(op, view(A,1:(size(B,1) == 1 ? size(A,1) : m)), b), size(B)), broadcast(op, A, zB))
290295
end
291296

292297
function layout_broadcasted(::AbstractPaddedLayout, _, op, A::AbstractMatrix, B::AbstractVector)
293298
a = paddeddata(A)
294299
n = size(a,1)
295300
zA = Zeros{eltype(A)}(size(A)...)
296-
CachedArray(makearray(broadcast(op, a, view(B,1:n)), size(A)), broadcast(op, zA, B))
301+
CachedArray(makearray(broadcast_deblock(op, a, view(B,1:(size(A,1) == 1 ? size(B,1) : n))), size(A)), broadcast(op, zA, B))
297302
end
298303

299304

@@ -724,10 +729,15 @@ function ArrayLayouts.qr!_layout(::AbstractPaddedLayout, ax, A)
724729
padqr(F, ax)
725730
end
726731

732+
colsupport(::QRCompactWYQLayout{<:AbstractPaddedLayout}, Q, k) = colsupport(paddeddata(Q.factors), k)
733+
rowsupport(::QRCompactWYQLayout{<:AbstractPaddedLayout}, Q, k) = colsupport(paddeddata(Q.factors), k)
734+
colsupport(::AdjQRCompactWYQLayout{<:AbstractPaddedLayout}, Q, k) = colsupport(paddeddata(Q'.factors), k)
735+
rowsupport(::AdjQRCompactWYQLayout{<:AbstractPaddedLayout}, Q, k) = colsupport(paddeddata(Q'.factors), k)
736+
727737
similar(M::Lmul{<:AdjQRCompactWYQLayout{<:PaddedColumns}, <:PaddedColumns}, ::Type{T}, ax) where T = CachedArray(Zeros{T}(ax))
728738

729739

730-
function materialize!(L::MatLmulVec{<:AdjQRCompactWYQLayout{<:PaddedColumns}, <:PaddedColumns})
740+
function materialize!(L::MatLmulVec{<:AdjQRCompactWYQLayout{<:PaddedColumns}, <:Union{AbstractStridedLayout,PaddedColumns}})
731741
Q,b = L.A',L.B
732742
F = paddeddata(Q.factors)
733743
m = size(F,1)
@@ -737,3 +747,49 @@ function materialize!(L::MatLmulVec{<:AdjQRCompactWYQLayout{<:PaddedColumns}, <:
737747
lmul!(Q̃', view(p_b,oneto(m)))
738748
b
739749
end
750+
751+
function materialize!(L::MatLmulMat{<:AdjQRCompactWYQLayout{<:PaddedColumns}, <:Union{AbstractStridedLayout,AbstractPaddedLayout}})
752+
Q,b = L.A',L.B
753+
F = paddeddata(Q.factors)
754+
m = size(F,1)
755+
resizedata!(b, m, size(b,2))
756+
= LinearAlgebra.QRCompactWYQ(F, Q.T)
757+
p_b = paddeddata(b)
758+
lmul!(Q̃', view(p_b,oneto(m),:))
759+
b
760+
end
761+
762+
763+
764+
function materialize!(L::MatLmulVec{<:QRCompactWYQLayout{<:PaddedColumns}, <:Union{AbstractStridedLayout,PaddedColumns}})
765+
Q,b = L.A,L.B
766+
F = paddeddata(Q.factors)
767+
m = size(F,1)
768+
resizedata!(b, m)
769+
= LinearAlgebra.QRCompactWYQ(F, Q.T)
770+
p_b = paddeddata(b)
771+
lmul!(Q̃, view(p_b,oneto(m)))
772+
b
773+
end
774+
775+
function materialize!(L::MatLmulMat{<:QRCompactWYQLayout{<:PaddedColumns}, <:Union{AbstractStridedLayout,AbstractPaddedLayout}})
776+
Q,b = L.A,L.B
777+
F = paddeddata(Q.factors)
778+
m = size(F,1)
779+
resizedata!(b, m, size(b,2))
780+
= LinearAlgebra.QRCompactWYQ(F, Q.T)
781+
p_b = paddeddata(b)
782+
lmul!(Q̃, view(p_b,oneto(m),:))
783+
b
784+
end
785+
786+
function materialize!(L::MatRmulMat{<:Union{AbstractStridedLayout,AbstractPaddedLayout}, <:QRCompactWYQLayout{<:PaddedColumns}})
787+
A,Q = L.A,L.B
788+
F = paddeddata(Q.factors)
789+
m = size(F,1)
790+
resizedata!(A, size(A,1), m)
791+
= LinearAlgebra.QRCompactWYQ(F, Q.T)
792+
p_A = paddeddata(A)
793+
rmul!(view(p_A,:, oneto(m)), Q̃)
794+
A
795+
end

test/blocktests.jl

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module LazyArraysBlockArraysTest
22
using LazyArrays, ArrayLayouts, BlockArrays, FillArrays, Test
3-
using LazyArrays: LazyArrayStyle, PaddedLayout, PaddedColumns, PaddedRows, paddeddata
4-
using BlockArrays: blockcolsupport, blockrowsupport
3+
using LazyArrays: LazyArrayStyle, PaddedLayout, PaddedColumns, PaddedRows, paddeddata, ApplyLayout
4+
using BlockArrays: blockcolsupport, blockrowsupport, blockvec
5+
const BlockVec{T, M<:AbstractMatrix{T}} = ApplyVector{T, typeof(blockvec), <:Tuple{M}}
56

67
@testset "Lazy BlockArrays" begin
78
@testset "LazyBlock" begin
@@ -143,5 +144,44 @@ using BlockArrays: blockcolsupport, blockrowsupport
143144
B = BlockedArray(Vcat([1 2 3; 4 5 6], Ones(3,3), fill(4, 2, 3))', [3], [2,3,2])
144145
@test ApplyArray(view(B, Block.(1:1), Block(1))) == [1 4; 2 5; 3 6]
145146
end
147+
148+
@testset "BlockVec" begin
149+
X = randn(5,4)
150+
b = BlockVec(X)
151+
@test size(b) == (20,)
152+
@test length(b) == 20
153+
@test MemoryLayout(b) isa ApplyLayout{typeof(blockvec)}
154+
@test b == vec(X)
155+
@test view(b, Block(3)) view(X, :, 3)
156+
@test b[Block(3)] isa Vector
157+
b[5] = 6
158+
@test X[5] == 6
159+
@test resize!(b, Block(2)) == b[Block.(1:2)]
160+
161+
c = BlockVec(X')
162+
@test c == vec(X')
163+
@test view(c, Block(3)) view(X', :, 3)
164+
@test resize!(c, Block(2)) == c[Block.(1:2)]
165+
166+
c = BlockVec(transpose(X))
167+
@test c == vec(transpose(X))
168+
@test view(c, Block(3)) view(transpose(X), :, 3)
169+
@test resize!(c, Block(2)) == c[Block.(1:2)]
170+
171+
X = cache(Zeros(5,6));
172+
X[1,1] = 2
173+
c = BlockVec(X);
174+
@test MemoryLayout(c) isa PaddedColumns
175+
@test paddeddata(c) isa BlockVec
176+
@test paddeddata(c) == [2]
177+
178+
a = ApplyArray(blockvec, (1:5)')
179+
b = BlockedArray(Vcat([1,2], Zeros(3)), (axes(a,1),))
180+
181+
@test a + b == b + a
182+
@test a - b == -(b-a)
183+
@test a + a == 2a
184+
@test b + b == 2b
185+
end
146186
end
147187
end

test/paddedtests.jl

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -457,22 +457,52 @@ paddeddata(a::PaddedPadded) = a
457457
@test B*p == Matrix(B)*p
458458
@test simplifiable(*,B,p) == Val(true)
459459
end
460+
461+
@testset "cached broadcasted" begin
462+
z = Zeros(5)
463+
a = cache(z); a[1] = 3;
464+
465+
@test z ./ a a .\ z z
466+
end
467+
468+
@testset "Number * padded matrix - of - vector" begin
469+
A = Vcat([1,2], Zeros(3,1))
470+
@test 2 * A == A * 2 == 2 * Matrix(A)
471+
end
460472

461473
@testset "QR" begin
462474
A = Vcat(randn(5,5), Zeros(4,5))
463475
F = qr!(copy(A))
464476
= qr!(Matrix(A))
465477
@test F.R .R
466-
b = Vcat([1,2], Zeros(7))
467-
@test F.Q'b .Q'b
478+
479+
Q = F.Q
480+
=.Q
481+
482+
b = cache(Vcat([1,2], Zeros(7)));
483+
B = cache(Vcat([1 2;3 4], Zeros(7,2)));
484+
485+
@test Q'b 'b
468486
@test ldiv!(F,cache(b)) ldiv!(F̃,Vector(b))
469-
end
487+
@test lmul!(Q, deepcopy(b)) lmul!(Q, Vector(b)) Q*b
488+
@test lmul!(Q', deepcopy(b)) lmul!(Q', Vector(b)) Q'b
470489

471-
@testset "cached broadcasted" begin
472-
z = Zeros(5)
473-
a = cache(z); a[1] = 3;
474-
475-
@test z ./ a a .\ z z
490+
491+
@test lmul!(Q, deepcopy(B)) lmul!(Q, Matrix(B)) Q*B
492+
@test lmul!(Q', deepcopy(B)) lmul!(Q', Matrix(B)) Q'B
493+
494+
@test Matrix(Q) [Q[k,j] for k in axes(A,1), j in axes(A,2)] Matrix(Q̃)
495+
@test colsupport(Q,3) == rowsupport(Q,3) == colsupport(Q',3) == rowsupport(Q',3) == Base.OneTo(5)
496+
497+
@test Q'A [F.R; zeros(4,5)]
498+
@test A'*Q [F.R; zeros(4,5)]'
499+
500+
M = ApplyArray(*, Q, b)
501+
@test colsupport(M) == Base.OneTo(5)
502+
503+
M = ApplyArray(*, Q, B)
504+
@test colsupport(M) == Base.OneTo(5)
505+
@test M[1,:] (Q*B)[1,:]
476506
end
477507
end
478508
end # module

0 commit comments

Comments
 (0)