def test_never_best_response_conditional(): """Test never best response conditional""" profiles = [ [2, 0], [0, 2], ] payoffs = [ [1, 0], [0, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.never_best_response(game, conditional=True) assert np.all(dom == [False, False]) profiles = [ [1, 1], [0, 2], ] payoffs = [ [2, 2], [0, 3], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.never_best_response(game, conditional=True) assert np.all(dom == [True, False])
def test_remove_dpr_profiles_with_no_data(): """Test that dpr removes profiles with no data""" profiles = [[1, 3], [3, 1]] payoffs = [[3, 4], [6, np.nan]] game = dpr.reduce_game(paygame.game(4, 2, profiles, payoffs), 2) assert game.num_profiles == 1 profiles = [[1, 3], [3, 1]] payoffs = [[np.nan, 4], [6, np.nan]] game = dpr.reduce_game(paygame.game(4, 2, profiles, payoffs), 2) assert game.is_empty() profiles = [[1, 3]] payoffs = [[3, 4]] game = dpr.reduce_game(paygame.game(4, 2, profiles, payoffs), 2) assert game.num_profiles == 1 profiles = [[1, 3]] payoffs = [[np.nan, 4]] game = dpr.reduce_game(paygame.game(4, 2, profiles, payoffs), 2) assert game.is_empty()
async def test_merge_trace(): """Test that traces are merged""" game0 = asyncgame.wrap( paygame.game(2, 2, [[2, 0], [1, 1], [0, 2]], [[0, 0], [1, 1], [0, 0]])) game1 = asyncgame.wrap( paygame.game(2, 2, [[2, 0], [1, 1], [0, 2]], [[0, 0], [1, 1], [0, 3]])) traces = await trace.trace_all_equilibria(game0, game1) assert len(traces) == 1
def test_weakly_dominated(): """Test weak domination""" profiles = [ [2, 0], [1, 1], [0, 2], ] payoffs = [ [2, 0], [2, 1], [0, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.weakly_dominated(game) assert np.all(dom == [False, True]) profiles = [[2, 0], [0, 2]] payoffs = [ [2, 0], [0, 2], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.weakly_dominated(game) assert np.all(dom == [False, False]) profiles = [ [2, 0], [1, 1], [0, 2], ] payoffs = [ [2, 0], [2, 1], [0, 2], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.weakly_dominated(game) assert np.all(dom == [False, True]) profiles = [ [2, 0], [1, 1], [0, 2], ] payoffs = [ [2, 0], [2, 2], [0, 2], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.weakly_dominated(game) assert np.all(dom == [True, True])
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_strictly_dominated_conditional(): """Test strict domination conditional""" profiles = [ [0, 2], [1, 1], ] payoffs = [ [0, 1], [2, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.strictly_dominated(game) assert np.all(dom == [False, False]) dom = dominance.strictly_dominated(game, conditional=False) assert np.all(dom == [False, True]) profiles = [ [2, 0], [1, 1], ] payoffs = [ [2, 0], [2, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.strictly_dominated(game) assert np.all(dom == [False, True]) profiles = [ [2, 0], [1, 1], ] payoffs = [ [2, 0], [2, 2], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.strictly_dominated(game) assert np.all(dom == [False, False]) profiles = [[2, 0], [0, 2]] payoffs = [ [2, 0], [0, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.strictly_dominated(game, conditional=False) assert np.all(dom == [False, False])
def test_pure_incomplete_data(): """Test pure regret with incomplete data""" profiles = [[2, 0]] payoffs = [[1.0, 0.0]] game = paygame.game(2, 2, profiles, payoffs) reg = regret.pure_strategy_regret(game, [2, 0]) assert np.isnan(reg), 'regret of missing profile not nan'
def test_analysis_dup_equilibria(): """Test analysis dpr equilibria""" # Two restrictions, but dominated, so identical equilibria profiles = [ [2, 0, 0, 0], [1, 1, 0, 0], [1, 0, 1, 0], [0, 2, 0, 0], [0, 1, 1, 0], [0, 0, 2, 0], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 0, 2], ] payoffs = [ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], ] game = paygame.game(2, 4, profiles, payoffs) game_str = json.dumps(game.to_json()) with stdin(game_str), stdout() as out, stderr() as err: assert run('analyze', '-s'), err.getvalue() assert 'Found 2 maximal complete restricted games' in out.getvalue()
def test_analysis_dev_explored(): """Test analysis deviations explored""" # Beneficial deviation to an already explored restriction profiles = [ [2, 0, 0, 0], [1, 1, 0, 0], [1, 0, 1, 0], [0, 2, 0, 0], [0, 1, 1, 0], [0, 0, 2, 0], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 0, 2], ] payoffs = [ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 0], ] game = paygame.game(2, 4, profiles, payoffs) game_str = json.dumps(game.to_json()) with stdin(game_str), stdout() as out, stderr() as err: assert run('analyze', '-s'), err.getvalue() assert ('Found no unexplored best-response restricted games' in out.getvalue())
def test_pure_strategy_deviation_gains(): """Test pure strategy deviation gains""" profiles = [[2, 0, 2, 0], [2, 0, 1, 1], [2, 0, 0, 2], [1, 1, 2, 0], [1, 1, 1, 1], [1, 1, 0, 2], [0, 2, 2, 0], [0, 2, 1, 1], [0, 2, 0, 2]] payoffs = [[1, 0, 2, 0], [3, 0, 4, 5], [6, 0, 0, 7], [8, 9, 10, 0], [11, 12, 13, 14], [15, 16, 0, 17], [0, 18, 19, 0], [0, 20, 21, 22], [0, 23, 0, 24]] game = paygame.game(2, [2, 2], profiles, payoffs) gains = regret.pure_strategy_deviation_gains(game, [2, 0, 2, 0]) assert np.allclose(gains, [0, 8, 0, 0, 0, 3, 0, 0]) gains = regret.pure_strategy_deviation_gains(game, [1, 1, 1, 1]) assert np.allclose(gains, [0, 9, -9, 0, 0, 4, -4, 0])
def test_mixed_incomplete_data_2(): """Test mixed with incomplete data""" profiles = [[2, 0]] payoffs = [[1.0, 0.0]] game = paygame.game(2, 2, profiles, payoffs) devgains = regret.mixture_deviation_gains(game, [1, 0]) assert np.allclose(devgains, [0, np.nan], equal_nan=True), \ "nonzero regret or deviation without payoff didn't return nan"
def test_profiles_payoffs(): """Test payoffs""" matg = matgame.matgame([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) copy = paygame.game_copy(matg) profs = [[1, 0, 1, 0], [1, 0, 0, 1], [0, 1, 1, 0], [0, 1, 0, 1]] pays = [[1, 0, 2, 0], [3, 0, 0, 4], [0, 5, 6, 0], [0, 7, 0, 8]] game = paygame.game([1, 1], 2, profs, pays) assert copy == game
def sym_2p2s_known_eq(eq_prob): """Generate a symmetric 2-player 2-strategy game This game has a single mixed equilibrium where strategy one is played with probability eq_prob. """ profiles = [[2, 0], [1, 1], [0, 2]] payoffs = [[0, 0], [eq_prob, 1 - eq_prob], [0, 0]] return paygame.game(2, 2, profiles, payoffs)
def test_analysis_no_data(): """Test analysis on empty game""" game = paygame.game([2], [2], [[1, 1]], [[5, float('nan')]]) game_str = json.dumps(game.to_json()) with stdin(game_str), stdout() as out, stderr() as err: assert run('analyze', '-s'), err.getvalue() out = out.getvalue() assert 'There was no profile with complete payoff data' in out assert 'Found no complete restricted games' in out
def test_canon(): """Test basic canon game""" profs = [[2, 0, 0, 3], [1, 1, 0, 3]] pays = [[1, 0, 0, 1], [2, 3, 0, np.nan]] game = paygame.game([2, 3], [3, 1], profs, pays) cgame = canongame.canon(game) assert cgame.num_profiles == 2 assert cgame.num_complete_profiles == 1 pay = cgame.get_payoffs([2, 0, 0]) assert np.allclose(pay, [1, 0, 0]) expected = [[2, 0, 0], [1, 1, 0]] assert np.all(cgame.profiles() == expected) expected = [[1, 0, 0], [2, 3, 0]] assert np.allclose(cgame.payoffs(), expected) assert np.allclose(cgame.deviation_payoffs([1, 0, 0]), [1, 3, np.nan], equal_nan=True) dev, jac = cgame.deviation_payoffs([0.5, 0.5, 0], jacobian=True) assert dev.shape == (3,) assert jac.shape == (3, 3) assert np.allclose(cgame.min_strat_payoffs(), [1, 3, np.nan], equal_nan=True) assert np.allclose(cgame.max_strat_payoffs(), [2, 3, np.nan], equal_nan=True) ngame = cgame.normalize() expected = [[0, 0, 0], [0.5, 1, 0]] assert utils.allclose_perm(ngame.payoffs(), expected) rgame = cgame.restrict([True, True, False]) expected = [[1, 0], [2, 3]] assert utils.allclose_perm(rgame.payoffs(), expected) copy_str = json.dumps(cgame.to_json()) copy = canongame.canon_json(json.loads(copy_str)) assert hash(cgame) == hash(copy) assert cgame == copy assert [2, 0, 0] in cgame assert [0, 2, 0] not in cgame assert repr(cgame) == 'CanonGame([2], [3], 2 / 6)' other = canongame.canon(gamegen.normal_aggfn([2, 2, 3], [3, 1, 1], 2)) assert other + cgame == cgame + other
def test_empty_dpr_1(): """Reduction is empty because profile is invalid""" profiles = [ [2, 4], ] payoffs = [ [1, 2], ] game = paygame.game(6, 2, profiles, payoffs) red_game = dpr.reduce_game(game, 2) assert np.all(red_game.num_role_players == [2]) assert red_game.is_empty()
def test_trace_equilibria(): """Test trace known game equilibrium""" profs = [[2, 0], [1, 1], [0, 2]] pays1 = [[1, 0], [1, 0], [0, 0]] game0 = paygame.game(2, 2, profs, pays1) pays2 = [[0, 0], [0, 1], [0, 1]] game1 = paygame.game(2, 2, profs, pays2) probs, mixes = trace.trace_equilibrium(game0, game1, 0, [1, 0], 1) assert np.isclose(probs[0], 0) assert np.isclose(probs[-1], 0.5, atol=1.1e-3) assert np.allclose(mixes, [1, 0]) probs, mixes = trace.trace_equilibrium(game0, game1, 1, [0, 1], 0) assert np.isclose(probs[0], 1) assert np.isclose(probs[-1], 0.5, atol=1.1e-3) assert np.allclose(mixes, [0, 1])
def test_mixed_incomplete_data(): """Test mixed incomplete data""" profiles = [[2, 0], [1, 1]] payoffs = [[4.3, 0], [6.2, 6.7]] game = paygame.game(2, 2, profiles, payoffs) dev_gain = regret.mixture_deviation_gains(game, [1, 0]) expected_gains = [0.0, 2.4] assert np.allclose(dev_gain, expected_gains), \ 'mixture gains wrong {} instead of {}'.format(dev_gain, expected_gains) dev_gain = regret.mixture_deviation_gains(game, game.uniform_mixture()) assert np.isnan(dev_gain).all(), 'had data for mixture without data'
def test_empty_dpr_2(): """Reduction is empty because profile doesn\'t have all payoffs""" profiles = [ [1, 3], ] payoffs = [ [1, 2], ] game = paygame.game(4, 2, profiles, payoffs) red_game = dpr.reduce_game(game, 2) assert np.all(red_game.num_role_players == [2]) assert np.all(red_game.profiles() == [[1, 1]]) assert [1, 1] not in red_game # incomplete profiles don't register
def test_dpr_incomplete_profile(): """Test that when allow_incomplete, we get appropriate payoffs""" profiles = [[4, 0, 0, 9], [1, 3, 9, 0], [2, 2, 9, 0]] payoffs = [[1, 0, 0, 2], [3, 4, 5, 0], [6, 7, 8, 0]] game = paygame.game([4, 9], 2, profiles, payoffs) red_game = dpr.reduce_game(game, [2, 3]) actual = red_game.get_payoffs([2, 0, 0, 3]) assert np.allclose(actual, [1, 0, 0, 2]) actual = red_game.get_payoffs([1, 1, 3, 0]) assert np.allclose(actual, [3, np.nan, 8, 0], equal_nan=True)
def test_profiles_payoffs(): """Test payoffs""" matg = matgame.matgame([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) copy = paygame.game_copy(matg) profs = [[1, 0, 1, 0], [1, 0, 0, 1], [0, 1, 1, 0], [0, 1, 0, 1]] pays = [[1, 0, 2, 0], [3, 0, 0, 4], [0, 5, 6, 0], [0, 7, 0, 8]] game = paygame.game([1, 1], 2, profs, pays) assert copy == game
def test_weakly_dominated_conditional(): """Test weak domination conditional""" profiles = [ [0, 2], [1, 1], ] payoffs = [ [0, 1], [1, 1], ] game = paygame.game(2, 2, profiles, payoffs) dom = dominance.weakly_dominated(game) assert np.all(dom == [True, False]) dom = dominance.weakly_dominated(game, conditional=False) assert np.all(dom == [True, True])
def test_maximal_restrictions_partial_profiles(): """Test that maximal restrictions properly handles partial profiles""" profiles = [[2, 0], [1, 1], [0, 2]] payoffs = [[1, 0], [np.nan, 2], [0, 3]] game = paygame.game([2], [2], profiles, payoffs) rests = restrict.maximal_restrictions(game) expected = utils.axis_to_elem(np.array([ [True, False], [False, True]])) assert np.setxor1d(utils.axis_to_elem(rests), expected).size == 0, \ "Didn't produce both pure restrictions"
def test_canon(): """Test basic canon game""" profs = [[2, 0, 0, 3], [1, 1, 0, 3]] pays = [[1, 0, 0, 1], [2, 3, 0, np.nan]] game = paygame.game([2, 3], [3, 1], profs, pays) cgame = canongame.canon(game) assert cgame.num_profiles == 2 assert cgame.num_complete_profiles == 1 pay = cgame.get_payoffs([2, 0, 0]) assert np.allclose(pay, [1, 0, 0]) expected = [[2, 0, 0], [1, 1, 0]] assert np.all(cgame.profiles() == expected) expected = [[1, 0, 0], [2, 3, 0]] assert np.allclose(cgame.payoffs(), expected) assert np.allclose(cgame.deviation_payoffs([1, 0, 0]), [1, 3, np.nan], equal_nan=True) dev, jac = cgame.deviation_payoffs([0.5, 0.5, 0], jacobian=True) assert dev.shape == (3, ) assert jac.shape == (3, 3) assert np.allclose(cgame.min_strat_payoffs(), [1, 3, np.nan], equal_nan=True) assert np.allclose(cgame.max_strat_payoffs(), [2, 3, np.nan], equal_nan=True) ngame = cgame.normalize() expected = [[0, 0, 0], [0.5, 1, 0]] assert utils.allclose_perm(ngame.payoffs(), expected) rgame = cgame.restrict([True, True, False]) expected = [[1, 0], [2, 3]] assert utils.allclose_perm(rgame.payoffs(), expected) copy_str = json.dumps(cgame.to_json()) copy = canongame.canon_json(json.loads(copy_str)) assert hash(cgame) == hash(copy) assert cgame == copy assert [2, 0, 0] in cgame assert [0, 2, 0] not in cgame assert repr(cgame) == 'CanonGame([2], [3], 2 / 6)' other = canongame.canon(gamegen.normal_aggfn([2, 2, 3], [3, 1, 1], 2)) assert other + cgame == cgame + other
def test_max_pure_profile_profile_game(): """Test that game are correct when profiles have incomplete data""" profiles = [[2, 0, 2, 0], [1, 1, 2, 0], [1, 1, 1, 1]] payoffs = [[np.nan, 0, 5, 0], # Max role 2 [2, 3, np.nan, 0], # Max role 1 [1, 1, 1, 1]] # Max total game = paygame.game([2, 2], [2, 2], profiles, payoffs) welfare, profile = regret.max_pure_social_welfare(game) assert welfare == 4 assert np.all(profile == [1, 1, 1, 1]) welfares, profiles = regret.max_pure_social_welfare(game, by_role=True) assert np.allclose(welfares, [5, 10]) expected = [[1, 1, 2, 0], [2, 0, 2, 0]] assert np.all(profiles == expected)
def find_eq(self, n=1): players = self.num_players strats = [self.ms] * len(players) eg = rsgame.empty(players, strats) profs = eg.all_profiles() pays = [] for p in profs: pays.append( utils.estimate_payoff(self.sim, p, self.num_players, n=n)) pays = np.array(pays) pays[profs == 0] = 0 pg = paygame.game(players, strats, profs, pays) self.game = pg # Compute the Nash for a couple of times nashes = [] for _ in range(5): n = nash.replicator_dynamics(pg, pg.random_mixture()) nashes.append(n) return nashes
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 sym_2p2s_game(a, b, c, d, distribution=default_distribution): # pylint: disable=invalid-name """Create a symmetric 2-player 2-strategy game of the specified form. Four payoff values get drawn from U(min_val, max_val), and then are assigned to profiles in order from smallest to largest according to the order parameters as follows: +---+-----+-----+ | | s0 | s1 | +---+-----+-----+ |s0 | a,a | b,c | +---+-----+-----+ |s1 | c,b | d,d | +---+-----+-----+ distribution must accept a size parameter a la numpy distributions. """ utils.check({a, b, c, d} == set(range(4)), 'numbers must be each of 1-4') # Generate payoffs payoffs = distribution(4) payoffs.sort() profs = [[2, 0], [1, 1], [0, 2]] pays = [[payoffs[a], 0], [payoffs[b], payoffs[c]], [0, payoffs[d]]] return paygame.game(2, 2, profs, pays)
def test_analysis_equilibria(): """Test analysis with equilibria""" profiles = [ # Complete deviations but unexplored [4, 0, 0, 0, 0], [3, 1, 0, 0, 0], [3, 0, 1, 0, 0], [3, 0, 0, 1, 0], [3, 0, 0, 0, 1], # Deviating restriction also explored [0, 4, 0, 0, 0], [0, 3, 1, 0, 0], [0, 2, 2, 0, 0], [0, 1, 3, 0, 0], [0, 0, 4, 0, 0], # Deviations [1, 3, 0, 0, 0], [1, 2, 1, 0, 0], [1, 1, 2, 0, 0], [1, 0, 3, 0, 0], [0, 3, 0, 1, 0], [0, 2, 1, 1, 0], [0, 1, 2, 1, 0], [0, 0, 3, 1, 0], [0, 3, 0, 0, 1], [0, 2, 1, 0, 1], [0, 1, 2, 0, 1], [0, 0, 3, 0, 1], # Deviating restriction [0, 2, 0, 2, 0], [0, 1, 0, 3, 0], [0, 0, 0, 4, 0], ] payoffs = [ # Complete deviations but unexplored [4, 0, 0, 0, 0], [4, 1, 0, 0, 0], [4, 0, 1, 0, 0], [4, 0, 0, 1, 0], [4, 0, 0, 0, 0], # Deviating restriction also explored [0, 1, 0, 0, 0], [0, 1, 4, 0, 0], [0, 1, 4, 0, 0], [0, 1, 4, 0, 0], [0, 0, 4, 0, 0], # Deviations [1, 3, 0, 0, 0], [1, 2, 1, 0, 0], [1, 1, 2, 0, 0], [1, 0, 3, 0, 0], [0, 3, 0, 5, 0], [0, 2, 1, 5, 0], [0, 1, 2, 5, 0], [0, 0, 3, 5, 0], [0, 3, 0, 0, 0], [0, 2, 1, 0, 0], [0, 1, 2, 0, 0], [0, 0, 3, 0, 0], # Deviating restriction [0, 2, 0, 2, 0], [0, 1, 0, 3, 0], [0, 0, 0, 4, 0], ] game = paygame.game([4], [5], profiles, payoffs) game_str = json.dumps(game.to_json()) with stdin(game_str), stdout() as out, stderr() as err: assert run('analyze', '-sd'), err.getvalue() out = out.getvalue() assert 'Found 1 dominated strategy' in out assert 'Found 1 unconfirmed candidate' in out assert 'Found 1 unexplored best-response restricted game' in out