Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ gtracer_SOURCES = \
src/solvers/gtracer/gnm.cc \
src/solvers/gtracer/ipa.cc

hp_SOURCES = \
src/solvers/hp/hp.h \
src/solvers/hp/hp.cc \
src/solvers/hp/hpsystem.h \
src/solvers/hp/hpsystem.cc

nashsupport_SOURCES = \
src/solvers/nashsupport/efgsupport.cc \
src/solvers/nashsupport/nfgsupport.cc \
Expand Down Expand Up @@ -306,15 +312,22 @@ liap_SOURCES = \
src/solvers/liap/nfgliap.cc \
src/solvers/liap/liap.h

path_SOURCES = \
src/solvers/path/path.cc \
src/solvers/path/path.h

logit_SOURCES = \
src/solvers/logit/logbehav.h \
src/solvers/logit/logbehav.imp \
src/solvers/logit/path.cc \
src/solvers/logit/path.h \
src/solvers/logit/logit.h \
src/solvers/logit/efglogit.cc \
src/solvers/logit/nfglogit.cc

homotopy_SOURCES = \
${path_SOURCES} \
${logit_SOURCES} \
${hp_SOURCES}

simpdiv_SOURCES = \
src/solvers/simpdiv/simpdiv.cc \
src/solvers/simpdiv/simpdiv.h
Expand Down Expand Up @@ -357,14 +370,14 @@ AM_CXXFLAGS = ${LLVM_CXXFLAGS} -Wall -Wsign-compare -Wunreachable-code
## recompiling the same core/games/solver sources from scratch.

noinst_LIBRARIES = libcore.a libgames.a libbimatrix.a libgtracer.a \
libliap.a liblogit.a libsimpdiv.a libenumpoly.a
libliap.a libhomotopy.a libsimpdiv.a libenumpoly.a

libcore_a_SOURCES = ${core_SOURCES}
libgames_a_SOURCES = ${game_SOURCES}
libbimatrix_a_SOURCES = ${bimatrix_SOURCES}
libgtracer_a_SOURCES = ${gtracerlib_SOURCES}
libliap_a_SOURCES = ${liap_SOURCES}
liblogit_a_SOURCES = ${logit_SOURCES}
libhomotopy_a_SOURCES = ${homotopy_SOURCES}
libsimpdiv_a_SOURCES = ${simpdiv_SOURCES}
libenumpoly_a_SOURCES = ${enumpoly_SOURCES}

Expand Down Expand Up @@ -443,7 +456,7 @@ gambit_SOURCES = \
gambit_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS)
gambit_CPPFLAGS = $(AM_CPPFLAGS) $(WX_CXXFLAGS)

gambit_LDADD_LIBS = libbimatrix.a libliap.a liblogit.a libgtracer.a \
gambit_LDADD_LIBS = libbimatrix.a libliap.a libhomotopy.a libgtracer.a \
libsimpdiv.a libenumpoly.a libgames.a libcore.a

gambit_DEPENDENCIES = $(RC_OBJECT_PATH) $(gambit_LDADD_LIBS)
Expand Down
56 changes: 55 additions & 1 deletion doc/algorithms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,49 @@ Algorithm Description
:ref:`lp` Compute equilibria in a two-player constant-sum game via linear programming :py:func:`pygambit.nash.lp_solve` :ref:`gambit-lp <gambit-lp>`
:ref:`lcp` Compute equilibria in a two-player game via linear complementarity :py:func:`pygambit.nash.lcp_solve` :ref:`gambit-lcp <gambit-lcp>`
:ref:`liap` Compute equilibria using function minimization :py:func:`pygambit.nash.liap_solve` :ref:`gambit-liap <gambit-liap>`
:ref:`logit` Trace logit QRE and approximate a Nash equilibrium at high precision :py:func:`pygambit.nash.logit_solve` :ref:`gambit-logit <gambit-logit>`
:ref:`logit` Trace logit QRE and approximate a Nash equilibrium at high precision :py:func:`pygambit.nash.logit_solve` :ref:`gambit-logit <gambit-logit>`
:ref:`simpdiv` Compute equilibria via simplicial subdivision :py:func:`pygambit.nash.simpdiv_solve` :ref:`gambit-simpdiv <gambit-simpdiv>`
:ref:`ipa` Compute equilibria using iterated polymatrix approximation :py:func:`pygambit.nash.ipa_solve` :ref:`gambit-ipa <gambit-ipa>`
:ref:`gnm` Compute equilibria using a global Newton method :py:func:`pygambit.nash.gnm_solve` :ref:`gambit-gnm <gambit-gnm>`
:ref:`hp` Compute a specific Nash equilibrium using a homotopy path-following method :py:func:`pygambit.nash.hp_solve` :ref:`gambit-hp <gambit-hp>`
================ =========================================================================== ======================================== ==========================================

.. _pygambit-nash-maxregret:

Acceptance criteria for approximate Nash equilibria
----------------------------------------------------

Some methods for computing Nash equilibria operate using floating-point arithmetic and/or
generate candidate equilibrium profiles using methods which involve some form of successive
approximation. The outputs of these methods therefore are in general
:math:`\varepsilon`-equilibria, for some positive :math:`\varepsilon`: a strategy profile at
which no player can gain more than :math:`\varepsilon` in expected payoff by unilaterally
deviating. Every Nash equilibrium is an :math:`\varepsilon`-equilibrium with
:math:`\varepsilon = 0`.

To provide a uniform interface across methods, where relevant Gambit provides a parameter
`maxregret`, which specifies the acceptance criterion for labeling the output of the
algorithm as an equilibrium. This parameter is interpreted *proportionally* to the range of
payoffs in the game: any profile returned as an equilibrium is guaranteed to be an
:math:`\varepsilon`-equilibrium, for :math:`\varepsilon` no more than `maxregret` times the
difference of the game's maximum and minimum payoffs. For example, with the default
`maxregret` of :math:`10^{-8}` in a game whose payoffs range over 4 units, any equilibrium
returned is guaranteed to have a regret, measured directly in the game's own payoffs, of no
more than :math:`4 \times 10^{-8}`.

Expressing `maxregret` scaled by the game's payoffs in this way standardises the behavior of
methods across games: for instance, doubling all the payoffs in a game does not change the
`maxregret` value needed to obtain equilibria of comparable quality.

Methods differ in the guarantees they offer once a `maxregret` criterion is specified.
Globally-convergent methods, such as :ref:`logit` and :ref:`gnm`, are guaranteed to eventually
satisfy any `maxregret` criterion, though a tighter criterion generally requires more
computation. Other methods, such as :ref:`liap`, are not globally convergent, and may fail to
find any equilibrium satisfying the criterion from a given starting point.

See the :doc:`stripped-down poker tutorial <tutorials/03_stripped_down_poker>` for a worked
example comparing `maxregret` across several methods.

.. _enumpure:

enumpure
Expand Down Expand Up @@ -234,3 +271,20 @@ The algorithm takes as a parameter a mixed strategy profile. This profile is
interpreted as defining a ray in the space of games. The profile must have
the property that, for each player, the most frequently played strategy must
be unique.

.. _hp:

hp
---
Computes the Nash equilibrium selected by the tracing procedure
of Harsanyi and Selten using a homotopy path-following method. The algorithm
was first described by Herings and Peeters :cite:p:`HerPee01`.

The algorithm takes as a parameter a mixed strategy profile, which acts as
the subjective prior beliefs of the players.
The profile must have the property that, for each player,
there must only exist one best response.

For generic games, the algorithm converges to the unique Nash equilibrium selected by
the tracing procedure of Harsanyi and Selten. For non-generic games, the algorithm may
converge to a Nash equilibrium that is not selected by the tracing procedure.
1 change: 1 addition & 0 deletions doc/gui.nash.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Method Parameters used by the graphical interface
``ipa`` One random perturbation.
``gnm`` One random perturbation; ending lambda ``-10``; 100 steps per support cell;
local Newton refinement every 3 steps, with at most 10 iterations.
``hp`` No method-specific parameters.
================ ============================================================================

For extensive games, there is an option of whether to use the
Expand Down
1 change: 1 addition & 0 deletions doc/pygambit.api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ Computation of Nash equilibria
simpdiv_solve
ipa_solve
gnm_solve
hp_solve


Computation of quantal response equilibria
Expand Down
10 changes: 10 additions & 0 deletions doc/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ @article{GovWil04
category = {articles_equilibria}
}

@article{HerPee01,
author = {Herings, P. J.-J. and Peeters, R. J. A. P.},
title = {A differentiable homotopy to compute {N}ash equilibria of n-person games},
journal = {Economic Theory},
volume = {18},
pages = {159--185},
year = {2001},
category = {articles_equilibria}
}

@article{HalPas21,
author = {Halpern, J. Y. and Pass, R.},
title = {Sequential equilibrium in games of imperfect recall},
Expand Down
81 changes: 81 additions & 0 deletions doc/tools.hp.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.. _gambit-hp:

:program:`gambit-hp`
=====================

Compute a Nash equilibrium in a strategic game using the homotopy method of
:cite:t:`HerPee01`.

The algorithm finds one equilibrium starting from any given prior
distribution over strategies, which must have a unique best response for
each player. Multiple prior distributions may be generated via the `-n`
option or specified via the `-s` option; different priors may result in
different equilibria being found.


.. program:: gambit-hp

.. cmdoption:: -d

Express all output using decimal representations
with the specified number of digits.

.. cmdoption:: -h

Prints a help message listing the available options.

.. cmdoption:: -m

Specify the maximum regret criterion for acceptance as an approximate Nash equilibrium
(default is 1e-8). See :ref:`pygambit-nash-maxregret` for interpretation and guidance.

.. cmdoption:: -n

Randomly generate the specified number of prior distributions.
Mutually exclusive with :option:`-s`.

.. cmdoption:: -R

Seeds the random number generator used to generate prior
distributions with the specified value, so that the sequence of priors
generated by :option:`-n` can be reproduced across runs. If not
specified, the generator is seeded from system entropy. Requires
:option:`-n`.

.. cmdoption:: -q

Suppresses printing of the banner at program launch.

.. cmdoption:: -s

Specifies a file containing a list of prior distributions over
strategies. The format of the file is comma-separated values,
one mixed strategy profile per line, in the same format used for
output of equilibria (excluding the initial NE tag).
Mutually exclusive with :option:`-n`.

.. cmdoption:: -V, --verbose

Show the prior distribution itself, tagged `prior`, followed by each
point traced along the homotopy path, tagged with the homotopy
parameter t in place of the NE tag. Note that the point at t=0 is the
best response to the prior, and so is generally a pure strategy profile
even when the prior itself is not. If this option is not specified,
only the equilibrium found is reported.

.. cmdoption:: -v, --version

Prints version information and exits.


Computing an equilibrium of the reduced strategic form of the example in
Figure 2 of :cite:p:`Sel75`, starting from the prior in which player 1
plays (0.5, 0.3, 0.2) and player 2 plays (0.6, 0.4)::

$ echo "0.5,0.3,0.2,0.6,0.4" > prior.csv
$ gambit-hp -s prior.csv catalog/journals/ijgt/selten1975/fig2.efg
Compute a Nash equilibrium using the Herings-Peeters (2001) homotopy method
Gambit version |release|, Copyright (C) 1994-2026, The Gambit Project
This is free software, distributed under the GNU GPL

NE,1.000000,0.000000,0.000000,0.999976,0.000024
1 change: 1 addition & 0 deletions doc/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ documentation.
tools.logit
tools.gnm
tools.ipa
tools.hp
24 changes: 1 addition & 23 deletions doc/tutorials/03_stripped_down_poker.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -675,29 +675,7 @@
"cell_type": "markdown",
"id": "b2867dca",
"metadata": {},
"source": [
"Acceptance criteria for Nash equilibria\n",
"---------------------------------------\n",
"\n",
"Some methods for computing Nash equilibria operate using floating-point arithmetic and/or generate candidate equilibrium profiles using methods which involve some form of successive approximations.\n",
"The outputs of these methods therefore are in general $\\varepsilon$-equilibria, for some positive $\\varepsilon$.\n",
"\n",
"$\\varepsilon$-equilibria (from [Wikipedia](https://en.wikipedia.org/wiki/Epsilon-equilibrium)):\n",
"\n",
"> In game theory, an epsilon-equilibrium, or near-Nash equilibrium, is a strategy profile that approximately satisfies the condition of Nash equilibrium. In a Nash equilibrium, no player has an incentive to change his behavior. In an approximate Nash equilibrium, this requirement is weakened to allow the possibility that a player may have a small incentive to do something different.\n",
"\n",
"> Given a game and a real non-negative parameter $\\varepsilon$, a strategy profile is said to be an $\\varepsilon$-equilibrium if it is not possible for any player to gain more than $\\varepsilon$ in expected payoff by unilaterally deviating from his strategy. Every Nash Equilibrium is an $\\varepsilon$-equilibrium where $\\varepsilon = 0$.\n",
"\n",
"\n",
"To provide a uniform interface across methods, where relevant Gambit provides a parameter\n",
"`maxregret`, which specifies the acceptance criterion for labeling the output of the\n",
"algorithm as an equilibrium.\n",
"This parameter is interpreted *proportionally* to the range of payoffs in the game.\n",
"Any profile returned as an equilibrium is guaranteed to be an $\\varepsilon$-equilibrium, for $\\varepsilon$ no more than `maxregret`\n",
"times the difference of the game's maximum and minimum payoffs.\n",
"\n",
"As an example, consider solving our one-card poker game using `logit_solve`. The range of the payoffs in this game is 4 (from +2 to -2):\n"
]
"source": "Acceptance criteria for Nash equilibria\n---------------------------------------\n\nSome methods for computing Nash equilibria operate using floating-point arithmetic and/or generate candidate equilibrium profiles using methods which involve some form of successive approximations, and so return only approximate equilibria.\nGambit expresses how close an approximation must be, before it is reported as an equilibrium, via a `maxregret` parameter, interpreted *proportionally* to the range of payoffs in the game.\nSee [Acceptance criteria for approximate Nash equilibria](../algorithms.html#pygambit-nash-maxregret) in the algorithms documentation for the full explanation of `maxregret` and the guarantees it provides.\n\nAs an example, consider solving our one-card poker game using `logit_solve`. The range of the payoffs in this game is 4 (from +2 to -2):\n"
},
{
"cell_type": "code",
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ gambit-simpdiv = "pygambit.cli.simpdiv:main"
gambit-gnm = "pygambit.cli.gnm:main"
gambit-ipa = "pygambit.cli.ipa:main"
gambit-enumpoly = "pygambit.cli.enumpoly:main"
gambit-hp = "pygambit.cli.hp:main"

[project.optional-dependencies]
test = ["pytest", "pytest-subtests", "nbformat", "nbclient", "ipykernel"]
Expand Down Expand Up @@ -124,6 +125,7 @@ markers = [
"nash_logit_behavior: tests of logit_solve in behavior strategies",
"nash_gnm_strategy: tests of gnm_solve in mixed strategies",
"nash_ipa_strategy: tests of lpa_solve in mixed strategies",
"nash_hp_strategy: tests of hp_solve in mixed strategies",
"nash_simpdiv: tests of simpdiv_solve (in mixed strategies)",
"nash_liap_strategy: tests of liap_solve (in mixed strategies)",
"nash_liap_agent: tests of liap_agent_solve (in mixed behaviors)",
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def run(self) -> None:
cppgambit_bimatrix = solver_library_config("cppgambit_bimatrix",
["linalg", "lp", "lcp", "enummixed"])
cppgambit_liap = solver_library_config("cppgambit_liap", ["liap"])
cppgambit_logit = solver_library_config("cppgambit_logit", ["logit"])
cppgambit_homotopy = solver_library_config("cppgambit_homotopy", ["path", "logit", "hp"])
cppgambit_gtracer = solver_library_config("cppgambit_gtracer", ["gtracer", "ipa", "gnm"])
cppgambit_simpdiv = solver_library_config("cppgambit_simpdiv", ["simpdiv"])
cppgambit_enumpoly = solver_library_config("cppgambit_enumpoly", ["nashsupport", "enumpoly"])
Expand All @@ -111,7 +111,7 @@ def run(self) -> None:

setuptools.setup(
cmdclass={"build_py": GambitBuildPy},
libraries=[cppgambit_bimatrix, cppgambit_liap, cppgambit_logit, cppgambit_simpdiv,
libraries=[cppgambit_bimatrix, cppgambit_liap, cppgambit_homotopy, cppgambit_simpdiv,
cppgambit_gtracer, cppgambit_enumpoly,
cppgambit_games, cppgambit_core],
ext_modules=Cython.Build.cythonize(libgambit,
Expand Down
8 changes: 4 additions & 4 deletions src/gui/dllogit.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ struct BehavLogitTraits {
const CancelToken &p_cancel)
{
const QREType start(p_game);
LogitBehaviorSolve(start, 1.0e-8, 1.0, 0.03, 1.1, Nash::NullBehaviorCallback<double>,
p_onEvent, p_cancel);
LogitBehaviorSolve(start, 1.0e-8, PathTracer::TraceDirection::Positive, 0.03, 1.1,
Nash::NullBehaviorCallback<double>, p_onEvent, p_cancel);
}
};

Expand Down Expand Up @@ -123,8 +123,8 @@ struct MixedLogitTraits {
const CancelToken &p_cancel)
{
const QREType start(p_game);
LogitStrategySolve(start, 1.0e-8, 1.0, 0.03, 1.1, Nash::NullStrategyCallback<double>,
p_onEvent, p_cancel);
LogitStrategySolve(start, 1.0e-8, PathTracer::TraceDirection::Positive, 0.03, 1.1,
Nash::NullStrategyCallback<double>, p_onEvent, p_cancel);
}
};

Expand Down
Loading
Loading