Skip to content

Commit

Permalink
Fix (l/r)mul! with Diagonal/Bidiagonal (#55052)
Browse files Browse the repository at this point in the history
  • Loading branch information
jishnub committed Nov 11, 2024
1 parent 6662c78 commit 0dd990e
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 2 deletions.
26 changes: 26 additions & 0 deletions stdlib/LinearAlgebra/src/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,32 @@ end
/(A::Bidiagonal, B::Number) = Bidiagonal(A.dv/B, A.ev/B, A.uplo)
\(B::Number, A::Bidiagonal) = Bidiagonal(B\A.dv, B\A.ev, A.uplo)

# B .= D * B
function lmul!(D::Diagonal, B::Bidiagonal)
_muldiag_size_check(D, B)
(; dv, ev) = B
isL = B.uplo == 'L'
dv[1] = D.diag[1] * dv[1]
for i in axes(ev,1)
ev[i] = D.diag[i + isL] * ev[i]
dv[i+1] = D.diag[i+1] * dv[i+1]
end
return B
end

# B .= B * D
function rmul!(B::Bidiagonal, D::Diagonal)
_muldiag_size_check(B, D)
(; dv, ev) = B
isU = B.uplo == 'U'
dv[1] *= D.diag[1]
for i in axes(ev,1)
ev[i] *= D.diag[i + isU]
dv[i+1] *= D.diag[i+1]
end
return B
end

function ==(A::Bidiagonal, B::Bidiagonal)
if A.uplo == B.uplo
return A.dv == B.dv && A.ev == B.ev
Expand Down
45 changes: 43 additions & 2 deletions stdlib/LinearAlgebra/src/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,49 @@ end
(*)(D::Diagonal, A::HermOrSym) =
mul!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), D, A)

rmul!(A::AbstractMatrix, D::Diagonal) = @inline mul!(A, A, D)
lmul!(D::Diagonal, B::AbstractVecOrMat) = @inline mul!(B, D, B)
function rmul!(A::AbstractMatrix, D::Diagonal)
_muldiag_size_check(A, D)
for I in CartesianIndices(A)
row, col = Tuple(I)
@inbounds A[row, col] *= D.diag[col]
end
return A
end
# T .= T * D
function rmul!(T::Tridiagonal, D::Diagonal)
_muldiag_size_check(T, D)
(; dl, d, du) = T
d[1] *= D.diag[1]
for i in axes(dl,1)
dl[i] *= D.diag[i]
du[i] *= D.diag[i+1]
d[i+1] *= D.diag[i+1]
end
return T
end

function lmul!(D::Diagonal, B::AbstractVecOrMat)
_muldiag_size_check(D, B)
for I in CartesianIndices(B)
row = I[1]
@inbounds B[I] = D.diag[row] * B[I]
end
return B
end

# in-place multiplication with a diagonal
# T .= D * T
function lmul!(D::Diagonal, T::Tridiagonal)
_muldiag_size_check(D, T)
(; dl, d, du) = T
d[1] = D.diag[1] * d[1]
for i in axes(dl,1)
dl[i] = D.diag[i+1] * dl[i]
du[i] = D.diag[i] * du[i]
d[i+1] = D.diag[i+1] * d[i+1]
end
return T
end

function (*)(A::AdjOrTransAbsMat, D::Diagonal)
Ac = copy_similar(A, promote_op(*, eltype(A), eltype(D.diag)))
Expand Down
9 changes: 9 additions & 0 deletions stdlib/LinearAlgebra/test/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -827,4 +827,13 @@ end
@test_throws "cannot set entry" B[1,2] = 4
end

@testset "rmul!/lmul! with banded matrices" begin
dv, ev = rand(4), rand(3)
for A in (Bidiagonal(dv, ev, :U), Bidiagonal(dv, ev, :L))
D = Diagonal(dv)
@test rmul!(copy(A), D) A * D
@test lmul!(D, copy(A)) D * A
end
end

end # module TestBidiagonal
13 changes: 13 additions & 0 deletions stdlib/LinearAlgebra/test/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1180,4 +1180,17 @@ end
@test *(Diagonal(ones(n)), Diagonal(1:n), Diagonal(ones(n)), Diagonal(1:n)) isa Diagonal
end

@testset "rmul!/lmul! with banded matrices" begin
@testset "$(nameof(typeof(B)))" for B in (
Bidiagonal(rand(4), rand(3), :L),
Tridiagonal(rand(3), rand(4), rand(3))
)
BA = Array(B)
D = Diagonal(rand(size(B,1)))
DA = Array(D)
@test rmul!(copy(B), D) B * D BA * DA
@test lmul!(D, copy(B)) D * B DA * BA
end
end

end # module TestDiagonal
8 changes: 8 additions & 0 deletions stdlib/LinearAlgebra/test/tridiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -802,4 +802,12 @@ end
end
end

@testset "rmul!/lmul! with banded matrices" begin
dl, d, du = rand(3), rand(4), rand(3)
A = Tridiagonal(dl, d, du)
D = Diagonal(d)
@test rmul!(copy(A), D) A * D
@test lmul!(D, copy(A)) D * A
end

end # module TestTridiagonal

0 comments on commit 0dd990e

Please sign in to comment.