From 5f191519e57c722c91d5f052d631da3c1cae1726 Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Thu, 12 Jul 2018 09:40:40 +0200 Subject: [PATCH] Add methods for dividing triangular by diagonal matrices. (#27999) * Add methods for dividing triangular by diagonal matrices. Fixes #27989. * Simplified tests. suggested by @fredrikekre * Test for element types instead, fix bug. For broadcasting, tranpose should be used instead of adjoint. * Matrix diagonal division through ldiv!/rdiv!. Removed previous direct implementations for upper/lower triangular, added ldiv!/rdiv! methods. Use reshape instead of transpose. * Fix ldiv! to \, use permutedims, restrict signature. --- stdlib/LinearAlgebra/src/diagonal.jl | 16 +++++++++++++++- stdlib/LinearAlgebra/test/diagonal.jl | 13 +++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index a664dfd046c6a..2d2557510cca0 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -335,6 +335,11 @@ ldiv!(adjD::Adjoint{<:Any,<:Diagonal{T}}, B::AbstractVecOrMat{T}) where {T} = ldiv!(transD::Transpose{<:Any,<:Diagonal{T}}, B::AbstractVecOrMat{T}) where {T} = (D = transD.parent; ldiv!(D, B)) +function ldiv!(D::Diagonal, A::Union{LowerTriangular,UpperTriangular}) + broadcast!(\, parent(A), D.diag, parent(A)) + A +end + function rdiv!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} @assert !has_offset_axes(A) dd = D.diag @@ -354,12 +359,19 @@ function rdiv!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} A end +function rdiv!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) + broadcast!(/, parent(A), parent(A), permutedims(D.diag)) + A +end rdiv!(A::AbstractMatrix{T}, adjD::Adjoint{<:Any,<:Diagonal{T}}) where {T} = (D = adjD.parent; rdiv!(A, conj(D))) rdiv!(A::AbstractMatrix{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = (D = transD.parent; rdiv!(A, D)) +(/)(A::Union{StridedMatrix, AbstractTriangular}, D::Diagonal) = + rdiv!((typeof(oneunit(eltype(D))/oneunit(eltype(A)))).(A), D) + (\)(F::Factorization, D::Diagonal) = ldiv!(F, Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D)) \(adjF::Adjoint{<:Any,<:Factorization}, D::Diagonal) = @@ -430,7 +442,9 @@ function ldiv!(D::Diagonal, B::StridedVecOrMat) end return B end -(\)(D::Diagonal, A::AbstractMatrix) = D.diag .\ A +(\)(D::Diagonal, A::AbstractMatrix) = + ldiv!(D, (typeof(oneunit(eltype(D))/oneunit(eltype(A)))).(A)) + (\)(D::Diagonal, b::AbstractVector) = D.diag .\ b (\)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag .\ Db.diag) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 344b9a37af733..028413ef3d318 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -460,4 +460,17 @@ end @test Transpose(x)*D*x == (Transpose(x)*D)*x == (Transpose(x)*Array(D))*x end +@testset "Triangular division by Diagonal #27989" begin + K = 5 + for elty in (Float32, Float64, ComplexF32, ComplexF64) + U = UpperTriangular(randn(elty, K, K)) + L = LowerTriangular(randn(elty, K, K)) + D = Diagonal(randn(elty, K)) + @test (U / D)::UpperTriangular{elty} == UpperTriangular(Matrix(U) / Matrix(D)) + @test (L / D)::LowerTriangular{elty} == LowerTriangular(Matrix(L) / Matrix(D)) + @test (D \ U)::UpperTriangular{elty} == UpperTriangular(Matrix(D) \ Matrix(U)) + @test (D \ L)::LowerTriangular{elty} == LowerTriangular(Matrix(D) \ Matrix(L)) + end +end + end # module TestDiagonal