def dev_profs(red_players, full_players, mask, rst): """Deviation profiles for a particular role""" rgame = rsgame.empty(red_players, support) sub_profs = restrict.translate(rgame.all_profiles(), rest) game = rsgame.empty(full_players, full_game.num_role_strats) non_devs = hierarchical.expand_profiles(game, sub_profs) ndevs = np.sum(~mask) devs = np.zeros((ndevs, full_game.num_strats), int) devs[:, rst:rst + mask.size][:, ~mask] = np.eye(ndevs, dtype=int) profs = non_devs[:, None] + devs profs.shape = (-1, full_game.num_strats) return profs
def test_random_hr_identity(_): """Test hierarchical identity""" num_strats = rand.randint(2, 20) profile = rand.randint(20, size=num_strats)[None] reduced_players = profile.sum() while reduced_players < 2: # pragma: no cover profile[0, rand.randint(num_strats)] += 1 reduced_players += 1 full_players = rand.randint(reduced_players + 1, reduced_players ** 2) game = rsgame.empty(reduced_players, num_strats) full_profile = hr.expand_profiles( rsgame.empty(full_players, num_strats), profile) red_profile = hr.reduce_profiles(game, full_profile) assert np.all(red_profile == profile), "reduction didn't pass identity"
def aggfn( # pylint: disable=too-many-arguments num_role_players, num_role_strats, action_weights, function_inputs, function_table, offsets=None): """Create an Aggfn with default names Parameters ---------- num_role_players : ndarray The number of players per role. num_role_strats : ndarray The number of strategies per role. action_weights : ndarray, float The action weights. function_inputs : ndarray, bool The input mask for each function. function_table : ndarray, float The function value relative to number of incoming edges. offsets : ndarray, float, optional A constant offset for each strategies payoff. Constant functions are not allowed in the function table as they are clutter, instead, constant functions can be specified here. """ return aggfn_replace(rsgame.empty(num_role_players, num_role_strats), action_weights, function_inputs, function_table, offsets)
async def test_sparse_trace(): """Test that tracing sparsely samples profiles""" base = rsgame.empty(4, 3) game1 = paygame.game_replace(base, base.all_profiles(), (base.all_profiles() > 0) * [1, 0, 0]) game2 = paygame.game_replace(base, base.all_profiles(), (base.all_profiles() > 0) * [-0.5, 1.5, 0]) save1 = savesched.savesched(gamesched.gamesched(game1)) save2 = savesched.savesched(gamesched.gamesched(game2)) sgame1 = schedgame.schedgame(save1) sgame2 = schedgame.schedgame(save2) await asyncio.gather(innerloop.inner_loop(sgame1), innerloop.inner_loop(sgame2)) # Assert that innerloop doesn't scheduler all profiles assert save1.get_game().num_profiles == 11 assert save2.get_game().num_profiles == 11 ((st1, *_, en1), _), ((st2, *_, en2), _) = ( # pylint: disable=too-many-star-expressions await trace.trace_all_equilibria(sgame1, sgame2)) # Assert that trace found the expected equilibria assert np.isclose(st1, 0) assert np.isclose(en1, 1 / 3, atol=1e-3) assert np.isclose(st2, 1 / 3, atol=1e-3) assert np.isclose(en2, 1) # Assert that trace didn't need many extra profiles assert save1.get_game().num_profiles == 12 assert save2.get_game().num_profiles == 12
def normal_aggfn(role_players, role_strats, functions, *, input_prob=0.2, weight_prob=0.2): """Generate a random normal AgfnGame Each function value is an i.i.d Gaussian random walk. Parameters ---------- role_players : int or ndarray The number of players per role. role_strats : int or ndarray The number of strategies per role. functions : int The number of functions to generate. input_prob : float, optional The probability of a strategy counting towards a function value. weight_prob : float, optional The probability of a function producing non-zero payoffs to a strategy. """ base = rsgame.empty(role_players, role_strats) inputs = _random_inputs(input_prob, base.num_strats, functions) weights = _random_weights(weight_prob, functions, base.num_strats) shape = (functions,) + tuple(base.num_role_players + 1) funcs = np.random.normal(0, 1 / np.sqrt(base.num_players + 1), shape) for role in range(1, base.num_roles + 1): funcs.cumsum(role, out=funcs) mean = funcs.mean(tuple(range(1, base.num_roles + 1))) mean.shape = (functions,) + (1,) * base.num_roles funcs -= mean return aggfn.aggfn_replace(base, weights, inputs, funcs)
def test_hierarchical_dev_expansion(): """Test that hierarchical dev expansion is correct""" game = rsgame.empty([9, 16], [4, 3]) mask = [True, False, True, False, False, True, False] profs = hr.expand_deviation_profiles(game, mask, [3, 4]) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [6, 3, 0, 0, 0, 16, 0], [3, 3, 3, 0, 0, 16, 0], [0, 3, 6, 0, 0, 16, 0], [6, 0, 0, 3, 0, 16, 0], [3, 0, 3, 3, 0, 16, 0], [0, 0, 6, 3, 0, 16, 0], [9, 0, 0, 0, 4, 12, 0], [6, 0, 3, 0, 4, 12, 0], [3, 0, 6, 0, 4, 12, 0], [0, 0, 9, 0, 4, 12, 0], [9, 0, 0, 0, 0, 12, 4], [6, 0, 3, 0, 0, 12, 4], [3, 0, 6, 0, 0, 12, 4], [0, 0, 9, 0, 0, 12, 4], ]) assert np.setxor1d(actual, expected).size == 0 profs = hr.expand_deviation_profiles(game, mask, [3, 4], 0) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [6, 3, 0, 0, 0, 16, 0], [3, 3, 3, 0, 0, 16, 0], [0, 3, 6, 0, 0, 16, 0], [6, 0, 0, 3, 0, 16, 0], [3, 0, 3, 3, 0, 16, 0], [0, 0, 6, 3, 0, 16, 0], ]) assert np.setxor1d(actual, expected).size == 0
def test_identity_dev_expansion(): """Test that identity dev expansion is correct""" game = rsgame.empty([3, 4], [4, 3]) mask = [True, False, True, False, False, True, False] profs = ir.expand_deviation_profiles(game, mask) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [2, 1, 0, 0, 0, 4, 0], [1, 1, 1, 0, 0, 4, 0], [0, 1, 2, 0, 0, 4, 0], [2, 0, 0, 1, 0, 4, 0], [1, 0, 1, 1, 0, 4, 0], [0, 0, 2, 1, 0, 4, 0], [3, 0, 0, 0, 1, 3, 0], [2, 0, 1, 0, 1, 3, 0], [1, 0, 2, 0, 1, 3, 0], [0, 0, 3, 0, 1, 3, 0], [3, 0, 0, 0, 0, 3, 1], [2, 0, 1, 0, 0, 3, 1], [1, 0, 2, 0, 0, 3, 1], [0, 0, 3, 0, 0, 3, 1], ]) assert np.setxor1d(actual, expected).size == 0 profs = ir.expand_deviation_profiles(game, mask, role_index=0) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [2, 1, 0, 0, 0, 4, 0], [1, 1, 1, 0, 0, 4, 0], [0, 1, 2, 0, 0, 4, 0], [2, 0, 0, 1, 0, 4, 0], [1, 0, 1, 1, 0, 4, 0], [0, 0, 2, 1, 0, 4, 0], ]) assert np.setxor1d(actual, expected).size == 0
def test_twins_dev_expansion(): """Test that dpr dev expansion is correct Note, this is the only one that has "new" code, so it's the most important to test.""" game = rsgame.empty([9, 16], [4, 3]) mask = [True, False, True, False, False, True, False] profs = tr.expand_deviation_profiles(game, mask) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [8, 1, 0, 0, 0, 16, 0], [0, 1, 8, 0, 0, 16, 0], [8, 0, 0, 1, 0, 16, 0], [0, 0, 8, 1, 0, 16, 0], [9, 0, 0, 0, 1, 15, 0], [5, 0, 4, 0, 1, 15, 0], [0, 0, 9, 0, 1, 15, 0], [9, 0, 0, 0, 0, 15, 1], [5, 0, 4, 0, 0, 15, 1], [0, 0, 9, 0, 0, 15, 1], ]) assert np.setxor1d(actual, expected).size == 0 profs = tr.expand_deviation_profiles(game, mask, role_index=0) actual = utils.axis_to_elem(profs) expected = utils.axis_to_elem([ [8, 1, 0, 0, 0, 16, 0], [0, 1, 8, 0, 0, 16, 0], [8, 0, 0, 1, 0, 16, 0], [0, 0, 8, 1, 0, 16, 0], ]) assert np.setxor1d(actual, expected).size == 0
def large_games(): """Games that test functionality in large spaces""" yield rsgame.empty([1, 1], [5, 5]) yield rsgame.empty([2, 2], [5, 5]) yield rsgame.empty([5, 5], [2, 2]) yield rsgame.empty([1, 1, 1, 1], 2) yield rsgame.empty([3, 3, 3], [3, 3, 3]) yield rsgame.empty([2, 3, 4], [4, 3, 2]) yield rsgame.empty(170, 2) yield rsgame.empty(180, 2)
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()
def dev_profs(players, mask, rst): """Get deviation profiles""" rgame = rsgame.empty(players, support) non_devs = translate(rgame.all_profiles(), rest) ndevs = np.sum(~mask) devs = np.zeros((ndevs, game.num_strats), int) devs[:, rst:rst + mask.size][:, ~mask] = np.eye(ndevs, dtype=int) profs = non_devs[:, None] + devs profs.shape = (-1, game.num_strats) return profs
def games(): """Test games""" yield rsgame.empty(1, 2) yield rsgame.empty(2, 2) yield rsgame.empty([2, 1], [1, 2]) yield rsgame.empty([1, 2], [2, 1]) yield rsgame.empty([2, 2], [2, 2]) yield rsgame.empty([3, 2], [2, 3]) yield rsgame.empty([1, 1, 1], 2)
def basic_games(): """Small basic games for testing""" yield rsgame.empty(1, 2) yield rsgame.empty(2, 2) yield rsgame.empty(2, 3) yield rsgame.empty(3, 2) yield rsgame.empty(3, 3) yield rsgame.empty([2, 3], [3, 2]) yield rsgame.empty([1, 1, 1], 2)
def test_identity_names(): """Test identity with names""" base = rsgame.empty(3, 2) game = paygame.game_names( ['role'], 3, [['a', 'b']], base.all_profiles(), np.zeros((base.num_all_profiles, base.num_strats))) redgame = ir.reduce_game(game) expected = paygame.game_names( ['role'], 3, [['a', 'b']], redgame.all_profiles(), np.zeros((redgame.num_all_profiles, base.num_strats))) assert redgame == expected
def test_dpr_names(): """Test names for dpr game""" base = rsgame.empty(3, 2) game = paygame.game_names( ['role'], 3, [['a', 'b']], base.all_profiles(), np.zeros((base.num_all_profiles, base.num_strats))) redgame = dpr.reduce_game(game, 2) expected = paygame.game_names( ['role'], 2, [['a', 'b']], redgame.all_profiles(), np.zeros((redgame.num_all_profiles, base.num_strats))) assert redgame == expected
def test_hierarchical_names(): """Test hierarchical with names""" base = rsgame.empty(4, 2) game = paygame.game_names( ['role'], 4, [['a', 'b']], base.all_profiles(), np.zeros((base.num_all_profiles, base.num_strats))) redgame = hr.reduce_game(game, 2) expected = paygame.game_names( ['role'], 2, [['a', 'b']], redgame.all_profiles(), np.zeros((redgame.num_all_profiles, base.num_strats))) assert redgame == expected
async def test_innerloop_dpr(redgame): """Test that inner loop handles dpr""" fullgame = rsgame.empty(redgame.num_role_players**2, redgame.num_role_strats) profs = dpr.expand_profiles(fullgame, redgame.all_profiles()) pays = np.random.random(profs.shape) pays[profs == 0] = 0 sgame = paygame.samplegame_replace(fullgame, profs, [pays[:, None]]) sched = gamesched.samplegamesched(sgame) game = schedgame.schedgame(sched, dpr, redgame.num_role_players) eqa = await innerloop.inner_loop(game) verify_dist_thresh(eqa)
async def test_sim_delayed_fail(tmpdir): """Test delayed simulation fail""" game = rsgame.empty(4, 3) game_file = str(tmpdir.join("game.json")) with open(game_file, "w") as fil: json.dump(game.to_json(), fil) script = str(tmpdir.join("script.sh")) with open(script, "w") as fil: fil.write("sleep 1 && false") sched = "sim:game:{},command:bash {}".format(game_file, script) with stdin(json.dumps({})): assert not await run("brute", sched)
def rand(players, strategies, functions): """Create random game""" base = rsgame.empty(players, strategies) action_weights = np.random.normal(0, 1, (functions, base.num_strats)) function_inputs = np.random.random((base.num_strats, functions)) < .5 for func in function_inputs.T: func[np.random.choice(base.num_strats, 2, False)] = [False, True] function_table = np.random.normal( 0, 1, (functions,) + tuple(base.num_role_players + 1)) offsets = np.random.normal(0, 1, base.num_strats) return aggfn.aggfn_replace(base, action_weights, function_inputs, function_table, offsets)
async def test_trace_norm(): """Test tracing""" base_game = rsgame.empty([3, 2], [2, 3]) async with mockserver.server() as server: game0 = add_singleton_role(base_game, 0, 'a', 'sx', 1) sched0 = await get_eosched(server, game0, 'game0') game1 = add_singleton_role(base_game, 1, 'r00', 's0', 3) sched1 = await get_eosched(server, game1, 'game1') with stdout() as out, stderr() as err: assert await run('trace', sched0, sched1), err.getvalue() traces = json.loads(out.getvalue()) verify_trace_json(base_game, traces)
async def test_trace_norm(): """Test tracing""" base_game = rsgame.empty([3, 2], [2, 3]) async with mockserver.server() as server: game0 = add_singleton_role(base_game, 0, "a", "sx", 1) sched0 = await get_eosched(server, game0, "game0") game1 = add_singleton_role(base_game, 1, "r00", "s0", 3) sched1 = await get_eosched(server, game1, "game1") with stdout() as out, stderr() as err: assert await run("trace", sched0, sched1), err.getvalue() traces = json.loads(out.getvalue()) verify_trace_json(base_game, traces)
def test_dpr_deviation_count(): """Test dpr dev count""" game = rsgame.empty(3, 2) num_devs = restrict.num_dpr_deviation_profiles( game, [True, False]) assert num_devs == 2 game = rsgame.empty([1, 3], 2) num_devs = restrict.num_dpr_deviation_profiles( game, [True, True, True, False]) assert num_devs == 6 game = rsgame.empty(1, [3, 1]) num_devs = restrict.num_dpr_deviation_profiles( game, [True, True, False, True]) assert num_devs == 1 game = rsgame.empty([3, 2, 1], [1, 2, 3]) num_devs = restrict.num_dpr_deviation_profiles( game, [True, True, False, True, False, True]) assert num_devs == 7
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"
async def test_sim_delayed_fail(tmpdir): """Test delayed simulation fail""" game = rsgame.empty(4, 3) game_file = str(tmpdir.join('game.json')) with open(game_file, 'w') as fil: json.dump(game.to_json(), fil) script = str(tmpdir.join('script.sh')) with open(script, 'w') as fil: fil.write('sleep 1 && false') sched = 'sim:game:{},command:bash {}'.format(game_file, script) with stdin(json.dumps({})): assert not await run( 'brute', sched)
def samplegame(players, strats, *args, **kwargs): """Generate a random role symmetric sample game Parameters ---------- players : int or [int] The number of players per role. strats : int or [int] The number of strategies per role. **args The arguments to pass to samplegame_replace. """ return samplegame_replace(rsgame.empty(players, strats), *args, **kwargs)
def matgame(payoff_matrix): """Create a game from a dense matrix with default names Parameters ---------- payoff_matrix : ndarray-like The matrix of payoffs for an asymmetric game. """ payoff_matrix = np.ascontiguousarray(payoff_matrix, float) return matgame_replace( rsgame.empty( np.ones(payoff_matrix.ndim - 1, int), np.array(payoff_matrix.shape[:-1], int)), payoff_matrix)
def test_approximate_dpr_expansion(): """Test expansion on approximate dpr""" full_game = rsgame.empty([8, 11], [2, 2]) red_prof = [[1, 2, 2, 2]] full_profs = dpr.expand_profiles( full_game, red_prof) profs = utils.axis_to_elem(full_profs) expected = utils.axis_to_elem([ [4, 4, 6, 5], [1, 7, 6, 5], [3, 5, 4, 7], [3, 5, 7, 4]]) assert np.setxor1d(profs, expected).size == 0, \ 'generated different profiles than expected'
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_rand_dpr_dev_expandion(players, strategies, red_players, _): """Test that dpr devs works for random games""" game = rsgame.empty(players, strategies) sup = (rand.random(game.num_roles) * game.num_role_strats).astype(int) + 1 inds = np.concatenate( [rand.choice(s, x) + o for s, x, o in zip(game.num_role_strats, sup, game.role_starts)]) mask = np.zeros(game.num_strats, bool) mask[inds] = True devs = dpr.expand_deviation_profiles(game, mask, red_players) assert np.all(np.sum(devs * ~mask, 1) == 1) for r_ind in range(game.num_roles): r_devs = dpr.expand_deviation_profiles(game, mask, red_players, r_ind) assert np.all(np.sum(r_devs * ~mask, 1) == 1)
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 game(players, strats, prob=1.0, distribution=default_distribution): """Generate a random role symmetric game with sparse profiles Parameters ---------- players : int or [int] The number of players per role. strats : int or [int] The number of strategies per role. prob : float, optional The probability of any profile being included in the game. distribution : (shape) -> ndarray, optional Distribution function to draw payoffs from. """ return game_replace(rsgame.empty(players, strats), prob, distribution)
def expand_profiles(full_game, profiles): """Expand profiles using twins reduction Parameters ---------- full_game : Game Game that expanded profiles will be valid for. profiles : ndarray-like The profiles to expand """ red_players = np.minimum(full_game.num_role_players, 2) profiles = np.asarray(profiles, int) red_game = rsgame.empty(red_players, full_game.num_role_strats) utils.check(red_game.is_profile(profiles).all(), 'profiles must be valid') return dpr.expand_profiles(full_game, profiles)
def test_restriction(): """Test basic restriction""" game = rsgame.empty([3, 4], [3, 2]) rest = np.asarray([1, 0, 1, 0, 1], bool) devs = restrict.deviation_profiles(game, rest) assert devs.shape[0] == 7, \ "didn't generate the right number of deviating profiles" adds = restrict.additional_strategy_profiles(game, rest, 1).shape[0] assert adds == 6, \ "didn't generate the right number of additional profiles" rest2 = rest.copy() rest2[1] = True assert (game.restrict(rest2).num_all_profiles == adds + game.restrict(rest).num_all_profiles), \ "additional profiles didn't return the proper amount"
def sparse_game(players, strats, num, distribution=default_distribution): """Generate a random role symmetric game with sparse profiles Parameters ---------- players : int or [int] The number of players per role. strats : int or [int] The number of strategies per role. num : int The number of profiles to draw payoffs for. distribution : (shape) -> ndarray, optional Distribution function to draw payoffs from. """ return gen_num_profiles( rsgame.empty(players, strats), num, distribution)
def expand_profiles(full_game, profiles): """Expand profiles using twins reduction Parameters ---------- full_game : Game Game that expanded profiles will be valid for. profiles : ndarray-like The profiles to expand """ red_players = np.minimum(full_game.num_role_players, 2) profiles = np.asarray(profiles, int) red_game = rsgame.empty(red_players, full_game.num_role_strats) utils.check( red_game.is_profile(profiles).all(), 'profiles must be valid') return dpr.expand_profiles(full_game, profiles)
def test_gen_profiles(players, strategies, _): """Test gen profiles""" base = rsgame.empty(players, strategies) game = gamegen.gen_profiles(base) 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" game = gamegen.gen_profiles(base, 0.0) assert game.is_empty(), "didn't generate a full game" game = gamegen.gen_profiles(base, 0.5) game = gamegen.gen_num_profiles(base, base.num_all_profiles // 2) assert game.num_profiles == game.num_all_profiles // 2
def additional_strategy_profiles(game, rest, role_strat_ind): """Returns all profiles added by strategy at index""" # This uses the observation that the added profiles are all of the profiles # of the new restricted game with one less player in role, and then where # that last player always plays strat rest = np.asarray(rest, bool) utils.check(game.is_restriction(rest), 'restriction must be valid') new_players = game.num_role_players.copy() new_players[game.role_indices[role_strat_ind]] -= 1 base = rsgame.empty(new_players, game.num_role_strats) new_mask = rest.copy() new_mask[role_strat_ind] = True profs = base.restrict(new_mask).all_profiles() expand_profs = np.zeros((profs.shape[0], game.num_strats), int) expand_profs[:, new_mask] = profs expand_profs[:, role_strat_ind] += 1 return expand_profs
def travellers_dilemma(players=2, max_value=100): """Return an instance of travellers dilemma Strategies range from 2 to max_value, thus there will be max_value - 1 strategies.""" utils.check(players > 1, 'players must be more than one') utils.check(max_value > 2, 'max value must be more than 2') base = rsgame.empty(players, max_value - 1) profiles = base.all_profiles() payoffs = np.zeros(profiles.shape) mins = np.argmax(profiles, -1) mask = profiles > 0 payoffs[mask] = mins.repeat(mask.sum(-1)) rows = np.arange(profiles.shape[0]) ties = profiles[rows, mins] > 1 lowest_pays = mins + 4 lowest_pays[ties] -= 2 payoffs[rows, mins] = lowest_pays return paygame.game_replace(base, profiles, payoffs)
def test_max_pure_profile(): """Test max_pure_prof""" profiles = [[2, 0], [1, 1], [0, 2]] payoffs = [[3, 0], [4, 4], [0, 1]] game = paygame.game(2, 2, profiles, payoffs) prof = regret.max_pure_social_welfare(game)[1] assert np.all(prof == [1, 1]) game = rsgame.empty(2, 2) welfare, prof = regret.max_pure_social_welfare(game) assert np.isnan(welfare) assert prof is None (welfare,), (prof,) = regret.max_pure_social_welfare(game, by_role=True) assert np.isnan(welfare) assert prof is None
def _random_aggfn( # pylint: disable=too-many-arguments role_players, role_strats, functions, input_prob, weight_prob, role_dist): """Base form for structured random aggfn generation role_dist takes a number of functions and a number of players and returns an ndarray of the function values. """ base = rsgame.empty(role_players, role_strats) inputs = _random_inputs(input_prob, base.num_strats, functions) weights = _random_weights(weight_prob, functions, base.num_strats) funcs = np.ones((functions,) + tuple(base.num_role_players + 1)) base_shape = [functions] + [1] * base.num_roles for role, play in enumerate(base.num_role_players): role_funcs = role_dist(functions, play) shape = base_shape.copy() shape[role + 1] = play + 1 role_funcs.shape = shape funcs *= role_funcs return aggfn.aggfn_replace(base, weights, inputs, funcs)