Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save drvinceknight/9c5c424f7fb663f446c068ac71fa0f69 to your computer and use it in GitHub Desktop.
Save drvinceknight/9c5c424f7fb663f446c068ac71fa0f69 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installing Nashpy\n",
"\n",
"If you want to install [Nashpy](https://github.com/drvinceknight/Nashpy), I recommend the following:\n",
"\n",
"1. Use the Anaconda distribution of Python (this works well on Windows)\n",
"2. Open a terminal (Mac OSX) or a command prompt (Windows) and type: `pip install nashpy`\n",
"\n",
"Once you have done that succsefully you should be able to `import nash` in Python to import the library."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the cell below I am importing the library and checking the version."
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'0.0.3'"
]
},
"execution_count": 90,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import nash\n",
"import numpy as np\n",
"import sympy as sym\n",
"sym.init_printing()\n",
"nash.__version__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Computing equilibria"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us use Nashpy to study the battle of the sexes game:\n",
"\n",
"\n",
"$$\n",
"A = \n",
"\\begin{pmatrix}\n",
"2 & 0\\\\\n",
"1 & 3\n",
"\\end{pmatrix}\n",
"$$\n",
"\n",
"\n",
"$$\n",
"B = \n",
"\\begin{pmatrix}\n",
"3 & 0\\\\\n",
"1 & 2\n",
"\\end{pmatrix}\n",
"$$"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Bi matrix game with payoff matrices:\n",
"\n",
"Row player:\n",
"[[2 0]\n",
" [1 3]]\n",
"\n",
"Column player:\n",
"[[3 0]\n",
" [1 2]]"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = [[2, 0], [1, 3]]\n",
"B = [[3, 0], [1, 2]]\n",
"g = nash.Game(A, B)\n",
"g"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can obtain the Nash equilibria for this game:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(array([ 1., 0.]), array([ 1., 0.])),\n",
" (array([ 0., 1.]), array([ 0., 1.])),\n",
" (array([ 0.25, 0.75]), array([ 0.75, 0.25]))]"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eq = list(g.equilibria())\n",
"eq"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that we have 3 equilibria: 2 pure, where the players coordinate and 1 mixed where the players don't.\n",
"\n",
"We can see the utility obtained by each player at each equilibria:\n",
"\n",
"- For the row player: $s_1 A s_2$\n",
"- For the column player: $s_1 B s_2$"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2.0 3.0\n",
"3.0 2.0\n",
"1.5 1.5\n"
]
}
],
"source": [
"for s1, s2 in eq:\n",
" row_util = np.dot(np.dot(s1, A), s2)\n",
" col_util = np.dot(np.dot(s1, B), s2)\n",
" print(row_util, col_util)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Numerical experiment"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us investigate the effect of the parameters on the mixed equilibria. The general form of a Battle of the sexes game is:\n",
"\n",
"$$\n",
"A = \n",
"\\begin{pmatrix}\n",
"a_{11} & a_{12}\\\\\n",
"a_{21} & a_{22}\n",
"\\end{pmatrix}\n",
"$$\n",
"\n",
"$$\n",
"B = \n",
"\\begin{pmatrix}\n",
"b_{11} & b_{12}\\\\\n",
"b_{21} & b_{22}\n",
"\\end{pmatrix}\n",
"$$\n",
"\n",
"with:\n",
"\n",
"$$\\min(a_{11}, a_{22}) > \\max(a_{12}, a_{21})$$ \n",
"$$\\min(b_{11}, b_{22}) > \\max(b_{12}, b_{21})$$ \n",
"\n",
"(The \"worse\" coordinated outcome is better than the \"best\" uncoordinated outcome.)\n",
"\n",
"Let us use a Numpy array to create a random battle of the sexes game with $0\\leq a_{ij},b_{ij}\\leq 1$."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def is_battle(A):\n",
" \"\"\"Checks if a numpy array is a battle of the sexes game\"\"\"\n",
" return min(A[0, 0], A[1, 1]) >= max(A[0, 1], A[1, 0])\n",
"\n",
"def random_battle(seed=0):\n",
" \"\"\"Repeatedly sample random matrices until we have a battle of the sexes game\"\"\"\n",
" np.random.seed(0)\n",
" A = np.random.random((2, 2))\n",
" B = np.random.random((2, 2))\n",
" while not is_battle(A) or not is_battle(B):\n",
" A = np.random.random((2, 2))\n",
" B = np.random.random((2, 2))\n",
" return nash.Game(A, B)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Bi matrix game with payoff matrices:\n",
"\n",
"Row player:\n",
"[[ 0.93081872 0.52076144]\n",
" [ 0.26720703 0.87739879]]\n",
"\n",
"Column player:\n",
"[[ 0.37191875 0.00138335]\n",
" [ 0.24768502 0.31823351]]"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"random_battle()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First of all let's see how many equilibria these games have:"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"list_of_eqs = []\n",
"N = 1000\n",
"for seed in range(N):\n",
" g = random_battle(seed)\n",
" list_of_eqs.append(list(g.equilibria()))"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(3, 3)"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"min(map(len, list_of_eqs)), max(map(len, list_of_eqs))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that we have in all cases 3 equilibria. Let us test if one of them is always mixed."
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def is_mixed(eq):\n",
" s1, s2 = eq\n",
" return max(s1) != 1 or max(s2) != 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us make sure that's working correctly, by checking the first equilibria from our experiment:"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(array([ 1., 0.]), array([ 1., 0.])),\n",
" (array([ 0., 1.]), array([ 0., 1.])),\n",
" (array([ 0.15994347, 0.84005653]), array([ 0.34955912, 0.65044088]))]"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eqs = list_of_eqs[0]\n",
"eqs"
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n",
"False\n",
"True\n"
]
}
],
"source": [
"for strategies in eqs:\n",
" print(is_mixed(strategies))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us check that all or equilibria have a mixed Nash equilibria:"
]
},
{
"cell_type": "code",
"execution_count": 86,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all(any(is_mixed(strategies) for strategies in eqs) for eqs in list_of_eqs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analytical analysis"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can verify this mathematically of course.\n",
"\n",
"Using a simple verification of best responses it is immediate to note that the following strateg pair is always an equilibria:\n",
"\n",
"$$\n",
"s_1 = (1, 0)\n",
"$$\n",
"\n",
"$$\n",
"s_2 = (1, 0)\n",
"$$\n",
"\n",
"Similarly for:\n",
"\n",
"$$\n",
"s_1 = (0, 1)\n",
"$$\n",
"\n",
"$$\n",
"s_2 = (0, 1)\n",
"$$\n",
"\n",
"We will now obtain the mixed Nash equilibria that always exists. Let us assume that:\n",
"\n",
"$$\n",
"s_1 = (x, 1 - x)\n",
"$$\n",
"\n",
"$$\n",
"s_2 = (y, 1 - y)\n",
"$$\n",
"\n",
"Using the equality of payoffs we know that these must satisfy:\n",
"\n",
"$$\n",
"y(b_{11} - b_{12}) + b_{12} = y(b_{21} - b_{22}) + b_{22}\n",
"$$\n",
"\n",
"and:\n",
"\n",
"$$\n",
"x(a_{11} - a_{21}) + b_{21} = x(a_{12} - a_{22}) + a_{22}\n",
"$$\n",
"\n",
"Let us use Sympy to obtain the solutions to these equations (which would of course be easy to do algebraically)."
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x, y = sym.symbols('x, y')\n",
"a_11, a_12, a_21, a_22 = sym.symbols('a_11. a_12, a_21, a_22')\n",
"b_11, b_12, b_21, b_22 = sym.symbols('b_11, b_12, b_21, b_22')"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAOUAAAAyBAMAAABR3AGyAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEImZRO/dMlQiu6vN\nZnZmcXX2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADqElEQVRYCb2Yz2sTQRTH36ZpkzQpWRQL/oAE\nigVBMB4U8VeDF49VkB5EMYIWvNSA4KnQXFqKBxsQPIhQpfReL560RjwoNIeAf4CB3q0tBVtrjTO7\ns7M78+Y12SbpwHRn3nfmfWZnuz++AWDlUI7/PYDyquRBomNFr9nl48BtWxDmWjtNa7FALOnYGCGg\n8Mv7bijxB0nmQGrJHAdYoQQ9nthxI8l1XSH66RIhwBYloPiIexnTFaSYA6PexdDlaKurBpiqO5PT\n5JZpuYe1vuxGCrLZrJHJOSMyrTJXfl4wp0wtr5bMCooKWKtM66+dKcMkQOTiWTVX5rO1DUMLtlNV\nSe+FZMbXIZ198h7gFHxQU83ZsBEpJyu8qgrqhWT2VCCThRmARzBVZslOjPPylbUug7XRV45t84oo\naiAkM5WD0RJnPoD5vJLpC0S3+vKJTV4VAXdCMtM1GLE5E4BtZrDsQg+7W9jeOzWooHZYZt66Cy5z\nQs21CUdqAH11t6qa1gvJTNb6cy4zwo7B8hEWWHdI1KCC2iGZ1tUrLAXf2+9aqsOr7DQH2EJ43buE\nZLrJGDOajRZx5mtwHXjdu+yLOQ0wOfvMRplj32bf8ooENbAf5ovHy3Cv0VAT8V5vo/GLV6woEfFw\nn88q0e520m+c/D/y3cUo2VPuRowrwS534rscEGn2iOzsKj6VWb6T+c4mbZIteYu9Hd45g+RLotG9\n4l7K6ToMau/fJstsX36aBThXbD9PiAwRtrfQ8zvEjPaHnnFO8UDvleg/Z9lr+fZX33KGfvcfSX32\nWYsFIgGt0H4FKeIDXnzmeiTaldAK7Vd0xfxeoV0JrWC/8lycgq6YmaQrAVIx+BXBRIqZOextMjqS\nisGvCCZSzEzSlQCpGPyKYCLFyJSuhDsTpUiF9iuxijdDMJGTMTKlK+HORClSIf1K7FLBmyGYyMkY\nmdKVuF/PAVciFdKvQNxlnq5WH1ar/DZBTsbIlK5EML2FA0iF9Csek80R54mcjJHpu5IZH+e0fIX0\nK+I8fSZyMmamdCWIKRWYUJcj/QpiSsVxM2yWkem7Ep3pK6RfQUzkZART/Q3DdyU601dIv4KYyMmI\nh3tvRd0p3uM8nemOYlHaryCmMyfoZKayTihp+NhkrgR4xYVFSb8C8RvehKNeA0BxMmvul5D3e5g/\nCrgr4RWXPf1K4vxOHU8JOhnL+51vzTAQT+1IZPCmSDOwY3ckYfMk8TuSdHyp+fCOjHhd42n+A6OT\nnhZFn3+gAAAAAElFTkSuQmCC\n",
"text/latex": [
"$$\\left\\{- \\frac{b_{12} - b_{22}}{b_{11} - b_{12} - b_{21} + b_{22}}\\right\\}$$"
],
"text/plain": [
"⎧ -(b₁₂ - b₂₂) ⎫\n",
"⎨─────────────────────⎬\n",
"⎩b₁₁ - b₁₂ - b₂₁ + b₂₂⎭"
]
},
"execution_count": 102,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sym.solveset(y * (b_11 - b_12) + b_12 - y * (b_21 - b_22) - b_22, y)"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPMAAAAyBAMAAAB7bPAdAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEImZRO/dMlQiu6vN\nZnZmcXX2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADlElEQVRYCe2YTWgTURDHJ2liNm1Dg2AvFRIo\nIp6sgh4q2CCIVwsiWCpWkIIoGhAFodBeKtVLAwUPVWjFq4d48SQ1p+IhaEHw6iJ6biuCH0Xjm5n3\n9vNteSvr5uLA7r6d35v/Py/d7u4EQMTeEdynF8tzyit3vq6G6RxLE2VptJjyogEeXmbr4s901upx\nKe7wSd+2J5nScIz/xAOtlPw8NrM2nQw0PbmUhhW+vCpm1sWjJ8cjPtguKKJCehpan270b0F29AjA\nTFDPQYSDVHceyzpzEXpW4RC8hFsvAmIuQmwUsax7tmGPDVdhtgH3SD2zPi3iurhUXUTYxDuWdX4V\nKnW4Ais1ae06uIiwC6JHsawrVVhEqcVyyNqDEJtEPOs5eGY1AG5A2NpFiE0ilnW/XbqWBciOhK09\nCLFJxLLOrB189AngnRDmy8x18CDEJhHLmgVz1Vw9ZO0iwv/IembhQRnmteKICGtpIPkXq77U6cDS\nzbWAEJ0iws0o5HNjpWo0O9FJA6sk96GWqKqRmHgcYEwbTU52kvUL9bI/klU1U3sl7k5woGY2OdlZ\nfecA9j9nzU5qwX7zNgyKZ3834k4V4Fi9G85Z8YVDz7duWB+mBXfjnyv3m9a7WUt/2b18S+nKjbRF\ny5Wv46kuPcaTy7IjP9kuKLIG/lu73422gXK+1aXhz2V3Lo52Qc7EUJX+C6cGivoqT2+l9HMX4C1A\noQUw/FR+BD/CNGJfcBUiVaW15gYK+ypvb6X0923AKBROTEG20ScNfAjTiP1BVYicKp+1aqG4gaK3\nTvXSm2231yfb7abQGyvjS741BXsaBXzOBxGlBRahBMWQqhDJKtBf4XnqrXzWolgtbQIy4paP1rXi\nV5EPIkqzNVPaUxUip8q3ajWzwr0VrlitWgyldeYLWOIWSNrWNpf4EYh00FpWIaJN1OmtuYGKsP4O\nva37rC1aXgplzQg74ZC1ixBjaK1lA6W3hjfwvlll7WHSEOuwecAIRDpoLasQ0SYO0tr/M45soCKs\nhz7eXauRdmmEHR1rRpgOWbtIVcnnRr4lRbyHCGuegtqn4Iw8sfnIe0yHrF2kqmarlOvTvQ1jXyW2\n5TKXZRp85L11FgqvF55oEKUF1gQip2qzTjPUr4be6dhX4XbbZylnFI/v2PlOZ8tbIMeYRhyBVFVG\n/Ta6qZupKU4uNTgutUo75eRUTZSsScdwqGlSkNycxxuo9QdwbrMU1kTUeAAAAABJRU5ErkJggg==\n",
"text/latex": [
"$$\\left\\{\\frac{a_{21} - a_{22}}{- a_{11.} + a_{12} + a_{21} - a_{22}}\\right\\}$$"
],
"text/plain": [
"⎧ a₂₁ - a₂₂ ⎫\n",
"⎨────────────────────────⎬\n",
"⎩-a_11. + a₁₂ + a₂₁ - a₂₂⎭"
]
},
"execution_count": 103,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sym.solveset(x * (a_11 - a_21) + a_21 - x * (a_12 - a_22) - a_22, x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that as:\n",
"\n",
"$$\\min(a_{11}, a_{22}) > \\max(a_{12}, a_{21})$$ \n",
"$$\\min(b_{11}, b_{22}) > \\max(b_{12}, b_{21})$$ \n",
"\n",
"the above expressions are between 0 and 1 (thus a valid probability)."
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [default]",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
@paulshuva
Copy link

While trying to run eq = list(g.equilibria()) ........ I am getting an attribute error: 'Game ' object has no attribute 'equilibria'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment