async def test_nash_failure(): """With regret thresh of zero, nash will fail""" game = gamegen.sym_2p2s_known_eq(1 / 3) sched = gamesched.gamesched(game) eqa = await innerloop.inner_loop(schedgame.schedgame(sched), regret_thresh=0) assert not eqa.size
def generate_games(num): # pylint: disable=too-many-branches """Produce num random games per type""" np.random.seed(0) with open(path.join(_DIR, 'example_games', 'hard_nash.json')) as fil: yield 'hard', gamereader.load(fil).normalize() with open(path.join(_DIR, 'example_games', '2x2x2.nfg')) as fil: yield 'gambit', gamereader.load(fil).normalize() for _ in range(num): yield 'random', gamegen.game(*random_small()).normalize() for _ in range(num): strats = np.random.randint(2, 5, np.random.randint(2, 4)) yield 'covariant', gamegen.covariant_game(strats).normalize() for _ in range(num): strats = np.random.randint(2, 5, 2) yield 'zero sum', gamegen.two_player_zero_sum_game(strats).normalize() for _ in range(num): yield 'prisoners', gamegen.prisoners_dilemma().normalize() for _ in range(num): yield 'chicken', gamegen.sym_2p2s_game(0, 3, 1, 2).normalize() for _ in range(num): prob = np.random.random() yield 'mix', gamegen.sym_2p2s_known_eq(prob).normalize() for _ in range(num): strats = np.random.randint(2, 4) plays = np.random.randint(2, 4) yield 'polymatrix', gamegen.polymatrix_game(plays, strats).normalize() for _ in range(num): wins = np.random.random(3) + .5 loss = -np.random.random(3) - .5 yield 'roshambo', gamegen.rock_paper_scissors(wins, loss).normalize() yield 'shapley easy', gamegen.rock_paper_scissors(win=2).normalize() yield 'shapley normal', gamegen.rock_paper_scissors(win=1).normalize() yield 'shapley hard', gamegen.rock_paper_scissors(win=0.5).normalize() for _ in range(num): yield 'normagg small', gamegen.normal_aggfn(*random_agg_small()) for _ in range(num): yield 'polyagg small', gamegen.poly_aggfn(*random_agg_small()) for _ in range(num): yield 'sineagg small', gamegen.sine_aggfn(*random_agg_small()) for _ in range(num): facs = np.random.randint(2, 6) req = np.random.randint(1, facs) players = np.random.randint(2, 11) yield 'congestion', gamegen.congestion(players, facs, req) for _ in range(num): strats = np.random.randint(2, 6) players = np.random.randint(2, 11) yield 'local effect', gamegen.local_effect(players, strats) for _ in range(num): yield 'normagg large', gamegen.normal_aggfn(*random_agg_large()) for _ in range(num): yield 'polyagg large', gamegen.poly_aggfn(*random_agg_large()) for _ in range(num): yield 'sineagg large', gamegen.sine_aggfn(*random_agg_large()) for _ in range(num): agg = gamegen.sine_aggfn(*random_agg_small()) with warnings.catch_warnings(): warnings.simplefilter('ignore', UserWarning) yield 'rbf', learning.rbfgame_train(agg)
def test_old_nash(): """Test old nash functions appropriately""" prob = 1 / np.sqrt(2) game = gamegen.sym_2p2s_known_eq(prob) eqa = nash.mixed_nash(game, processes=2) assert eqa.shape == (1, 2) eqm, = eqa assert np.allclose(eqm, [prob, 1 - prob], atol=1e-3)
def test_mixed_equilibria(): """Test that mixed equilibria works for easy case""" prob = 1 / np.sqrt(2) game = gamegen.sym_2p2s_known_eq(prob) eqa = nash.mixed_equilibria(game, processes=1) assert eqa.shape == (1, 2) eqm, = eqa assert np.allclose(eqm, [prob, 1 - prob], atol=1e-3)
def test_mixed_known_eq(methods, eq_prob): game = gamegen.sym_2p2s_known_eq(eq_prob) eqa = nash.mixed_nash(game, processes=1, **methods) assert eqa.shape[0] >= 1, "didn't find equilibrium" expected = [eq_prob, 1 - eq_prob] assert np.isclose(eqa, expected, atol=1e-3, rtol=1e-3).all(1).any(), \ "didn't find correct equilibrium {} instead of {}".format( eqa, expected)
def test_optimization_stable_point(eq_prob): game = gamegen.sym_2p2s_known_eq(eq_prob) opt = nash.RegretOptimizer(game) val, grad = opt.grad(np.array([eq_prob, 1 - eq_prob]), 1) assert np.isclose(val, 0), \ "value at equilibrium was not close to zero: {}".format(val) assert np.allclose(grad, 0), \ "grad at equilibrium was not close to zero: {}".format(grad)
def test_old_nash_at_least_one(): """Test old nash functions appropriately""" prob = 1 / np.sqrt(2) game = gamegen.sym_2p2s_known_eq(prob) eqa = nash.mixed_nash(game, replicator=dict(max_iters=0), at_least_one=True) assert eqa.shape == (1, 2) eqm, = eqa assert np.allclose(eqm, [prob, 1 - prob], atol=1e-3)
def test_old_nash_min_reg(): """Test old nash functions appropriately""" prob = 1 / np.sqrt(2) game = gamegen.sym_2p2s_known_eq(prob) eqa = nash.mixed_nash(game, replicator=dict(max_iters=0), min_reg=True) assert eqa.shape == (1, 2) eqm, = eqa reg = regret.mixture_regret(game, eqm) assert reg > 1e-3
async def test_innerloop_known_eq(eq_prob): """Test that inner loop finds known equilibria""" game = gamegen.sym_2p2s_known_eq(eq_prob) sched = gamesched.gamesched(game) eqa = await innerloop.inner_loop(schedgame.schedgame(sched), devs_by_role=True) assert eqa.size, "didn't find equilibrium" expected = [eq_prob, 1 - eq_prob] assert np.isclose(eqa, expected, atol=1e-3, rtol=1e-3).all(-1).any() verify_dist_thresh(eqa)
def test_at_least_one(): # Equilibrium of game is not at a starting point for equilibria finding game = gamegen.sym_2p2s_known_eq(1/math.sqrt(2)) # Don't converge opts = {'max_iters': 0} eqa = nash.mixed_nash(game, processes=1, replicator=opts) assert eqa.size == 0, "found an equilibrium normally" eqa = nash.mixed_nash(game, replicator=opts, processes=1, at_least_one=True) assert eqa.shape[0] == 1, "at_least_one didn't return anything"
async def test_backups_used(): """Test that outerloop uses backups Since restricted game size is 1, but the only equilibria has support two, this must use backups to find an equilibrium.""" sgame = gamegen.sym_2p2s_known_eq(0.5) sched = gamesched.gamesched(sgame) eqa = await innerloop.inner_loop(schedgame.schedgame(sched), restricted_game_size=1) assert eqa.size, "didn't find equilibrium" expected = [0.5, 0.5] assert np.isclose(eqa, expected, atol=1e-3, rtol=1e-3).all(-1).any() verify_dist_thresh(eqa)
def random_pairs(): """Generate random pairs of games""" mix = gamegen.sym_2p2s_known_eq(.5) dom1 = paygame.game( 2, 2, [[2, 0], [1, 1], [0, 2]], [[.1, 0], [.1, 0], [0, 0]]) dom2 = paygame.game( 2, 2, [[2, 0], [1, 1], [0, 2]], [[0, 0], [0, .1], [0, .1]]) yield mix, dom1 yield dom1, mix yield mix, dom2 yield dom2, mix for base in tu.edge_games(): play, strats = base.num_role_players, base.num_role_strats yield (gamegen.poly_aggfn(play, strats, 6), gamegen.poly_aggfn(play, strats, 6))
def test_sym_2p2s_known_eq(eq_prob): game = gamegen.sym_2p2s_known_eq(eq_prob) assert game.is_complete(), "didn't generate a full game" assert game.is_symmetric(), \ "didn't generate a symmetric game" assert np.all(2 == game.num_players), \ "didn't generate correct number of strategies" assert np.all(2 == game.num_strategies), \ "didn't generate correct number of strategies" eqm = np.array([eq_prob, 1 - eq_prob]) reg = regret.mixture_regret(game, eqm) assert np.isclose(reg, 0), \ "expected equilibrium wasn't an equilibrium, reg: {}".format(reg) for non_eqm in game.pure_mixtures(): reg = regret.mixture_regret(game, non_eqm) # If eq_prob is 0 or 1, then pure is the desired mixture assert non_eqm[0] == eq_prob or not np.isclose(reg, 0), \ "pure mixtures was equilibrium, {} {}".format(non_eqm, reg)
def test_sym_2p2s_known_eq(eq_prob): """Test known equilibrium game""" game = gamegen.sym_2p2s_known_eq(eq_prob) assert game.is_complete(), "didn't generate a full game" assert game.is_symmetric(), \ "didn't generate a symmetric game" assert np.all(game.num_role_players == 2), \ "didn't generate correct number of strategies" assert np.all(game.num_role_strats == 2), \ "didn't generate correct number of strategies" eqm = np.array([eq_prob, 1 - eq_prob]) reg = regret.mixture_regret(game, eqm) assert np.isclose(reg, 0), \ "expected equilibrium wasn't an equilibrium, reg: {}".format(reg) for non_eqm in game.pure_mixtures(): reg = regret.mixture_regret(game, non_eqm) # If eq_prob is 0 or 1, then pure is the desired mixture assert non_eqm[0] == eq_prob or not np.isclose(reg, 0), \ 'pure mixtures was equilibrium, {} {}'.format(non_eqm, reg)
def test_replicator_dynamics_noop(): """Test that max_iters stops replicator dynamics""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.replicator_dynamics(game, [1 / 2, 1 / 2], max_iters=0) # pylint: disable=unexpected-keyword-arg assert np.allclose(eqm, [1 / 2, 1 / 2])
def test_old_nash_failure(): """Test old nash functions appropriately""" prob = 1 / np.sqrt(2) game = gamegen.sym_2p2s_known_eq(prob) eqa = nash.mixed_nash(game, replicator=dict(max_iters=0)) assert not eqa.size
def test_replicator_dynamics_noop(): """Test that max_iters stops replicator dynamics""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.replicator_dynamics(game, [1/2, 1/2], max_iters=0) # pylint: disable=unexpected-keyword-arg assert np.allclose(eqm, [1/2, 1/2])
def test_replicator_dynamics(): """Test that it works for games we know it works for""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.replicator_dynamics(game, [1/2, 1/2]) assert np.allclose(eqm, [1 / np.sqrt(2), 1 - 1 / np.sqrt(2)])
def test_regret_matching_failure(): """Test that it works for games we know it works for""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.regret_matching(game, [0, 2]) assert np.allclose(eqm, [1/2, 1/2], atol=1e-2)
def test_regret_matching_failure(): """Test that it works for games we know it works for""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.regret_matching(game, [0, 2]) assert np.allclose(eqm, [1 / 2, 1 / 2], atol=1e-2)
def test_replicator_dynamics(): """Test that it works for games we know it works for""" game = gamegen.sym_2p2s_known_eq(1 / np.sqrt(2)) eqm = nash.replicator_dynamics(game, [1 / 2, 1 / 2]) assert np.allclose(eqm, [1 / np.sqrt(2), 1 - 1 / np.sqrt(2)])