Skip to content

Commit

Permalink
New tests for trembling-hand, proper eq, efficiency metrics. Also, th…
Browse files Browse the repository at this point in the history
…ere is a test case where the behavioral equilibrium differs from the Nash equilibrium
  • Loading branch information
Konstantinos Varsos committed Nov 16, 2023
1 parent a907caa commit 7dede73
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NFG 1 R "Augmented Entry-Detterence Game" { "Player 1" "Player 2" }

{ { "1" "2" "3" }
{ { "1" "2" }
{ "1" "2" "3" }
}
""
Expand Down
119 changes: 92 additions & 27 deletions src/pygambit/tests/test_mixed_new.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import pytest
import numpy as np
from scipy.optimize import minimize

import pygambit
import pygambit as gbt
Expand Down Expand Up @@ -138,50 +140,113 @@ def test_regret(game: gbt.Game):


@pytest.mark.parametrize(
"game,data,opt",
[(gbt.Game.read_game("test_games/Cl_BLotto_game.nfg"),
[4.0, 3.5, 3.2857, 3.2], 4.0)]
"game",
[gbt.Game.read_game("test_games/Cl_BLotto_game.nfg")]
)
def test_price_of_anarchy(game: gbt.Game, data: float, opt: float):
assert min(data) / opt == 3.2/4.0
def test_metrics(game: gbt.Game):
def tmp_matrix(game, n, m):
A = np.zeros((n, m))
B = np.zeros((n, m))
for i in range(n):
for j in range(m):
A[i, j] = game.outcomes[n*j + i][game.players[0]]
B[i, j] = game.outcomes[n*j + i][game.players[1]]
return A, B
equilibria = gbt.nash.enummixed_solve(game, rational=False)
n = len(game.players[0].strategies)
m = len(game.players[1].strategies)
A, B = tmp_matrix(game, n, m)
welfare = []
for eq in equilibria:
u = [eq._getprob_strategy(game.players[0].strategies[i]) for i in range(n)]
v = [eq._getprob_strategy(game.players[1].strategies[i]) for i in range(m)]
welfare.append((np.dot(u, np.dot(A + B, v))))
opt = (A + B).max()
assert min(welfare) / opt == 3.2/4.0
assert max(welfare) / opt == 1.0


@pytest.mark.parametrize(
"game,tremble",
[(gbt.Game.read_game("test_games/Entry_Detterence_game.nfg"), 0.001)]
)
def test_non_perfect(game: gbt.Game, tremble: float):
assert game.outcomes[1]["Player 1"] - tremble > game.outcomes[0]["Player 1"]
assert not game.outcomes[2]["Player 1"] + tremble < game.outcomes[3]["Player 1"]


@pytest.mark.parametrize(
"game,tremble",
[(gbt.Game.read_game("test_games/Aug_Entry_Detterence_game.nfg"), 0.001)]
)
def test_perfect(game: gbt.Game, tremble: float):
game.outcomes[1]["Player 1"] = 3*(1 - 4*tremble/3) + 2*tremble
game.outcomes[0]["Player 1"] = 2*tremble/3 + 3*(1 - 4*tremble/3) + tremble
game.outcomes[1]["Player 2"] = 1
game.outcomes[0]["Player 2"] = 2*tremble
assert game.outcomes[1]["Player 1"] > game.outcomes[0]["Player 1"]
assert game.outcomes[1]["Player 2"] > game.outcomes[0]["Player 2"]
def test_trembling_hand_perfect(game: gbt.Game, tremble: float):
profile = game.mixed_strategy_profile(rational=False)
profile[game.players[0]] = [tremble, 1-tremble]
profile[game.players[1]] = [1 - tremble, 1]
n = len(game.players[0].strategies)
m = len(game.players[1].strategies)
u = [profile._getprob_strategy(game.players[0].strategies[i]) for i in range(n)]
v = [profile._getprob_strategy(game.players[1].strategies[i]) for i in range(m)]
expect1 = []
expect2 = []
for i in range(n):
tmp = 0
for j in range(m):
tmp += v[j]*game.outcomes[2*i + j][game.players[0]]
expect1.append(tmp)
for i in range(n):
tmp = 0
for j in range(m):
tmp += u[j]*game.outcomes[2*i + j][game.players[1]]
expect2.append(tmp)
s_eq_u = [0, 1]
s_eq_v = [1, 0]
assert (
expect1[s_eq_u[1]] > expect1[s_eq_u[0]]
and
expect2[s_eq_v[1]] > expect2[s_eq_v[0]]
)
s_eq_u = [1, 0]
s_eq_v = [0, 1]
assert (
expect1[s_eq_u[1]] < expect1[s_eq_u[0]]
or
expect2[s_eq_v[1]] < expect2[s_eq_v[0]]
)


@pytest.mark.parametrize(
"game,tremble",
[(gbt.Game.read_game("test_games/Aug_Entry_Detterence_game.nfg"), 0.001)]
)
def test_proper(game: gbt.Game, tremble: float):
support_profile = game.support_profile()
assert support_profile[0]
def test_not_proper(game: gbt.Game, tremble: float):
profile = game.mixed_strategy_profile(rational=False)
profile[game.players[0]] = [1 - tremble, tremble]
n = len(game.players[0].strategies)
m = len(game.players[1].strategies)
u = [profile._getprob_strategy(game.players[0].strategies[i]) for i in range(n)]
expect2 = []
for i in range(m):
tmp = 0
for j in range(n):
tmp += u[j]*game.outcomes[2*i + j][game.players[1]]
expect2.append(tmp)
profile[game.players[1]] = [tremble, 1 - tremble - tremble**2, tremble**2]
v = [profile._getprob_strategy(game.players[1].strategies[i]) for i in range(m)]
expect1 = []
for i in range(n):
tmp = 0
for j in range(m):
tmp += v[j]*game.outcomes[3*i + j][game.players[0]]
expect1.append(tmp)
assert (
expect1[1] > expect1[0]
and
expect2[1] == max(expect2)
)


@pytest.mark.parametrize(
"game",
[gbt.Game.read_game("test_games/Mixed_vs_Behavioral.efg")]
)
def test_mixed_vs_behavioral(game: gbt.Game):
behav = gbt.nash.lcp_solve(game, use_strategic=False, rational=True)
mixed = gbt.nash.lcp_solve(game, use_strategic=False, rational=False)
assert behav[0] != mixed[0]
def f(x):
return -x**2 - 10*x*(1 - x) - 2*(1 - x)
profile = game.mixed_behavior_profile(rational=False)
res = minimize(f, 1/2)
p = res.x
profile[game.players[0]] = [[p, 1 - p], [1]]
mixed = gbt.nash.enummixed_solve(game, rational=True)
assert not profile[game.players[0]] == mixed[0][game.players[0]]

0 comments on commit 7dede73

Please sign in to comment.