diff --git a/src/SparseArrays.jl b/src/SparseArrays.jl index ddf00d5d..7c6984cf 100644 --- a/src/SparseArrays.jl +++ b/src/SparseArrays.jl @@ -11,7 +11,7 @@ using Base.Order: Forward using LinearAlgebra using LinearAlgebra: AdjOrTrans, AdjointFactorization, TransposeFactorization, matprod, AbstractQ, AdjointQ, HessenbergQ, QRCompactWYQ, QRPackedQ, LQPackedQ, MulAddMul, - UpperOrLowerTriangular, @stable_muladdmul + UpperOrLowerTriangular, UnitUpperOrUnitLowerTriangular, @stable_muladdmul import Base: +, -, *, \, /, ==, zero diff --git a/src/linalg.jl b/src/linalg.jl index 627e51c7..69e2a0d5 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -1309,18 +1309,24 @@ function LinearAlgebra.generic_trimatdiv!(C::StridedVecOrMat, uploc, isunitc, :: C end -function (\)(A::Union{UpperTriangular,LowerTriangular}, B::AbstractSparseMatrixCSC) - require_one_based_indexing(B) - TAB = promote_op(\, eltype(A), eltype(B)) - ldiv!(Matrix{TAB}(undef, size(B)), A, B) -end -function (\)(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::AbstractSparseMatrixCSC) - require_one_based_indexing(B) - TAB = LinearAlgebra._inner_type_promotion(\, eltype(A), eltype(B)) - ldiv!(Matrix{TAB}(undef, size(B)), A, B) -end -# (*)(L::DenseTriangular, B::AbstractSparseMatrixCSC) = lmul!(L, Array(B)) - +matop_dest(::typeof(\), A, b::AbstractSparseVector) = + Vector{promote_op(\, eltype(A), eltype(b))}(undef, length(b)) +matop_dest(::typeof(\), A::UnitUpperOrUnitLowerTriangular, b::AbstractSparseVector) = + Vector{LinearAlgebra._inner_type_promotion(\, eltype(A), eltype(b))}(undef, length(b)) +matop_dest(::typeof(\), A::Diagonal, b::AbstractSparseVector) = + similar(b , promote_op(\, eltype(A), eltype(b))) +matop_dest(::typeof(\), A, B::QuasiSparseMatrix) = + Matrix{promote_op(\, eltype(A), eltype(B))}(undef, size(B)) +matop_dest(::typeof(\), A::Diagonal, B::QuasiSparseMatrix) = + similar(B , promote_op(\, eltype(A), eltype(B)), size(B)) +matop_dest(::typeof(\), A::UnitUpperOrUnitLowerTriangular, B::QuasiSparseMatrix) = + Matrix{LinearAlgebra._inner_type_promotion(\, eltype(A), eltype(B))}(undef, size(B)) +matop_dest(::typeof(/), A::QuasiSparseMatrix, B) = + Matrix{promote_op(/, eltype(A), eltype(B))}(undef, size(A)) +matop_dest(::typeof(/), A::QuasiSparseMatrix, B::UnitUpperOrUnitLowerTriangular) = + Matrix{LinearAlgebra._inner_type_promotion(/, eltype(A), eltype(B))}(undef, size(A)) +matop_dest(::typeof(/), A::QuasiSparseMatrix, B::Diagonal) = + similar(A , promote_op(/, eltype(A), eltype(B)), size(A)) ## end of triangular # symmetric/Hermitian diff --git a/src/sparsevector.jl b/src/sparsevector.jl index 7df73108..cc243168 100644 --- a/src/sparsevector.jl +++ b/src/sparsevector.jl @@ -2130,17 +2130,6 @@ for isunittri in (true, false), islowertri in (true, false) halfstr = islowertri ? "Lower" : "Upper" tritype = :(LinearAlgebra.$(Symbol(unitstr, halfstr, "Triangular"))) - # build out-of-place left-division operations - # broad method where elements are Numbers - @eval function \(A::$tritype{<:TA,<:AbstractMatrix}, b::AbstractCompressedVector{Tb}) where {TA<:Number,Tb<:Number} - TAb = $(isunittri ? - :(typeof(zero(TA)*zero(Tb) + zero(TA)*zero(Tb))) : - :(typeof((zero(TA)*zero(Tb) + zero(TA)*zero(Tb))/one(TA))) ) - return LinearAlgebra.ldiv!(convert(AbstractArray{TAb}, A), convert(Array{TAb}, b)) - end - # fallback where elements are not Numbers - @eval \(A::$tritype, b::AbstractCompressedVector) = LinearAlgebra.ldiv!(A, copy(b)) - # faster method requiring good view support of the # triangular matrix type. hence the StridedMatrix restriction. for (istrans, applyxform, xformtype, xformop) in ( diff --git a/test/linalg.jl b/test/linalg.jl index c50de457..758ed3cb 100644 --- a/test/linalg.jl +++ b/test/linalg.jl @@ -147,6 +147,44 @@ end end end +@testset "destination array density in solves" begin + O = diagm(-1 => fill(-1, 9), 0 => fill(2, 10), 1 => fill(-1, 9)) + wrappers = (a -> Bidiagonal(a, :U), + a -> Bidiagonal(a, :L), + SymTridiagonal, + Tridiagonal, + LowerTriangular, + UnitLowerTriangular, + UpperTriangular, + UnitUpperTriangular, + # UpperHessenberg, + a -> UpperHessenberg(float(a)) + ) + for T in wrappers + A = T(O) + bs = sprandn(10, 0.3) + bd = Array(bs) + x = A \ bs + @test x ≈ A \ bd + @test !issparse(x) + Bs = sprandn(10, 3, 0.2) + Bd = Matrix(Bs) + X = A \ Bs + @test X ≈ A \ Bd + @test !issparse(X) + Cs = copy(Bs') + Cd = Matrix(Cs) + Y = Cs / A + @test Y ≈ Cd / A + @test !issparse(Y) + end + b, B = ones(Int, 10), ones(Int, 10, 10) + for T in (UnitLowerTriangular, UnitUpperTriangular) + A = T(O) + @test eltype(A \ b) == eltype(A \ B) == eltype(B / A) == Int + end +end + @testset "multiplication of special sparse with dense matrix" begin # this results in a call of the most generic multiplication code in LinearAlgebra.jl A = randn(2, 2) @@ -228,6 +266,7 @@ begin AW = tr(wr(A)) MAW = tr(wr(MA)) @test AW \ B ≈ MAW \ B + @test !issparse(AW \ B) # and for SparseMatrixCSCView - a view of all rows and unit range of cols vAW = tr(wr(view([zero(A)+I A], :, (n+1):2n))) @test vAW \ B ≈ AW \ B