Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isposdef rewrite with help of cholfact #22245

Merged
merged 1 commit into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
isposdef rewrite with help of cholfact
  • Loading branch information
fredrikekre committed Jun 8, 2017
commit 6a3364125346400d8d0e5a43c1d189a501ae7bab
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Deprecated or removed
* The `cholfact`/`cholfact!` methods that accepted an `uplo` symbol have been deprecated
in favor of using `Hermitian` (or `Symmetric`) views ([#22187], [#22188]).

* `isposdef(A::AbstractMatrix, UL::Symbol)` and `isposdef!(A::AbstractMatrix, UL::Symbol)`
have been deprecated in favor of `isposdef(Hermitian(A, UL))` and `isposdef!(Hermitian(A, UL))`
respectively ([#22245]).

* The function `current_module` is deprecated and replaced with `@__MODULE__` ([#22064]).
This caused the deprecation of some reflection methods (such as `macroexpand` and `isconst`),
which now require a module argument.
Expand Down
4 changes: 4 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,10 @@ end
@deprecate cholfact!(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0) cholfact!(Hermitian(A, uplo), Val{true}, tol = tol)
@deprecate cholfact(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0) cholfact(Hermitian(A, uplo), Val{true}, tol = tol)

# PR #22245
@deprecate isposdef(A::AbstractMatrix, UL::Symbol) isposdef(Hermitian(A, UL))
@deprecate isposdef!(A::StridedMatrix, UL::Symbol) isposdef!(Hermitian(A, UL))

# also remove all support machinery in src for current_module when removing this deprecation
# and make Base.include an error
_current_module() = ccall(:jl_get_current_module, Ref{Module}, ())
Expand Down
10 changes: 6 additions & 4 deletions base/linalg/cholesky.jl
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ and return a `Cholesky` factorization. The matrix `A` can either be a [`Symmetri
`StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`.
The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`.
The following functions are available for `Cholesky` objects: [`size`](@ref), [`\\`](@ref),
[`inv`](@ref), and [`det`](@ref).
[`inv`](@ref), [`det`](@ref), [`logdet`](@ref) and [`isposdef`](@ref).

# Example

Expand Down Expand Up @@ -461,17 +461,19 @@ function A_ldiv_B!(C::CholeskyPivoted, B::StridedMatrix)
end
end

isposdef(C::Cholesky) = C.info == 0

function det(C::Cholesky)
C.info == 0 || throw(PosDefException(C.info))
dd = one(real(eltype(C)))
@inbounds for i in 1:size(C.factors,1)
dd *= real(C.factors[i,i])^2
end
dd
@assertposdef dd C.info
end

function logdet(C::Cholesky)
C.info == 0 || throw(PosDefException(C.info))
# need to check first, or log will throw DomainError
isposdef(C) || throw(PosDefException(C.info))
dd = zero(real(eltype(C)))
@inbounds for i in 1:size(C.factors,1)
dd += log(real(C.factors[i,i]))
Expand Down
22 changes: 8 additions & 14 deletions base/linalg/dense.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ function scale!(X::Array{T}, s::Real) where T<:BlasComplex
X
end

# Test whether a matrix is positive-definite
isposdef!(A::StridedMatrix{<:BlasFloat}, UL::Symbol) = LAPACK.potrf!(char_uplo(UL), A)[2] == 0

"""
isposdef!(A) -> Bool

Test whether a matrix is positive definite, overwriting `A` in the process.
Test whether a matrix is positive definite by trying to perform a
Cholesky factorization of `A`, overwriting `A` in the process.
See also [`isposdef`](@ref).

# Example

Expand All @@ -51,16 +50,14 @@ julia> A
2.0 6.78233
```
"""
isposdef!(A::StridedMatrix) = ishermitian(A) && isposdef!(A, :U)
isposdef!(A::AbstractMatrix) = ishermitian(A) && isposdef(cholfact!(Hermitian(A)))

function isposdef(A::AbstractMatrix{T}, UL::Symbol) where T
S = typeof(sqrt(one(T)))
isposdef!(S == T ? copy(A) : convert(AbstractMatrix{S}, A), UL)
end
"""
isposdef(A) -> Bool

Test whether a matrix is positive definite.
Test whether a matrix is positive definite by trying to perform a
Cholesky factorization of `A`.
See also [`isposdef!`](@ref)

# Example

Expand All @@ -74,10 +71,7 @@ julia> isposdef(A)
true
```
"""
function isposdef(A::AbstractMatrix{T}) where T
S = typeof(sqrt(one(T)))
isposdef!(S == T ? copy(A) : convert(AbstractMatrix{S}, A))
end
isposdef(A::AbstractMatrix) = ishermitian(A) && isposdef(cholfact(Hermitian(A)))
isposdef(x::Number) = imag(x)==0 && real(x) > 0

stride1(x::Array) = 1
Expand Down
2 changes: 0 additions & 2 deletions base/linalg/symmetric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,6 @@ det(A::Symmetric) = det(bkfact(A))
inv(A::Hermitian{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = Hermitian{T,S}(inv(bkfact(A)), A.uplo)
inv(A::Symmetric{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = Symmetric{T,S}(inv(bkfact(A)), A.uplo)

isposdef!(A::HermOrSym{<:BlasFloat,<:StridedMatrix}) = ishermitian(A) && LAPACK.potrf!(A.uplo, A.data)[2] == 0

eigfact!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}) = Eigen(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)...)

function eigfact(A::RealHermSymComplexHerm)
Expand Down
11 changes: 11 additions & 0 deletions test/linalg/cholesky.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,33 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
capds = cholfact(apds)
@test inv(capds)*apds ≈ eye(n)
@test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n
@test logdet(capds) ≈ log(det(capds))
@test isposdef(capds)
if eltya <: BlasReal
capds = cholfact!(copy(apds))
@test inv(capds)*apds ≈ eye(n)
@test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n
@test logdet(capds) ≈ log(det(capds))
@test isposdef(capds)
end
ulstring = sprint(show,capds[:UL])
@test sprint(show,capds) == "$(typeof(capds)) with factor:\n$ulstring"
else
capdh = cholfact(apdh)
@test inv(capdh)*apdh ≈ eye(n)
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
@test logdet(capdh) ≈ log(det(capdh))
@test isposdef(capdh)
capdh = cholfact!(copy(apdh))
@test inv(capdh)*apdh ≈ eye(n)
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
@test logdet(capdh) ≈ log(det(capdh))
@test isposdef(capdh)
capdh = cholfact!(copy(apd))
@test inv(capdh)*apdh ≈ eye(n)
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
@test logdet(capdh) ≈ log(det(capdh))
@test isposdef(capdh)
ulstring = sprint(show,capdh[:UL])
@test sprint(show,capdh) == "$(typeof(capdh)) with factor:\n$ulstring"
end
Expand Down Expand Up @@ -270,6 +280,7 @@ end
for T in (Float32, Float64, Complex64, Complex128)
A = T[1 2; 2 1]; B = T[1, 1]
C = cholfact(A)
@test !isposdef(C)
@test_throws PosDefException C\B
@test_throws PosDefException det(C)
@test_throws PosDefException logdet(C)
Expand Down
7 changes: 6 additions & 1 deletion test/linalg/dense.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ bimg = randn(n,2)/2

apd = ainit'*ainit # symmetric positive-definite
@testset "Positive definiteness" begin
@test isposdef(apd,:U)
@test !isposdef(ainit)
@test isposdef(apd)
if eltya != Int # cannot perform cholfact! for Matrix{Int}
@test !isposdef!(copy(ainit))
@test isposdef!(copy(apd))
end
end
@testset "For b containing $eltyb" for eltyb in (Float32, Float64, Complex64, Complex128, Int)
binit = eltyb == Int ? rand(1:5, n, 2) : convert(Matrix{eltyb}, eltyb <: Complex ? complex.(breal, bimg) : breal)
Expand Down
1 change: 1 addition & 0 deletions test/linalg/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ end
end

@testset "isposdef" begin
@test isposdef(Diagonal(1.0 + rand(n)))
@test !isposdef(Diagonal(-1.0 * rand(n)))
end

Expand Down
3 changes: 2 additions & 1 deletion test/linalg/eigen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ aimg = randn(n,n)/2
@test eab[1] == eigvals(fill(α,1,1),fill(β,1,1))
@test eab[2] == eigvecs(fill(α,1,1),fill(β,1,1))

d,v = eig(a)
@testset "non-symmetric eigen decomposition" begin
d, v = eig(a)
for i in 1:size(a,2)
@test a*v[:,i] ≈ d[i]*v[:,i]
end
f = eigfact(a)
@test det(a) ≈ det(f)
@test inv(a) ≈ inv(f)
@test isposdef(a) == isposdef(f)
@test eigvals(f) === f[:values]
@test eigvecs(f) === f[:vectors]

Expand Down