Import tests: Shayan1/Prod/tests/test_solver
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,145 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from nash import solver
|
||||||
|
from nash.game import Game
|
||||||
|
|
||||||
|
PRICING = Game.load_from_json("games/pricing.json")
|
||||||
|
MATCHING_PENNIES = Game.load_from_json("games/matching_pennies.json")
|
||||||
|
|
||||||
|
|
||||||
|
def test_pricing_has_one_pure_equilibrium_low_low():
|
||||||
|
equilibria = solver.find_pure_nash_equilibria(PRICING)
|
||||||
|
assert equilibria == [(1, 1)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_matching_pennies_has_no_pure_equilibrium():
|
||||||
|
equilibria = solver.find_pure_nash_equilibria(MATCHING_PENNIES)
|
||||||
|
assert equilibria == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_pricing_mixed_equilibrium_matches_pure_equilibrium():
|
||||||
|
equilibria = solver.find_mixed_nash_equilibria(PRICING)
|
||||||
|
assert len(equilibria) == 1
|
||||||
|
x, y = equilibria[0]
|
||||||
|
assert np.allclose(x, [0, 1], atol=1e-6)
|
||||||
|
assert np.allclose(y, [0, 1], atol=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_matching_pennies_mixed_equilibrium_is_fifty_fifty():
|
||||||
|
equilibria = solver.find_mixed_nash_equilibria(MATCHING_PENNIES)
|
||||||
|
assert len(equilibria) == 1
|
||||||
|
x, y = equilibria[0]
|
||||||
|
assert np.allclose(x, [0.5, 0.5], atol=1e-6)
|
||||||
|
assert np.allclose(y, [0.5, 0.5], atol=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_mixed_solver_rejects_more_than_two_players():
|
||||||
|
game = Game(
|
||||||
|
players=["A", "B", "C"],
|
||||||
|
strategies=[["x", "y"], ["x", "y"], ["x", "y"]],
|
||||||
|
payoffs=[np.zeros((2, 2, 2))] * 3,
|
||||||
|
)
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
solver.find_mixed_nash_equilibria(game)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pure_equilibrium_finder_supports_n_players():
|
||||||
|
# Simple 3-player coordination game: everyone matching strategy 0 is the
|
||||||
|
# unique pure Nash equilibrium (payoff 1 if all match, 0 otherwise).
|
||||||
|
payoff = np.zeros((2, 2, 2))
|
||||||
|
payoff[0, 0, 0] = 1
|
||||||
|
game = Game(
|
||||||
|
players=["A", "B", "C"],
|
||||||
|
strategies=[["x", "y"], ["x", "y"], ["x", "y"]],
|
||||||
|
payoffs=[payoff, payoff, payoff],
|
||||||
|
)
|
||||||
|
equilibria = solver.find_pure_nash_equilibria(game)
|
||||||
|
assert (0, 0, 0) in equilibria
|
||||||
|
|
||||||
|
def test_pricing_has_dominant_strategies():
|
||||||
|
result = solver.find_dominant_strategies(PRICING)
|
||||||
|
# Both companies have "Low" (index 1) as strictly dominant strategy:
|
||||||
|
# Company A: Low beats High vs any B strategy (10>8, 5>2)
|
||||||
|
# Company B: Low beats High vs any A strategy (10>8, 5>2)
|
||||||
|
assert result == {0: 1, 1: 1}
|
||||||
|
|
||||||
|
|
||||||
|
def test_matching_pennies_has_no_dominant_strategies():
|
||||||
|
result = solver.find_dominant_strategies(MATCHING_PENNIES)
|
||||||
|
assert result == {0: None, 1: None}
|
||||||
|
|
||||||
|
|
||||||
|
def test_dominant_strategies_supports_n_players():
|
||||||
|
# 3-player game: players 0,1 have strictly dominant strategy 0;
|
||||||
|
# player 2 has no dominant strategy.
|
||||||
|
payoffs_0 = np.zeros((2, 2, 2))
|
||||||
|
payoffs_1 = np.zeros((2, 2, 2))
|
||||||
|
payoffs_2 = np.zeros((2, 2, 2))
|
||||||
|
for profile in np.ndindex(2, 2, 2):
|
||||||
|
payoffs_0[profile] = 10.0 if profile[0] == 0 else 1.0
|
||||||
|
payoffs_1[profile] = 10.0 if profile[1] == 0 else 1.0
|
||||||
|
payoffs_2[profile] = float(profile[0] + profile[1])
|
||||||
|
game = Game(
|
||||||
|
players=["A", "B", "C"],
|
||||||
|
strategies=[["x", "y"], ["x", "y"], ["x", "y"]],
|
||||||
|
payoffs=[payoffs_0, payoffs_1, payoffs_2],
|
||||||
|
)
|
||||||
|
result = solver.find_dominant_strategies(game)
|
||||||
|
assert result[0] == 0
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[2] is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_dominant_strategies_one_strategy_player():
|
||||||
|
# Player 0 has 1 strategy, Player 1 has 2 strategies
|
||||||
|
payoffs_0 = np.array([[5.0, 5.0]]) # 1x2 matrix
|
||||||
|
payoffs_1 = np.array([[10.0, 1.0]]) # 1x2 matrix
|
||||||
|
game = Game(
|
||||||
|
players=["A", "B"],
|
||||||
|
strategies=[["only"], ["x", "y"]],
|
||||||
|
payoffs=[payoffs_0, payoffs_1],
|
||||||
|
)
|
||||||
|
result = solver.find_dominant_strategies(game)
|
||||||
|
# Player 0 has no dominant strategy (None) because they only have 1 strategy.
|
||||||
|
# Player 1 has dominant strategy 0 (10.0 > 1.0).
|
||||||
|
assert result == {0: None, 1: 0}
|
||||||
|
|
||||||
|
|
||||||
|
def test_reduce_game_pricing():
|
||||||
|
reduced, logs = solver.reduce_game(PRICING)
|
||||||
|
assert len(logs) == 2
|
||||||
|
assert "Player 'Company A' eliminated dominated strategy 'High'" in logs[0]
|
||||||
|
assert "Player 'Company B' eliminated dominated strategy 'High'" in logs[1]
|
||||||
|
assert reduced.strategies == [["Low"], ["Low"]]
|
||||||
|
assert np.allclose(reduced.payoffs[0], [[5]])
|
||||||
|
assert np.allclose(reduced.payoffs[1], [[5]])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reduce_game_matching_pennies():
|
||||||
|
reduced, logs = solver.reduce_game(MATCHING_PENNIES)
|
||||||
|
assert len(logs) == 0
|
||||||
|
assert reduced.strategies == MATCHING_PENNIES.strategies
|
||||||
|
assert np.allclose(reduced.payoffs[0], MATCHING_PENNIES.payoffs[0])
|
||||||
|
assert np.allclose(reduced.payoffs[1], MATCHING_PENNIES.payoffs[1])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reduce_game_n_players():
|
||||||
|
payoffs_0 = np.zeros((2, 2, 2))
|
||||||
|
payoffs_1 = np.zeros((2, 2, 2))
|
||||||
|
payoffs_2 = np.zeros((2, 2, 2))
|
||||||
|
payoffs_0[0, :, :] = 1.0
|
||||||
|
payoffs_0[1, :, :] = 2.0
|
||||||
|
payoffs_1[:, 0, :] = 1.0
|
||||||
|
payoffs_1[:, 1, :] = 2.0
|
||||||
|
payoffs_2[:, :, 0] = 1.0
|
||||||
|
payoffs_2[:, :, 1] = 2.0
|
||||||
|
game = Game(
|
||||||
|
players=["P0", "P1", "P2"],
|
||||||
|
strategies=[["A", "B"], ["C", "D"], ["E", "F"]],
|
||||||
|
payoffs=[payoffs_0, payoffs_1, payoffs_2]
|
||||||
|
)
|
||||||
|
reduced, logs = solver.reduce_game(game)
|
||||||
|
assert len(logs) == 3
|
||||||
|
assert reduced.strategies == [["B"], ["D"], ["F"]]
|
||||||
|
assert np.allclose(reduced.payoffs[0], [[[2.0]]])
|
||||||
Reference in New Issue
Block a user