Skip to content

Commit d1b0cd0

Browse files
authored
Backports for v1.12 (#624)
2 parents f3610c0 + e1817e8 commit d1b0cd0

File tree

5 files changed

+57
-17
lines changed

5 files changed

+57
-17
lines changed

src/linalg.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ end
12941294

12951295
\(A::Transpose{<:Complex,<:Hermitian{<:Complex,<:AbstractSparseMatrixCSC}}, B::Vector) = copy(A) \ B
12961296

1297-
function rdiv!(A::AbstractSparseMatrixCSC{T}, D::Diagonal{T}) where T
1297+
function rdiv!(A::AbstractSparseMatrixCSC, D::Diagonal)
12981298
dd = D.diag
12991299
if (k = length(dd)) size(A, 2)
13001300
throw(DimensionMismatch("size(A, 2)=$(size(A, 2)) should be size(D, 1)=$k"))
@@ -1312,7 +1312,7 @@ function rdiv!(A::AbstractSparseMatrixCSC{T}, D::Diagonal{T}) where T
13121312
A
13131313
end
13141314

1315-
function ldiv!(D::Diagonal{T}, A::AbstractSparseMatrixCSC{T}) where {T}
1315+
function ldiv!(D::Diagonal, A::Union{AbstractSparseMatrixCSC, AbstractSparseVector})
13161316
# require_one_based_indexing(A)
13171317
if size(A, 1) != length(D.diag)
13181318
throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(size(A, 1)) rows"))

src/solvers/cholmod.jl

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,16 @@ function __init__()
231231

232232
# Register gc tracked allocator if CHOLMOD is new enough
233233
if current_version >= v"4.0.3"
234-
ccall((:SuiteSparse_config_malloc_func_set, :libsuitesparseconfig),
234+
ccall((:SuiteSparse_config_malloc_func_set, libsuitesparseconfig),
235235
Cvoid, (Ptr{Cvoid},), cglobal(:jl_malloc, Ptr{Cvoid}))
236-
ccall((:SuiteSparse_config_calloc_func_set, :libsuitesparseconfig),
236+
ccall((:SuiteSparse_config_calloc_func_set, libsuitesparseconfig),
237237
Cvoid, (Ptr{Cvoid},), cglobal(:jl_calloc, Ptr{Cvoid}))
238-
ccall((:SuiteSparse_config_realloc_func_set, :libsuitesparseconfig),
238+
ccall((:SuiteSparse_config_realloc_func_set, libsuitesparseconfig),
239239
Cvoid, (Ptr{Cvoid},), cglobal(:jl_realloc, Ptr{Cvoid}))
240-
ccall((:SuiteSparse_config_free_func_set, :libsuitesparseconfig),
240+
ccall((:SuiteSparse_config_free_func_set, libsuitesparseconfig),
241241
Cvoid, (Ptr{Cvoid},), cglobal(:jl_free, Ptr{Cvoid}))
242242
elseif current_version >= v"3.0.0"
243-
cnfg = cglobal((:SuiteSparse_config, :libsuitesparseconfig), Ptr{Cvoid})
243+
cnfg = cglobal((:SuiteSparse_config, libsuitesparseconfig), Ptr{Cvoid})
244244
unsafe_store!(cnfg, cglobal(:jl_malloc, Ptr{Cvoid}), 1)
245245
unsafe_store!(cnfg, cglobal(:jl_calloc, Ptr{Cvoid}), 2)
246246
unsafe_store!(cnfg, cglobal(:jl_realloc, Ptr{Cvoid}), 3)
@@ -1563,6 +1563,9 @@ Setting the optional `shift` keyword argument computes the factorization of
15631563
it should be a permutation of `1:size(A,1)` giving the ordering to use
15641564
(instead of CHOLMOD's default AMD ordering).
15651565
1566+
See also [`ldlt`](@ref) for a similar factorization that does not require
1567+
positive definiteness, but can be significantly slower than `cholesky`.
1568+
15661569
# Examples
15671570
15681571
In the following example, the fill-reducing permutation used is `[3, 2, 1]`.
@@ -1728,6 +1731,10 @@ To include the effects of permutation, it is typically preferable to extract
17281731
`P'*L`) and `LtP = F.UP` (the equivalent of `L'*P`).
17291732
The complete list of supported factors is `:L, :PtL, :D, :UP, :U, :LD, :DU, :PtLD, :DUP`.
17301733
1734+
Unlike the related Cholesky factorization, the ``LDL'`` factorization does not
1735+
require `A` to be positive definite. However, it still requires all leading
1736+
principal minors to be well-conditioned and will fail if this is not satisfied.
1737+
17311738
When `check = true`, an error is thrown if the decomposition fails.
17321739
When `check = false`, responsibility for checking the decomposition's
17331740
validity (via [`issuccess`](@ref)) lies with the user.
@@ -1737,6 +1744,9 @@ Setting the optional `shift` keyword argument computes the factorization of
17371744
it should be a permutation of `1:size(A,1)` giving the ordering to use
17381745
(instead of CHOLMOD's default AMD ordering).
17391746
1747+
See also [`cholesky`](@ref) for a factorization that can be significantly
1748+
faster than `ldlt`, but requires `A` to be positive definite.
1749+
17401750
!!! note
17411751
This method uses the CHOLMOD[^ACM887][^DavisHager2009] library from [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse).
17421752
CHOLMOD only supports real or complex types in single or double precision.

src/sparsematrix.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,7 +2283,7 @@ function (+)(A::Array, B::SparseMatrixCSCUnion)
22832283
for j in axes(B,2)
22842284
for i in nzrange(B, j)
22852285
rowidx = rowinds[i]
2286-
C[rowidx,j] = A[rowidx,j] + nzvals[i]
2286+
C[rowidx,j] = A[rowidx,j] + nzvals[i]
22872287
end
22882288
end
22892289
return C
@@ -2452,7 +2452,7 @@ function Base._mapreduce(f, op::Union{typeof(Base.mul_prod),typeof(*)}, ::Base.I
24522452
else
24532453
v = f(zero(T))^(nzeros)
24542454
# Bail out early if initial reduction value is zero or if there are no stored elements
2455-
(v == zero(T) || nnzA == 0) ? v : v*Base._mapreduce(f, op, nzvalview(A))
2455+
(_iszero(v) || nnzA == 0) ? v : v*Base._mapreduce(f, op, nzvalview(A))
24562456
end
24572457
end
24582458

@@ -4074,9 +4074,9 @@ function _blockdiag(::Type{Tv}, ::Type{Ti}, X::AbstractSparseMatrixCSC...) where
40744074
end
40754075

40764076
## Structure query functions
4077-
issymmetric(A::AbstractSparseMatrixCSC) = is_hermsym(A, identity)
4077+
issymmetric(A::AbstractSparseMatrixCSC) = is_hermsym(A, transpose)
40784078

4079-
ishermitian(A::AbstractSparseMatrixCSC) = is_hermsym(A, conj)
4079+
ishermitian(A::AbstractSparseMatrixCSC) = is_hermsym(A, adjoint)
40804080

40814081
function is_hermsym(A::AbstractSparseMatrixCSC, check::Function)
40824082
m, n = size(A)
@@ -4112,6 +4112,12 @@ function is_hermsym(A::AbstractSparseMatrixCSC, check::Function)
41124112
return false
41134113
end
41144114
else
4115+
# if nzrange(A, row) is empty, then A[:, row] is all zeros.
4116+
# Specifically, A[col, row] is zero.
4117+
# However, we know at this point that A[row, col] is not zero
4118+
# This means that the matrix is not symmetric
4119+
isempty(nzrange(A, row)) && return false
4120+
41154121
offset = tracker[row]
41164122

41174123
# If the matrix is unsymmetric, there might not exist
@@ -4605,6 +4611,6 @@ function copytrito!(M::AbstractMatrix, S::AbstractSparseMatrixCSC, uplo::Char)
46054611
(uplo == 'U' && row <= col) || (uplo == 'L' && row >= col) || continue
46064612
M[row, col] = nz[i]
46074613
end
4608-
end
4614+
end
46094615
return M
46104616
end

src/sparsevector.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,7 +1932,7 @@ function _spmul!(y::AbstractVector, A::AbstractMatrix, x::AbstractSparseVector,
19321932
"Matrix A has $m rows, but vector y has a length $(length(y))"))
19331933
m == 0 && return y
19341934
β != one(β) && LinearAlgebra._rmul_or_fill!(y, β)
1935-
α == zero(α) && return y
1935+
_iszero(α) && return y
19361936

19371937
xnzind = nonzeroinds(x)
19381938
xnzval = nonzeros(x)
@@ -1960,7 +1960,7 @@ function _At_or_Ac_mul_B!(tfun::Function,
19601960
"Matrix A has $m columns, but vector y has a length $(length(y))"))
19611961
m == 0 && return y
19621962
β != one(β) && LinearAlgebra._rmul_or_fill!(y, β)
1963-
α == zero(α) && return y
1963+
_iszero(α) && return y
19641964

19651965
xnzind = nonzeroinds(x)
19661966
xnzval = nonzeros(x)
@@ -2055,7 +2055,7 @@ function _spmul!(y::AbstractVector, A::AbstractSparseMatrixCSC, x::AbstractSpars
20552055
"Matrix A has $m rows, but vector y has a length $(length(y))"))
20562056
m == 0 && return y
20572057
β != one(β) && LinearAlgebra._rmul_or_fill!(y, β)
2058-
α == zero(α) && return y
2058+
_iszero(α) && return y
20592059

20602060
xnzind = nonzeroinds(x)
20612061
xnzval = nonzeros(x)
@@ -2087,7 +2087,7 @@ function _At_or_Ac_mul_B!(tfun::Function,
20872087
"Matrix A has $m rows, but vector y has a length $(length(y))"))
20882088
n == 0 && return y
20892089
β != one(β) && LinearAlgebra._rmul_or_fill!(y, β)
2090-
α == zero(α) && return y
2090+
_iszero(α) && return y
20912091

20922092
xnzind = nonzeroinds(x)
20932093
xnzval = nonzeros(x)
@@ -2421,7 +2421,7 @@ import Base.fill!
24212421
function fill!(A::Union{AbstractCompressedVector, AbstractSparseMatrixCSC}, x)
24222422
T = eltype(A)
24232423
xT = convert(T, x)
2424-
if xT == zero(T)
2424+
if _iszero(xT)
24252425
fill!(nonzeros(A), xT)
24262426
else
24272427
_fillnonzero!(A, xT)

test/linalg.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ end
338338
@test lmul!(transpose(copy(D)), copy(b)) transpose(MD)*bd
339339
@test lmul!(adjoint(copy(D)), copy(b)) MD'*bd
340340
end
341+
342+
v = sprand(eltype(D), size(D,1), 0.1)
343+
@test ldiv!(D, copy(v)) == D \ Array(v)
341344
end
342345
end
343346

@@ -425,6 +428,27 @@ end
425428
@test issymmetric(sparse([1 0; 1 0])) == false
426429
@test issymmetric(sparse([0 1; 1 0])) == true
427430
@test issymmetric(sparse([1 1; 1 0])) == true
431+
432+
# test some non-trivial cases
433+
local S
434+
@testset "random matrices" begin
435+
for sparsity in (0.1, 0.01, 0.0)
436+
S = sparse(Symmetric(sprand(20, 20, sparsity)))
437+
@test issymmetric(S)
438+
@test ishermitian(S)
439+
S = sparse(Symmetric(sprand(ComplexF64, 20, 20, sparsity)))
440+
@test issymmetric(S)
441+
@test !ishermitian(S) || isreal(S)
442+
S = sparse(Hermitian(sprand(ComplexF64, 20, 20, sparsity)))
443+
@test ishermitian(S)
444+
@test !issymmetric(S) || isreal(S)
445+
end
446+
end
447+
448+
@testset "issue #605" begin
449+
S = sparse([2, 3, 1], [1, 1, 3], [1, 1, 1], 3, 3)
450+
@test !issymmetric(S)
451+
end
428452
end
429453

430454
@testset "rotations" begin

0 commit comments

Comments
 (0)