@@ -39,6 +39,10 @@ class EquilibriumTestCase:
3939 prob_tol : float | gbt .Rational = Q (0 )
4040
4141
42+ ##################################################################################################
43+ # NASH SOLVER IN MIXED STRATEGIES
44+ ##################################################################################################
45+
4246ENUMPURE_CASES = [
4347 # Zero-sum games
4448 pytest .param (
@@ -248,6 +252,153 @@ def test_nash_strategy_solver(test_case: EquilibriumTestCase, subtests) -> None:
248252 for strategy in player .strategies :
249253 assert abs (eq [strategy ] - expected [strategy ]) <= test_case .prob_tol
250254
255+ ##################################################################################################
256+ # NASH SOLVER IN MIXED BEHAVIORS
257+ ##################################################################################################
258+
259+ # games.read_from_file("two_player_perfect_info_win_lose.efg"),
260+ # [[[0, 1], [1, 0]], [[1, 0], [1, 0]]],
261+
262+ # games.read_from_file("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg"),
263+ # [[[0, 1], [1, 0]], [[1, 0], [1, 0]]],
264+
265+ # games.create_2x2_zero_sum_efg(missing_term_outcome=False),
266+ # [[["1/2", "1/2"]], [["1/2", "1/2"]]],
267+
268+ # games.create_2x2_zero_sum_efg(missing_term_outcome=True),
269+ # [[["1/2", "1/2"]], [["1/2", "1/2"]]],
270+
271+ # games.create_matching_pennies_efg(with_neutral_outcome=False),
272+ # [[["1/2", "1/2"]], [["1/2", "1/2"]]],
273+
274+ # games.create_matching_pennies_efg(with_neutral_outcome=True),
275+ # [[["1/2", "1/2"]], [["1/2", "1/2"]]],
276+
277+ # games.create_stripped_down_poker_efg(),
278+ # [[[1, 0], ["1/3", "2/3"]], [["2/3", "1/3"]]],
279+
280+ # games.create_stripped_down_poker_efg(nonterm_outcomes=True),
281+ # [[[1, 0], ["1/3", "2/3"]], [["2/3", "1/3"]]],
282+
283+ # games.create_kuhn_poker_efg(),
284+ # [
285+ # [[1, 0], [1, 0], [1, 0], ["2/3", "1/3"], [1, 0], [0, 1]],
286+ # [[1, 0], ["2/3", "1/3"], [0, 1], [0, 1], ["2/3", "1/3"], [1, 0]],
287+ # ],
288+
289+ # games.create_kuhn_poker_efg(nonterm_outcomes=True),
290+ # [
291+ # [
292+ # [1, 0],
293+ # [1, 0],
294+ # [1, 0],
295+ # ["2/3", "1/3"],
296+ # [1, 0],
297+ # [0, 1],
298+ # ],
299+ # [[1, 0], ["2/3", "1/3"], [0, 1], [0, 1], ["2/3", "1/3"], [1, 0]],
300+ # ],
301+
302+ # games.read_from_file("zerosum_efg_from_sequence_form_STOC94_paper.efg"),
303+ # [
304+ # [[0, 1], ["2/3", "1/3"], ["1/3", "2/3"]],
305+ # [["5/6", "1/6"], ["5/9", "4/9"]],
306+ # ],
307+
308+ # games.read_from_file("perfect_info_with_chance.efg"),
309+ # [[[0, 1]], [[1, 0], [1, 0]]],
310+
311+ # games.read_from_file("2_player_chance.efg"),
312+ # [
313+ # [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]],
314+ # [["2/3", "1/3"], ["2/3", "1/3"], ["1/3", "2/3"]],
315+ # ],
316+
317+ # games.read_from_file("2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg"),
318+ # [
319+ # [["1/3", 0, "2/3"], ["2/3", 0, "1/3"]],
320+ # [["2/3", "1/3"], ["2/3", "1/3"], ["1/3", "2/3"]],
321+ # ],
322+
323+ # games.read_from_file("large_payoff_game.efg"),
324+ # [
325+ # [[1, 0], [1, 0]],
326+ # [[0, 1], ["9999999999999999999/10000000000000000000", "1/10000000000000000000"]],
327+ # ],
328+
329+ # games.read_from_file("chance_in_middle.efg"),
330+ # [[["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]]],
331+
332+ # games.read_from_file("chance_in_middle_with_nonterm_outcomes.efg"),
333+ # [[["3/11", "8/11"], [1, 0], [1, 0], [1, 0], [1, 0]], [[1, 0], ["6/11", "5/11"]]],
334+
335+
336+ LP_BEHAVIOR_RATIONAL_CASES = [
337+ pytest .param (
338+ EquilibriumTestCase (
339+ factory = functools .partial (
340+ games .read_from_file , "chance_in_middle_with_nonterm_outcomes.efg"
341+ ),
342+ solver = gbt .nash .lp_solve ,
343+ expected = [
344+ [
345+ [d ("3/11" , "8/11" ), d (1 , 0 ), d (1 , 0 ), d (1 , 0 ), d (1 , 0 )],
346+ [d (1 , 0 ), d ("6/11" , "5/11" )]
347+ ]
348+ ],
349+ ),
350+ marks = pytest .mark .nash_enumpure_strategy ,
351+ id = "test1_TODO" ,
352+ ),
353+ ]
354+
355+ CASES = []
356+ CASES += LP_BEHAVIOR_RATIONAL_CASES
357+
358+
359+ @pytest .mark .nash
360+ @pytest .mark .parametrize ("test_case" , CASES , ids = lambda c : c .label )
361+ def test_nash_behavior_solver (test_case : EquilibriumTestCase , subtests ) -> None :
362+ """Test calls of Nash solvers in mixed behaviors
363+
364+ Subtests:
365+ - Max regret no more than `test_case.regret_tol`
366+ - Agent max regret no more than max regret (+ `test_case.regret_tol`)
367+ - Equilibria are output in the expected order. Equilibria are deemed to match if the maximum
368+ difference in probabilities is no more than `test_case.prob_tol`
369+ """
370+ game = test_case .factory ()
371+ result = test_case .solver (game )
372+ with subtests .test ("number of equilibria found" ):
373+ assert len (result .equilibria ) == len (test_case .expected )
374+ for i , (eq , exp ) in enumerate (zip (result .equilibria , test_case .expected , strict = True )):
375+ with subtests .test (eq = i , check = "max_regret" ):
376+ assert eq .max_regret () <= test_case .regret_tol
377+ with subtests .test (eq = i , check = "max_regret" ):
378+ assert eq .agent_max_regret () <= eq .max_regret () + test_case .regret_tol
379+ with subtests .test (eq = i , check = "strategy_profile" ):
380+ expected = game .mixed_behavior_profile (rational = True , data = exp )
381+ for player in game .players :
382+ for action in player .actions :
383+ assert abs (eq [action ] - expected [action ]) <= test_case .prob_tol
384+
385+ # def test_lp_behavior_rational(game: gbt.Game, mixed_behav_prof_data: list):
386+ # """Test calls of LP for mixed behavior equilibria, rational precision,
387+ # using max_regret and agent_max_regret (internal consistency); and
388+ # comparison to a previously computed equilibrium using this function (regression test).
389+ # """
390+ # result = gbt.nash.lp_solve(game, use_strategic=False, rational=True)
391+ # assert len(result.equilibria) == 1
392+ # eq = result.equilibria[0]
393+ # assert eq.max_regret() == 0
394+ # assert eq.agent_max_regret() == 0
395+ # expected = game.mixed_behavior_profile(rational=True, data=mixed_behav_prof_data)
396+ # assert eq == expected
397+
398+ ##################################################################################################
399+ # AGENTS NASH SOLVERS (IN MIXED BEHAVIORS
400+ ##################################################################################################
401+
251402
252403ENUMPURE_AGENT_CASES = [
253404 # #############################################################
@@ -515,6 +666,7 @@ def test_nash_strategy_solver(test_case: EquilibriumTestCase, subtests) -> None:
515666# ),
516667# ##############################################################################
517668
669+
518670AGENT_CASES = []
519671AGENT_CASES += ENUMPURE_AGENT_CASES
520672AGENT_CASES += ENUMPOLY_AGENT_CASES
@@ -547,6 +699,10 @@ def test_nash_agent_solver(test_case: EquilibriumTestCase, subtests) -> None:
547699 assert abs (eq [action ] - expected [action ]) <= test_case .prob_tol
548700
549701
702+ ##################################################################################################
703+ # TEMP FOR ISSUE 660
704+ ##################################################################################################
705+
550706ENUMPOLY_ISSUE_660_CASES = [
551707 # 2-player non-zero-sum games
552708 pytest .param (
@@ -607,6 +763,10 @@ def test_nash_agent_solver_no_subtests_only_profile(test_case: EquilibriumTestCa
607763 assert abs (eq [action ] - expected [action ]) <= test_case .prob_tol
608764
609765
766+ ##################################################################################################
767+ # AGENT UNORDERED
768+ ##################################################################################################
769+
610770ENUMPOLY_AGENT_UNORDERED_CASES = [
611771 pytest .param (
612772 EquilibriumTestCase (
@@ -671,6 +831,11 @@ def are_the_same(game, found, candidate):
671831 assert found
672832
673833
834+ ##################################################################################################
835+ # STILL TODO........
836+ ##################################################################################################
837+
838+
674839def test_lcp_strategy_double ():
675840 """Test calls of LCP for mixed strategy equilibria, floating-point."""
676841 game = games .read_from_file ("stripped_down_poker.efg" )
@@ -958,120 +1123,6 @@ def test_lp_behavior_double():
9581123 # For floating-point results are not exact, so we skip testing exact values for now
9591124
9601125
961- @pytest .mark .nash
962- @pytest .mark .nash_lp_behavior
963- @pytest .mark .parametrize (
964- "game,mixed_behav_prof_data" ,
965- [
966- (
967- games .read_from_file ("two_player_perfect_info_win_lose.efg" ),
968- [[[0 , 1 ], [1 , 0 ]], [[1 , 0 ], [1 , 0 ]]],
969- ),
970- (
971- games .read_from_file ("two_player_perfect_info_win_lose_with_nonterm_outcomes.efg" ),
972- [[[0 , 1 ], [1 , 0 ]], [[1 , 0 ], [1 , 0 ]]],
973- ),
974- (
975- games .create_2x2_zero_sum_efg (missing_term_outcome = False ),
976- [[["1/2" , "1/2" ]], [["1/2" , "1/2" ]]],
977- ),
978- (
979- games .create_2x2_zero_sum_efg (missing_term_outcome = True ),
980- [[["1/2" , "1/2" ]], [["1/2" , "1/2" ]]],
981- ),
982- (
983- games .create_matching_pennies_efg (with_neutral_outcome = False ),
984- [[["1/2" , "1/2" ]], [["1/2" , "1/2" ]]],
985- ),
986- (
987- games .create_matching_pennies_efg (with_neutral_outcome = True ),
988- [[["1/2" , "1/2" ]], [["1/2" , "1/2" ]]],
989- ),
990- (
991- games .create_stripped_down_poker_efg (),
992- [[[1 , 0 ], ["1/3" , "2/3" ]], [["2/3" , "1/3" ]]],
993- ),
994- (
995- games .create_stripped_down_poker_efg (nonterm_outcomes = True ),
996- [[[1 , 0 ], ["1/3" , "2/3" ]], [["2/3" , "1/3" ]]],
997- ),
998- (
999- games .create_kuhn_poker_efg (),
1000- [
1001- [[1 , 0 ], [1 , 0 ], [1 , 0 ], ["2/3" , "1/3" ], [1 , 0 ], [0 , 1 ]],
1002- [[1 , 0 ], ["2/3" , "1/3" ], [0 , 1 ], [0 , 1 ], ["2/3" , "1/3" ], [1 , 0 ]],
1003- ],
1004- ),
1005- (
1006- games .create_kuhn_poker_efg (nonterm_outcomes = True ),
1007- [
1008- [
1009- [1 , 0 ],
1010- [1 , 0 ],
1011- [1 , 0 ],
1012- ["2/3" , "1/3" ],
1013- [1 , 0 ],
1014- [0 , 1 ],
1015- ],
1016- [[1 , 0 ], ["2/3" , "1/3" ], [0 , 1 ], [0 , 1 ], ["2/3" , "1/3" ], [1 , 0 ]],
1017- ],
1018- ),
1019- (
1020- games .read_from_file ("zerosum_efg_from_sequence_form_STOC94_paper.efg" ),
1021- [
1022- [[0 , 1 ], ["2/3" , "1/3" ], ["1/3" , "2/3" ]],
1023- [["5/6" , "1/6" ], ["5/9" , "4/9" ]],
1024- ],
1025- ),
1026- (
1027- games .read_from_file ("perfect_info_with_chance.efg" ),
1028- [[[0 , 1 ]], [[1 , 0 ], [1 , 0 ]]],
1029- ),
1030- (
1031- games .read_from_file ("2_player_chance.efg" ),
1032- [
1033- [["1/3" , 0 , "2/3" ], ["2/3" , 0 , "1/3" ]],
1034- [["2/3" , "1/3" ], ["2/3" , "1/3" ], ["1/3" , "2/3" ]],
1035- ],
1036- ),
1037- (
1038- games .read_from_file ("2_player_chance_nonterm_outcomes_and_missing_term_outcomes.efg" ),
1039- [
1040- [["1/3" , 0 , "2/3" ], ["2/3" , 0 , "1/3" ]],
1041- [["2/3" , "1/3" ], ["2/3" , "1/3" ], ["1/3" , "2/3" ]],
1042- ],
1043- ),
1044- (
1045- games .read_from_file ("large_payoff_game.efg" ),
1046- [
1047- [[1 , 0 ], [1 , 0 ]],
1048- [[0 , 1 ], ["9999999999999999999/10000000000000000000" , "1/10000000000000000000" ]],
1049- ],
1050- ),
1051- (
1052- games .read_from_file ("chance_in_middle.efg" ),
1053- [[["3/11" , "8/11" ], [1 , 0 ], [1 , 0 ], [1 , 0 ], [1 , 0 ]], [[1 , 0 ], ["6/11" , "5/11" ]]],
1054- ),
1055- (
1056- games .read_from_file ("chance_in_middle_with_nonterm_outcomes.efg" ),
1057- [[["3/11" , "8/11" ], [1 , 0 ], [1 , 0 ], [1 , 0 ], [1 , 0 ]], [[1 , 0 ], ["6/11" , "5/11" ]]],
1058- ),
1059- ],
1060- )
1061- def test_lp_behavior_rational (game : gbt .Game , mixed_behav_prof_data : list ):
1062- """Test calls of LP for mixed behavior equilibria, rational precision,
1063- using max_regret and agent_max_regret (internal consistency); and
1064- comparison to a previously computed equilibrium using this function (regression test).
1065- """
1066- result = gbt .nash .lp_solve (game , use_strategic = False , rational = True )
1067- assert len (result .equilibria ) == 1
1068- eq = result .equilibria [0 ]
1069- assert eq .max_regret () == 0
1070- assert eq .agent_max_regret () == 0
1071- expected = game .mixed_behavior_profile (rational = True , data = mixed_behav_prof_data )
1072- assert eq == expected
1073-
1074-
10751126def test_liap_strategy ():
10761127 """Test calls of liap for mixed strategy equilibria."""
10771128 game = games .read_from_file ("stripped_down_poker.efg" )
0 commit comments