From d885ef09fe818da8c70174cb58fbdad86f9d1565 Mon Sep 17 00:00:00 2001 From: William de Vazelhes 80055062 Date: Mon, 3 Aug 2020 14:09:55 +0200 Subject: [PATCH 1/3] Fix test for components_from_metric and add tests for _check_sdp_from_eigen --- test/test_components_metric_conversion.py | 9 ++--- test/test_utils.py | 47 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/test/test_components_metric_conversion.py b/test/test_components_metric_conversion.py index b9da87ed..bab44158 100644 --- a/test/test_components_metric_conversion.py +++ b/test/test_components_metric_conversion.py @@ -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) diff --git a/test/test_utils.py b/test/test_utils.py index fdcb864a..3f271fe8 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -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)""" From e1d4e62292a84ec8aaf6fb0209b981691da70484 Mon Sep 17 00:00:00 2001 From: William de Vazelhes 80055062 Date: Mon, 3 Aug 2020 14:35:23 +0200 Subject: [PATCH 2/3] Fix trailing whitespace --- test/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_utils.py b/test/test_utils.py index 3f271fe8..9b8b5e7e 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1079,7 +1079,7 @@ def test__check_sdp_from_eigen_tol_non_psd(w, tol): @pytest.mark.unit @pytest.mark.parametrize('w, is_definite', - [(np.array([1e5, 1e5, 1e5, 1e5, + [(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): From e099ca3a0d9d3ed649cea639d150669fa92d893e Mon Sep 17 00:00:00 2001 From: William de Vazelhes 80055062 Date: Mon, 3 Aug 2020 14:42:33 +0200 Subject: [PATCH 3/3] Remove unused LinAlgError --- test/test_components_metric_conversion.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_components_metric_conversion.py b/test/test_components_metric_conversion.py index bab44158..04d0d007 100644 --- a/test/test_components_metric_conversion.py +++ b/test/test_components_metric_conversion.py @@ -1,7 +1,6 @@ import unittest import numpy as np import pytest -from numpy.linalg import LinAlgError from scipy.stats import ortho_group from sklearn.datasets import load_iris from numpy.testing import assert_array_almost_equal, assert_allclose