{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![alt text](https://github.com/callysto/callysto-sample-notebooks/blob/master/notebooks/images/Callysto_Notebook-Banner_Top_06.06.18.jpg?raw=true)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: scipy in /opt/conda/lib/python3.6/site-packages (1.1.0)\r\n" ] } ], "source": [ "## Import various packages that enable this notebook to work\n", "\n", "import sys\n", "!{sys.executable} -m pip install scipy\n", "\n", "import numpy\n", "import pylab\n", "from scipy import optimize" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "## Define the Benefit and Cost Functions\n", "\n", "def Benefit(x):\n", " return x*(4-x)\n", "\n", "def Cost(x):\n", " return x*x" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "## Define the Payoff functions for both players\n", "\n", "def APayoff(a,b): return Benefit(a+b)-Cost(a)\n", "def BPayoff(a,b): return Benefit(a+b)-Cost(b)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "An investment of b = 0.0 yields a payoff of 2.04\n", "An investment of b = 0.1 yields a payoff of 2.3\n", "An investment of b = 0.2 yields a payoff of 2.52\n", "An investment of b = 0.3 yields a payoff of 2.7\n", "An investment of b = 0.4 yields a payoff of 2.84\n", "An investment of b = 0.5 yields a payoff of 2.94\n", "An investment of b = 0.6 yields a payoff of 3.0\n", "An investment of b = 0.7 yields a payoff of 3.02\n", "An investment of b = 0.8 yields a payoff of 3.0\n", "An investment of b = 0.9 yields a payoff of 2.94\n", "An investment of b = 1.0 yields a payoff of 2.84\n" ] } ], "source": [ "## Suppose A invests a=0.6. How should B respond?\n", "## Let's try all the values from 0 to 1, in increments of 0.1\n", "\n", "for b in range(0,11):\n", " print(\"An investment of b =\", b/10, \"yields a payoff of\", round(BPayoff(0.6,b/10),4))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "## Given an input value for the variable a, this function determines the optimal value of b.\n", "## Thus, after A invests some amount a, this function calculates B's best response move b that maximizes his payoff,\n", "## i.e., minimizes the value of -BPayoff. We do this to take advantage of Python's Optimize.Minimize function.\n", "\n", "def GetBestB(a):\n", " def func(x): return -BPayoff(a,x)\n", " BestB = optimize.minimize_scalar(func,bounds=(0,1), method='bounded')\n", " b = BestB.x\n", " return b" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6999999999999995" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "GetBestB(0.6)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3.15, 3.02)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Thus, if A selects a=0.6, B will respond with b=0.7, which is the move that maximizes B's payoff.\n", "## Below we see the payoffs for both players.\n", "\n", "APayoff(0.6,0.7),BPayoff(0.6,0.7)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "## Now that we can caculate GetBestB(a) for all values of a, A wants to select the value of a that maximizes her payoff.\n", "## The function below determines this value of a.\n", "\n", "def GetBestA():\n", " def f(x): return -APayoff(x,GetBestB(x))\n", " BestA = optimize.minimize_scalar(f,bounds=(0,1), method='bounded')\n", " a = BestA.x\n", " return a" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A's optimal strategy is a = 0.40000000000000124\n", "B's optimal strategy is b = 0.7999999999999986\n", "The payoff to A is 3.1999999999999984 and the payoff to B is 2.7200000000000015\n" ] } ], "source": [ "## Now we have Python determine the optimal values of a and b.\n", "\n", "a = GetBestA()\n", "b = GetBestB(a)\n", "print(\"A's optimal strategy is a =\", a)\n", "print(\"B's optimal strategy is b =\", b)\n", "print(\"The payoff to A is\", APayoff(a,b), \"and the payoff to B is\", BPayoff(a,b))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "## Let's generalize this to other Benefit and Cost functions.\n", "## We'll assume that the Benefit and Cost functions are quadratic, i.e, Benefit(x)=px^2+qx+r and Cost(x)=sx^2+tx+u\n", "## The function below is simply a cut+paste of what we showed above.\n", "\n", "def CalculatePayoffs(p,q,r,s,t,u):\n", " \n", " def Benefit(x): return p*x*x + q*x + r\n", " def Cost(x): return s*x*x + t*x + u\n", " \n", " def APayoff(a,b): return Benefit(a+b)-Cost(a)\n", " def BPayoff(a,b): return Benefit(a+b)-Cost(b)\n", " \n", " def GetBestB(a):\n", " def func(x): return -BPayoff(a,x)\n", " BestB = optimize.minimize_scalar(func,bounds=(0,1), method='bounded')\n", " b = BestB.x\n", " return b\n", "\n", " def GetBestA():\n", " def f(x): return -APayoff(x,GetBestB(x))\n", " BestA = optimize.minimize_scalar(f,bounds=(0,1), method='bounded')\n", " a = BestA.x\n", " return a\n", "\n", " a = GetBestA()\n", " b = GetBestB(a)\n", " print(\"A's optimal strategy is a =\", a)\n", " print(\"B's optimal strategy is b =\", b)\n", " print(\"The payoff to A is\", APayoff(a,b), \"and the payoff to B is\", BPayoff(a,b))\n", " print()\n", " return" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A's optimal strategy is a = 0.39999999999999575\n", "B's optimal strategy is b = 0.8000000000000033\n", "The payoff to A is 3.200000000000002 and the payoff to B is 2.7199999999999935\n", "\n" ] } ], "source": [ "## Let's double-check our answers for our original question, where Benefit(x)=x(4-x)=-x^2+4x+0 and Cost(x)=x^2.\n", "## Thus, we have p=-1, q=4, r=0, s=1, t=0, u=0 in this example.\n", "\n", "CalculatePayoffs(-1,4,0,1,0,0)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "a58fc58e8f8b492ea7c8c06774fe69fc", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=-1, description='p', max=10, min=-10), IntSlider(value=4, description='q…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Now use the SLIDERS below to adjust the values of p,q,r,s,t,u. Instantly we see the optimal values and payoffs.\n", "## Do you notice anything interesting? \n", "\n", "from __future__ import print_function\n", "from ipywidgets import interact, interactive, fixed, interact_manual\n", "import ipywidgets as widgets\n", "\n", "interact(CalculatePayoffs, \n", " p=widgets.IntSlider(min=-10, max=10, step=1, value=-1),\n", " q=widgets.IntSlider(min=-10, max=10, step=1, value=4),\n", " r=widgets.IntSlider(min=-10, max=10, step=1, value=0),\n", " s=widgets.IntSlider(min=-10, max=10, step=1, value=1),\n", " t=widgets.IntSlider(min=-10, max=10, step=1, value=0),\n", " u=widgets.IntSlider(min=-10, max=10, step=1, value=0))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Here are some questions to ponder. \n", "\n", "#### When is A's optimal strategy equal to a=0? And when is it equal to a=1?\n", "#### When is B's optimal strategy equal to b=0? And when is it equal to b=1?\n", "#### When is A's payoff higher than B's payoff? And how does this relate to the first and second derivatives of the Benefit and Cost functions?\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Additional References\n", "\n", "https://mast.queensu.ca/~math9-12/The%20parent%20game.html\n", "\n", "https://en.wikipedia.org/wiki/Stackelberg_competition\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![alt text](https://github.com/callysto/callysto-sample-notebooks/blob/master/notebooks/images/Callysto_Notebook-Banners_Bottom_06.06.18.jpg?raw=true)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }