Skip to content

Commit 98a0f15

Browse files
authored
Make fillband! public and specialize for banded matrices (#1345)
In parallel with `fillstored!`, this allows one to fill a structured matrix. In addition, this is a useful function in structured matrix multiplication operations where only certain bands need to be populated. It would be good to have this public, so that sparse matrix types may add methods.
1 parent b9d8843 commit 98a0f15

16 files changed

+413
-1
lines changed

src/LinearAlgebra.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ public AbstractTriangular,
180180
symmetric_type,
181181
zeroslike,
182182
matprod_dest,
183-
fillstored!
183+
fillstored!,
184+
fillband!
184185

185186
const BlasFloat = Union{Float64,Float32,ComplexF64,ComplexF32}
186187
const BlasReal = Union{Float64,Float32}

src/adjtrans.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,8 @@ diagview(A::Adjoint, k::Integer = 0) = _vecadjoint(diagview(parent(A), -k))
576576
# triu and tril
577577
triu!(A::AdjOrTransAbsMat, k::Integer = 0) = wrapperop(A)(tril!(parent(A), -k))
578578
tril!(A::AdjOrTransAbsMat, k::Integer = 0) = wrapperop(A)(triu!(parent(A), -k))
579+
580+
function fillband!(A::AdjOrTrans, v, k1, k2)
581+
fillband!(parent(A), wrapperop(A)(v), -k2, -k1)
582+
return A
583+
end

src/bidiag.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,3 +1543,30 @@ function Base._sum(A::Bidiagonal, dims::Integer)
15431543
end
15441544
res
15451545
end
1546+
1547+
function fillband!(B::Bidiagonal, x, l, u)
1548+
if l > u
1549+
return B
1550+
end
1551+
if ((B.uplo == 'U' && (l < 0 || u > 1)) ||
1552+
(B.uplo == 'L' && (l < -1 || u > 0))) && !iszero(x)
1553+
throw_fillband_error(l, u, x)
1554+
else
1555+
if B.uplo == 'U'
1556+
if l <= 1 <= u
1557+
fill!(B.ev, x)
1558+
end
1559+
if l <= 0 <= u
1560+
fill!(B.dv, x)
1561+
end
1562+
else # B.uplo == 'L'
1563+
if l <= 0 <= u
1564+
fill!(B.dv, x)
1565+
end
1566+
if l <= -1 <= u
1567+
fill!(B.ev, x)
1568+
end
1569+
end
1570+
end
1571+
return B
1572+
end

src/dense.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,23 @@ tril(M::Matrix, k::Integer) = tril!(copy(M), k)
205205
fillband!(A::AbstractMatrix, x, l, u)
206206
207207
Fill the band between diagonals `l` and `u` with the value `x`.
208+
209+
# Examples
210+
```jldoctest
211+
julia> A = zeros(4,4)
212+
4×4 Matrix{Float64}:
213+
0.0 0.0 0.0 0.0
214+
0.0 0.0 0.0 0.0
215+
0.0 0.0 0.0 0.0
216+
0.0 0.0 0.0 0.0
217+
218+
julia> LinearAlgebra.fillband!(A, 2, 0, 1)
219+
4×4 Matrix{Float64}:
220+
2.0 2.0 0.0 0.0
221+
0.0 2.0 2.0 0.0
222+
0.0 0.0 2.0 2.0
223+
0.0 0.0 0.0 2.0
224+
```
208225
"""
209226
function fillband!(A::AbstractMatrix{T}, x, l, u) where T
210227
require_one_based_indexing(A)

src/diagonal.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,3 +1216,18 @@ end
12161216

12171217
uppertriangular(D::Diagonal) = D
12181218
lowertriangular(D::Diagonal) = D
1219+
1220+
throw_fillband_error(l, u, x) = throw(ArgumentError(lazy"cannot set bands $l:$u to a nonzero value ($x)"))
1221+
1222+
function fillband!(D::Diagonal, x, l, u)
1223+
if l > u
1224+
return D
1225+
end
1226+
if (l < 0 || u > 0) && !iszero(x)
1227+
throw_fillband_error(l, u, x)
1228+
end
1229+
if l <= 0 <= u
1230+
fill!(D.diag, x)
1231+
end
1232+
return D
1233+
end

src/hessenberg.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ lmul!(x::Number, H::UpperHessenberg) = (lmul!(x, H.data); H)
124124

125125
fillstored!(H::UpperHessenberg, x) = (fillband!(H.data, x, -1, size(H,2)-1); H)
126126

127+
function fillband!(H::UpperHessenberg, x, l, u)
128+
if l > u
129+
return H
130+
end
131+
if l < -1 && !iszero(x)
132+
throw_fillband_error(l, u, x)
133+
end
134+
fillband!(H.data, x, l, u)
135+
return H
136+
end
137+
127138
+(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data+B.data)
128139
-(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data-B.data)
129140

src/symmetric.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,19 @@ function fillstored!(A::HermOrSym{T}, x) where T
414414
return A
415415
end
416416

417+
function fillband!(A::HermOrSym, x, l, u)
418+
if isa(A, Hermitian)
419+
ishermitian(x) || throw(ArgumentError("cannot fill Hermitian matrix with a non-hermitian value"))
420+
elseif isa(A, Symmetric)
421+
issymmetric(x) || throw(ArgumentError("cannot fill Symmetric matrix with an asymmetric value"))
422+
end
423+
l == -u || throw(ArgumentError(lazy"lower and upper bands must be equal in magnitude and opposite in sign, got l=$(l), u=$(u)"))
424+
lp = A.uplo == 'U' ? 0 : l
425+
up = A.uplo == 'U' ? u : 0
426+
applytri(A -> fillband!(A, x, lp, up), A)
427+
return A
428+
end
429+
417430
Base.isreal(A::HermOrSym{<:Real}) = true
418431
function Base.isreal(A::HermOrSym)
419432
n = size(A, 1)

src/triangular.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,36 @@ fillstored!(A::UnitLowerTriangular, x) = (fillband!(A.data, x, 1-size(A,1), -1);
931931
fillstored!(A::UpperTriangular, x) = (fillband!(A.data, x, 0, size(A,2)-1); A)
932932
fillstored!(A::UnitUpperTriangular, x) = (fillband!(A.data, x, 1, size(A,2)-1); A)
933933

934+
function fillband!(A::LowerOrUnitLowerTriangular, x, l, u)
935+
if l > u
936+
return A
937+
end
938+
if u > 0 && !iszero(x)
939+
throw_fillband_error(l, u, x)
940+
end
941+
isunit = A isa UnitLowerTriangular
942+
if isunit && u >= 0 && x != oneunit(x)
943+
throw(ArgumentError(lazy"cannot set the diagonal band to a non-unit value ($x)"))
944+
end
945+
fillband!(A.data, x, l, min(u, -isunit))
946+
return A
947+
end
948+
949+
function fillband!(A::UpperOrUnitUpperTriangular, x, l, u)
950+
if l > u
951+
return A
952+
end
953+
if l < 0 && !iszero(x)
954+
throw_fillband_error(l, u, x)
955+
end
956+
isunit = A isa UnitUpperTriangular
957+
if isunit && l <= 0 && x != oneunit(x)
958+
throw(ArgumentError(lazy"cannot set the diagonal band to a non-unit value ($x)"))
959+
end
960+
fillband!(A.data, x, max(l, isunit), u)
961+
return A
962+
end
963+
934964
# Binary operations
935965
# use broadcasting if the parents are strided, where we loop only over the triangular part
936966
function +(A::UpperTriangular, B::UpperTriangular)

src/tridiag.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,3 +1189,44 @@ function _opnorm1Inf(A::SymTridiagonal, p::Real)
11891189
),
11901190
normfirst, normend)
11911191
end
1192+
1193+
function fillband!(T::Tridiagonal, x, l, u)
1194+
if l > u
1195+
return T
1196+
end
1197+
if (l < -1 || u > 1) && !iszero(x)
1198+
throw_fillband_error(l, u, x)
1199+
else
1200+
if l <= -1 <= u
1201+
fill!(T.dl, x)
1202+
end
1203+
if l <= 0 <= u
1204+
fill!(T.d, x)
1205+
end
1206+
if l <= 1 <= u
1207+
fill!(T.du, x)
1208+
end
1209+
end
1210+
return T
1211+
end
1212+
1213+
function fillband!(T::SymTridiagonal, x, l, u)
1214+
if l > u
1215+
return T
1216+
end
1217+
if (l <= 1 <= u) != (l <= -1 <= u)
1218+
throw(ArgumentError(lazy"cannot set only one off-diagonal band of a SymTridiagonal"))
1219+
elseif (l < -1 || u > 1) && !iszero(x)
1220+
throw_fillband_error(l, u, x)
1221+
elseif l <= 0 <= u && !issymmetric(x)
1222+
throw(ArgumentError(lazy"cannot set entries in the diagonal band of a SymTridiagonal to an asymmetric value $x"))
1223+
else
1224+
if l <= 0 <= u
1225+
fill!(T.dv, x)
1226+
end
1227+
if l <= 1 <= u
1228+
fill!(T.ev, x)
1229+
end
1230+
end
1231+
return T
1232+
end

test/adjtrans.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,4 +809,16 @@ end
809809
end
810810
end
811811

812+
@testset "fillband!" begin
813+
for A in (rand(4, 4), rand(ComplexF64,4,4))
814+
B = similar(A)
815+
for op in (adjoint, transpose), k in -3:3
816+
B .= op(A)
817+
LinearAlgebra.fillband!(op(A), 1, k, k)
818+
LinearAlgebra.fillband!(B, 1, k, k)
819+
@test op(A) == B
820+
end
821+
end
822+
end
823+
812824
end # module TestAdjointTranspose

0 commit comments

Comments
 (0)