예제 #1
0
def test_normalformgame_constant_payoffs():
    g = NormalFormGame((2, 2))

    ok_(g.is_nash((0, 0)))
    ok_(g.is_nash((0, 1)))
    ok_(g.is_nash((1, 0)))
    ok_(g.is_nash((1, 1)))
예제 #2
0
    def __init__(self, data):
        if isinstance(data, NormalFormGame):
            if data.N != 2:
                raise ValueError('input game must be a two-player game')
            self.g = data
        else:  # data must be array_like
            payoffs = np.asarray(data)
            if not (payoffs.ndim in [2, 3]):
                raise ValueError(
                    'input data must be a square matrix or a bimatrix')
            self.g = NormalFormGame(payoffs)

        self.N = self.g.N  # Must be 2
        self.players = self.g.players
        self.nums_actions = self.g.nums_actions
        self.tie_breaking = 'smallest'

        self.current_actions = np.zeros(self.N, dtype=int)

        self.belief_sizes = tuple(self.nums_actions[1 - i]
                                  for i in range(self.N))
        # Create instance variable `current_belief` for self.players
        for player, belief_size in zip(self.players, self.belief_sizes):
            player.current_belief = np.empty(belief_size)

        self._decreasing_gain = lambda t: 1 / (t + 1)
        self.step_size = self._decreasing_gain
예제 #3
0
class TestNormalFormGame_Asym2p:
    """Test the methods of NormalFormGame with asymmetric two players"""
    def setUp(self):
        """Setup a NormalFormGame instance"""
        matching_pennies_bimatrix = [[(1, -1), (-1, 1)], [(-1, 1), (1, -1)]]
        self.g = NormalFormGame(matching_pennies_bimatrix)

    def test_getitem(self):
        assert_array_equal(self.g[1, 0], [-1, 1])

    def test_is_nash_against_pure(self):
        ok_(not self.g.is_nash((0, 0)))

    def test_is_nash_against_mixed(self):
        ok_(self.g.is_nash(([1 / 2, 1 / 2], [1 / 2, 1 / 2])))
예제 #4
0
class TestNormalFormGame_Sym2p:
    """Test the methods of NormalFormGame with symmetric two players"""
    def setUp(self):
        """Setup a NormalFormGame instance"""
        coordination_game_matrix = [[4, 0], [3, 2]]
        self.g = NormalFormGame(coordination_game_matrix)

    def test_getitem(self):
        assert_array_equal(self.g[0, 1], [0, 3])

    def test_is_nash_pure(self):
        ok_(self.g.is_nash((0, 0)))

    def test_is_nash_mixed(self):
        ok_(self.g.is_nash(([2 / 3, 1 / 3], [2 / 3, 1 / 3])))
예제 #5
0
    def __init__(self, data):
        if isinstance(data, NormalFormGame):
            if data.N != 2:
                raise ValueError('input game must be a two-player game')
            self.g = data
        else:  # data must be array_like
            payoffs = np.asarray(data)
            if not (payoffs.ndim in [2, 3]):
                raise ValueError(
                    'input data must be a square matrix or a bimatrix'
                )
            self.g = NormalFormGame(payoffs)

        self.N = self.g.N  # Must be 2
        self.players = self.g.players
        self.nums_actions = self.g.nums_actions
        self.tie_breaking = 'smallest'

        self.current_actions = np.zeros(self.N, dtype=int)

        self.belief_sizes = tuple(
            self.nums_actions[1-i] for i in range(self.N)
        )
        # Create instance variable `current_belief` for self.players
        for player, belief_size in zip(self.players, self.belief_sizes):
            player.current_belief = np.empty(belief_size)

        self._decreasing_gain = lambda t: 1 / (t+1)
        self.step_size = self._decreasing_gain
예제 #6
0
def test_normalformgame_setitem_1p():
    g = NormalFormGame(2)

    eq_(g.N, 1)  # Number of players

    g[0] = 10  # Set payoff 10 for action 0
    eq_(g.players[0].payoff_array[0], 10)
예제 #7
0
def test_normalformgame_input_action_sizes():
    g = NormalFormGame((2, 3, 4))

    eq_(g.N, 3)  # Number of players

    assert_array_equal(g.players[0].payoff_array, np.zeros((2, 3, 4)))
    assert_array_equal(g.players[1].payoff_array, np.zeros((3, 4, 2)))
    assert_array_equal(g.players[2].payoff_array, np.zeros((4, 2, 3)))
예제 #8
0
class TestNormalFormGame_3p:
    """Test the methods of NormalFormGame with three players"""
    def setUp(self):
        """Setup a NormalFormGame instance"""
        payoffs_2opponents = [[[3, 6], [4, 2]], [[1, 0], [5, 7]]]
        player = Player(payoffs_2opponents)
        self.g = NormalFormGame([player for i in range(3)])

    def test_getitem(self):
        assert_array_equal(self.g[0, 0, 1], [6, 4, 1])

    def test_is_nash_pure(self):
        ok_(self.g.is_nash((0, 0, 0)))
        ok_(not self.g.is_nash((0, 0, 1)))

    def test_is_nash_mixed(self):
        p = (1 + np.sqrt(65)) / 16
        ok_(self.g.is_nash(([1 - p, p], [1 - p, p], [1 - p, p])))
예제 #9
0
def test_normalformgame_setitem():
    g = NormalFormGame((2, 2))
    g[0, 0] = (0, 10)
    g[0, 1] = (0, 10)
    g[1, 0] = (3, 5)
    g[1, 1] = (-2, 0)

    assert_array_equal(g.players[0].payoff_array, [[0, 0], [3, -2]])
    assert_array_equal(g.players[1].payoff_array, [[10, 5], [10, 0]])
예제 #10
0
class TestNormalFormGame_1p:
    """Test for degenerate NormalFormGame with a single player"""
    def setUp(self):
        """Setup a NormalFormGame instance"""
        data = [[0], [1], [1]]
        self.g = NormalFormGame(data)

    def test_construction(self):
        """Degenerate game: construction"""
        ok_(self.g.N == 1)
        assert_array_equal(self.g.players[0].payoff_array, [0, 1, 1])

    def test_getitem(self):
        """Degenerate game: __getitem__"""
        eq_(self.g[0], 0)

    def test_is_nash_pure(self):
        """Degenerate game: is_nash with pure action"""
        ok_(self.g.is_nash((1, )))
        ok_(not self.g.is_nash((0, )))

    def test_is_nash_mixed(self):
        """Degenerate game: is_nash with mixed action"""
        ok_(self.g.is_nash(([0, 1 / 2, 1 / 2], )))
예제 #11
0
def test_normalformgame_invalid_input_payoff_profiles():
    g = NormalFormGame(np.zeros((2, 2, 1)))
예제 #12
0
def test_normalformgame_invalid_input_nosquare_matrix():
    g = NormalFormGame(np.zeros((2, 3)))
예제 #13
0
def test_normalformgame_invalid_input_players_num_inconsistent():
    p0 = Player(np.zeros((2, 2, 2)))
    p1 = Player(np.zeros((2, 2, 2)))
    g = NormalFormGame([p0, p1])
예제 #14
0
class FictitiousPlay(object):
    """
    Fictitious play with two players

    Parameters
    ----------
    data : array_like(float) or NormalFormGame


    Attributes
    ----------
    g : NormalFormGame

    players : list(Player)  # tuple

    nums_actions : tuple(int)

    current_beliefs : tuple(ndarray(float, ndim=1))

    """
    def __init__(self, data):
        if isinstance(data, NormalFormGame):
            if data.N != 2:
                raise ValueError('input game must be a two-player game')
            self.g = data
        else:  # data must be array_like
            payoffs = np.asarray(data)
            if not (payoffs.ndim in [2, 3]):
                raise ValueError(
                    'input data must be a square matrix or a bimatrix')
            self.g = NormalFormGame(payoffs)

        self.N = self.g.N  # Must be 2
        self.players = self.g.players
        self.nums_actions = self.g.nums_actions
        self.tie_breaking = 'smallest'

        self.current_actions = np.zeros(self.N, dtype=int)

        self.belief_sizes = tuple(self.nums_actions[1 - i]
                                  for i in range(self.N))
        # Create instance variable `current_belief` for self.players
        for player, belief_size in zip(self.players, self.belief_sizes):
            player.current_belief = np.empty(belief_size)

        self._decreasing_gain = lambda t: 1 / (t + 1)
        self.step_size = self._decreasing_gain

    def __repr__(self):
        msg = "Fictitious play for "
        g_repr = self.g.__repr__()
        msg += g_repr
        return msg

    def __str__(self):
        return self.__repr__()

    def set_init_actions(self, init_actions=None):
        if init_actions is None:
            init_actions = np.zeros(self.N, dtype=int)
            for i, n in enumerate(self.nums_actions):
                init_actions[i] = np.random.randint(n)
        self.current_actions[:] = init_actions

        # Initialize current_belief for each player
        for i, player in enumerate(self.players):
            player.current_belief[:] = \
                pure2mixed(self.belief_sizes[i], init_actions[1-i])

    @property
    def current_beliefs(self):
        return tuple(player.current_belief for player in self.players)

    def play(self):
        for i, player in enumerate(self.players):
            self.current_actions[i] = \
                player.best_response(player.current_belief,
                                     tie_breaking=self.tie_breaking)

    def update_beliefs(self, step_size):
        for i, player in enumerate(self.players):
            # x[i] = x[i] + step_size * (a[1-i] - x[i])
            #      = (1-step_size) * x[i] + step_size * a[1-i]
            # where x[i] = player's current_belief,
            #       a[1-i] = opponent's current_action.
            player.current_belief *= 1 - step_size
            player.current_belief[self.current_actions[1 - i]] += step_size

    def simulate(self, ts_length, init_actions=None):
        beliefs_sequence = np.empty((ts_length, sum(self.nums_actions)))
        beliefs_iter = self.simulate_iter(ts_length, init_actions)

        for t, beliefs in enumerate(beliefs_iter):
            (beliefs_sequence[t, :self.belief_sizes[0]],
             beliefs_sequence[t, self.belief_sizes[0]:]) = beliefs

        return (beliefs_sequence[:, :self.belief_sizes[0]],
                beliefs_sequence[:, self.belief_sizes[0]:])

    def simulate_iter(self, ts_length, init_actions=None):
        self.set_init_actions(init_actions)

        for t in range(ts_length):
            yield self.current_beliefs
            self.play()
            self.update_beliefs(self.step_size(t + 1))

    def replicate(self, T, num_reps, init_actions=None):
        """
        Returns
        -------
        out : tuple(ndarray(float, ndim=2))

        """
        out = np.empty((num_reps, sum(self.nums_actions)))

        for j in range(num_reps):
            beliefs_iter = self.simulate_iter(T + 1, init_actions)
            for beliefs in beliefs_iter:
                x = beliefs
            out[j, :self.belief_sizes[0]], out[j, self.belief_sizes[0]:] = x

        return out[:, :self.belief_sizes[0]], out[:, self.belief_sizes[0]:]
예제 #15
0
def test_normalformgame_input_action_sizes_1p():
    g = NormalFormGame(2)

    eq_(g.N, 1)  # Number of players

    assert_array_equal(g.players[0].payoff_array, np.zeros(2))
예제 #16
0
 def setUp(self):
     """Setup a NormalFormGame instance"""
     data = [[0], [1], [1]]
     self.g = NormalFormGame(data)
예제 #17
0
 def setUp(self):
     '''Setup a FictitiousPlay instance'''
     payoff_bimatrix = np.zeros((2, 3, 2))  # 2 x 3 game
     g = NormalFormGame(payoff_bimatrix)
     self.fp = FictitiousPlay(g)
예제 #18
0
 def setUp(self):
     """Setup a NormalFormGame instance"""
     matching_pennies_bimatrix = [[(1, -1), (-1, 1)], [(-1, 1), (1, -1)]]
     self.g = NormalFormGame(matching_pennies_bimatrix)
예제 #19
0
 def setUp(self):
     """Setup a NormalFormGame instance"""
     payoffs_2opponents = [[[3, 6], [4, 2]], [[1, 0], [5, 7]]]
     player = Player(payoffs_2opponents)
     self.g = NormalFormGame([player for i in range(3)])
예제 #20
0
 def setUp(self):
     """Setup a NormalFormGame instance"""
     coordination_game_matrix = [[4, 0], [3, 2]]
     self.g = NormalFormGame(coordination_game_matrix)
예제 #21
0
class FictitiousPlay(object):
    """
    Fictitious play with two players

    Parameters
    ----------
    data : array_like(float) or NormalFormGame


    Attributes
    ----------
    g : NormalFormGame

    players : list(Player)  # tuple

    nums_actions : tuple(int)

    current_beliefs : tuple(ndarray(float, ndim=1))

    """
    def __init__(self, data):
        if isinstance(data, NormalFormGame):
            if data.N != 2:
                raise ValueError('input game must be a two-player game')
            self.g = data
        else:  # data must be array_like
            payoffs = np.asarray(data)
            if not (payoffs.ndim in [2, 3]):
                raise ValueError(
                    'input data must be a square matrix or a bimatrix'
                )
            self.g = NormalFormGame(payoffs)

        self.N = self.g.N  # Must be 2
        self.players = self.g.players
        self.nums_actions = self.g.nums_actions
        self.tie_breaking = 'smallest'

        self.current_actions = np.zeros(self.N, dtype=int)

        self.belief_sizes = tuple(
            self.nums_actions[1-i] for i in range(self.N)
        )
        # Create instance variable `current_belief` for self.players
        for player, belief_size in zip(self.players, self.belief_sizes):
            player.current_belief = np.empty(belief_size)

        self._decreasing_gain = lambda t: 1 / (t+1)
        self.step_size = self._decreasing_gain

    def __repr__(self):
        msg = "Fictitious play for "
        g_repr = self.g.__repr__()
        msg += g_repr
        return msg

    def __str__(self):
        return self.__repr__()

    def set_init_actions(self, init_actions=None):
        if init_actions is None:
            init_actions = np.zeros(self.N, dtype=int)
            for i, n in enumerate(self.nums_actions):
                init_actions[i] = np.random.randint(n)
        self.current_actions[:] = init_actions

        # Initialize current_belief for each player
        for i, player in enumerate(self.players):
            player.current_belief[:] = \
                pure2mixed(self.belief_sizes[i], init_actions[1-i])

    @property
    def current_beliefs(self):
        return tuple(player.current_belief for player in self.players)

    def play(self):
        for i, player in enumerate(self.players):
            self.current_actions[i] = \
                player.best_response(player.current_belief,
                                     tie_breaking=self.tie_breaking)

    def update_beliefs(self, step_size):
        for i, player in enumerate(self.players):
            # x[i] = x[i] + step_size * (a[1-i] - x[i])
            #      = (1-step_size) * x[i] + step_size * a[1-i]
            # where x[i] = player's current_belief,
            #       a[1-i] = opponent's current_action.
            player.current_belief *= 1 - step_size
            player.current_belief[self.current_actions[1-i]] += step_size

    def simulate(self, ts_length, init_actions=None):
        beliefs_sequence = np.empty((ts_length, sum(self.nums_actions)))
        beliefs_iter = self.simulate_iter(ts_length, init_actions)

        for t, beliefs in enumerate(beliefs_iter):
            (beliefs_sequence[t, :self.belief_sizes[0]],
             beliefs_sequence[t, self.belief_sizes[0]:]) = beliefs

        return (beliefs_sequence[:, :self.belief_sizes[0]],
                beliefs_sequence[:, self.belief_sizes[0]:])

    def simulate_iter(self, ts_length, init_actions=None):
        self.set_init_actions(init_actions)

        for t in range(ts_length):
            yield self.current_beliefs
            self.play()
            self.update_beliefs(self.step_size(t+1))

    def replicate(self, T, num_reps, init_actions=None):
        """
        Returns
        -------
        out : tuple(ndarray(float, ndim=2))

        """
        out = np.empty((num_reps, sum(self.nums_actions)))

        for j in range(num_reps):
            beliefs_iter = self.simulate_iter(T+1, init_actions)
            for beliefs in beliefs_iter:
                x = beliefs
            out[j, :self.belief_sizes[0]], out[j, self.belief_sizes[0]:] = x

        return out[:, :self.belief_sizes[0]], out[:, self.belief_sizes[0]:]