Skip to content

Commit

Permalink
Merge pull request #11826 from JuliaLang/anj/logabsdet
Browse files Browse the repository at this point in the history
Fix #3070. Rename logdet2 to logabsdet + export and tests.
  • Loading branch information
andreasnoack committed Jun 25, 2015
2 parents aa1149a + b3e69cb commit 4ae258b
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 4 deletions.
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ export
ldltfact,
ldltfact!,
linreg,
logabsdet,
logdet,
lu,
lufact!,
Expand Down
1 change: 1 addition & 0 deletions base/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export
ldltfact!,
ldltfact,
linreg,
logabsdet,
logdet,
lu,
lufact,
Expand Down
2 changes: 2 additions & 0 deletions base/linalg/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -533,3 +533,5 @@ end
det(x::Number) = x

logdet(A::AbstractMatrix) = logdet(lufact(A))
logabsdet(A::AbstractMatrix) = logabsdet(lufact(A))

8 changes: 5 additions & 3 deletions base/linalg/lu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,29 +160,31 @@ function det{T,S}(A::LU{T,S})
return prod(diag(A.factors)) * (isodd(sum(A.ipiv .!= 1:n)) ? -one(T) : one(T))
end

function logdet2{T<:Real,S}(A::LU{T,S}) # return log(abs(det)) and sign(det)
function logabsdet{T<:Real,S}(A::LU{T,S}) # return log(abs(det)) and sign(det)
n = chksquare(A)
dg = diag(A.factors)
s = (isodd(sum(A.ipiv .!= 1:n)) ? -one(T) : one(T)) * prod(sign(dg))
sum(log(abs(dg))), s
end

function logdet{T<:Real,S}(A::LU{T,S})
d,s = logdet2(A)
d,s = logabsdet(A)
if s < 0
throw(DomainError())
end
d
end

_mod2pi(x::BigFloat) = mod(x, big(2)*π) # we don't want to export this, but we use it below
_mod2pi(x) = mod2pi(x)
function logdet{T<:Complex,S}(A::LU{T,S})
n = chksquare(A)
s = sum(log(diag(A.factors)))
if isodd(sum(A.ipiv .!= 1:n))
s = Complex(real(s), imag(s)+π)
end
r, a = reim(s)
a = π-mod2pi-a) #Take principal branch with argument (-pi,pi]
a = π - _mod2pi- a) #Take principal branch with argument (-pi,pi]
complex(r,a)
end

Expand Down
6 changes: 6 additions & 0 deletions doc/stdlib/linalg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ Linear algebra functions in Julia are largely implemented by calling functions f
``\`` ✓ ✓ ✓
``cond`` ✓ ✓
``det`` ✓ ✓ ✓
``logdet`` ✓ ✓
``logabsdet`` ✓ ✓
``size`` ✓ ✓
================== ====== ======================== =============

Expand Down Expand Up @@ -564,6 +566,10 @@ Linear algebra functions in Julia are largely implemented by calling functions f

Log of matrix determinant. Equivalent to ``log(det(M))``, but may provide increased accuracy and/or speed.

.. function:: logabsdet(M)

Log of absolute value of determinant of real matrix. Equivalent to ``(log(abs(det(M))), sign(det(M)))``, but may provide increased accuracy and/or speed.

.. function:: inv(M)

Matrix inverse
Expand Down
2 changes: 1 addition & 1 deletion test/choosetests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function choosetests(choices = [])
"linalg/lapack", "linalg/triangular", "linalg/tridiag",
"linalg/bidiag", "linalg/diagonal",
"linalg/pinv", "linalg/givens", "linalg/cholesky",
"linalg/lu", "linalg/symmetric"]
"linalg/lu", "linalg/symmetric", "linalg/generic"]
if Base.USE_GPL_LIBS
push!(linalgtests, "linalg/arnoldi")
end
Expand Down
29 changes: 29 additions & 0 deletions test/linalg/generic.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Base.Test

debug = false

srand(123)

n = 5 # should be odd

for elty in (Int, Rational{BigInt}, Float32, Float64, BigFloat, Complex{Float32}, Complex{Float64}, Complex{BigFloat})
if elty <: Int
A = rand(-n:n, n, n) + 10I
elseif elty <: Rational
A = Rational{BigInt}[rand(-n:n)/rand(1:n) for i = 1:n, j = 1:n] + 10I
elseif elty <: Real
A = convert(Matrix{elty}, randn(n,n)) + 10I
else
A = convert(Matrix{elty}, complex(randn(n,n), randn(n,n)))
end

debug && println("element type: $elty")

@test_approx_eq logdet(A) log(det(A))
if elty <: Real
@test_approx_eq logabsdet(A)[1] log(abs(det(A)))
@test logabsdet(A)[2] == sign(abs(det(A)))
@test_throws DomainError logdet(convert(Matrix{elty}, -eye(n)))
@test logabsdet(convert(Matrix{elty}, -eye(n)))[2] == -1
end
end

0 comments on commit 4ae258b

Please sign in to comment.