Skip to content

Commit dc76b65

Browse files
authored
Add extra step in _qr to allow dispatch on length, Bidiagonal solve (#26)
* Add extra step in _qr to allow dispatch on length (for InfiniteLinearAlgebra.jl) * Add _mul(layoutA, layoutB, A, B), Bidiagonal substitution * v0.3.6 * Update ArrayLayouts.jl * Add Bidiagonal tests * Update runtests.jl
1 parent 5e0f275 commit dc76b65

File tree

8 files changed

+143
-29
lines changed

8 files changed

+143
-29
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ArrayLayouts"
22
uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.3.5"
4+
version = "0.3.6"
55

66
[deps]
77
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"

src/ArrayLayouts.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ Base.print_matrix_row(io::IO,
249249
LayoutVector,
250250
AbstractTriangular{<:Any,<:LayoutMatrix},
251251
AdjOrTrans{<:Any,<:LayoutMatrix},
252+
AdjOrTrans{<:Any,<:LayoutVector},
252253
HermOrSym{<:Any,<:LayoutMatrix},
253254
SubArray{<:Any,2,<:LayoutMatrix},
254255
Diagonal{<:Any,<:LayoutVector}}, A::Vector,

src/factorizations.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,8 @@ function materialize!(M::Rmul{<:Any,<:AdjQRPackedQLayout})
274274
end
275275

276276

277-
_qr(layout, axes, A; kwds...) = Base.invoke(qr, Tuple{AbstractMatrix{eltype(A)}}, A; kwds...)
277+
__qr(layout, lengths, A; kwds...) = Base.invoke(qr, Tuple{AbstractMatrix{eltype(A)}}, A; kwds...)
278+
_qr(layout, axes, A; kwds...) = __qr(layout, map(length, axes), A; kwds...)
278279
_qr(layout, axes, A, pivot::P; kwds...) where P = Base.invoke(qr, Tuple{AbstractMatrix{eltype(A)},P}, A, pivot; kwds...)
279280
_lu(layout, axes, A; kwds...) = Base.invoke(lu, Tuple{AbstractMatrix{eltype(A)}}, A; kwds...)
280281
_lu(layout, axes, A, pivot::P; kwds...) where P = Base.invoke(lu, Tuple{AbstractMatrix{eltype(A)},P}, A, pivot; kwds...)

src/ldiv.jl

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,35 @@ const BlasMatRdivMat{styleA, styleB, T<:BlasFloat} = MatRdivMat{styleA, styleB,
109109

110110
macro _layoutldiv(Typ)
111111
esc(quote
112-
LinearAlgebra.ldiv!(A::$Typ, x::AbstractVector) = ArrayLayouts.materialize!(ArrayLayouts.Ldiv(A,x))
113-
LinearAlgebra.ldiv!(A::$Typ, x::AbstractMatrix) = ArrayLayouts.materialize!(ArrayLayouts.Ldiv(A,x))
114-
LinearAlgebra.ldiv!(A::$Typ, x::StridedVector) = ArrayLayouts.materialize!(ArrayLayouts.Ldiv(A,x))
115-
LinearAlgebra.ldiv!(A::$Typ, x::StridedMatrix) = ArrayLayouts.materialize!(ArrayLayouts.Ldiv(A,x))
112+
LinearAlgebra.ldiv!(A::$Typ, x::AbstractVector) = ArrayLayouts.ldiv!(A,x)
113+
LinearAlgebra.ldiv!(A::$Typ, x::AbstractMatrix) = ArrayLayouts.ldiv!(A,x)
114+
LinearAlgebra.ldiv!(A::$Typ, x::StridedVector) = ArrayLayouts.ldiv!(A,x)
115+
LinearAlgebra.ldiv!(A::$Typ, x::StridedMatrix) = ArrayLayouts.ldiv!(A,x)
116116

117-
LinearAlgebra.ldiv!(A::Factorization, x::$Typ) = ArrayLayouts.materialize!(ArrayLayouts.Ldiv(A,x))
117+
LinearAlgebra.ldiv!(A::Factorization, x::$Typ) = ArrayLayouts.ldiv!(A,x)
118118

119-
Base.:\(A::$Typ, x::AbstractVector) = ArrayLayouts.materialize(ArrayLayouts.Ldiv(A,x))
120-
Base.:\(A::$Typ, x::AbstractMatrix) = ArrayLayouts.materialize(ArrayLayouts.Ldiv(A,x))
119+
Base.:\(A::$Typ, x::AbstractVector) = ArrayLayouts.ldiv(A,x)
120+
Base.:\(A::$Typ, x::AbstractMatrix) = ArrayLayouts.ldiv(A,x)
121121

122-
Base.:\(x::AbstractMatrix, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Ldiv(x,A))
123-
Base.:\(x::Diagonal, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Ldiv(x,A))
122+
Base.:\(x::AbstractMatrix, A::$Typ) = ArrayLayouts.ldiv(x,A)
123+
Base.:\(x::Diagonal, A::$Typ) = ArrayLayouts.ldiv(x,A)
124124

125-
Base.:\(x::$Typ, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Ldiv(x,A))
125+
Base.:\(A::Bidiagonal{<:Number}, B::$Typ{<:Number}) = ArrayLayouts.ldiv(A,B)
126+
Base.:\(A::Bidiagonal, B::$Typ) = ArrayLayouts.ldiv(A,B)
127+
Base.:\(transA::Transpose{<:Number,<:Bidiagonal{<:Number}}, B::$Typ{<:Number}) = ArrayLayouts.ldiv(transA,B)
128+
Base.:\(transA::Transpose{<:Any,<:Bidiagonal}, B::$Typ) = ArrayLayouts.ldiv(transA,B)
129+
Base.:\(adjA::Adjoint{<:Number,<:Bidiagonal{<:Number}}, B::$Typ{<:Number}) = ArrayLayouts.ldiv(adjA,B)
130+
Base.:\(adjA::Adjoint{<:Any,<:Bidiagonal}, B::$Typ) = ArrayLayouts.ldiv(adjA,B)
126131

127-
Base.:/(A::$Typ, x::AbstractVector) = ArrayLayouts.materialize(ArrayLayouts.Rdiv(A,x))
128-
Base.:/(A::$Typ, x::AbstractMatrix) = ArrayLayouts.materialize(ArrayLayouts.Rdiv(A,x))
132+
Base.:\(x::$Typ, A::$Typ) = ArrayLayouts.ldiv(x,A)
129133

130-
Base.:/(x::AbstractMatrix, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Rdiv(x,A))
131-
Base.:/(x::Diagonal, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Rdiv(x,A))
134+
Base.:/(A::$Typ, x::AbstractVector) = ArrayLayouts.rdiv(A,x)
135+
Base.:/(A::$Typ, x::AbstractMatrix) = ArrayLayouts.rdiv(A,x)
132136

133-
Base.:/(x::$Typ, A::$Typ) = ArrayLayouts.materialize(ArrayLayouts.Rdiv(x,A))
137+
Base.:/(x::AbstractMatrix, A::$Typ) = ArrayLayouts.rdiv(x,A)
138+
Base.:/(x::Diagonal, A::$Typ) = ArrayLayouts.rdiv(x,A)
139+
140+
Base.:/(x::$Typ, A::$Typ) = ArrayLayouts.rdiv(x,A)
134141
end)
135142
end
136143

@@ -148,3 +155,5 @@ macro layoutldiv(Typ)
148155
ArrayLayouts.@_layoutldiv UnitLowerTriangular{T, <:SubArray{T,2,<:$Typ{T}}} where T
149156
end)
150157
end
158+
159+
@_layoutldiv LayoutVector

src/muladd.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ function MulAdd(A::AbstractArray{T}, B::AbstractMatrix{V}) where {T,V}
444444
MulAdd(scalarone(TV), A, B, scalarzero(TV), fillzeros(TV,(axes(A,1),axes(B,2))))
445445
end
446446

447-
mul(A::AbstractArray, B::AbstractArray) = materialize(MulAdd(A,B))
447+
@inline _mul(layoutA, layoutB, A, B) = materialize(MulAdd(A,B))
448+
@inline mul(A::AbstractArray, B::AbstractArray) = _mul(MemoryLayout(A), MemoryLayout(B), A, B)
448449

449450
macro layoutmul(Typ)
450451
ret = quote

src/triangular.jl

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ materialize!(M::MatRmulMat{<:AbstractStridedLayout,<:TriangularLayout}) = Linear
116116
########
117117

118118

119-
@inline function copyto!(dest::AbstractArray, M::Ldiv{<:TriangularLayout})
119+
@inline function copyto!(dest::AbstractArray, M::Ldiv{<:Union{TriangularLayout,BidiagonalLayout}})
120120
A, B = M.A, M.B
121121
dest B || copyto!(dest, B)
122122
ldiv!(A, dest)
@@ -149,7 +149,7 @@ for UNIT in ('U', 'N')
149149
end
150150
end
151151

152-
function materialize!(M::MatLdivMat{<:TriangularLayout})
152+
function materialize!(M::MatLdivMat{<:Union{TriangularLayout,BidiagonalLayout}})
153153
A,X = M.A,M.B
154154
size(A,2) == size(X,1) || thow(DimensionMismatch("Dimensions must match"))
155155
@views for j in axes(X,2)
@@ -229,3 +229,63 @@ function materialize!(M::MatLdivVec{<:TriangularLayout{'L','U'}})
229229
end
230230
b
231231
end
232+
233+
function _bidiag_backsub!(M)
234+
A,b = M.A, M.B
235+
N = last(colsupport(b,1))
236+
dv = diagonaldata(A)
237+
ev = supdiagonaldata(A)
238+
b[N] = bj1 = dv[N]\b[N]
239+
240+
@inbounds for j = (N - 1):-1:1
241+
bj = b[j]
242+
bj -= ev[j] * bj1
243+
dvj = dv[j]
244+
if iszero(dvj)
245+
throw(SingularEbception(j))
246+
end
247+
bj = dvj\bj
248+
b[j] = bj1 = bj
249+
end
250+
251+
b
252+
end
253+
254+
function _bidiag_forwardsub!(M)
255+
A, b = M.A, M.B
256+
dv = diagonaldata(A)
257+
ev = subdiagonaldata(A)
258+
N = length(b)
259+
b[1] = bj1 = dv[1]\b[1]
260+
@inbounds for j = 2:N
261+
bj = b[j]
262+
bj -= ev[j - 1] * bj1
263+
dvj = dv[j]
264+
if iszero(dvj)
265+
throw(SingularEbception(j))
266+
end
267+
bj = dvj\bj
268+
b[j] = bj1 = bj
269+
end
270+
b
271+
end
272+
273+
#Generic solver using naive substitution, based on LinearAlgebra/src/bidiag.jl
274+
function materialize!(M::MatLdivVec{<:BidiagonalLayout})
275+
A,b = M.A,M.B
276+
require_one_based_indexing(A, b)
277+
N = size(A, 2)
278+
if N != length(b)
279+
throw(DimensionMismatch("second dimension of A, $N, does not match one of the length of b, $(length(b))"))
280+
end
281+
282+
if N == 0
283+
return b
284+
end
285+
286+
if bidiagonaluplo(A) == 'L' #do forward substitution
287+
_bidiag_forwardsub!(M)
288+
else #do backward substitution
289+
_bidiag_backsub!(M)
290+
end
291+
end

test/runtests.jl

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,45 @@ MemoryLayout(::Type{MyVector}) = DenseColumnMajor()
7272
muladd!(1.0, A, A, 2.0, B)
7373
@test all(B .=== A.A^2 + 2Bin)
7474

75-
# tiled_blasmul!
76-
B = MyMatrix(copy(Bin))
77-
muladd!(1.0, Ones(5,5), A, 2.0, B)
75+
@testset "tiled_blasmul!" begin
76+
B = MyMatrix(copy(Bin))
77+
muladd!(1.0, Ones(5,5), A, 2.0, B)
78+
end
7879

79-
#generic_blasmul!
80-
A = BigFloat.(randn(5,5))
81-
Bin = BigFloat.(randn(5,5))
82-
B = copy(Bin)
83-
muladd!(1.0, Ones(5,5), A, 2.0, B)
84-
@test B == Ones(5,5)*A + 2.0Bin
80+
@testset "generic_blasmul!" begin
81+
A = BigFloat.(randn(5,5))
82+
Bin = BigFloat.(randn(5,5))
83+
B = copy(Bin)
84+
muladd!(1.0, Ones(5,5), A, 2.0, B)
85+
@test B == Ones(5,5)*A + 2.0Bin
86+
end
8587

8688
C = MyMatrix([1 2; 3 4])
8789
@test stringmime("text/plain", C) == "2×2 MyMatrix:\n 1.0 2.0\n 3.0 4.0"
90+
91+
@testset "layoutldiv" begin
92+
A = MyMatrix(randn(5,5))
93+
x = randn(5)
94+
X = randn(5,5)
95+
t = view(randn(10),[1,3,4,6,7])
96+
T = view(randn(10,5),[1,3,4,6,7],:)
97+
= copy(t)
98+
= copy(T)
99+
B = Bidiagonal(randn(5),randn(4),:U)
100+
@test ldiv!(A, copy(x)) A\x
101+
@test A\t A\
102+
# QR is not general enough
103+
@test_broken ldiv!(A, t) A\t
104+
@test ldiv!(A, copy(X)) A\X
105+
@test A\T A\
106+
@test_broken A/T A/
107+
@test_broken ldiv!(A, T) A\T
108+
@test B\A B\Matrix(A)
109+
@test transpose(B)\A transpose(B)\Matrix(A)
110+
@test B'\A B'\Matrix(A)
111+
@test A\A I
112+
@test_broken A/A I
113+
end
88114
end
89115
end
90116

test/test_ldiv.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,21 @@ import ArrayLayouts: ApplyBroadcastStyle, QRCompactWYQLayout, QRCompactWYLayout,
233233
end
234234
end
235235
end
236+
237+
@testset "Bidiagonal" begin
238+
n = 10
239+
L = Bidiagonal(randn(n), randn(n-1), :L)
240+
U = Bidiagonal(randn(n), randn(n-1), :U)
241+
b = randn(n)
242+
B = randn(n,2)
243+
244+
@test ArrayLayouts.ldiv(L,b) == L \ b
245+
@test ArrayLayouts.ldiv(U,b) == U \ b
246+
@test ArrayLayouts.ldiv(L,B) == L \ B
247+
@test ArrayLayouts.ldiv(U,B) == U \ B
248+
249+
@test_throws DimensionMismatch ArrayLayouts.ldiv(L,randn(3))
250+
@test_throws DimensionMismatch materialize!(Ldiv(L,randn(3)))
251+
end
236252
end
237253

0 commit comments

Comments
 (0)