Skip to content

Commit e85f6ce

Browse files
rahulsavanitturocy
andauthored
Weaken test for enumpoly that ignores output order (#590)
* Create a weaker test for enumpoly that ignores output order * Update test_nash.py Closes #589. --------- Co-authored-by: Ted Turocy <ted.turocy@gmail.com>
1 parent 95280e8 commit e85f6ce

1 file changed

Lines changed: 85 additions & 10 deletions

File tree

tests/test_nash.py

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,42 +95,118 @@ def test_enummixed_rational():
9595
[[[["1/4", "1/4", "1/4", "1/4"]], [["1/4", "1/4", "1/4", "1/4"]]]],
9696
1,
9797
),
98+
# 3-player game
99+
# (
100+
# games.create_mixed_behav_game_efg(),
101+
# [
102+
# [[["1/2", "1/2"]], [["2/5", "3/5"]], [["1/4", "3/4"]]],
103+
# [[["2/5", "3/5"]], [["1/2", "1/2"]], [["1/3", "2/3"]]],
104+
# ],
105+
# 2, # 9 in total found by enumpoly (see unordered test)
106+
# ),
107+
],
108+
)
109+
def test_enumpoly_ordered_behavior(
110+
game: gbt.Game, mixed_behav_prof_data: list, stop_after: typing.Union[None, int]
111+
):
112+
"""Test calls of enumpoly for mixed behavior equilibria,
113+
using max_regret (internal consistency); and comparison to a set of previously
114+
computed equilibria using this function (regression test).
115+
This set will be the full set of all computed equilibria if stop_after is None,
116+
else the first stop_after-many equilibria.
117+
118+
This is the "ordered" version where we test for the outputs coming in a specific
119+
order; there is also an "unordered" version. The game 2x2x2.nfg, for example,
120+
has a point at which the Jacobian is singular. As a result, the order in which it
121+
returns the two totally-mixed equilbria is system-dependent due, essentially,
122+
to inherent numerical instability near that point.
123+
"""
124+
if stop_after:
125+
result = gbt.nash.enumpoly_solve(
126+
game, use_strategic=False, stop_after=stop_after, maxregret=0.00001
127+
)
128+
assert len(result.equilibria) == stop_after
129+
else:
130+
# compute all
131+
result = gbt.nash.enumpoly_solve(game, use_strategic=False)
132+
assert len(result.equilibria) == len(mixed_behav_prof_data)
133+
for eq, exp in zip(result.equilibria, mixed_behav_prof_data):
134+
assert abs(eq.max_regret()) <= TOL
135+
expected = game.mixed_behavior_profile(rational=True, data=exp)
136+
for p in game.players:
137+
for i in p.infosets:
138+
for a in i.actions:
139+
assert abs(eq[p][i][a] - expected[p][i][a]) <= TOL
140+
141+
142+
@pytest.mark.nash
143+
@pytest.mark.nash_enumpoly_behavior
144+
@pytest.mark.parametrize(
145+
"game,mixed_behav_prof_data,stop_after",
146+
[
98147
# 3-player game
99148
(
100149
games.create_mixed_behav_game_efg(),
101150
[
102-
[[["1/2", "1/2"]], [["2/5", "3/5"]], [["1/4", "3/4"]]],
103151
[[["2/5", "3/5"]], [["1/2", "1/2"]], [["1/3", "2/3"]]],
152+
[[["1/2", "1/2"]], [["2/5", "3/5"]], [["1/4", "3/4"]]],
153+
[[["1/2", "1/2"]], [["1/2", "1/2"]], [[1, 0]]],
154+
[[["1/3", "2/3"]], [[1, 0]], [["1/4", "3/4"]]],
155+
[[[1, 0]], [[1, 0]], [[1, 0]]],
156+
[[[1, 0]], [[0, 1]], [[0, 1]]],
157+
[[[0, 1]], [["1/4", "3/4"]], [["1/3", "2/3"]]],
158+
[[[0, 1]], [[1, 0]], [[0, 1]]],
159+
[[[0, 1]], [[0, 1]], [[1, 0]]],
104160
],
105-
2, # 9 in total found by enumpoly
161+
9,
106162
),
107163
],
108164
)
109-
def test_enumpoly_behavior_rational(
165+
def test_enumpoly_unordered_behavior(
110166
game: gbt.Game, mixed_behav_prof_data: list, stop_after: typing.Union[None, int]
111167
):
112-
"""Test calls of enumpoly for mixed behavior equilibria, rational precision,
168+
"""Test calls of enumpoly for mixed behavior equilibria,
113169
using max_regret (internal consistency); and comparison to a set of previously
114170
computed equilibria using this function (regression test).
171+
115172
This set will be the full set of all computed equilibria if stop_after is None,
116173
else the first stop_after-many equilibria.
174+
175+
This is the "unordered" version where we test for the outputs belong to a set
176+
of expected output; there is also an "unordered" that expects the outputs in a specific order.
177+
178+
In this unordered version, once something from the expected set is found it is removed,
179+
so we are checking for no duplicate outputs.
117180
"""
118181
if stop_after:
119182
result = gbt.nash.enumpoly_solve(
120-
game, use_strategic=False, stop_after=stop_after
183+
game, use_strategic=False, stop_after=stop_after, maxregret=0.00001
121184
)
122185
assert len(result.equilibria) == stop_after
123186
else:
124187
# compute all
125188
result = gbt.nash.enumpoly_solve(game, use_strategic=False)
189+
126190
assert len(result.equilibria) == len(mixed_behav_prof_data)
127-
for eq, exp in zip(result.equilibria, mixed_behav_prof_data):
128-
assert abs(eq.max_regret()) <= TOL
129-
expected = game.mixed_behavior_profile(rational=True, data=exp)
191+
192+
def are_the_same(game, found, candidate):
130193
for p in game.players:
131194
for i in p.infosets:
132195
for a in i.actions:
133-
assert abs(eq[p][i][a] - expected[p][i][a]) <= TOL
196+
if not abs(found[p][i][a] - candidate[p][i][a]) <= TOL:
197+
return False
198+
return True
199+
200+
for eq in result.equilibria:
201+
assert abs(eq.max_regret()) <= TOL
202+
found = False
203+
for exp in mixed_behav_prof_data[:]:
204+
expected = game.mixed_behavior_profile(rational=True, data=exp)
205+
if are_the_same(game, eq, expected):
206+
mixed_behav_prof_data.remove(exp)
207+
found = True
208+
break
209+
assert found
134210

135211

136212
def test_lcp_strategy_double():
@@ -261,7 +337,6 @@ def test_lp_behavior_double():
261337

262338

263339
@pytest.mark.nash
264-
@pytest.mark.slow
265340
@pytest.mark.nash_lp_behavior
266341
@pytest.mark.parametrize(
267342
"game,mixed_behav_prof_data",

0 commit comments

Comments
 (0)