From e4f7e0b7b2fb4bf8f5de180ac73132c331e4ad5d Mon Sep 17 00:00:00 2001 From: Vince Knight Date: Sat, 17 Jun 2017 19:53:34 +0100 Subject: [PATCH] Write reference documentation. --- docs/how-to/calculate-utilities.rst | 7 -- docs/how-to/create-a-game.rst | 8 -- .../find-equilibria-for-large-games.rst | 8 -- docs/how-to/index.rst | 8 -- docs/how-to/install-nashpy.rst | 7 -- .../how-to/solve-with-support-enumeration.rst | 7 -- docs/how-to/solve-with-vertex-enumeration.rst | 7 -- docs/reference/bibliography.rst | 11 ++ docs/reference/index.rst | 8 +- docs/reference/source/nash.rst | 2 +- docs/reference/support-enumeration.rst | 49 +++++++-- docs/reference/vertex-enumeration.rst | 100 ++++++++++++++++-- docs/tutorial/index.rst | 8 -- src/nash/algorithms/support_enumeration.py | 3 +- src/nash/algorithms/vertex_enumeration.py | 3 +- 15 files changed, 152 insertions(+), 84 deletions(-) create mode 100644 docs/reference/bibliography.rst diff --git a/docs/how-to/calculate-utilities.rst b/docs/how-to/calculate-utilities.rst index 312320e4..e09cd2be 100644 --- a/docs/how-to/calculate-utilities.rst +++ b/docs/how-to/calculate-utilities.rst @@ -25,10 +25,3 @@ strategies:: >>> sigma_c = np.array([1 / 2, 1 / 2]) >>> prisoners_dilemma[sigma_r, sigma_c] array([ 2.25, 2.25]) - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/create-a-game.rst b/docs/how-to/create-a-game.rst index 1341efca..2649f86a 100644 --- a/docs/how-to/create-a-game.rst +++ b/docs/how-to/create-a-game.rst @@ -38,11 +38,3 @@ dilemma `_:: Column player: [[3 5] [0 1]] - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/find-equilibria-for-large-games.rst b/docs/how-to/find-equilibria-for-large-games.rst index 9d1ffd2b..ec1563c2 100644 --- a/docs/how-to/find-equilibria-for-large-games.rst +++ b/docs/how-to/find-equilibria-for-large-games.rst @@ -24,11 +24,3 @@ Let us get the first equilibria found by :code:`Nashpy` when using (array([ 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.]), array([ 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.])) - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/index.rst b/docs/how-to/index.rst index 7ddf269d..07e82850 100644 --- a/docs/how-to/index.rst +++ b/docs/how-to/index.rst @@ -12,11 +12,3 @@ How to: solve-with-support-enumeration.rst solve-with-vertex-enumeration.rst find-equilibria-for-large-games.rst - - -Indices and tables -++++++++++++++++++ - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/install-nashpy.rst b/docs/how-to/install-nashpy.rst index aa0b1c15..f2341321 100644 --- a/docs/how-to/install-nashpy.rst +++ b/docs/how-to/install-nashpy.rst @@ -11,10 +11,3 @@ To install a development version from source:: $ git clone https://github.com/drvinceknight/Nashpy.git $ cd nashpy $ python setup.py develop - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/solve-with-support-enumeration.rst b/docs/how-to/solve-with-support-enumeration.rst index 7e906768..40ac0d62 100644 --- a/docs/how-to/solve-with-support-enumeration.rst +++ b/docs/how-to/solve-with-support-enumeration.rst @@ -17,10 +17,3 @@ equilibria:: >>> for eq in equilibria: ... print(eq) (array([ 0.5, 0.5]), array([ 0.5, 0.5])) - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/how-to/solve-with-vertex-enumeration.rst b/docs/how-to/solve-with-vertex-enumeration.rst index f4bafe4a..96f69fa5 100644 --- a/docs/how-to/solve-with-vertex-enumeration.rst +++ b/docs/how-to/solve-with-vertex-enumeration.rst @@ -16,10 +16,3 @@ equilibria:: >>> for eq in equilibria: ... print(eq) (array([ 0.5, 0.5]), array([ 0.5, 0.5])) - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/reference/bibliography.rst b/docs/reference/bibliography.rst new file mode 100644 index 00000000..3d7dc195 --- /dev/null +++ b/docs/reference/bibliography.rst @@ -0,0 +1,11 @@ +.. _bibliography: + +Bibliography +============ + +This is a collection of various bibliographic items referenced in the +documentation. + +.. [Nisan2007] Nisan, Noam, et al., eds. Algorithmic game theory. Vol. 1. Cambridge: Cambridge University Press, 2007. +.. [Ziegler2012] Ziegler, Günter M. Lectures on polytopes. Vol. 152. Springer Science & Business Media, 2012. APA + diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 78e3c190..a1ea1fd7 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -6,11 +6,5 @@ Reference support-enumeration.rst vertex-enumeration.rst + bibliography.rst source/nash.rst - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/reference/source/nash.rst b/docs/reference/source/nash.rst index 08ff7fba..162e76a6 100644 --- a/docs/reference/source/nash.rst +++ b/docs/reference/source/nash.rst @@ -1,4 +1,4 @@ -nash package +Source files ============ Subpackages diff --git a/docs/reference/support-enumeration.rst b/docs/reference/support-enumeration.rst index a1615f72..5dcfa9ce 100644 --- a/docs/reference/support-enumeration.rst +++ b/docs/reference/support-enumeration.rst @@ -3,11 +3,48 @@ Support enumeration =================== -Background material on support enumeration. +The support enumeration algorithm implemented in :code:`Nashpy` is based on the +one described in [Nisan2007]_. -Indices and tables ------------------- +The algorithm is as follows: -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +For a nondegenerate 2 player game :math:`(A, B)\in{\mathbb{R}^{m\times n}}^2` +the following algorithm returns all nash equilibria: + +1. For all :math:`1\leq k\leq \min(m, n)`; +2. For all pairs of support :math:`(I, J)` with :math:`|I|=|J|=k` +3. Solve the following equations (this ensures we have best responses): + + .. math:: + + \sum_{i\in I}{\sigma_{r}}_iB_{ij}=v\text{ for all }j\in J + + \sum_{j\in J}A_{ij}{\sigma_{c}}_j=u\text{ for all }i\in I + +4. Solve + + - :math:`\sum_{i=1}^{m}{\sigma_{r}}_i=1` and :math:`{\sigma_{r}}_i\geq 0` + for all :math:`i` + - :math:`\sum_{j=1}^{n}{\sigma_{c}}_i=1` and :math:`{\sigma_{c}}_j\geq 0` + for all :math:`j` + +5. Check the best response condition. + +Repeat steps 3,4 and 5 for all potential support pairs. + +Discussion +---------- + +1. Step 1 is a complete enumeration of all possible strategies that the + equilibria could be. +2. Step 2 is based on the definition of a non degenerate game which ensures that + equilibria will be on supports of the same size. +3. Step 3 are the linear equations that are to be solved, for a given pair of + supports these ensure that neither player has an incentive to move to another + strategy on that support. +4. Step 4 is to ensure we have mixed strategies. +5. Step 5 is a final check that there is no better utility outside of the + supports. + +In :code:`Nashpy` this is all implemented algebraically using :code:`Numpy` to +solve the linear equations. diff --git a/docs/reference/vertex-enumeration.rst b/docs/reference/vertex-enumeration.rst index 2cbd0386..b4316011 100644 --- a/docs/reference/vertex-enumeration.rst +++ b/docs/reference/vertex-enumeration.rst @@ -3,11 +3,99 @@ Vertex enumeration ================== -Background material on vertex enumeration. +The vertex enumeration algorithm implemented in :code:`Nashpy` is based on the +one described in [Nisan2007]_. -Indices and tables ------------------- +The algorithm is as follows: -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +For a nondegenerate 2 player game :math:`(A, B)\in{\mathbb{R}^{m\times n}}^2` +the following algorithm returns all nash equilibria: + +1. Obtain the best response Polytopes :math:`P` and :math:`Q`. +2. For all pairs of vertices of :math:`P` and :math:`Q`. +3. Check if the pair is fully labeled and return the normalised probability + vectors. + +Repeat steps 2 and 3 for all pairs of vertices. + +Discussion +========== + +1. Before creating the best response Polytope we need to consider the best + response Polyhedron. For the row player, this corresponds to the set of all + the mixed strategies available to the row player as well as an upper bound on + the utilities to the column player. Analogously for the column player: + + .. math:: + + \bar P = \{(x, v) \in \mathbb{R}^m \times \mathbb{R}\;|\; x\geq 0, + \mathbb{1}x=1, + B^Tx\leq\mathbb{1}v\} + + \bar Q = \{(y, u) \in \mathbb{R}^n \times \mathbb{R}\;|\; y\geq 0, + \mathbb{1}y=1, + Ay\leq\mathbb{1}u\} + + + Note that in both definitions above we have a total of :math:`m + n` + inequalities in the constraints. + + For :math:`P`, the first :math:`m` of those + constraints correspond to the elements of :math:`x` being greater or equal to + 0. For a given :math:`x`, if :math:`x_i=0`, we say that :math:`x` has label + :math`i`. This corresponds to strategy :math:`i` not being in the support of + :math:`x`. + + For the last :math:`n` of these inequalities, when they are equalities they + correspond to whether or not strategy :math:`1\leq j \leq n` of the other + player is a best response to :math:`x`. Similarly, if strategy :math:`j` is a + best response to :math:`x` then we say that :math:`x` has label :math:`m + + j`. + + This all holds analogously for the column player. If the labels of a pair of + elements of :math:`\bar P` and :math:`\bar Q` give the full set of integers + from :math:`1` to :math:`m + n` then they represent strategies that are best + responses to each other. Since, this would imply that either a pure stragey + is not played or it is a best response to the other players strategy. + + The difficulty with using the best response Polyhedron is that the upper + bound on the utilities of both players (:math:`u, v`) is not known. + Importantly, we do not need to know it. Thus, we assume that in both cases: + :math:`u=v=1` (this simply corresponds to a scaling of our strategy vectors). + + This allows us to define the best response Polytopes: + + .. math:: + + P = \{(x, v) \in \mathbb{R}^m \times \mathbb{R}\;|\; x\geq 0, + B^Tx\leq 1\} + + Q = \{(y, u) \in \mathbb{R}^n \times \mathbb{R}\;|\; y\geq 0, + Ay\leq 1\} + + +2. Step 2: The vertices of these polytopes are the points that will have labels + (they are the points that lie at the intersection of the underlying + halfspaces [Ziegler2012]_). + + To find these vertices, :code:`nashpy` uses :code:`scipy` which has a handy + class for creating Polytopes using the inequality definitions and being able + to return the vertices. Here is the wrapper written in :code:`nashpy` that is + used by the vertex enumeration algorithm to give the vertices and + corresponding labels:: + + >>> import nash + >>> import numpy as np + >>> A = np.array([[3, 1], [1, 3]]) + >>> halfspaces = nash.polytope.build_halfspaces(A) + >>> vertices = nash.polytope.non_trivial_vertices(halfspaces) + >>> for vertex in vertices: + ... print(vertex) + (array([ 0.333..., 0...]), {0, 3}) + (array([ 0..., 0.333...]), {1, 2}) + (array([ 0.25, 0.25]), {0, 1}) + +3. Step 3, we iterate over all pairs of the vertices of both polytopes and pick + out the ones that are fully labeled. Because of the scaling that took place + to create the Polytope from the Polyhedron, we will need to return a + normalisation of both vertices. diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst index 5bcf575e..3e77743b 100644 --- a/docs/tutorial/index.rst +++ b/docs/tutorial/index.rst @@ -186,11 +186,3 @@ players do not have an incentive to deviate. We can find these using *Nash* equilibria is an important concept as it allows to gain an initial understanding of emergent behaviour in complex systems. - - -Indices and tables -++++++++++++++++++ - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/src/nash/algorithms/support_enumeration.py b/src/nash/algorithms/support_enumeration.py index 19b83909..c50f3bac 100644 --- a/src/nash/algorithms/support_enumeration.py +++ b/src/nash/algorithms/support_enumeration.py @@ -146,8 +146,7 @@ def support_enumeration(A, B): """ Obtain the Nash equilibria using support enumeration. - Algorithm implemented here is Algorithm 3.4 of Nisan, Noam, et al., eds. - Algorithmic game theory. Cambridge University Press, 2007. + Algorithm implemented here is Algorithm 3.4 of [Nisan2007]_ 1. For each k in 1...min(size of strategy sets) 2. For each I,J supports of size k diff --git a/src/nash/algorithms/vertex_enumeration.py b/src/nash/algorithms/vertex_enumeration.py index a9b6eaff..71a177bc 100644 --- a/src/nash/algorithms/vertex_enumeration.py +++ b/src/nash/algorithms/vertex_enumeration.py @@ -9,8 +9,7 @@ def vertex_enumeration(A, B): Obtain the Nash equilibria using enumeration of the vertices of the best response polytopes. - Algorithm implemented here is Algorithm 3.5 of Nisan, Noam, et al., eds. - Algorithmic game theory. Cambridge University Press, 2007. + Algorithm implemented here is Algorithm 3.5 of [Nisan2007]_ 1. Build best responses polytopes of both players 2. For each vertex pair of both polytopes