Created
January 23, 2017 10:12
-
-
Save drvinceknight/9c5c424f7fb663f446c068ac71fa0f69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
While trying to run eq = list(g.equilibria()) ........ I am getting an attribute error: 'Game ' object has no attribute 'equilibria'