X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=test%2Fsymmetric_linear_game_test.py;h=cf305f0ae133699a1be00a3dce8c27c72c9f2a7c;hb=dd58b25641f37f52b7327b1b779a606c33e230eb;hp=b9c29fe68056f52da980443809e881ce6faa28ad;hpb=0b6e486f52b6c42f78ba408543be0cc4b66fada7;p=dunshire.git diff --git a/test/symmetric_linear_game_test.py b/test/symmetric_linear_game_test.py index b9c29fe..cf305f0 100644 --- a/test/symmetric_linear_game_test.py +++ b/test/symmetric_linear_game_test.py @@ -43,17 +43,28 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def test_solutions_dont_change_orthant(self): + """ + If we solve the same game twice over the nonnegative orthant, + then we should get the same solution both times. The solution to + a game is not unique, but the process we use is (as far as we + know) deterministic. + """ G = random_orthant_game() self.assert_solutions_dont_change(G) def test_solutions_dont_change_icecream(self): + """ + If we solve the same game twice over the ice-cream cone, then we + should get the same solution both times. The solution to a game + is not unique, but the process we use is (as far as we know) + deterministic. + """ G = random_icecream_game() self.assert_solutions_dont_change(G) def assert_solutions_dont_change(self, G): """ - If we solve the same problem twice, we should get - the same answer both times. + Solve ``G`` twice and check that the solutions agree. """ soln1 = G.solution() soln2 = G.solution() @@ -69,6 +80,10 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def assert_player1_start_valid(self, G): + """ + Ensure that player one's starting point satisfies both the + equality and cone inequality in the CVXOPT primal problem. + """ x = G.player1_start()['x'] s = G.player1_start()['s'] s1 = s[0:G.dimension()] @@ -79,7 +94,8 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def test_player1_start_valid_orthant(self): """ - Ensure that player one's starting point is in the orthant. + Ensure that player one's starting point is feasible over the + nonnegative orthant. """ G = random_orthant_game() self.assert_player1_start_valid(G) @@ -87,13 +103,18 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def test_player1_start_valid_icecream(self): """ - Ensure that player one's starting point is in the ice-cream cone. + Ensure that player one's starting point is feasible over the + ice-cream cone. """ G = random_icecream_game() self.assert_player1_start_valid(G) def assert_player2_start_valid(self, G): + """ + Check that player two's starting point satisfies both the + cone inequality in the CVXOPT dual problem. + """ z = G.player2_start()['z'] z1 = z[0:G.dimension()] z2 = z[G.dimension():] @@ -102,7 +123,8 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def test_player2_start_valid_orthant(self): """ - Ensure that player two's starting point is in the orthant. + Ensure that player two's starting point is feasible over the + nonnegative orthant. """ G = random_orthant_game() self.assert_player2_start_valid(G) @@ -110,7 +132,8 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 def test_player2_start_valid_icecream(self): """ - Ensure that player two's starting point is in the ice-cream cone. + Ensure that player two's starting point is feasible over the + ice-cream cone. """ G = random_icecream_game() self.assert_player2_start_valid(G) @@ -212,25 +235,25 @@ class SymmetricLinearGameTest(TestCase): # pylint: disable=R0904 value that is the negation of the original game. Comes from some corollary. """ - # This is the "correct" representation of ``M``, but - # COLUMN indexed... - M = -G.L().trans() - - # so we have to transpose it when we feed it to the constructor. + # Since L is a CVXOPT matrix, it will be transposed automatically. # Note: the condition number of ``H`` should be comparable to ``G``. - H = SymmetricLinearGame(M.trans(), G.K(), G.e2(), G.e1()) + H = SymmetricLinearGame(-G.L(), G.K(), G.e2(), G.e1()) soln1 = G.solution() x_bar = soln1.player1_optimal() y_bar = soln1.player2_optimal() soln2 = H.solution() - mod = G.tolerance_scale(soln1) - self.assert_within_tol(-soln1.game_value(), soln2.game_value(), mod) + modifier = G.tolerance_scale(soln1) + self.assert_within_tol(-soln1.game_value(), + soln2.game_value(), + modifier) # Make sure the switched optimal pair works. Since x_bar and # y_bar come from G, we use the same modifier. - self.assert_within_tol(soln2.game_value(), H.payoff(y_bar, x_bar), mod) + self.assert_within_tol(soln2.game_value(), + H.payoff(y_bar, x_bar), + modifier)