]> gitweb.michael.orlitzky.com - dunshire.git/blobdiff - test/symmetric_linear_game_test.py
Add game accessor methods for its L, K, e1, e2, and dimension.
[dunshire.git] / test / symmetric_linear_game_test.py
index da72fd03cca7215602ff81174a906795ffc189a9..bba2f7ccfcb48c38312e5d5849aae892d40eac31 100644 (file)
@@ -36,12 +36,28 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
     """
     Tests for the SymmetricLinearGame and Solution classes.
     """
-    def assert_within_tol(self, first, second):
+    def assert_within_tol(self, first, second, modifier=1):
         """
         Test that ``first`` and ``second`` are equal within a multiple of
         our default tolerances.
+
+        Parameters
+        ----------
+
+        first : float
+            The first number to compare.
+
+        second : float
+            The second number to compare.
+
+        modifier : float
+            A scaling factor (default: 1) applied to the default
+            ``EPSILON`` for this comparison. If you have a poorly-
+            conditioned matrix, for example, you may want to set this
+            greater than one.
+
         """
-        self.assertTrue(abs(first - second) < EPSILON)
+        self.assertTrue(abs(first - second) < EPSILON*modifier)
 
 
     def assert_solution_exists(self, G):
@@ -50,9 +66,8 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         """
         soln = G.solution()
 
-        expected = inner_product(G._L*soln.player1_optimal(),
-                                 soln.player2_optimal())
-        self.assert_within_tol(soln.game_value(), expected)
+        expected = G.payoff(soln.player1_optimal(), soln.player2_optimal())
+        self.assert_within_tol(soln.game_value(), expected, G.condition())
 
 
 
@@ -113,7 +128,7 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         (alpha, H) = random_nn_scaling(G)
         value1 = G.solution().game_value()
         value2 = H.solution().game_value()
-        self.assert_within_tol(alpha*value1, value2)
+        self.assert_within_tol(alpha*value1, value2, H.condition())
 
 
     def test_scaling_orthant(self):
@@ -151,10 +166,12 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         (alpha, H) = random_translation(G)
         value2 = H.solution().game_value()
 
-        self.assert_within_tol(value1 + alpha, value2)
+        self.assert_within_tol(value1 + alpha, value2, H.condition())
 
         # Make sure the same optimal pair works.
-        self.assert_within_tol(value2, inner_product(H._L*x_bar, y_bar))
+        self.assert_within_tol(value2,
+                               H.payoff(x_bar, y_bar),
+                               H.condition())
 
 
     def test_translation_orthant(self):
@@ -182,22 +199,25 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         """
         # This is the "correct" representation of ``M``, but
         # COLUMN indexed...
-        M = -G._L.trans()
+        M = -G.L().trans()
 
         # so we have to transpose it when we feed it to the constructor.
         # Note: the condition number of ``H`` should be comparable to ``G``.
-        H = SymmetricLinearGame(M.trans(), G._K, G._e2, G._e1)
+        H = SymmetricLinearGame(M.trans(), G.K(), G.e2(), G.e1())
 
         soln1 = G.solution()
         x_bar = soln1.player1_optimal()
         y_bar = soln1.player2_optimal()
         soln2 = H.solution()
 
-        self.assert_within_tol(-soln1.game_value(), soln2.game_value())
+        self.assert_within_tol(-soln1.game_value(),
+                               soln2.game_value(),
+                               H.condition())
 
         # Make sure the switched optimal pair works.
         self.assert_within_tol(soln2.game_value(),
-                               inner_product(M*y_bar, x_bar))
+                               H.payoff(y_bar, x_bar),
+                               H.condition())
 
 
     def test_opposite_game_orthant(self):
@@ -228,11 +248,11 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         y_bar = soln.player2_optimal()
         value = soln.game_value()
 
-        ip1 = inner_product(y_bar, G._L*x_bar - value*G._e1)
-        self.assert_within_tol(ip1, 0)
+        ip1 = inner_product(y_bar, G.L()*x_bar - value*G.e1())
+        self.assert_within_tol(ip1, 0, G.condition())
 
-        ip2 = inner_product(value*G._e2 - G._L.trans()*y_bar, x_bar)
-        self.assert_within_tol(ip2, 0)
+        ip2 = inner_product(value*G.e2() - G.L().trans()*y_bar, x_bar)
+        self.assert_within_tol(ip2, 0, G.condition())
 
 
     def test_orthogonality_orthant(self):
@@ -277,7 +297,7 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
         #
         # See :meth:`assert_within_tol` for an explanation of the
         # fudge factors.
-        eigs = eigenvalues_re(G._L)
+        eigs = eigenvalues_re(G.L())
 
         if soln.game_value() > EPSILON:
             # L should be positive stable
@@ -290,7 +310,9 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904
 
         # The dual game's value should always equal the primal's.
         dualsoln = G.dual().solution()
-        self.assert_within_tol(dualsoln.game_value(), soln.game_value())
+        self.assert_within_tol(dualsoln.game_value(),
+                               soln.game_value(),
+                               G.condition())
 
 
     def test_lyapunov_orthant(self):