Skip to content

Commit

Permalink
Integrate lrsnash with enummixed call
Browse files Browse the repository at this point in the history
  • Loading branch information
tturocy committed Oct 18, 2024
1 parent 4d41ac6 commit adb97e7
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 9 deletions.
34 changes: 28 additions & 6 deletions src/pygambit/nash.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import pygambit.gambit as libgbt

from . import nashphc
from . import nashlrs, nashphc

MixedStrategyEquilibriumSet = list[libgbt.MixedStrategyProfile]
MixedBehaviorEquilibriumSet = list[libgbt.MixedBehaviorProfile]
Expand Down Expand Up @@ -103,7 +103,7 @@ def enumpure_solve(game: libgbt.Game, use_strategic: bool = True) -> NashComputa
def enummixed_solve(
game: libgbt.Game,
rational: bool = True,
use_lrs: bool = False
lrsnash_path: pathlib.Path | str | None = None,
) -> NashComputationResult:
"""Compute all :ref:`mixed-strategy Nash equilibria <gambit-enummixed>`
of a two-player game using the strategic representation.
Expand All @@ -112,11 +112,23 @@ def enummixed_solve(
----------
game : Game
The game to compute equilibria in.
rational : bool, default True
Compute using rational numbers. If `False`, using floating-point
arithmetic. Using rationals is more precise, but slower.
use_lrs : bool, default False
If `True`, use the implementation based on ``lrslib``. This is experimental.
lrsnash_path : pathlib.Path | str | None = None,
If specified, use lrsnash [1]_ to solve the systems of equations.
This argument specifies the path to the lrsnash executable.
.. versionadded:: 16.3.0
Returns
-------
res : NashComputationResult
The result represented as a ``NashComputationResult`` object.
.. [1] http://cgm.cs.mcgill.ca/~avis/C/lrs.html
Returns
-------
Expand All @@ -128,14 +140,24 @@ def enummixed_solve(
RuntimeError
If game has more than two players.
"""
if use_lrs or rational:
if lrsnash_path is not None:
equilibria = nashlrs.lrsnash_solve(game, lrsnash_path=lrsnash_path)
return NashComputationResult(
game=game,
method="enummixed",
rational=True,
use_strategic=True,
parameters={"lrsnash_path": lrsnash_path},
equilibria=equilibria,
)
if rational:
equilibria = libgbt._enummixed_strategy_solve_rational(game)
else:
equilibria = libgbt._enummixed_strategy_solve_double(game)
return NashComputationResult(
game=game,
method="enummixed",
rational=use_lrs or rational,
rational=rational,
use_strategic=True,
equilibria=equilibria
)
Expand Down
10 changes: 7 additions & 3 deletions src/pygambit/nashlrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""

import itertools
import pathlib
import subprocess
import sys

Expand Down Expand Up @@ -33,9 +34,12 @@ def _parse_lrs_output(game: gbt.Game, txt: str) -> list[gbt.MixedStrategyProfile
return eqa


def lrsnash_solve(game: gbt.Game) -> list[gbt.MixedStrategyProfileRational]:
def lrsnash_solve(game: gbt.Game,
lrsnash_path: pathlib.Path | str) -> list[gbt.MixedStrategyProfileRational]:
if len(game.players) != 2:
raise RuntimeError("Method only valid for two-player games.")
with util.make_temporary(_generate_lrs_input(game)) as infn:
result = subprocess.run(["./lrsnash", infn], encoding="utf-8",
result = subprocess.run([lrsnash_path, infn], encoding="utf-8",
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
raise ValueError(f"PHC run failed with return code {result.returncode}")
Expand All @@ -44,7 +48,7 @@ def lrsnash_solve(game: gbt.Game) -> list[gbt.MixedStrategyProfileRational]:

def main():
game = gbt.Game.parse_game(sys.stdin.read())
eqa = lrsnash_solve(game)
eqa = lrsnash_solve(game, "./lrsnash")
for eqm in eqa:
print("NE," +
",".join(str(eqm[strat]) for player in game.players for strat in player.strategies))
Expand Down

0 comments on commit adb97e7

Please sign in to comment.