Skip to content

Commit

Permalink
TEST: Increase coverage on game_theory (#343)
Browse files Browse the repository at this point in the history
* TEST: Add tests for mclennen_tourky.py

* TEST: Add test for exceptions in support_enumeration.py

* TEST: Add tests for vertex_enumeration.py

* FIX: Correct typo

* RFC: Change assert_allclose to assert_array_equal
  • Loading branch information
QBatista authored and mmcky committed Oct 1, 2017
1 parent b4b215f commit 21c1a94
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 4 deletions.
97 changes: 95 additions & 2 deletions quantecon/game_theory/tests/test_mclennan_tourky.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
"""
import numpy as np
from nose.tools import ok_
from numpy.testing import assert_array_equal
from nose.tools import ok_, raises
from quantecon.game_theory import Player, NormalFormGame, mclennan_tourky
from quantecon.game_theory.mclennan_tourky import (
_best_response_selection, _flatten_action_profile, _is_epsilon_nash
)


class TestMclennanTourky():
Expand Down Expand Up @@ -54,13 +58,102 @@ def test_pure_nash(self):
NE, res = mclennan_tourky(d['g'], init=init, full_output=True)
ok_(res.num_iter==1)

def test_epsilon_nash(self):

class TestMclennanTourkyInvalidInputs():
def setUp(self):
self.bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
self.g = NormalFormGame(self.bimatrix)

@raises(TypeError)
def test_mclennan_tourky_invalid_g(self):
mclennan_tourky(self.bimatrix)

@raises(TypeError)
def test_mclennan_tourky_invalid_init_type(self):
mclennan_tourky(self.g, 1)

@raises(ValueError)
def test_mclennan_tourky_invalid_init_length(self):
mclennan_tourky(self.g, [1])


class TestEpsilonNash():
def setUp(self):
def anti_coordination(N, v):
payoff_array = np.empty((2,)*N)
payoff_array[0, :] = 1
payoff_array[1, :] = 0
payoff_array[1].flat[0] = v
g = NormalFormGame((Player(payoff_array),)*N)
return g

def p_star(N, v):
# Unique symmetric NE mixed action: [p_star, 1-p_star]
return 1 / (v**(1/(N-1)))

def epsilon_nash_interval(N, v, epsilon):
# Necessary, but not sufficient, condition: lb < p < ub
lb = p_star(N, v) - epsilon / ((N-1)*(v**(1/(N-1))-1))
ub = p_star(N, v) + epsilon / (N-1)
return lb, ub

self.game_dicts = []
v = 2
epsilon = 1e-5

Ns = [2, 3, 4]
for N in Ns:
g = anti_coordination(N, v)
lb, ub = epsilon_nash_interval(N, v, epsilon)
d = {'g': g,
'epsilon': epsilon,
'lb': lb,
'ub': ub}
self.game_dicts.append(d)

self.bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
self.g = NormalFormGame(self.bimatrix)

def test_epsilon_nash_with_full_output(self):
for d in self.game_dicts:
NE, res = \
mclennan_tourky(d['g'], epsilon=d['epsilon'], full_output=True)
for i in range(d['g'].N):
ok_(d['lb'] < NE[i][0] < d['ub'])

def test_epsilon_nash_without_full_output(self):
for d in self.game_dicts:
NE = mclennan_tourky(d['g'], epsilon=d['epsilon'],
full_output=False)
for i in range(d['g'].N):
ok_(d['lb'] < NE[i][0] < d['ub'])

def test_is_epsilon_nash_no_indptr(self):
ok_(_is_epsilon_nash([1., 0., 0., 1., 0.], self.g, 1e-5))


def test_flatten_action_profile():
unflattened_actions = [[1/3, 1/3, 1/3], [1/2, 1/2]]
flattened_actions = [1/3, 1/3, 1/3, 1/2, 1/2]
test_obj = _flatten_action_profile(unflattened_actions, [0, 3, 5])
assert_array_equal(test_obj, flattened_actions)


def test_best_response_selection_no_indptr():
bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
g = NormalFormGame(bimatrix)

test_obj = _best_response_selection([1/3, 1/3, 1/3, 1/2,1/2], g)
expected_output = np.array([0., 1., 0., 0., 1.])

assert_array_equal(test_obj, expected_output)


if __name__ == '__main__':
import sys
Expand Down
10 changes: 9 additions & 1 deletion quantecon/game_theory/tests/test_support_enumeration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"""
import numpy as np
from numpy.testing import assert_allclose
from nose.tools import eq_
from nose.tools import eq_, raises
from quantecon.util import check_random_state
from quantecon.game_theory import Player, NormalFormGame, support_enumeration

Expand Down Expand Up @@ -71,6 +71,14 @@ def test_no_error_skew_sym(self):
NEs = support_enumeration(g)


@raises(TypeError)
def test_support_enumeration_invalid_g():
bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
support_enumeration(bimatrix)


if __name__ == '__main__':
import sys
import nose
Expand Down
19 changes: 18 additions & 1 deletion quantecon/game_theory/tests/test_vertex_enumeration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"""
import numpy as np
from numpy.testing import assert_allclose, assert_array_equal
from nose.tools import eq_
from nose.tools import eq_, raises
from quantecon.game_theory import NormalFormGame, vertex_enumeration
from quantecon.game_theory.vertex_enumeration import _BestResponsePolytope

Expand Down Expand Up @@ -46,6 +46,14 @@ def test_vertex_enumeration(self):
assert_allclose(action_computed, action)


@raises(TypeError)
def test_vertex_enumeration_invalid_g():
bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
vertex_enumeration(bimatrix)


class TestBestResponsePolytope:
def setUp(self):
# From von Stengel 2007 in Algorithmic Game Theory
Expand Down Expand Up @@ -98,6 +106,15 @@ def test_best_response_polytope(self):
assert_allclose(vertices_computed, self.vertices_P, atol=1e-15)


@raises(TypeError)
def test_best_response_polytope_invalid_player_instance():
bimatrix = [[(3, 3), (3, 2)],
[(2, 2), (5, 6)],
[(0, 3), (6, 1)]]
g = NormalFormGame(bimatrix)
_BestResponsePolytope(g)


if __name__ == '__main__':
import sys
import nose
Expand Down

0 comments on commit 21c1a94

Please sign in to comment.