GithubHelp home page GithubHelp logo

drvinceknight / nashpy Goto Github PK

View Code? Open in Web Editor NEW
319.0 10.0 69.0 3.44 MB

A python library for 2 player games.

Home Page: http://nashpy.readthedocs.io

License: MIT License

Python 99.37% TeX 0.63%
mathematics computer-science python game nash equilibria algorithm

nashpy's Introduction

DOI Discord Gitter DOI

Nashpy: a python library for 2 player games.

Nashpy is:

Documentation

Full documentation is available here: http://nashpy.readthedocs.io/

Installation

$ python -m pip install nashpy

To install Nashpy on Fedora, use:

$ dnf install python3-nashpy

Usage

Create bi matrix games by passing two 2 dimensional arrays/lists:

>>> import nashpy as nash
>>> A = [[1, 2], [3, 0]]
>>> B = [[0, 2], [3, 1]]
>>> game = nash.Game(A, B)
>>> for eq in game.support_enumeration():
...     print(eq)
(array([1., 0.]), array([0., 1.]))
(array([0., 1.]), array([1., 0.]))
(array([0.5, 0.5]), array([0.5, 0.5]))
>>> game[[0, 1], [1, 0]]
array([3, 3])

Other game theoretic software

  • Gambit is a library with a python api and support for more algorithms and more than 2 player games.
  • Game theory explorer a web interface to gambit useful for teaching.
  • Axelrod a research library aimed at the study of the Iterated Prisoners dilemma

Development

Clone the repository and create a virtual environment:

$ git clone https://github.com/drvinceknight/nashpy.git
$ cd nashpy
$ python -m venv env

Activate the virtual environment and install tox:

$ source env/bin/activate
$ python -m pip install tox

Make modifications.

To run the tests:

$ python -m tox

To build the documentation. First install the software which also installs the documentation build requirements.

$ python -m pip install flit
$ python -m flit install --symlink

Then:

$ cd docs
$ make html

Full contribution documentation is available at https://nashpy.readthedocs.io/en/latest/contributing/index.html

Pull requests are welcome.

Code of conduct

In the interest of fostering an open and welcoming environment, all contributors, maintainers and users are expected to abide by the Python code of conduct: https://www.python.org/psf/codeofconduct/

nashpy's People

Contributors

alex-konovalov avatar arwheel avatar asinghgaba avatar drvinceknight avatar emielsteegh avatar fil avatar firefly-cpp avatar katiemcgoldrick avatar l30bigdick avatar michalispanayides avatar newaijj avatar nikoleta-v3 avatar riabaldevia avatar robert-szeto avatar sandeepvshenoy avatar theref avatar tokheim avatar volume-on-max avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nashpy's Issues

One policy is [-inf, nan, nan, inf] when using vertex_enumeration

I just come across a matrix that come across inf and nan result when solving
The game matrix is:
[[ -4.74849287 -1.41955836 -1.41955836 -2.46551608]
[-100. -0.80877032 -0.80877032 -1.42923881]
[ -3.99960399 -1.41955836 -1.41955836 -1.42923881]
[ -2.46551608 -0.80877032 -0.80877032 -2.46551608]]
and this can not be solved using support_enumeration, and using vertex_enumeration, it will return
one solution that policy is [-inf, nan, nan, inf] and the reward is nan, could you tell me why?

lemke_howson not working properly...

I have:
3 x 3 Payoff matrix A:
-1 -1 -1
0 0 0
-1 -1 -10000

3 x 3 Payoff matrix B:
-1 -1 -1
0 0 0
-1 -1 -10000

The output is:

eqs = test.lemke_howson(initial_dropped_label=0)
list(eqs)
[array([0, 0]), array([ 0.33445946, 0.33445946, 0.33445946, -0.00337838])]

Feature request: Nash equilibrium with maximal entropy

Nash equilibria are not unique. Currently, the package returns a list of equilibria to handle this problem. However, this becomes troublesome when the game is degenerate.

It would be better if the package provides an option to return the one with maximal entropy, which is unique and has a better interpretability.

PS. Thanks for this easy-to-use package!

Refactor all tests

Refactor all tests to make use of fact that pytest is the runner.๏ปฟ

review for JOSS

Looks good to me. A few details:

  • Version: Does the release version given match the GitHub release (v0.0.14)?
    No: I see nashpy-0.0.17

  • References: Do all archival references that should have a DOI list one (e.g., papers, datasets, software)?
    Only one reference in paper.bib has a DOI.

  • Suggestions: I wonder if you could give more real-world usage examples and algorithms limitations. In particular, I tried with a few large random matrices 0 sum games and the game.support_enumeration() computation takes forever.

PS: testing at https://colab.research.google.com/drive/1UGrlXawmReLX4-y_vQqQeXhFEttfOWW9

(See openjournals/joss-reviews#904)

Lexicographic minimum ratio test?

Is the lexicographic minimum ratio test (mentioned here) already being used by this implementation of Lemke-Howson? Would using it make it possible to use Lemke-Howson on degenerate games? (I ask mainly because LH seems to be much faster that the other solvers, but doesn't work on degenerate games that I'm encountering in the wild).

I looked into the code a bit, and the answer to "Is it being used?" seemed to be no, but I don't really understand the test or the code well enough to be sure.

Refactor lemke_howson

After #71 there is now a lexicographic Lemke Howson implementation. It's currently implemented separately in lemke_howson_lex.py.

We should refactor lemke_howson.py so that the algorithm takes an argument which is the pivoting function to use so that this line https://github.com/drvinceknight/Nashpy/blob/master/src/nashpy/algorithms/lemke_howson.py#L64 would become:

lemke_howson(A, B, initial_dropped_label=0, pivoting_function=lexicographic_integer_pivot)

where lexicographic_integer_pivot would be a function defined in integer_pivoting/integer_pivoting.py where basic_integer_pivot would also be.

This would then lead to:

  • Removing the *_lex.py files (lexicographic would be the default).
  • Refactoring the tests (according to #74) to also verify explicitly that the degenerate cases are taken care of by the lexicographic pivot and that for non degenerate cases we get no differences.
  • Refactoring the documentation to include background information on lexicographic pivoting.

Potential overflow issue

I tried the lemke_howson algorithm on a 1203x1203 payoff matrix, with each cell within [-5, 5]. The returned probabilities are arrays of nan, and there is warning about overflow:

/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:50: RuntimeWarning: overflow encountered in multiply
  tableau[i, :] * pivot_element -
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:51: RuntimeWarning: overflow encountered in multiply
  tableau[pivot_row_index, :] * tableau[i, column_index])
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:51: RuntimeWarning: invalid value encountered in subtract
  tableau[pivot_row_index, :] * tableau[i, column_index])
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:51: RuntimeWarning: overflow encountered in subtract
  tableau[pivot_row_index, :] * tableau[i, column_index])
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:27: RuntimeWarning: invalid value encountered in true_divide
  return np.argmax(tableau[:, column_index] / tableau[:, -1])
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:50: RuntimeWarning: invalid value encountered in multiply
  tableau[i, :] * pivot_element -
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/integer_pivoting/integer_pivoting.py:51: RuntimeWarning: invalid value encountered in multiply
  tableau[pivot_row_index, :] * tableau[i, column_index])
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/algorithms/lemke_howson.py:50: RuntimeWarning: invalid value encountered in double_scalars
  vertex.append(tableau[i, -1] / row)
/home/zheng/anaconda3/lib/python3.7/site-packages/nashpy/algorithms/lemke_howson.py:113: RuntimeWarning: The Lemke Howson algorithm has returned probability vectors of 
incorrect shapes. This indicates an error. Your game could be degenerate.
  warnings.warn(msg, RuntimeWarning)

support_enumeration() not returning equilibrium

The code below returns no equilibria using the support enumeration method.

import numpy as np
import nashpy as nash

A = np.matrix([[ 0, -1,  1,  1],
               [ 1,  0, -1, -1],
               [-1,  1,  0, -1],
               [-1,  1,  1,  0]])

game = nash.Game(A)

print(len(list(game.support_enumeration()))) # Returns 0

An even number of equilibria was returned, which indicates the game is degenerate

Hello, I have been using Nashpy and have come across the warning that says: "An even number of equilibria was returned, which indicates the game is degenerate. Consider using another algorithm to investigate." Why is it that an even number of equilibria means the game is degenerate? Wouldn't anything other than 1 equilibria be degenerate? Also, what are the policies to follow in these cases? If there are 0 equilibria returned, then I would just set the mixed strategy to be equal across all choices. If there are multiple equilibria, then I can think of multiple options... You could choose one at random. If you do this, however, you would have to do so separately for each agent, since they can't know each other's moves. Or, you could pick the one that gives the greatest total utility, or is there some way of "averaging" all the equilibria? As far as I know, degenerate games can't be truly "solved," I am just wondering if there is any policy to follow that is valid or best. Thank you!

Issue with Lemke_howson_enumeration

Dear Vincent,

First of all, thank you for making this python package available. I explain the three approaches that you implemented in my course and would like to let the students play with the package.

Now the Lemke Howson implementation appears to suffer from a problem as it is unable to find one of the equilibria in the following game. I added the entire python code at the end to give all the details.

This game has 3 equilibria, which are found by the other two approaches.
(array([1., 0., 0.]), array([1., 0.]))
(array([0.8, 0.2, 0. ]), array([0.66666667, 0.33333333]))
(array([0. , 0.33333333, 0.66666667]), array([0.33333333, 0.66666667]))

the one in the middle is not found.

Any ideas what is happening here?
Thanks for the assistance.
Best

Tom

Type "help", "copyright", "credits" or "license" for more information.

import nashpy as nash
import numpy as np
A=np.array([[3,3],[2,5],[0,6]])
B=np.array([[3,2],[2,6],[3,1]])
mygame=nash.Game(A,B)
mygame
Bi matrix game with payoff matrices:

Row player:
[[3 3]
[2 5]
[0 6]]

Column player:
[[3 2]
[2 6]
[3 1]]

equilibria=mygame.lemke_howson_enumeration()
for eq in equilibria:
... print(eq)
...
(array([1., 0., 0.]), array([1., 0.]))
(array([0. , 0.33333333, 0.66666667]), array([0.33333333, 0.66666667]))
(array([1., 0., 0.]), array([1., 0.]))
(array([1., 0., 0.]), array([1., 0.]))
(array([0. , 0.33333333, 0.66666667]), array([0.33333333, 0.66666667]))

Lemke-Howson fails to find any equilibrium on nondegenerate game

The following test results in an exception:

def test_that_fails(self):
        A = np.array([[ 9.5, -7.8 ], [ -9.6, 0.3 ], [ -7.1, -1.4 ], [ 5.9, 7.6 ], [ 9, 0.3 ], [ 7.5, 6.9 ], [ -3.1, 3.6 ], [ -8.4, -3.7 ]])
        B = np.array([[ 0.2, 0.6 ], [ 0.4, 0.1 ], [ 0.9, 0 ], [ 0.4, 0.1 ], [ 0.1, 0.2 ], [ 0.2, 0.1 ], [ 0.8, 1 ], [ 0.2, 0.4 ]])
        print("A")
        print(A)
        print("B")
        print(B)
        for eq in lemke_howson(A, B, 9):
            print(eq)

Note that if I use support enumeration or the lexicographic Lemke-Howson (or drop any other label initially), the algorithm works and produces a unique equilibrium in which both the row and column player have mixed strategies with support of 2. If that is correct, the game is nondegenerate, so it is my understanding that Lemke-Howson should produce an equilibrium.

Thank you very much for this very useful resource and also for your excellent videos.

Prune the dominated supports

Currently, the linear equation corresponding to indifference on a given support is calculated for all supports.

This could be made slightly more efficient by "pruning" these supports: so only solve the indifference condition if the support is not 'obviously' dominated by strategies outside of the support.

Missing Nash Equilibria in support_enumeration?!

I stumbled upon this game:

A = np.array([[0, 0, 6, 0, 0], [0, 0, 3, 2, 1], [4, 3, 0, 0, 1]])
B = np.array([[3, 0, 2, 1, 0], [0, 2, 0, 0, 4], [4, 0, 2, 4, 4]])

which is supposed to have 8 Nash equilibria (players are minimizers):

y: [ 1 0 0 ]        J1: 0       z: [ 0  1   0   0   0 ]        J2: 0
y: [ 1 0 0 ]        J1: 0       z: [ 0  0   0   0   1 ]        J2: 0
y: [ 2/3 1/3 0 ]    J1: 0       z: [ 0  1   0   0   0 ]        J2: 2/3
y: [ 1/3 1/2 1/6 ]  J1: 4/3     z: [ 0  4/9 2/9 1/3 0 ]        J2: 1
y: [ 0 1/2 1/2 ]    J1: 3/2     z: [ 0  1/2 1/2 0   0 ]        J2: 1
y: [ 0 1 0 ]        J1: 12/7    z: [3/7 0   4/7 0   0 ]        J2: 0
y: [ 0 1 0 ]        J1: 0       z: [1   0   0   0   0 ]        J2: 0
y: [ 0 1 0 ]        J1: 3/2     z: [3/8 0   1/4 3/8 0 ]        J2: 0

these equilibria are consistent with a support enumeration algorithm I wrote in matlab and with some online solver like this.

While vertex_enumeration returns the correct equilibria, support_enumeration(-A,-B) only 5 of them, invariant to different values of tol.
Do you know why?

Thanks for your work,
Best

review 2 for JOSS

Hello @drvinceknight, here there are some minor comments regarding openjournals/joss-reviews#904. Overall, it looks good!

  1. The DOI at

    doi={https://doi.org/10.1057},

    can not be resolved

  2. In all places, DOI is given as a URL, except here:

    doi = {10.5281/zenodo.1163694},

    To be consistent, I suggest to stick to the same style.

  3. I've corrected two typos at #50

  4. Just in case, do not forget in case you may have to mention any funding in acknowledgements.

Does not find equilibrium although equilibria exist

Hi,

I am not sure why or in what kinds of cases this issue arises, but I seem to be getting it with the following payoff matrix.

1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 
0.0 1.0 0.0 0.6666666666666666 0.0 0.6666666666666666 0.0 0.5 
0.0 0.0 1.0 0.6666666666666666 0.0 0.0 0.6666666666666666 0.5 
0.0 0.6666666666666666 0.6666666666666666 1.0 0.0 0.5 0.5 0.8 
0.0 0.0 0.0 0.0 1.0 0.6666666666666666 0.6666666666666666 0.5 
0.0 0.6666666666666666 0.0 0.5 0.6666666666666666 1.0 0.5 0.8 
0.0 0.0 0.6666666666666666 0.5 0.6666666666666666 0.5 1.0 0.8 
0.0 0.5 0.5 0.8 0.5 0.8 0.8 1.0

Sorry the matrix isn't well formatted, but it is the F1 scores of binary representation of row and column indexes. The following code snippet will hopefully reproduce the error.

input:

import nashpy
import numpy as np
from sklearn.metrics import f1_score
bits = 3
matrix_size = 2**bits
a = np.zeros((matrix_size,matrix_size))
p1_actions = np.array([[*map(int, bin(i)[2:].zfill(bits))] for i in range(matrix_size)])
p2_actions = np.array([[*map(int, bin(j)[2:].zfill(bits))] for j in range(matrix_size)])
for i in range(p1_actions):
    for j in range(p2_actions):
        a[i][j] = f1_score(p1_actions[i],p2_actions[j],zero_division=1)

g = nashpy.Game(a)
equ = list(g.support_enumeration())
print(equ)

output:

/usr/local/lib/python3.7/site-packages/nashpy/algorithms/support_enumeration.py:196: RuntimeWarning: 
An even number of (0) equilibria was returned. This
indicates that the game is degenerate. Consider using another algorithm
to investigate.
                  
  warnings.warn(warning, RuntimeWarning)
[]

I have tried giving the same matrix to gambit, and using the online solver https://cgi.csc.liv.ac.uk/~rahul/bimatrix_solver/ and it seems the equilibria should exist. I have tried using the non_degenerate parameter and increasing tol. It doesn't seem to help.

Environment:
Mac OSX. Python 3.7.5. Nashpy 0.0.19.

Thank you for your time.

Degenerate Game in support_enumeration

Hi, I just came across the problem, the matrix A:[[-100, 0, 0, -100],[0, 0, 0, -100],[-100, 0 ,0, 0],[0, 0, 0, -50]] do get the solution in support_enumeration(), however, the matrix B [[-100, 0, 0, -100],[0, 0, 0, -100],[-100, 0 ,0, 0],[0, 0, 0, -33.3333333]] can not get the solution and saying an even number of (0) equilibria was returned. This indicates that the game is degenerate. I checked the formal issue and thought this problem has been solved, but I don't know why this still comes to my situation. Thanks a lot.

Write documentation

Given that this has moved to incorporate more algorithms (vertex enumeration in #26 and LH in #25), proper documentation is needed.

  • Tutorial (solve a simple game etc)
  • How tos (create game, calculate utilities, each algorithm)
  • References (mathematics behind each algorithm)
  • Discussion (Nash's theorem and other neat things)

Unexpected behavior - no equilibrium for a simple game

Hi,

I discovered that support_enumeration fails to find a mixed NE for the following game (the list is empty). Is it a well known issue?
`
import nash
import numpy as np
M = [[ 0., 1., -0., -1.],
[-1., 0., 1., 1.],
[ 0., -1., 0., 1.],
[ 1., -1., -1., 0.]]

rps = nash.Game(M)
print(rps)
eqs = list(rps.support_enumeration())
print(eqs)
`

0 equilibria with support_enumeration

Version: 0.0.19
Input matrices:
[[52.46337363, 69.47195938, 0. , 54.14372075],
[77. , 88. , 84.85714286, 92.4 ],
[77.78571429, 87.35294118, 93.5 , 91.38461538],
[66.37100751, 43.4530444 , 0. , 60.36191831]]
[[23.52690518, 17.35459006, 88.209 , 20.8021711 ],
[16.17165 , 0. , 14.00142857, 6.46866 ],
[ 0. , 5.76529412, 0. , 0. ],
[15.68327304, 40.68156322, 84.00857143, 11.06596804]]

Fix pip install

Collecting nashpy
  Downloading nashpy-0.0.1.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/98/t82xlbq54gz005lb_w2rrlg80000gn/T/pip-build-151tqcys/nashpy/setup.py", line 6, in <module>
        with open('requirements.txt') as f:
    FileNotFoundError: [Errno 2] No such file or directory: 'requirements.txt'

Iterating generator with equilibria seems very slow

Hi,

I am using both Support and Vertex Enumeration to compute the equilibria of a zero-sum game. This is done as follows (U the payoff matrix):

import nashpy

game = nashpy.Game(U)
equilibria = game.support_enumeration()
for i, eq in enumerate(equilibria):
print('Solution ', i)
print('Row player strategy: ', eq[0])
print('Column player strategy: ', eq[1])

The above code seems to work fine when each player has a small number of strategies available (e.g 2-5). However, when I try to solve slightly larger games (e.g 10 strategies) iterating over the results for Support Enumeration becomes extremely slow. This also applies to Vertex Enumeration when the problem size increases a bit more (e.g. 50-100 strategies).

Is this normal/expected? If so is there any workaround this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.