Skip to content

[MRG] Fix test for components_from_metric and add tests for _check_sdp_from_eigen #303

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

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 3 additions & 6 deletions test/test_components_metric_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,14 @@ def test_components_from_metric_edge_cases(self):
L = components_from_metric(M)
assert_allclose(L.T.dot(L), M)

# matrix with a determinant still high but which should be considered as a
# non-definite matrix (to check we don't test the definiteness with the
# determinant which is a bad strategy)
# matrix with a determinant still high but which is
# undefinite w.r.t to numpy standards
M = np.diag([1e5, 1e5, 1e5, 1e5, 1e5, 1e5, 1e-20])
M = P.dot(M).dot(P.T)
assert np.abs(np.linalg.det(M)) > 10
assert np.linalg.slogdet(M)[1] > 1 # (just to show that the computed
# determinant is far from null)
with pytest.raises(LinAlgError) as err_msg:
np.linalg.cholesky(M)
assert str(err_msg.value) == 'Matrix is not positive definite'
assert np.linalg.matrix_rank(M) < M.shape[0]
# (just to show that this case is indeed considered by numpy as an
# indefinite case)
L = components_from_metric(M)
Expand Down
47 changes: 47 additions & 0 deletions test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,53 @@ def test__check_sdp_from_eigen_returns_definiteness(w, is_definite):
assert _check_sdp_from_eigen(w) == is_definite


@pytest.mark.unit
@pytest.mark.parametrize('w, tol, is_definite',
[(np.array([5., 3.]), 2, True),
(np.array([5., 1.]), 2, False),
(np.array([5., -1.]), 2, False)])
def test__check_sdp_from_eigen_tol_psd(w, tol, is_definite):
"""Tests that _check_sdp_from_eigen, for PSD matrices, returns
False if an eigenvalue is lower than tol"""
assert _check_sdp_from_eigen(w, tol=tol) == is_definite


@pytest.mark.unit
@pytest.mark.parametrize('w, tol',
[(np.array([5., -3.]), 2),
(np.array([1., -3.]), 2)])
def test__check_sdp_from_eigen_tol_non_psd(w, tol):
"""Tests that _check_sdp_from_eigen raises a NonPSDError
when there is a negative value with abs value higher than tol"""
with pytest.raises(NonPSDError):
_check_sdp_from_eigen(w, tol=tol)


@pytest.mark.unit
@pytest.mark.parametrize('w, is_definite',
[(np.array([1e5, 1e5, 1e5, 1e5,
1e5, 1e5, 1e-20]), False),
(np.array([1e-10, 1e-10]), True)])
def test__check_sdp_from_eigen_tol_default_psd(w, is_definite):
"""Tests that the default tol argument gives good results for edge cases
like even if the determinant is high but clearly one eigenvalue is low,
(undefinite so returns False) or when all eigenvalues are low (definite so
returns True)"""
assert _check_sdp_from_eigen(w, tol=None) == is_definite


@pytest.mark.unit
@pytest.mark.parametrize('w',
[np.array([1., -1.]),
np.array([-1e-10, 1e-10])])
def test__check_sdp_from_eigen_tol_default_non_psd(w):
"""Tests that the default tol argument is good for raising
NonPSDError, e.g. that when a value is clearly relatively
negative it raises such an error"""
with pytest.raises(NonPSDError):
_check_sdp_from_eigen(w, tol=None)


def test__check_n_components():
"""Checks that n_components returns what is expected
(including the errors)"""
Expand Down