From b701403c21a795ff7033cab5a753807c181517b1 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 13 Oct 2016 14:17:54 -0400 Subject: [PATCH] Add tests for Lyapunov games over the ice-cream cone. --- TODO | 1 - src/dunshire/games.py | 68 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index 9699cd1..9b54805 100644 --- a/TODO +++ b/TODO @@ -21,4 +21,3 @@ 9. We only need to include the API docs for dunshire.games in the "user manual;" everything else can go in an appendix. -10. Test Lyapunov games over the ice cream cone. diff --git a/src/dunshire/games.py b/src/dunshire/games.py index 1364fdd..3d4b09a 100644 --- a/src/dunshire/games.py +++ b/src/dunshire/games.py @@ -531,6 +531,39 @@ def _random_diagonal_matrix(dims): return matrix([[uniform(-10, 10)*int(i == j) for i in range(dims)] for j in range(dims)]) + +def _random_skew_symmetric_matrix(dims): + """ + Generate a random skew-symmetrix (``dims``-by-``dims``) matrix. + + Examples + -------- + + >>> A = _random_skew_symmetric_matrix(randint(1, 10)) + >>> norm(A + A.trans()) < options.ABS_TOL + True + + """ + strict_ut = [[uniform(-10, 10)*int(i < j) for i in range(dims)] + for j in range(dims)] + + strict_ut = matrix(strict_ut, (dims,dims)) + return (strict_ut - strict_ut.trans()) + + +def _random_lyapunov_like_icecream(dims): + """ + Generate a random Lyapunov-like matrix over the ice-cream cone in + ``dims`` dimensions. + """ + a = matrix([uniform(-10,10)], (1,1)) + b = matrix([uniform(-10,10) for idx in range(dims-1)], (dims-1, 1)) + D = _random_skew_symmetric_matrix(dims-1) + a*identity(dims-1) + row1 = append_col(a, b.trans()) + row2 = append_col(b, D) + return append_row(row1,row2) + + def _random_orthant_params(): """ Generate the ``L``, ``K``, ``e1``, and ``e2`` parameters for a @@ -825,15 +858,10 @@ class SymmetricLinearGameTest(TestCase): self.assertTrue(game.solution().game_value() >= -options.ABS_TOL) - def test_lyapunov_orthant(self): + def assert_lyapunov_works(self, L, K, e1, e2): """ - Test that a Lyapunov game on the nonnegative orthant works. + Check that Lyapunov games act the way we expect. """ - (L, K, e1, e2) = _random_orthant_params() - - # Ignore that L, we need a diagonal (Lyapunov-like) one. - # (And we don't need to transpose those.) - L = _random_diagonal_matrix(K.dimension()) game = SymmetricLinearGame(L, K, e1, e2) soln = game.solution() @@ -852,3 +880,29 @@ class SymmetricLinearGameTest(TestCase): # The dual game's value should always equal the primal's. dualsoln = game.dual().solution() self.assert_within_tol(dualsoln.game_value(), soln.game_value()) + + + def test_lyapunov_orthant(self): + """ + Test that a Lyapunov game on the nonnegative orthant works. + """ + (L, K, e1, e2) = _random_orthant_params() + + # Ignore that L, we need a diagonal (Lyapunov-like) one. + # (And we don't need to transpose those.) + L = _random_diagonal_matrix(K.dimension()) + + self.assert_lyapunov_works(L, K, e1, e2) + + + def test_lyapunov_icecream(self): + """ + Test that a Lyapunov game on the ice-cream cone works. + """ + (L, K, e1, e2) = _random_icecream_params() + + # Ignore that L, we need a diagonal (Lyapunov-like) one. + # (And we don't need to transpose those.) + L = _random_lyapunov_like_icecream(K.dimension()) + + self.assert_lyapunov_works(L, K, e1, e2) -- 2.44.2