From ca0fd1fd4b9a6b9f8b04f24b9f0a4afdc22b9403 Mon Sep 17 00:00:00 2001
From: celvira <clement.elvira@centralesupelec.fr>
Date: Mon, 6 Sep 2021 17:16:23 +0200
Subject: [PATCH] Adding some unit-test

---
 run_tests.sh                        |  1 +
 tests/__init__.py                   |  1 +
 tests/test_generalized_screening.py | 58 +++++++++++++++++
 tests/test_solver.py                | 42 +++++++++++++
 tests/test_utils.py                 | 96 +++++++++++++++++++++++++++++
 5 files changed, 198 insertions(+)
 create mode 100755 run_tests.sh
 create mode 100755 tests/__init__.py
 create mode 100644 tests/test_generalized_screening.py
 create mode 100644 tests/test_solver.py
 create mode 100644 tests/test_utils.py

diff --git a/run_tests.sh b/run_tests.sh
new file mode 100755
index 0000000..ebc4a76
--- /dev/null
+++ b/run_tests.sh
@@ -0,0 +1 @@
+python -m unittest
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100755
index 0000000..7c68785
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
\ No newline at end of file
diff --git a/tests/test_generalized_screening.py b/tests/test_generalized_screening.py
new file mode 100644
index 0000000..c497b08
--- /dev/null
+++ b/tests/test_generalized_screening.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+import unittest
+import numpy as np
+
+from src.dictionaries import generate_dic
+from src.solver.slope import primal_func, dual_func, slope_gp
+from src.solver.parameters import SlopeParameters
+from src.screening.singletest import GapSphereSingleTest
+from src.screening.gap_ptest import GAP_Ptest
+import src.utils as utils
+
+class TestSolver(unittest.TestCase):
+
+   def test_gp_cost_decrease(self):
+      """ Run a non accelerated proximal gradient algorithm
+      assess that the cost function decreaes
+      """
+
+      # 1. Create problem
+      m = 20
+      n = 50
+      matA = generate_dic("gaussian", m, n, True)
+      vecy = np.random.randn(m)
+      vec_gammas = np.linspace(.5, 1, n)[::-1]
+
+      # 2. Compute lambda_max
+      lbd_max = utils.get_lambda_max(vecy, matA, vec_gammas)
+      lbd = .6 * lbd_max
+
+      # 3. Eval solution of slope problem
+      algParameters = SlopeParameters()
+      algParameters.gap_stopping = 1e-12
+      algParameters.max_it = 100000
+      algParameters.accelerated = False
+      out = slope_gp(vecy, matA, .5*lbd_max, vec_gammas, algParameters)
+
+      vecu = vecy - matA @ out["sol"]
+      beta_dual = np.sort(np.abs(matA.T @ vecu))[::-1]
+      beta_dual = np.cumsum(beta_dual) / np.cumsum(lbd * vec_gammas)
+      vecu /= np.max(beta_dual)
+      Atu = matA.T @ vecu
+
+      pval = primal_func(vecy, matA @ out["sol"], out["sol"], lbd, vec_gammas)
+      dval = dual_func(vecy, np.linalg.norm(vecy, 2)**2, vecu)
+      gap = np.abs(pval - dval)
+
+      # 4. Start screening test
+      test1 = GapSphereSingleTest()
+      test2 = GAP_Ptest(np.cumsum(vec_gammas))
+
+      out1 = test1.apply_test(Atu, gap, lbd, vec_gammas)
+      out2 = test2.apply_test(Atu, gap, lbd, vec_gammas)
+
+         # 1e-15 due to machine precision error
+      self.assertTrue( (out2 >= out1).all() )
+
+if __name__ == '__main__':
+   unittest.main()
\ No newline at end of file
diff --git a/tests/test_solver.py b/tests/test_solver.py
new file mode 100644
index 0000000..1bea217
--- /dev/null
+++ b/tests/test_solver.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+import unittest
+import numpy as np
+
+import src.utils as utils
+from src.dictionaries import generate_dic
+from src.solver.slope import slope_gp
+from src.solver.parameters import SlopeParameters
+
+
+class TestSolver(unittest.TestCase):
+
+   def test_gp_cost_decrease(self):
+      """ Run a non accelerated proximal gradient algorithm
+      assess that the cost function decreaes
+      """
+
+      # 1. Create problem
+      m = 20
+      n = 50
+      matA = generate_dic("gaussian", m, n, True)
+      vecy = np.random.randn(m)
+      vec_gammas = np.linspace(0, 1, n)[::-1]
+
+      # 2. Compute lambda_max
+      lbd_max = utils.get_lambda_max(vecy, matA, vec_gammas)
+
+      # 3. Eval solution of slope problem
+      algParameters = SlopeParameters()
+      algParameters.max_it = 1000
+      algParameters.accelerated = False
+      out = slope_gp(vecy, matA, .5*lbd_max, vec_gammas, algParameters)
+
+      # 4. Assert that the zero vector is solution
+      vec_cost = out["cost_function"]
+      vec_diff = (vec_cost[1:] - vec_cost[:-1])
+
+         # 1e-15 due to machine precision error
+      self.assertTrue( (vec_diff <= 1e-14).all() )
+
+if __name__ == '__main__':
+   unittest.main()
\ No newline at end of file
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100644
index 0000000..4017a3c
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+import unittest
+import numpy as np
+
+import src.utils as utils
+from src.dictionaries import generate_dic
+from src.solver.slope import slope_gp
+
+class TestUtilsModule(unittest.TestCase):
+
+   def test_coherence(self):
+      """ Compute the coherence manually and compare it 
+      to the value output by the module
+      """
+
+      # 1. Create dictionary
+      m = 20
+      n = 50
+      matA = generate_dic("gaussian", m, n, True)
+
+      # 2. Compute coherence with module
+      mu = utils.compute_coherence(matA)
+
+      # 3. Compute coherence with brute force
+      mu_prime = np.max(np.abs((matA.T @ matA) - np.eye(n)))
+
+      # 4. Test
+      self.assertAlmostEqual(mu, mu_prime, 14)
+
+
+   def test_cound_coherence_function(self):
+      """ Compute the coherence manually and compare it 
+      to the value output by the module
+      """
+
+      # 1. Create dictionary
+      m = 20
+      n = 50
+      matA = generate_dic("gaussian", m, n, True)
+
+      # 2. Compute coherence with module
+      mu = utils.compute_coherence(matA)
+      coherence_func = utils.compute_coherence_function(matA)
+
+      # 3. Test
+      self.assertAlmostEqual(mu, coherence_func[1], 14)
+      self.assertTrue( (coherence_func <= mu * np.arange(n)).all() )
+
+
+   def test_coherences_pulse(self):
+      """
+         test on analytic dictionary defined in tropp's paper "greed is good"
+         (unnormalzied dictionary)
+      """
+
+      # 1. Create dictionary
+      m = 50
+      n = 30
+      matA = np.zeros((m, n))
+
+      beta = .5
+      for j in range(n):
+         for i in range(j, m):
+            matA[i, j] = np.sqrt(1 - beta**2) * beta**(i-j)
+
+      # 2. Compute coherence with module
+      mu = utils.compute_coherence(matA)
+      mu_star = matA[:, 0] @ matA[:, 1]
+
+      # 3. Test
+      self.assertAlmostEqual(mu, mu_star, 14)
+
+
+   def test_get_lambda_max(self):
+      """
+      """
+
+      # 1. Create problem
+      m = 20
+      n = 50
+      matA = generate_dic("gaussian", m, n, True)
+      vecy = np.random.randn(m)
+      vec_gammas = np.linspace(0, 1, n)[::-1]
+
+      # 2. Compute lambda_max
+      lbd_max = utils.get_lambda_max(vecy, matA, vec_gammas)
+
+      # 3. Eval solution of slope problem
+      out = slope_gp(vecy, matA, lbd_max, vec_gammas)
+
+      # 4. Assert that the zero vector is solution
+      self.assertTrue( (out["sol"] == np.zeros(n)).all() )
+
+
+if __name__ == '__main__':
+   unittest.main()
\ No newline at end of file
-- 
GitLab