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