Skip to content

Commit 4aad389

Browse files
committed
Implement suggestions from review
1 parent 036a649 commit 4aad389

File tree

3 files changed

+13
-68
lines changed

3 files changed

+13
-68
lines changed

src/ParameterHandling.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ export flatten,
1414
fixed,
1515
deferred,
1616
orthogonal,
17-
positive_definite,
18-
positive_semidefinite
17+
positive_definite
1918

2019
include("flatten.jl")
2120
include("parameters_base.jl")

src/parameters_matrix.jl

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -38,66 +38,30 @@ function flatten(::Type{T}, X::Orthogonal) where {T<:Real}
3838
return v, unflatten_Orthogonal
3939
end
4040

41-
"""
42-
positive_semidefinite(X::AbstractMatrix{<:Real})
43-
44-
Produce a parameter whose `value` is constrained to be a positive-semidefinite matrix. The
45-
argument `X` needs to be a positive-definite matrix
46-
(see https://en.wikipedia.org/wiki/Definite_matrix).
47-
48-
The unconstrained parameter is a `LowerTriangular` matrix, stored as a vector.
49-
50-
!!! warning
51-
Even though the matrix needs to be positive-definite upon construction, the
52-
unconstrained parameter can become zero, which represents a matrix which is merely
53-
positive-semidefinite. To get a matrix that is always strictly positive-definite, use
54-
`positive_definite`.
55-
"""
56-
function positive_semidefinite(X::AbstractMatrix{<:Real})
57-
isposdef(X) || throw(ArgumentError("X is not positive-definite"))
58-
return PositiveSemiDefinite(tril_to_vec(cholesky(X).L))
59-
end
60-
6141
"""
6242
positive_definite(X::AbstractMatrix{<:Real}, ε = eps(T))
6343
64-
Produce a parameter whose `value` is constrained to be a strictly positive-semidefinite
44+
Produce a parameter whose `value` is constrained to be a strictly positive-definite
6545
matrix. The argument `X` minus `ε` times the identity needs to be a positive-definite matrix
6646
(see https://en.wikipedia.org/wiki/Definite_matrix). The optional second argument `ε` must
6747
be a positive real number.
6848
6949
The unconstrained parameter is a `LowerTriangular` matrix, stored as a vector.
7050
"""
7151
function positive_definite(X::AbstractMatrix{T}, ε=eps(T)) where {T<:Real}
72-
ε > 0 || throw(ArgumentError("ε is not positive. Use `positive_semidefinite` instead."))
52+
ε > 0 || throw(ArgumentError("ε must be positive."))
7353
_X = X - ε * I
7454
isposdef(_X) || throw(ArgumentError("X-ε*I is not positive-definite for ε="))
7555
return PositiveDefinite(tril_to_vec(cholesky(_X).L), ε)
7656
end
7757

78-
struct PositiveSemiDefinite{TL<:AbstractVector{<:Real}} <: AbstractParameter
79-
L::TL
80-
end
81-
82-
Base.:(==)(X::PositiveSemiDefinite, Y::PositiveSemiDefinite) = X.L == Y.L
83-
84-
A_At(X) = X * X'
85-
86-
value(X::PositiveSemiDefinite) = A_At(vec_to_tril(X.L))
87-
88-
function flatten(::Type{T}, X::PositiveSemiDefinite) where {T<:Real}
89-
v, unflatten_v = flatten(T, X.L)
90-
function unflatten_PositiveSemiDefinite(v_new::Vector{T})
91-
return PositiveSemiDefinite(unflatten_v(v_new))
92-
end
93-
return v, unflatten_PositiveSemiDefinite
94-
end
95-
9658
struct PositiveDefinite{TL<:AbstractVector{<:Real},Tε<:Real} <: AbstractParameter
9759
L::TL
9860
ε::Tε
9961
end
10062

63+
A_At(X) = X * X'
64+
10165
Base.:(==)(X::PositiveDefinite, Y::PositiveDefinite) = X.L == Y.L && X.ε == Y.ε
10266

10367
value(X::PositiveDefinite) = A_At(vec_to_tril(X.L)) + X.ε * I

test/parameters_matrix.jl

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,47 +24,29 @@ using ParameterHandling: vec_to_tril, tril_to_vec
2424
end
2525
end
2626

27-
@testset "positive_semidefinite" begin
27+
@testset "positive_definite" begin
2828
@testset "vec_tril_conversion" begin
2929
X = tril!(rand(3, 3))
3030
@test vec_to_tril(tril_to_vec(X)) == X
3131
@test_throws ErrorException tril_to_vec(rand(4, 5))
3232
end
3333
X_mat = ParameterHandling.A_At(rand(3, 3)) # Create a positive definite object
34-
X = positive_semidefinite(X_mat)
35-
@test X == X
34+
X = positive_definite(X_mat)
3635
@test value(X) X_mat
3736
@test isposdef(value(X))
3837
@test vec_to_tril(X.L) cholesky(X_mat).L
39-
@test_throws ArgumentError positive_semidefinite(rand(3, 3))
40-
test_parameter_interface(X)
4138

42-
x, re = flatten(X)
43-
Δl = first(
44-
Zygote.gradient(x) do x
45-
X = re(x)
46-
return logdet(value(X))
47-
end,
48-
)
49-
ΔL = first(
50-
Zygote.gradient(vec_to_tril(X.L)) do L
51-
return logdet(L * L')
52-
end,
53-
)
54-
@test vec_to_tril(Δl) == tril(ΔL)
55-
ChainRulesTestUtils.test_rrule(vec_to_tril, x)
56-
end
57-
58-
@testset "positive_definite" begin
59-
X_mat = ParameterHandling.A_At(rand(3, 3)) # Create a positive definite object
60-
X = positive_definite(X_mat)
61-
@test isposdef(value(X))
62-
X.L .= 0 # zero the unconstrained value
39+
# Zeroing the unconstrained value preserve positivity
40+
X.L .= 0
6341
@test isposdef(value(X))
42+
43+
# Check that zeroing the unconstrained value does not affect the original array
6444
@test X != positive_definite(X_mat)
45+
6546
@test positive_definite(X_mat, 1e-5) != positive_definite(X_mat, 1e-6)
6647
@test_throws ArgumentError positive_definite(zeros(3, 3))
6748
@test_throws ArgumentError positive_definite(X_mat, 0.0)
49+
6850
test_parameter_interface(X)
6951

7052
x, re = flatten(X)

0 commit comments

Comments
 (0)