Skip to content

Commit b656a89

Browse files
committed
isposdef rewrite with help of cholfact
1 parent 80369bf commit b656a89

File tree

7 files changed

+35
-22
lines changed

7 files changed

+35
-22
lines changed

base/linalg/cholesky.jl

+6-4
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ and return a `Cholesky` factorization. The matrix `A` can either be a [`Symmetri
288288
`StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`.
289289
The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`.
290290
The following functions are available for `Cholesky` objects: [`size`](@ref), [`\\`](@ref),
291-
[`inv`](@ref), and [`det`](@ref).
291+
[`inv`](@ref), [`det`](@ref), [`logdet`](@ref) and [`isposdef`](@ref).
292292
293293
# Example
294294
@@ -461,17 +461,19 @@ function A_ldiv_B!(C::CholeskyPivoted, B::StridedMatrix)
461461
end
462462
end
463463

464+
isposdef(C::Cholesky) = C.info == 0
465+
464466
function det(C::Cholesky)
465-
C.info == 0 || throw(PosDefException(C.info))
466467
dd = one(real(eltype(C)))
467468
@inbounds for i in 1:size(C.factors,1)
468469
dd *= real(C.factors[i,i])^2
469470
end
470-
dd
471+
@assertposdef dd C.info
471472
end
472473

473474
function logdet(C::Cholesky)
474-
C.info == 0 || throw(PosDefException(C.info))
475+
# need to check first, or log will throw DomainError
476+
isposdef(C) || throw(PosDefException(C.info))
475477
dd = zero(real(eltype(C)))
476478
@inbounds for i in 1:size(C.factors,1)
477479
dd += log(real(C.factors[i,i]))

base/linalg/dense.jl

+9-14
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ function scale!(X::Array{T}, s::Real) where T<:BlasComplex
2929
X
3030
end
3131

32-
# Test whether a matrix is positive-definite
33-
isposdef!(A::StridedMatrix{<:BlasFloat}, UL::Symbol) = LAPACK.potrf!(char_uplo(UL), A)[2] == 0
34-
3532
"""
3633
isposdef!(A) -> Bool
3734
38-
Test whether a matrix is positive definite, overwriting `A` in the process.
35+
Test whether a matrix is positive definite by trying to perform a
36+
Cholesky factorization of `A`, overwriting `A` in the process.
37+
See also [`isposdef`](@ref).
3938
4039
# Example
4140
@@ -51,16 +50,14 @@ julia> A
5150
2.0 6.78233
5251
```
5352
"""
54-
isposdef!(A::StridedMatrix) = ishermitian(A) && isposdef!(A, :U)
53+
isposdef!(A::AbstractMatrix) = ishermitian(A) && isposdef(cholfact!(Hermitian(A)))
5554

56-
function isposdef(A::AbstractMatrix{T}, UL::Symbol) where T
57-
S = typeof(sqrt(one(T)))
58-
isposdef!(S == T ? copy(A) : convert(AbstractMatrix{S}, A), UL)
59-
end
6055
"""
6156
isposdef(A) -> Bool
6257
63-
Test whether a matrix is positive definite.
58+
Test whether a matrix is positive definite by trying to perform a
59+
Cholesky factorization of `A`.
60+
See also [`isposdef!`](@ref)
6461
6562
# Example
6663
@@ -74,10 +71,8 @@ julia> isposdef(A)
7471
true
7572
```
7673
"""
77-
function isposdef(A::AbstractMatrix{T}) where T
78-
S = typeof(sqrt(one(T)))
79-
isposdef!(S == T ? copy(A) : convert(AbstractMatrix{S}, A))
80-
end
74+
isposdef(A::AbstractMatrix{T}) where {T} =
75+
isposdef!(copy_oftype(A, promote_type(typeof(chol(one(T))),Float32)))
8176
isposdef(x::Number) = imag(x)==0 && real(x) > 0
8277

8378
stride1(x::Array) = 1

base/linalg/symmetric.jl

-2
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,6 @@ det(A::Symmetric) = det(bkfact(A))
308308
inv(A::Hermitian{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = Hermitian{T,S}(inv(bkfact(A)), A.uplo)
309309
inv(A::Symmetric{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = Symmetric{T,S}(inv(bkfact(A)), A.uplo)
310310

311-
isposdef!(A::HermOrSym{<:BlasFloat,<:StridedMatrix}) = ishermitian(A) && LAPACK.potrf!(A.uplo, A.data)[2] == 0
312-
313311
eigfact!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}) = Eigen(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)...)
314312

315313
function eigfact(A::RealHermSymComplexHerm)

test/linalg/cholesky.jl

+11
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,33 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
6767
capds = cholfact(apds)
6868
@test inv(capds)*apds eye(n)
6969
@test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n
70+
@test logdet(capds) log(det(capds))
71+
@test isposdef(capds)
7072
if eltya <: BlasReal
7173
capds = cholfact!(copy(apds))
7274
@test inv(capds)*apds eye(n)
7375
@test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n
76+
@test logdet(capds) log(det(capds))
77+
@test isposdef(capds)
7478
end
7579
ulstring = sprint(show,capds[:UL])
7680
@test sprint(show,capds) == "$(typeof(capds)) with factor:\n$ulstring"
7781
else
7882
capdh = cholfact(apdh)
7983
@test inv(capdh)*apdh eye(n)
8084
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
85+
@test logdet(capdh) log(det(capdh))
86+
@test isposdef(capdh)
8187
capdh = cholfact!(copy(apdh))
8288
@test inv(capdh)*apdh eye(n)
8389
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
90+
@test logdet(capdh) log(det(capdh))
91+
@test isposdef(capdh)
8492
capdh = cholfact!(copy(apd))
8593
@test inv(capdh)*apdh eye(n)
8694
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
95+
@test logdet(capdh) log(det(capdh))
96+
@test isposdef(capdh)
8797
ulstring = sprint(show,capdh[:UL])
8898
@test sprint(show,capdh) == "$(typeof(capdh)) with factor:\n$ulstring"
8999
end
@@ -270,6 +280,7 @@ end
270280
for T in (Float32, Float64, Complex64, Complex128)
271281
A = T[1 2; 2 1]; B = T[1, 1]
272282
C = cholfact(A)
283+
@test !isposdef(C)
273284
@test_throws PosDefException C\B
274285
@test_throws PosDefException det(C)
275286
@test_throws PosDefException logdet(C)

test/linalg/dense.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ bimg = randn(n,2)/2
4949

5050
apd = ainit'*ainit # symmetric positive-definite
5151
@testset "Positive definiteness" begin
52-
@test isposdef(apd,:U)
52+
@test !isposdef(ainit)
53+
@test isposdef(apd)
54+
if eltya != Int # cannot perform cholfact! for Matrix{Int}
55+
@test !isposdef!(copy(ainit))
56+
@test isposdef!(copy(apd))
57+
end
5358
end
5459
@testset "For b containing $eltyb" for eltyb in (Float32, Float64, Complex64, Complex128, Int)
5560
binit = eltyb == Int ? rand(1:5, n, 2) : convert(Matrix{eltyb}, eltyb <: Complex ? complex.(breal, bimg) : breal)

test/linalg/diagonal.jl

+1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ end
235235
end
236236

237237
@testset "isposdef" begin
238+
@test isposdef(Diagonal(1.0 + rand(n)))
238239
@test !isposdef(Diagonal(-1.0 * rand(n)))
239240
end
240241

test/linalg/eigen.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ aimg = randn(n,n)/2
3535
@test eab[1] == eigvals(fill(α,1,1),fill(β,1,1))
3636
@test eab[2] == eigvecs(fill(α,1,1),fill(β,1,1))
3737

38-
d,v = eig(a)
3938
@testset "non-symmetric eigen decomposition" begin
39+
d,v = eig(a)
4040
for i in 1:size(a,2)
4141
@test a*v[:,i] d[i]*v[:,i]
4242
end
4343
f = eigfact(a)
4444
@test det(a) det(f)
4545
@test inv(a) inv(f)
46+
@test isposdef(a) == isposdef(f)
4647
@test eigvals(f) === f[:values]
4748
@test eigvecs(f) === f[:vectors]
4849

0 commit comments

Comments
 (0)