Skip to content

Commit

Permalink
Standardization of QRE computation interface:
Browse files Browse the repository at this point in the history
* Simplify and rationalize naming of various functions to work with QRE correspondence
* Move functions other than logit_solve into the qre module.
* Added an appropriate section to the user guide summarizing QRE facilities.
  • Loading branch information
tturocy committed Jun 12, 2024
1 parent 1c38cb6 commit 86a14c9
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 938 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- Maximum-likelihood estimation for logit QRE using empirical payoffs has an improved internal
calculation of log-likelihood, and returns the estimated profile instead of just a list of
probabilities.
- Reorganized naming conventions in pygambit for functions for computing QRE in both strategic
and agent versions, and added a corresponding section in the user guide.


## [16.1.2] - unreleased
Expand Down
2 changes: 1 addition & 1 deletion doc/formats.bagg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ separated by whitespaces. Lines with starting '#' are treated as comments and ar

#. utility function for each action node: same as in `the AGG format`_.

.. _the AGG format: file-formats-agg_
.. _the AGG format: _file-formats-agg
2 changes: 1 addition & 1 deletion doc/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Downloading Gambit
==================

Gambit source code and built binaries can be downloaded from the project
`GitHub repository releases section`<https://github.com/gambitproject/gambit/releases>.
`GitHub repository releases section <https://github.com/gambitproject/gambit/releases>`_.

Older versions of Gambit can be downloaded from
`http://sourceforge.net/projects/gambit/files
Expand Down
8 changes: 3 additions & 5 deletions doc/pygambit.api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,8 @@ Computation of quantal response equilibria
.. autosummary::
:toctree: api/

fit_strategy_empirical
fit_strategy_fixedpoint
logit_solve_branch
logit_solve_lambda
logit_estimate
LogitQREMixedStrategyFitResult

fit_behavior_empirical
fit_behavior_fixedpoint
LogitQREMixedBehaviorFitResult
67 changes: 57 additions & 10 deletions doc/pygambit.user.rst
Original file line number Diff line number Diff line change
Expand Up @@ -686,14 +686,13 @@ from different starting points.
gbt.nash.simpdiv_solve(g.random_strategy_profile(denom=10, gen=gen))
Estimating quantal response equilibria
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Quantal response equilibrium
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Alongside computing quantal response equilibria, Gambit can also perform maximum likelihood
estimation, computing the QRE which best fits an empirical distribution of play.

As an example we consider an asymmetric matching pennies game studied in [Och95]_,
analysed in [McKPal95]_ using QRE.
Gambit implements the idea of [McKPal95]_ and [McKPal98]_ to compute Nash equilibria
via path-following a branch of the logit quantal response equilibrium (LQRE) correspondence
using the function :py:func:`.logit_solve`. As an example, we will consider an
asymmetric matching pennies game from [Och95]_ as analyzed in [McKPal95]_.

.. ipython:: python
Expand All @@ -702,13 +701,52 @@ analysed in [McKPal95]_ using QRE.
[[0, 1.1141], [1.1141, 0]],
title="Ochs (1995) asymmetric matching pennies as transformed in McKelvey-Palfrey (1995)"
)
data = g.mixed_strategy_profile([[128*0.527, 128*(1-0.527)], [128*0.366, 128*(1-0.366)]])
gbt.nash.logit_solve(g)
:py:func:`.logit_solve` returns only the limiting (approximate) Nash equilibrium found.
Profiles along the QRE correspondence are frequently of interest in their own right.
Gambit offers several functions for more detailed examination of branches of the
QRE correspondence.

The function :py:func:`.logit_solve_branch` uses the same procedure as :py:func:`.logit_solve`,
but returns a list of LQRE profiles computed along the branch instead of just the limiting
approximate Nash equilibrium.

.. ipython:: python
qres = gbt.qre.logit_solve_branch(g)
len(qres)
qres[0]
qres[5]
Estimation of QRE in the strategic form is done using :py:func:`.fit_strategy_fixedpoint`.
:py:func:`.logit_solve_branch` uses an adaptive step size heuristic to find points on
the branch. The parameters `first_step` and `max_accel` are used to adjust the initial
step size and the maximum rate at which the step size changes adaptively. The step size
used is computed as the distance traveled along the path, and, importantly, not the
distance as measured by changes in the precision parameter lambda. As a result the
lambda values for which profiles are computed cannot be controlled in advance.
In some situations, the LQRE profiles at specified values of lambda are of interest.
For this, Gambit provides :py:func:`.logit_solve_lambda`. This function provides
accurate values of strategy profiles at one or more specified values of lambda.

.. ipython:: python
fit = gbt.qre.fit_strategy_fixedpoint(data)
qres = gbt.qre.logit_solve_lambda(g, lam=[1, 2, 3])
qres[0]
qres[1]
qres[2]
LQRE are frequently taken to data by using maximum likelihood estimation to find the
LQRE profile that best fits an observed profile of play. This is provided by
the function :py:func:`.logit_estimate`. We replicate the analysis of a block
of the data from [Och95]_ for which [McKPal95]_ estimated an LQRE.

.. ipython:: python
data = g.mixed_strategy_profile([[128*0.527, 128*(1-0.527)], [128*0.366, 128*(1-0.366)]])
fit = gbt.qre.logit_estimate(data)
The returned :py:class:`.LogitQREMixedStrategyFitResult` object contains the results of the
estimation.
Expand All @@ -723,6 +761,15 @@ log-likelihood is correct for use in likelihoood-ratio tests. [#f1]_
print(fit.profile)
print(fit.log_like)
All of the functions above also support working with the agent LQRE of [McKPal98]_.
Agent QRE are computed as the default behavior whenever the game has a extensive (tree)
representation. For :py:func:`.logit_solve`, :py:func:`.logit_solve_branch`, and
:py:func:`.logit_solve_lambda`, this can be overriden by passing `use_strategic=True`;
this will compute LQRE using the reduced strategy set of the game instead.
Likewise, :py:func:`.logit_estimate` will perform estimation using agent LQRE if the
data passed are a :py:class:`.MixedBehaviorProfile`, and will return a
:py:class:`.LogitQREMixedBehaviorFitResult` object.

.. rubric:: Footnotes

.. [#f1] The log-likelihoods quoted in [McKPal95]_ are exactly a factor of 10 larger than
Expand Down
28 changes: 0 additions & 28 deletions src/pygambit/nash.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,31 +585,3 @@ def logit_solve(
equilibria=equilibria,
parameters={"first_step": first_step, "max_accel": max_accel},
)


def logit_solve_branch(
game: libgbt.Game,
use_strategic: bool = False,
maxregret: float = 1.0e-8,
first_step: float = .03,
max_accel: float = 1.1,
):
if maxregret <= 0.0:
raise ValueError("logit_solve(): maxregret argument must be positive")
if not game.is_tree or use_strategic:
return libgbt._logit_strategy_branch(game, maxregret, first_step, max_accel)
else:
return libgbt._logit_behavior_branch(game, maxregret, first_step, max_accel)


def logit_solve_lambda(
game: libgbt.Game,
lam: typing.Union[float, typing.List[float]],
use_strategic: bool = False,
first_step: float = .03,
max_accel: float = 1.1,
):
if not game.is_tree or use_strategic:
return libgbt._logit_strategy_lambda(game, lam, first_step, max_accel)
else:
return libgbt._logit_behavior_lambda(game, lam, first_step, max_accel)
Loading

0 comments on commit 86a14c9

Please sign in to comment.