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)
async def test_innerloop_failures(players, strats, count, when): """Test that inner loop handles exceptions during scheduling""" game = gamegen.game(players, strats) sched = gamesched.gamesched(game) esched = tu.ExceptionScheduler(sched, count, when) sgame = schedgame.schedgame(esched) with pytest.raises(tu.SchedulerException): await innerloop.inner_loop(sgame, restricted_game_size=5)
def test_nan_deviations(players, strategies): """Test nan deviations""" game = gamegen.game(players, strategies) for mix in game.random_mixtures(20, alpha=0.05): mix = game.trim_mixture_support(mix) gains = regret.mixture_deviation_gains(game, mix) assert not np.isnan(gains).any(), \ 'deviation gains in complete game were nan'
def test_game(players, strategies, _): """Test game""" game = gamegen.game(players, strategies) assert game.is_complete(), "didn't generate a full game" assert np.all(players == game.num_role_players), \ "didn't generate correct number of strategies" assert np.all(strategies == game.num_role_strats), \ "didn't generate correct number of strategies"
async def test_random_mean_reg(players, strats): """Test that no bootstraps works""" game = gamegen.game(players, strats) mix = game.random_mixture() sched = gamesched.gamesched(game) mean, boot = await bootstrap.deviation_payoffs(sched, mix, 20) assert mean.shape == (game.num_strats, ) assert boot.shape == (0, game.num_strats)
def test_game(players, strategies, _): """Test game""" game = gamegen.game(players, strategies) assert game.is_complete(), "didn't generate a full game" assert np.all(players == game.num_role_players), \ "didn't generate correct number of strategies" assert np.all(strategies == game.num_role_strats), \ "didn't generate correct number of strategies"
def test_empty_add_noise(): """Test adding noise to an empty game""" base_game = rsgame.empty([3, 3], [4, 4]) game = gamegen.gen_noise(base_game) assert game.is_empty() base_game = gamegen.game([3] * 3, 4) game = gamegen.gen_noise(base_game, 0, 0) assert game.is_empty()
async def test_basic_profile(players, strats): """Test that basic profile sampling works""" game = gamegen.game(players, strats) basesched = gamesched.gamesched(game) sched = canonsched.canon(basesched) assert np.all(sched.num_role_strats > 1) pay = await sched.sample_payoffs(sched.random_profile()) assert pay.size == sched.num_strats assert str(sched) == str(basesched)
def test_empty_add_noise(): """Test adding noise to an empty game""" base_game = rsgame.empty([3, 3], [4, 4]) game = gamegen.gen_noise(base_game) assert game.is_empty() base_game = gamegen.game([3] * 3, 4) game = gamegen.gen_noise(base_game, 0, 0) assert game.is_empty()
async def test_boot_symmetric(tmpdir): """Test bootstrapping a symmetric game""" game = gamegen.game(4, 3) mix_file = str(tmpdir.join("mix.json")) with open(mix_file, "w") as fil: json.dump(game.mixture_to_json(game.random_mixture()), fil) with stdin(json.dumps(game.to_json())), stdout() as out, stderr() as err: assert await run("boot", "game:game:-", mix_file, "10"), err.getvalue() results = json.loads(out.getvalue()) assert {"surplus", "regret", "response"} == results.keys()
async def test_basic_profile(): """Test basic profile""" game = gamegen.game([4, 3], [3, 4]) profs = game.random_profiles(20) sched = gamesched.gamesched(game) assert rsgame.empty_copy(sched) == rsgame.empty_copy(game) paylist = await asyncio.gather(*[sched.sample_payoffs(p) for p in profs]) pays = np.stack(paylist) assert np.allclose(pays[profs == 0], 0) assert str(sched) == repr(game)
async def test_boot_symmetric(tmpdir): """Test bootstrapping a symmetric game""" game = gamegen.game(4, 3) mix_file = str(tmpdir.join('mix.json')) with open(mix_file, 'w') as fil: json.dump(game.mixture_to_json(game.random_mixture()), fil) with stdin(json.dumps(game.to_json())), stdout() as out, stderr() as err: assert await run( 'boot', 'game:game:-', mix_file, '10'), err.getvalue() results = json.loads(out.getvalue()) assert {'surplus', 'regret', 'response'} == results.keys()
async def test_mix_asyncgame(): """Test that that mixture async games work""" game0 = gamegen.game([4, 3], [3, 4]) game1 = gamegen.game([4, 3], [3, 4]) agame = asyncgame.mix(asyncgame.wrap(game0), asyncgame.wrap(game1), 0.4) assert agame.get_game() == rsgame.mix(game0, game1, 0.4) assert str(agame) == "{} - 0.4 - {}".format(repr(game0), repr(game1)) rest = agame.random_restriction() rgame = await agame.get_restricted_game(rest) assert rgame.is_complete() assert rsgame.empty_copy(rgame) == rsgame.empty_copy(game0.restrict(rest)) dgame = await agame.get_deviation_game(rest) mix = restrict.translate(rgame.random_mixture(), rest) assert not np.isnan(dgame.deviation_payoffs(mix)).any() dup = asyncgame.mix(asyncgame.wrap(game0), asyncgame.wrap(game1), 0.4) assert hash(dup) == hash(agame) assert dup == agame
def test_gen_noise(players, strategies, lower, prob, _): """Test generate noise""" roles = max(np.array(players).size, np.array(strategies).size) base_game = gamegen.game(players, strategies) game = gamegen.gen_noise(base_game, prob, lower) assert lower == 0 or game.is_complete(), "didn't generate a full game" assert game.num_roles == roles, \ "didn't generate correct number of players" assert np.all(strategies == game.num_role_strats), \ "didn't generate correct number of strategies" assert np.all(game.num_samples >= min(lower, 1)), \ "didn't generate appropriate number of samples"
def test_keep_profiles(players, strategies, _): """Test keep profiles""" game = gamegen.game(players, strategies) test = gamegen.keep_num_profiles(game, 4) assert test.num_profiles == 4 test = gamegen.keep_profiles(game, 0.0) assert test.is_empty(), "didn't generate a full game" test = gamegen.keep_num_profiles(game, 0) assert test.is_empty(), "didn't generate a full game" gamegen.keep_profiles(game, 0.5)
def test_gen_noise(players, strategies, lower, prob, _): """Test generate noise""" roles = max(np.array(players).size, np.array(strategies).size) base_game = gamegen.game(players, strategies) game = gamegen.gen_noise(base_game, prob, lower) assert lower == 0 or game.is_complete(), "didn't generate a full game" assert game.num_roles == roles, \ "didn't generate correct number of players" assert np.all(strategies == game.num_role_strats), \ "didn't generate correct number of strategies" assert np.all(game.num_samples >= min(lower, 1)), \ "didn't generate appropriate number of samples"
def test_random_approximate_dpr(players, strategies, _): """Test approximate dpr preserves completeness on random games""" game = gamegen.game(players, strategies) red_counts = 2 + (rand.random(game.num_roles) * (game.num_role_players - 1)).astype(int) red_counts[game.num_role_players == 1] = 1 # Try to reduce game red_game = dpr.reduce_game(game, red_counts) # Assert that reducing all profiles covers reduced game assert red_game.is_complete(), 'DPR did not preserve completeness'
def test_keep_profiles(players, strategies, _): """Test keep profiles""" game = gamegen.game(players, strategies) test = gamegen.keep_num_profiles(game, 4) assert test.num_profiles == 4 test = gamegen.keep_profiles(game, 0.0) assert test.is_empty(), "didn't generate a full game" test = gamegen.keep_num_profiles(game, 0) assert test.is_empty(), "didn't generate a full game" gamegen.keep_profiles(game, 0.5)
async def test_duplicate_prof(): """Test that duplicate profiles can be scheduled""" game = gamegen.game([4, 3], [3, 4]) profs = game.random_profiles(20) sched = gamesched.gamesched(game) paylist1 = await asyncio.gather(*[sched.sample_payoffs(p) for p in profs]) pays1 = np.stack(paylist1) paylist2 = await asyncio.gather(*[sched.sample_payoffs(p) for p in profs]) pays2 = np.stack(paylist2) assert np.allclose(pays1[profs == 0], 0) assert np.allclose(pays2[profs == 0], 0) assert np.allclose(pays1, pays2)
async def test_random_pure_boot_reg(players, strats): """Test that bootstrap works for pure mixtures""" game = gamegen.game(players, strats) sched = gamesched.gamesched(game) for mix in game.pure_mixtures(): devs = game.deviation_payoffs(mix) mean, boot = await bootstrap.deviation_payoffs(sched, mix, 20, boots=101) assert np.allclose(devs, mean) assert np.allclose(devs, boot) assert mean.shape == (game.num_strats, ) assert boot.shape == (101, game.num_strats)
async def test_basic_asyncgame(): """Test that wrapped async games work""" game = gamegen.game([4, 3], [3, 4]) agame = asyncgame.wrap(game) rest = agame.random_restriction() rgame = await agame.get_restricted_game(rest) assert rgame.is_complete() assert rsgame.empty_copy(rgame) == rsgame.empty_copy(game.restrict(rest)) dgame = await agame.get_deviation_game(rest) mix = restrict.translate(rgame.random_mixture(), rest) assert not np.isnan(dgame.deviation_payoffs(mix)).any() dup = asyncgame.wrap(game) assert hash(dup) == hash(agame) assert dup == agame
async def test_random_boot_reg(players, strats): """Test that bootstrap works for random mixtures""" game = gamegen.game(players, strats) mix = game.random_mixture() devs = game.deviation_payoffs(mix) sched = gamesched.gamesched(game) mean, boot = await bootstrap.deviation_payoffs(sched, mix, 20, boots=101, chunk_size=5) assert mean.shape == (game.num_strats, ) assert boot.shape == (101, game.num_strats) # These aren't guaranteed to be false, but it's incredibly unlikely assert not np.allclose(devs, mean) assert not np.allclose(devs, boot)
def test_approximate_dpr_reduce_game(): """Test approximate dpr game reduction""" game = gamegen.game([3, 4], 2) redgame = dpr.reduce_game(game, 2) # Pure strategies are reduced properly assert (redgame.get_payoffs([2, 0, 0, 2])[0] == game.get_payoffs([3, 0, 0, 4])[0]) # Mixed strategies are reduced properly assert (redgame.get_payoffs([1, 1, 1, 1])[0] == game.get_payoffs([1, 2, 2, 2])[0]) assert (redgame.get_payoffs([1, 1, 1, 1])[1] == game.get_payoffs([2, 1, 2, 2])[1]) assert (redgame.get_payoffs([1, 1, 1, 1])[2] == game.get_payoffs([2, 1, 1, 3])[2]) assert (redgame.get_payoffs([1, 1, 1, 1])[3] == game.get_payoffs([2, 1, 3, 1])[3])
def test_random_matgame_copy(players, strats): """Test copy""" game = gamegen.game(players, strats) matg = matgame.matgame_copy(game) inds = np.cumsum(game.num_role_players[:-1] * game.num_role_strats[:-1]) mprofs = matg.random_profiles(20) mpays = matg.get_payoffs(mprofs) mpays = np.concatenate( [m.reshape(20, p, -1).mean(1).filled(0) for m, p in zip(np.split(np.ma.masked_array(mpays, mprofs == 0), inds, 1), game.num_role_players)], 1) profs = np.concatenate( [m.reshape(20, p, -1).sum(1) for m, p in zip(np.split(mprofs, inds, 1), game.num_role_players)], 1) pays = game.get_payoffs(profs) assert np.allclose(mpays, pays)
def test_random_matgame_copy(players, strats): """Test copy""" game = gamegen.game(players, strats) matg = matgame.matgame_copy(game) inds = np.cumsum(game.num_role_players[:-1] * game.num_role_strats[:-1]) mprofs = matg.random_profiles(20) mpays = matg.get_payoffs(mprofs) mpays = np.concatenate([ m.reshape(20, p, -1).mean(1).filled(0) for m, p in zip( np.split(np.ma.masked_array(mpays, mprofs == 0), inds, 1), game.num_role_players) ], 1) profs = np.concatenate([ m.reshape(20, p, -1).sum(1) for m, p in zip(np.split(mprofs, inds, 1), game.num_role_players) ], 1) pays = game.get_payoffs(profs) assert np.allclose(mpays, pays)
def test_random_dpr(keep_prob, game_desc, _): """Simple test that dpr functions are consistent""" players, strategies, red_players = game_desc # Create game game = gamegen.game(players, strategies, keep_prob) # Try to reduce game red_game = dpr.reduce_game(game, red_players) assert (rsgame.empty(red_players, strategies) == dpr.reduce_game(rsgame.empty(players, strategies), red_players)) # Assert that reducing all profiles covers reduced game reduced_profiles = utils.axis_to_elem(red_game.profiles()) reduced_full_profiles = utils.axis_to_elem( dpr.reduce_profiles(red_game, game.profiles())) assert np.setdiff1d(reduced_profiles, reduced_full_profiles).size == 0, \ "reduced game contained profiles it shouldn't have" # Assert that all contributing profiles are in the expansion of the reduced # game, we need to first filter for complete profiles full_profiles = utils.axis_to_elem(game.profiles()) complete_profs = ~np.isnan(red_game.payoffs()).any(1) full_reduced_profiles = utils.axis_to_elem( dpr.expand_profiles(game, red_game.profiles()[complete_profs])) assert np.setdiff1d(full_reduced_profiles, full_profiles).size == 0, \ 'full game did not have data for all profiles required of reduced' # Assert that dpr counts are accurate num_dpr_profiles = dpr.expand_profiles( game, red_game.all_profiles()).shape[0] assert num_dpr_profiles == red_game.num_all_dpr_profiles # Test the dpr deviation profile counts are accurate rest = red_game.random_restriction() dpr_devs = dpr.expand_profiles( game, restrict.deviation_profiles(red_game, rest)).shape[0] num = restrict.num_dpr_deviation_profiles(red_game, rest) assert dpr_devs == num, \ "num_dpr_deviation_profiles didn't return correct number"
def test_random_twins(players, strategies, keep_prob, _): """Test random twins reduction""" # Create game and reduction game = gamegen.game(players, strategies, keep_prob) # Try to reduce game red_game = tr.reduce_game(game) # Assert that reducing all profiles covers reduced game reduced_full_profiles = utils.axis_to_elem( tr.reduce_profiles(red_game, game.profiles())) reduced_profiles = utils.axis_to_elem(red_game.profiles()) assert np.setdiff1d(reduced_profiles, reduced_full_profiles).size == 0, \ "reduced game contained profiles it shouldn't have" # Assert that all contributing profiles are in the expansion of the reduced # game. We need to remove partial profiles first full_profiles = utils.axis_to_elem(game.profiles()) complete_profs = ~np.isnan(red_game.payoffs()).any(1) full_reduced_profiles = utils.axis_to_elem( tr.expand_profiles(game, red_game.profiles()[complete_profs])) assert np.setdiff1d(full_reduced_profiles, full_profiles).size == 0, \ 'full game did not have data for all profiles required of reduced'
def test_random_identity(keep_prob, game_desc, _): """Test random identity""" players, strategies = game_desc # Create game and reduction game = gamegen.game(players, strategies, keep_prob) assert (paygame.game_copy(rsgame.empty(players, strategies)) == ir.reduce_game(rsgame.empty(players, strategies))) # Try to reduce game red_game = ir.reduce_game(game) # Assert that reducing all profiles covers reduced game reduced_full_profiles = utils.axis_to_elem( ir.reduce_profiles(red_game, game.profiles())) reduced_profiles = utils.axis_to_elem(red_game.profiles()) assert np.setxor1d(reduced_full_profiles, reduced_profiles).size == 0, \ "reduced game didn't match full game" full_profiles = utils.axis_to_elem(game.profiles()) full_reduced_profiles = utils.axis_to_elem( ir.expand_profiles(game, red_game.profiles())) assert np.setxor1d(full_profiles, full_reduced_profiles).size == 0, \ 'full game did not match reduced game'
def test_random_hierarchical(keep_prob, players, strategies, red_players, _): """Test random hierarchical""" # Create game and reduction game = gamegen.game(players, strategies, keep_prob) assert (rsgame.empty(red_players, strategies) == hr.reduce_game(rsgame.empty(players, strategies), red_players)) # Try to reduce game red_game = hr.reduce_game(game, red_players) # Assert that reducing all profiles covers reduced game reduced_full_profiles = utils.axis_to_elem( hr.reduce_profiles(red_game, game.profiles())) reduced_profiles = utils.axis_to_elem(red_game.profiles()) assert np.setxor1d(reduced_profiles, reduced_full_profiles).size == 0, \ "reduced game contained profiles it shouldn't have" # Assert that all contributing profiles are in the expansion of the reduced # game. Since hr doesn't add any incomplete profiles, it can't produce any full_profiles = utils.axis_to_elem(game.profiles()) full_reduced_profiles = utils.axis_to_elem( hr.expand_profiles(game, red_game.profiles())) assert np.setdiff1d(full_reduced_profiles, full_profiles).size == 0, \ 'full game did not have data for all profiles required of reduced'
def test_keep_num_profiles(players, strategies, _): """Test keep a number of profiles""" game = gamegen.game(players, strategies, 0.5) num = game.num_profiles // 2 test = gamegen.keep_num_profiles(game, num) assert test.num_profiles == num
def test_multi_role(func): """Test that at least one iteration works on a multi role game""" game = gamegen.game([2, 3], [3, 2]) mix = game.random_mixture() eqm = func(game, mix) assert game.is_mixture(eqm)
def test_random_identity_test(players, strats, _): """Test that dumping and loading is identity""" game = matgame.matgame_copy(gamegen.game(players, strats)) string = gambit.dumps(game) copy = gambit.loads(string) assert game == copy
def test_sample_profiles(players, strats, _): """Test sample profiles""" game = gamegen.game(players, strats) profiles = gamegen.sample_profiles(game, 5) uprofs = utils.axis_from_elem(np.unique(utils.axis_to_elem(profiles))) assert uprofs.shape == (5, game.num_strats)
def test_sample_profiles(players, strats, _): """Test sample profiles""" game = gamegen.game(players, strats) profiles = gamegen.sample_profiles(game, 5) uprofs = utils.axis_from_elem(np.unique(utils.axis_to_elem(profiles))) assert uprofs.shape == (5, game.num_strats)
def test_keep_num_profiles(players, strategies, _): """Test keep a number of profiles""" game = gamegen.game(players, strategies, 0.5) num = game.num_profiles // 2 test = gamegen.keep_num_profiles(game, num) assert test.num_profiles == num
def create(args): """Create role symmetric game""" players, strats = zip(*(map(int, ps.split(':')) for ps in args.pands.split(','))) return gamegen.game(players, strats)
def test_random_identity_test(players, strats, _): """Test that dumping and loading is identity""" game = matgame.matgame_copy(gamegen.game(players, strats)) string = gambit.dumps(game) copy = gambit.loads(string) assert game == copy
def test_multi_role(func): """Test that at least one iteration works on a multi role game""" game = gamegen.game([2, 3], [3, 2]) mix = game.random_mixture() eqm = func(game, mix) assert game.is_mixture(eqm)
def fix_game(): """Get a standard game""" return gamegen.game([3, 2], [2, 3])
def create(args): """Create role symmetric game""" players, strats = zip(*(map(int, ps.split(':')) for ps in args.pands.split(','))) return gamegen.game(players, strats)