Skip to content

Commit

Permalink
Fix \ and .'\ for Symmetric and Hermitian sparse matrices. (#19242)
Browse files Browse the repository at this point in the history
(cherry picked from commit d9d0fad)
  • Loading branch information
andreasnoack authored and tkelman committed Feb 22, 2017
1 parent df8a997 commit 5c9edd0
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 9 deletions.
7 changes: 5 additions & 2 deletions base/linalg/factorization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ function (\){T<:BlasReal}(F::Factorization{T}, B::VecOrMat{Complex{T}})
end

for (f1, f2) in ((:\, :A_ldiv_B!),
(:Ac_ldiv_B, :Ac_ldiv_B!),
(:At_ldiv_B, :At_ldiv_B!))
(:Ac_ldiv_B, :Ac_ldiv_B!))
@eval begin
function $f1(F::Factorization, B::AbstractVecOrMat)
TFB = typeof(one(eltype(F)) / one(eltype(B)))
Expand All @@ -48,6 +47,10 @@ for f in (:A_ldiv_B!, :Ac_ldiv_B!, :At_ldiv_B!)
$f(A, copy!(Y, B))
end

# fallback methods for transposed solves
At_ldiv_B{T<:Real}(F::Factorization{T}, B::AbstractVecOrMat) = Ac_ldiv_B(F, B)
At_ldiv_B(F::Factorization, B) = conj.(Ac_ldiv_B(F, conj.(B)))

"""
A_ldiv_B!([Y,] A, B) -> Y
Expand Down
13 changes: 13 additions & 0 deletions base/sparse/cholmod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,19 @@ Ac_ldiv_B(L::Factor, B::VecOrMat) = convert(Matrix, solve(CHOLMOD_A, L, Dense(B)
Ac_ldiv_B(L::Factor, B::Sparse) = spsolve(CHOLMOD_A, L, B)
Ac_ldiv_B(L::Factor, B::SparseVecOrMat) = Ac_ldiv_B(L, Sparse(B))

for f in (:\, :Ac_ldiv_B)
@eval function ($f)(A::Union{Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}},
Hermitian{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}},
Hermitian{Complex{Float64},SparseMatrixCSC{Complex{Float64},SuiteSparse_long}}}, B::StridedVecOrMat)
try
return ($f)(cholfact(A), B)
catch e
isa(e, LinAlg.PosDefException) || rethrow(e)
return ($f)(ldltfact(A) , B)
end
end
end

## Other convenience methods
function diag{Tv}(F::Factor{Tv})
f = unsafe_load(get(F.p))
Expand Down
7 changes: 1 addition & 6 deletions base/sparse/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -864,12 +864,7 @@ function (\)(A::SparseMatrixCSC, B::AbstractVecOrMat)
return UpperTriangular(A) \ B
end
if ishermitian(A)
try
return cholfact(Hermitian(A)) \ B
catch e
isa(e, PosDefException) || rethrow(e)
return ldltfact(Hermitian(A)) \ B
end
Hermitian(A) \ B
end
return lufact(A) \ B
else
Expand Down
2 changes: 1 addition & 1 deletion test/linalg/lu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int)
εb = eps(abs(float(one(eltyb))))
ε = max(εa,εb)

debug && println("(Automatic) Square LU decomposition")
debug && println("(Automatic) Square LU decomposition. eltya: $eltya, eltyb: $eltyb")
κ = cond(a,1)
lua = factorize(a)
@test_throws KeyError lua[:Z]
Expand Down
17 changes: 17 additions & 0 deletions test/sparsedir/cholmod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ for elty in (Float64, Complex{Float64})
@test_throws DimensionMismatch F\CHOLMOD.Sparse(sparse(ones(elty, 4)))
@test F'\ones(elty, 5) full(A1pd)'\ones(5)
@test F'\sparse(ones(elty, 5)) full(A1pd)'\ones(5)
@test F.'\ones(elty, 5) conj(A1pd)'\ones(elty, 5)
@test logdet(F) logdet(full(A1pd))
@test det(F) == exp(logdet(F))
let # to test supernodal, we must use a larger matrix
Expand Down Expand Up @@ -671,3 +672,19 @@ let m = 400, n = 500
@test s.is_super == 0
@test F\b ones(m + n)
end

# Test that \ and '\ and .'\ work for Symmetric and Hermitian. This is just
# a dispatch exercise so it doesn't matter that the complex matrix has
# zero imaginary parts
let Apre = sprandn(10, 10, 0.2) - I
for A in (Symmetric(Apre), Hermitian(Apre),
Symmetric(Apre + 10I), Hermitian(Apre + 10I),
Hermitian(complex(Apre)), Hermitian(complex(Apre) + 10I))

x = ones(10)
b = A*x
@test x A\b
@test A.'\b A'\b
end
end

0 comments on commit 5c9edd0

Please sign in to comment.