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
     ])
Example #6
0
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