def test_empty_add_noise(): base_game = rsgame.game([3, 3], [4, 4]) game = gamegen.add_noise(base_game, 1) assert game.is_empty() base_game = gamegen.role_symmetric_game([3] * 3, 4) game = gamegen.add_noise(base_game, 0) assert game.is_empty()
def test_rand_dpr_allow_incomplete(add_prob, num_obs, game_desc): """Test that allow_incomplete works for random games""" # Generate games players, strategies, red_players = game_desc base = rsgame.BaseGame(players, strategies) game = gamegen.add_profiles(base, add_prob) sgame = gamegen.add_noise(game, 1, num_obs) red = reduction.DeviationPreserving(strategies, players, red_players) # Try to reduce game red_game = red.reduce_game(game, True) red_sgame = red.reduce_game(sgame, True) # Verify that when allow_incomplete, then reduce returns all profiles reduced_full_profiles = utils.axis_to_elem( red.reduce_profiles(game.profiles)) reduced_profiles = utils.axis_to_elem(red_game.profiles) assert np.setxor1d(reduced_profiles, reduced_full_profiles).size == 0 reduced_sample_profiles = utils.axis_to_elem(red_sgame.profiles) assert np.setxor1d(reduced_sample_profiles, reduced_full_profiles).size == 0 redord = np.argsort(reduced_profiles) redsord = np.argsort(reduced_sample_profiles) assert np.all(np.isnan(red_game.payoffs[redord]) == np.isnan(red_sgame.payoffs[redsord])), \ "sample game and game didn't have same nan payoffs" assert all(np.all(np.isnan(p).any(-1) == np.isnan(p).all(-1)) for p in red_sgame.sample_payoffs), \ "some sample payoffs had partial nans"
def test_mixture_regret_single_mix(players, strategies): num_boots = 200 game = gamegen.add_noise(gamegen.role_symmetric_game(players, strategies), 1, 3) mix = game.random_mixtures()[0] boots = bootstrap.mixture_regret(game, mix, num_boots, processes=1) assert boots.shape == (1, num_boots) assert np.all(boots >= 0)
def test_mixture_welfare(players, strategies): num_mixes = 5 num_boots = 200 game = gamegen.add_noise(gamegen.role_symmetric_game(players, strategies), 1, 3) mixes = game.random_mixtures(num_mixes) boots = bootstrap.mixture_welfare(game, mixes, num_boots, processes=1) assert boots.shape == (num_mixes, num_boots)
def test_mixture_regret_parallel(): num_mixes = 5 num_boots = 200 game = gamegen.add_noise(gamegen.role_symmetric_game([4, 3], [3, 4]), 1, 3) mixes = game.random_mixtures(num_mixes) boots = bootstrap.mixture_regret(game, mixes, num_boots) assert boots.shape == (num_mixes, num_boots) assert np.all(boots >= 0)
def test_json_copy_samplegame(game_size, samples): base = gamegen.role_symmetric_game(*game_size) game1 = gamegen.add_noise(base, 1, samples) serial = gamegen.serializer(game1) game2, _ = gameio.read_samplegame(serial.to_samplegame_json(game1)) assert game1 == game2 assert np.all(game1.profiles == game2.profiles) assert np.allclose(game1.payoffs, game2.payoffs) for spay1, spay2 in zip(game1.sample_payoffs, game2.sample_payoffs): assert np.allclose(spay1, spay2)
def test_add_noise(players, strategies, lower, upper): roles = max(np.array(players).size, np.array(strategies).size) base_game = gamegen.role_symmetric_game(players, strategies) game = gamegen.add_noise(base_game, lower, upper) 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_strategies), \ "didn't generate correct number of strategies" assert (np.all(game.num_samples >= min(lower, 1)) and np.all(game.num_samples <= upper)), \ "didn't generate appropriate number of samples"
def test_subgame_preserves_completeness(players, strategies, _): """Test that subgame function preserves completeness""" game = gamegen.role_symmetric_game(players, strategies) assert game.is_complete(), "gamegen didn't create complete game" mask = game.random_subgames() sub_game = subgame.subgame(game, mask) assert sub_game.is_complete(), "subgame didn't preserve game completeness" sgame = gamegen.add_noise(game, 1, 3) sub_sgame = subgame.subgame(sgame, mask) assert sub_sgame.is_complete(), \ "subgame didn't preserve sample game completeness"
def test_dpr(keep_prob, game_desc): """Simple test that dpr functions are consistent""" players, strategies, red_players = game_desc # Create game and reduction game = gamegen.role_symmetric_game(players, strategies) game = gamegen.drop_profiles(game, keep_prob) sgame = gamegen.add_noise(game, 1, 3) red = reduction.DeviationPreserving(strategies, players, red_players) # Try to reduce game assert rsgame.basegame_copy(game) == red.full_game assert red.reduce_game(rsgame.basegame_copy(game)) == red.red_game red_game = red.reduce_game(game) red_game2 = reduction.reduce_game_dpr(game, red_players) red_sgame = red.reduce_game(sgame) # Assert that reduce_game_dpr produces identical results reduced_profiles = utils.axis_to_elem(red_game.profiles) reduced_profiles2 = utils.axis_to_elem(red_game2.profiles) assert np.setxor1d(reduced_profiles, reduced_profiles2).size == 0, \ "different reduction functions didn't produce identical results" # Assert that reducing all profiles covers reduced game reduced_full_profiles = utils.axis_to_elem( red.reduce_profiles(game.profiles)) assert np.setdiff1d(reduced_profiles, reduced_full_profiles).size == 0, \ "reduced game contained profiles it shouldn't have" reduced_sample_profiles = utils.axis_to_elem(red_sgame.profiles) assert np.setdiff1d(reduced_sample_profiles, reduced_full_profiles).size == 0, \ "reduced sample game contained profiles it shouldn't have" assert np.setxor1d(reduced_sample_profiles, reduced_profiles).size == 0, \ "reduced sample game and reduced game had different profiles" # Assert that all contributing profiles are in the expansion of the reduced # game full_profiles = utils.axis_to_elem(game.profiles) full_reduced_profiles = utils.axis_to_elem( red.expand_profiles(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" full_reduced_sample_profiles = utils.axis_to_elem( red.expand_profiles(red_sgame.profiles)) assert np.setdiff1d(full_reduced_sample_profiles, full_profiles).size == 0, \ ("full sample game did not have data for all profiles required of " "reduced") assert np.setxor1d(full_reduced_profiles, full_reduced_sample_profiles).size == 0, \ "sample game didn't produce identical results"
def test_sgboot_1(): with tempfile.NamedTemporaryFile('w') as mixed, \ tempfile.NamedTemporaryFile('w') as game: sgame = gamegen.add_noise(gamegen.role_symmetric_game([2, 3], [4, 3]), 20) serial = gamegen.serializer(sgame) json.dump(serial.to_samplegame_json(sgame), game) game.flush() profs = [serial.to_prof_json(sgame.uniform_mixture())] json.dump(profs, mixed) mixed.flush() run('sgboot', '-i', game.name, mixed.name, '-o/dev/null')
def test_mixture_regret(players, strategies): num_mixes = 5 num_boots = 200 game = gamegen.add_noise(gamegen.role_symmetric_game(players, strategies), 1, 3) mixes = game.random_mixtures(num_mixes) boots = bootstrap.mixture_regret(game, mixes, num_boots, processes=1) assert boots.shape == (num_mixes, num_boots) assert np.all(boots >= 0) perc_boots = bootstrap.mixture_regret(game, mixes, num_boots, [2.5, 97.5], processes=1) assert perc_boots.shape == (num_mixes, 2) assert np.all(perc_boots >= 0)
def test_learning(): with tempfile.NamedTemporaryFile('w') as game: sgame = gamegen.add_noise(gamegen.role_symmetric_game([2, 2], [3, 3]), 10) serial = gamegen.game_serializer(sgame) json.dump(sgame.to_json(serial), game) game.flush() assert not subprocess.run([GA, 'learning', '-i', game.name, '-o/dev/null', '-p1', '--dist-thresh', '1e-3', '-r1e-3', '-t1e-3', '--rand-restarts', '0', '-m10000', '-c1e-8']).returncode game.seek(0) assert not subprocess.run([GA, 'learning'], stdin=game).returncode
def test_drop_profiles(players, strategies): game = gamegen.role_symmetric_game(players, strategies) # Since independent drops might drop nothing, we keep nothing dropped = gamegen.drop_profiles(game, 0) assert dropped.is_empty(), "didn't drop any profiles" # 40% mean even one profile games will be incomplete dropped = gamegen.drop_profiles(game, 0.4, independent=False) assert not dropped.is_complete(), "didn't drop any profiles" sgame = gamegen.add_noise(game, 3) dropped = gamegen.drop_profiles(sgame, 0) assert dropped.is_empty(), "didn't drop any profiles" # 40% mean even one profile games will be incomplete dropped = gamegen.drop_profiles(sgame, 0.4, independent=False) assert not dropped.is_complete(), "didn't drop any profiles"
def test_sgboot_2(): with tempfile.NamedTemporaryFile('w') as mixed: sgame = gamegen.add_noise(gamegen.role_symmetric_game([2, 3], [4, 3]), 20) serial = gamegen.serializer(sgame) game_str = json.dumps(serial.to_samplegame_json(sgame)) profs = [serial.to_prof_json(sgame.uniform_mixture())] json.dump(profs, mixed) mixed.flush() string, _ = run('sgboot', mixed.name, '-tsurplus', '--processes', '1', '-n21', '-p', '5', '95', '-m', input=game_str) data = json.loads(string) assert all(j.keys() == {'5', '95', 'mean'} for j in data) assert all(j['5'] <= j['95'] for j in data)
def test_drop_samples(players, strategies): game = gamegen.role_symmetric_game(players, strategies) num_samples = 10000 // game.num_profiles game = gamegen.add_noise(game, num_samples) # Since independent drops might drop nothing, we keep nothing dropped = gamegen.drop_samples(game, 0) assert dropped.is_empty(), "didn't drop any profiles" # 40% mean even one profile games will be incomplete dropped = gamegen.drop_samples(game, 1) assert (dropped.is_complete() and np.all(dropped.num_samples == [num_samples])) # We drop half of samples, meaning is highly unlikely the game is complete # or empty, but these "can" still happen dropped = gamegen.drop_samples(game, .5) assert (not dropped.is_complete() or not np.all(dropped.num_samples == [num_samples])) assert not dropped.is_empty()
def test_sgboot(): with tempfile.NamedTemporaryFile('w') as mixed, \ tempfile.NamedTemporaryFile('w') as game: sgame = gamegen.add_noise(gamegen.role_symmetric_game([2, 3], [4, 3]), 20) serial = gamegen.game_serializer(sgame) json.dump(sgame.to_json(serial), game) game.flush() profs = [serial.to_prof_json(sgame.uniform_mixture())] json.dump(profs, mixed) mixed.flush() assert not subprocess.run([GA, 'sgboot', '-i', game.name, mixed.name, '-o/dev/null']).returncode game.seek(0) assert not subprocess.run([GA, 'sgboot', mixed.name, '-tsurplus', '--processes', '1', '-n21', '-p', '5', '95', '-m'], stdin=game).returncode
def test_sample_game_to_str(): base = gamegen.role_symmetric_game([2, 1], [1, 2]) serial = gamegen.game_serializer(base) game = gamegen.add_noise(base, 3) expected = ('SampleGame:\n Roles: r0, r1\n Players:\n 2x r0\n' ' 1x r1\n Strategies:\n r0:\n s0\n' ' r1:\n s0\n s1\n' 'payoff data for 2 out of 2 profiles\n' '3 observations per profile') assert game.to_str(serial) == expected game = rsgame.SampleGame(base) expected = ('SampleGame:\n Roles: r0, r1\n Players:\n 2x r0\n' ' 1x r1\n Strategies:\n r0:\n s0\n' ' r1:\n s0\n s1\n' 'payoff data for 2 out of 2 profiles\n' '1 observation per profile') assert game.to_str(serial) == expected game = rsgame.SampleGame(rsgame.BaseGame(base)) expected = ('SampleGame:\n Roles: r0, r1\n Players:\n 2x r0\n' ' 1x r1\n Strategies:\n r0:\n s0\n' ' r1:\n s0\n s1\n' 'payoff data for 0 out of 2 profiles\n' 'no observations') assert game.to_str(serial) == expected profiles = [[2, 1, 0], [2, 0, 1]] spayoffs = [ [[[1], [2], [0]]], [[[3, 4], [0] * 2, [5, 6]]], ] game = rsgame.SampleGame(base, profiles, spayoffs) expected = ('SampleGame:\n Roles: r0, r1\n Players:\n 2x r0\n' ' 1x r1\n Strategies:\n r0:\n s0\n' ' r1:\n s0\n s1\n' 'payoff data for 2 out of 2 profiles\n' '1 to 2 observations per profile') assert game.to_str(serial) == expected
def test_hierarchical(keep_prob, game_desc): players, strategies, red_players = game_desc # Create game and reduction game = gamegen.role_symmetric_game(players, strategies) game = gamegen.drop_profiles(game, keep_prob) sgame = gamegen.add_noise(game, 1, 3) red = reduction.Hierarchical(strategies, players, red_players) # Try to reduce game assert rsgame.basegame_copy(game) == red.full_game assert red.reduce_game(rsgame.basegame_copy(game)) == red.red_game red_game = red.reduce_game(game) red_sgame = red.reduce_game(sgame) # Assert that reducing all profiles covers reduced game reduced_full_profiles = utils.axis_to_elem( red.reduce_profiles(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" reduced_sample_profiles = utils.axis_to_elem(red_sgame.profiles) assert np.setxor1d(reduced_sample_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 full_profiles = utils.axis_to_elem(game.profiles) full_reduced_profiles = utils.axis_to_elem( red.expand_profiles(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" full_reduced_sample_profiles = utils.axis_to_elem( red.expand_profiles(red_sgame.profiles)) assert np.setdiff1d(full_reduced_sample_profiles, full_profiles).size == 0, \ "full game did not have data for all profiles required of reduced" assert np.setxor1d(full_reduced_profiles, full_reduced_sample_profiles).size == 0, \ "sample game didn't produce identical results"
def test_sample_game_function(game_size, samples): base = gamegen.role_symmetric_game(*game_size) game = gamegen.add_noise(base, 1, samples) # Test constructors game2 = rsgame.SampleGame(game) assert not np.may_share_memory(game.profiles, game2.profiles) assert not np.may_share_memory(game.payoffs, game2.payoffs) assert not any(np.may_share_memory(sp, sp2) for sp, sp2 in zip(game.sample_payoffs, game2.sample_payoffs)) assert np.all(game.profiles == game2.profiles) assert np.all(game.payoffs == game2.payoffs) assert all(np.all(sp == sp2) for sp, sp2 in zip(game.sample_payoffs, game2.sample_payoffs)) game3 = rsgame.SampleGame(base) assert not np.may_share_memory(base.profiles, game3.profiles) assert not np.may_share_memory(base.payoffs, game3.payoffs) assert np.all(base.profiles == game3.profiles) assert np.all(base.payoffs == game3.payoffs) assert np.all(game3.num_samples == 1) game4 = rsgame.SampleGame(rsgame.BaseGame(*game_size)) assert game4.is_empty() game5 = rsgame.SampleGame(*game_size) assert game5.is_empty() game5 = rsgame.SampleGame(game.num_players, game.num_strategies, game.profiles, game.sample_payoffs) # Test that various methods can be called assert (np.all(1 <= game.num_samples) and np.all(game.num_samples <= samples)) game.resample() game.resample(1) game.remean() assert repr(game) is not None
def test_samplegame_resample(): game = gamegen.role_symmetric_game([1, 2, 3], [4, 3, 2]) game = gamegen.add_noise(game, 1, 20) payoffs = game.payoffs.copy() min_values = game.min_payoffs().copy() max_values = game.max_payoffs().copy() game.resample() # This isn't guaranteed to be true, but they're highly unlikely assert np.any(payoffs != game.payoffs), \ "resampling didn't change payoffs" game.remean() assert np.allclose(payoffs, game.payoffs), \ "remeaning didn't reset payoffs properly" assert np.allclose(min_values, game.min_payoffs()), \ "remeaning didn't reset minimum payoffs properly" assert np.allclose(max_values, game.max_payoffs()), \ "remeaning didn't reset minimum payoffs properly"
def test_json_copy_sample_game(game_size, samples): base = gamegen.role_symmetric_game(*game_size) game1 = gamegen.add_noise(base, 1, samples) serial = gamegen.game_serializer(game1) game2, _ = gameio.read_sample_game(game1.to_json(serial)) assert game1 == game2