def test_extensive_to_matrix_game(self): kuhn_game = pyspiel.load_game("kuhn_poker") kuhn_matrix_game = pyspiel.extensive_to_matrix_game(kuhn_game) unused_p0_strategy, unused_p1_strategy, p0_sol_val, p1_sol_val = ( lp_solver.solve_zero_sum_matrix_game(kuhn_matrix_game)) # value from Kuhn 1950 or https://en.wikipedia.org/wiki/Kuhn_poker self.assertAlmostEqual(p0_sol_val, -1 / 18) self.assertAlmostEqual(p1_sol_val, +1 / 18)
def test_extensive_to_matrix_game_type(self): game = pyspiel.extensive_to_matrix_game(pyspiel.load_game("kuhn_poker")) game_type = game.get_type() self.assertEqual(game_type.dynamics, pyspiel.GameType.Dynamics.SIMULTANEOUS) self.assertEqual(game_type.chance_mode, pyspiel.GameType.ChanceMode.DETERMINISTIC) self.assertEqual(game_type.information, pyspiel.GameType.Information.ONE_SHOT) self.assertEqual(game_type.utility, pyspiel.GameType.Utility.ZERO_SUM)
def test_extensive_to_matrix_game_payoff_matrix(self): turn_based_game = pyspiel.load_game_as_turn_based("matrix_pd") matrix_game = pyspiel.extensive_to_matrix_game(turn_based_game) orig_game = pyspiel.load_matrix_game("matrix_pd") for row in range(orig_game.num_rows()): for col in range(orig_game.num_cols()): for player in range(2): self.assertEqual( orig_game.player_utility(player, row, col), matrix_game.player_utility(player, row, col))
def test_kuhn_poker(self): game = pyspiel.extensive_to_matrix_game( pyspiel.load_game("kuhn_poker")) solver = double_oracle.DoubleOracleSolver(game) solution, iteration, value = solver.solve( initial_strategies=[[0], [0]]) # check if solution is Nash exp_utilty = solution[0] @ solver.payoffs @ solution[1] self.assertAlmostEqual(max(solver.payoffs[0] @ solution[1]), exp_utilty[0]) self.assertAlmostEqual(max(solution[0] @ solver.payoffs[1]), exp_utilty[1]) self.assertEqual(iteration, 8) self.assertAlmostEqual(value, 0.0)
def test_iterated_dominance_auction(self): # find a strategy through iterated dominance that's not strictly dominant auction = pyspiel.extensive_to_matrix_game( pyspiel.load_game("first_sealed_auction(max_value=3)")) auction_dom, auction_live = self._checked_iterated_dominance( auction, lp_solver.DOMINANCE_STRICT) # there's just one non-dominated action self.assertEqual(auction_dom.num_rows(), 1) self.assertEqual(auction_dom.num_cols(), 1) best_action = [ auction.row_action_name(row) for row in range(auction.num_rows()) ].index(auction_dom.row_action_name(0)) self.assertTrue(auction_live[0][best_action]) # other actions are all weakly but not all strictly dominated self.assertNotIn(False, [ lp_solver.is_dominated(action, auction, 0, lp_solver.DOMINANCE_WEAK) for action in range(6) if action != best_action ]) self.assertIn(False, [ lp_solver.is_dominated(action, auction, 0, lp_solver.DOMINANCE_STRICT) for action in range(6) if action != best_action ])
def main(_): game = pyspiel.load_game(FLAGS.game) print("loaded game") # convert game to matrix form if it isn't already a matrix game if not isinstance(game, pyspiel.MatrixGame): game = pyspiel.extensive_to_matrix_game(game) num_rows, num_cols = game.num_rows(), game.num_cols() print("converted to matrix form with shape (%d, %d)" % (num_rows, num_cols)) # use iterated dominance to reduce the space unless the solver is LP (fast) if FLAGS.solver != "linear": if FLAGS.mode == "all": game, _ = lp_solver.iterated_dominance( game, tol=FLAGS.tol, mode=lp_solver.DOMINANCE_STRICT) num_rows, num_cols = game.num_rows(), game.num_cols() print( "discarded strictly dominated actions yielding shape (%d, %d)" % (num_rows, num_cols)) if FLAGS.mode == "one": game, _ = lp_solver.iterated_dominance( game, tol=FLAGS.tol, mode=lp_solver.DOMINANCE_VERY_WEAK) num_rows, num_cols = game.num_rows(), game.num_cols() print( "discarded very weakly dominated actions yielding shape (%d, %d)" % (num_rows, num_cols)) # game is now finalized num_rows, num_cols = game.num_rows(), game.num_cols() row_actions = [game.row_action_name(row) for row in range(num_rows)] col_actions = [game.col_action_name(col) for col in range(num_cols)] row_payoffs, col_payoffs = utils.game_payoffs_array(game) pure_nash = list( zip(*((row_payoffs >= row_payoffs.max(0, keepdims=True) - FLAGS.tol) & (col_payoffs >= col_payoffs.max(1, keepdims=True) - FLAGS.tol) ).nonzero())) if pure_nash: print("found %d pure equilibria" % len(pure_nash)) if FLAGS.mode == "pure": if not pure_nash: print("found no pure equilibria") return print("pure equilibria:") for row, col in pure_nash: print("payoffs %f, %f:" % (row_payoffs[row, col], col_payoffs[row, col])) print("row action:") print(row_actions[row]) print("col action:") print(col_actions[col]) print("") return if FLAGS.mode == "one" and pure_nash: print("pure equilibrium:") row, col = pure_nash[0] print("payoffs %f, %f:" % (row_payoffs[row, col], col_payoffs[row, col])) print("row action:") print(row_actions[row]) print("col action:") print(col_actions[col]) print("") return for row, action in enumerate(row_actions): print("row action %s:" % row) print(action) print("--") for col, action in enumerate(col_actions): print("col action %s:" % col) print(action) print("--") if num_rows == 1 or num_cols == 1: equilibria = itertools.product(np.eye(num_rows), np.eye(num_cols)) elif FLAGS.solver == "linear": if FLAGS.mode != "one" or (row_payoffs + col_payoffs).max() > ( row_payoffs + col_payoffs).min() + FLAGS.tol: raise ValueError( "can't use linear solver for non-constant-sum game or " "for finding all optima!") print("using linear solver") def gen(): p0_sol, p1_sol, _, _ = lp_solver.solve_zero_sum_matrix_game( pyspiel.create_matrix_game(row_payoffs - col_payoffs, col_payoffs - row_payoffs)) yield (np.squeeze(p0_sol, 1), np.squeeze(p1_sol, 1)) equilibria = gen() elif FLAGS.solver == "lrsnash": print("using lrsnash solver") equilibria = lrs_solve(row_payoffs, col_payoffs) elif FLAGS.solver == "nashpy": if FLAGS.mode == "all": print("using nashpy vertex enumeration") equilibria = nashpy.Game(row_payoffs, col_payoffs).vertex_enumeration() else: print("using nashpy Lemke-Howson solver") equilibria = lemke_howson_solve(row_payoffs, col_payoffs) print("equilibria:" if FLAGS.mode == "all" else "an equilibrium:") equilibria = iter(equilibria) # check that there's at least one equilibrium try: equilibria = itertools.chain([next(equilibria)], equilibria) except StopIteration: print("not found!") for row_mixture, col_mixture in equilibria: print("payoffs %f, %f for %s, %s" % (row_mixture.dot(row_payoffs.dot(col_mixture)), row_mixture.dot( col_payoffs.dot(col_mixture)), row_mixture, col_mixture)) if FLAGS.mode == "one": return