Skip to content

Instantly share code, notes, and snippets.

@dansbecker
Created December 17, 2012 17:50
Show Gist options
  • Save dansbecker/4320314 to your computer and use it in GitHub Desktop.
Save dansbecker/4320314 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "Untitled0"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"INSTRUCTIONS: \n",
"IGNORE THE CELL IMMEDIATELY BELOW THESE INSTRUCTIONS, AND SKIP TO CELL 2. CELL 2 CONTAINS THE MARGINAL COSTS AND THE DEMAND FUNCITONS. SET THE COSTS AND DEMAND FUNCTION, AND PRESS SHIFT-ENTER WHILE IN THAT CELL TO SEE THE RESULTS.\n"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from __future__ import division\n",
"from numpy import sqrt, linspace\n",
"from scipy.optimize import minimize\n",
"from pandas import DataFrame\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# IGNORE EVERYTHING IN THIS CELL \n",
"\n",
"\n",
"\n",
"def calc_p_t(demand_fn, q_l, q_f):\n",
"\t\"\"\"returns transaction price that clears market for given qty of legit and fraud goods\"\"\"\n",
"\treturn demand_fn(q_l)*(q_l/(q_l+q_f))\n",
"\n",
"def profit(demand_fn, q_l, q_f, my_c, my_id):\n",
"\t\"\"\"my_id is l to calculate legitimate firm's profit, and f to calculate fraudster profit\"\"\"\n",
"\tif my_id == \"l\":\n",
"\t\tmy_q = q_l\n",
"\telse:\n",
"\t\tmy_q = q_f\n",
"\tif my_q<=0:\n",
"\t\treturn 0\n",
"\tp_t = calc_p_t(demand_fn, q_l, q_f)\n",
"\treturn my_q*(p_t-my_c)\n",
"\n",
"def best_resp_at_point(demand_fn, opponent_q, my_c, my_id):\n",
"\t\"\"\"Returns the best qty to sell for firm described by my_id (l or f) given opponents qty\"\"\"\n",
"\tif my_id == 'l':\n",
"\t\tfn_to_minimize = lambda q: -1 * profit(demand_fn, q, opponent_q, my_c, my_id)\n",
"\tif my_id == 'f':\n",
"\t\tfn_to_minimize = lambda q: -1 * profit(demand_fn, opponent_q, q, my_c, my_id)\n",
"\tminimization_object = minimize(\n",
"\t\t\tfun\t\t= fn_to_minimize,\n",
"\t\t\tx0\t\t= 0.1,\n",
"\t\t\tmethod\t= 'Nelder-Mead')\n",
"\tresponse_qty = minimization_object['x'][0]\n",
"\toutput = round(response_qty,4)\n",
"\toutput = max(0, output)\n",
"\treturn output\n",
"\n",
"\n",
"def all_best_resp(demand_fn, my_c, my_id):\n",
"\t\"\"\"returns list of points in best response fn for firm described by my_id.\n",
"\tpoints are listed as ordered pairs with opponents qt, floory first, and response second\"\"\"\n",
"\tif my_id == \"f\":\t\t\t#top val fraudster could have to respond to\n",
"\t\ttop_val_to_consider = demand_fn(0)\n",
"\tif my_id == \"l\":\t\t\t#top val legit could have to respond to\n",
"\t\ttop_val_to_consider = 10 * demand_fn(0)\n",
"\topponent_q_vals = linspace(0, top_val_to_consider, 500)\n",
"\toutput = [(q, best_resp_at_point(demand_fn, q, my_c, my_id)) for q in opponent_q_vals \n",
"\t\t\t\t\t\t\t\t\tif best_resp_at_point(demand_fn, q, my_c, my_id)>0]\n",
"\treturn output\n",
"\n",
"\n",
"def best_response_lookup(best_resp_fn, qty):\n",
"\t\"\"\"Takes own best response fn and opponents qty. Returns own production\"\"\"\n",
"\tmax_iter = 25\n",
"\tpoints_to_search_through = [point[0] for point in best_resp_fn]\n",
"\tindex_upper_bound = len(best_resp_fn)\n",
"\tindex = int(index_upper_bound/2)\n",
"\tif (qty<best_resp_fn[0][0]) or (qty>best_resp_fn[-1][0]):\n",
"\t\treturn 0\n",
"\tfor i in range(max_iter):\n",
"\t\tif qty<points_to_search_through[index]:\n",
"\t\t\tindex_upper_bound = index\n",
"\t\t\tindex = int(index/2)\n",
"\t\telif qty>points_to_search_through[index+1]:\n",
"\t\t\tindex = int((index + index_upper_bound)/2)\n",
"\t\telif qty==points_to_search_through[index]:\n",
"\t\t\treturn best_resp_fn[index][1]\n",
"\t\telse:\t\t\t\t\t#qty between index and index+1\n",
"\t\t\t\t\t\t\t\t#interpolate value between those points\n",
"\t\t\trelative_loc_of_qty = (qty-points_to_search_through[index])/(points_to_search_through[index+1]-points_to_search_through[index])\n",
"\t\t\treturn ((1-relative_loc_of_qty) * best_resp_fn[index][1] +\n",
"\t\t\t\t\trelative_loc_of_qty * best_resp_fn[index+1][1])\n",
"\tprint \"Failed to find point in best_resp_fn \" \n",
"\tprint best_resp_fn\n",
"\tprint \"qty was \" + str(qty)\n",
"\n",
"def find_equilibrium(brl, brf):\n",
"\t\"\"\"Find intersection of two best response functions. Returns quantities for both players\"\"\"\n",
"\tmax_iter = 25\n",
"\tcurrent_q_f = 0\n",
"\tprevious_q_f = 0\n",
"\tprevious_q_l = 0\n",
"\tfor i in xrange(max_iter):\n",
"\t\tcurrent_q_l = best_response_lookup(brl, current_q_f)\n",
"\t\tcurrent_q_f = best_response_lookup(brf, current_q_l)\n",
"\t\tif (current_q_l==previous_q_l) and (current_q_f == previous_q_f):\n",
"\t\t\treturn current_q_l, current_q_f\n",
"\t\telse:\n",
"\t\t\tprevious_q_l = current_q_l\n",
"\t\t\tprevious_q_f = current_q_f\n",
"\tprint \"No equilibrium found.\" \n",
"\tprint \"Double check market collapse from best response functions\"\n",
"\tprint_best_responses(brl, brf)\n",
"\treturn (0, 0)\n",
"\n",
"def calc_consumer_surplus(demand_fn, q_l, p_effective):\n",
"\t\"\"\"Returns consumer surplus calculated by numerical integration\"\"\"\n",
"\tnum_bins = 100\n",
"\tbin_width = q_l/num_bins\n",
"\tbin_mid_points = linspace(0, q_l, num_bins, endpoint=False) + bin_width/2\n",
"\tvalue = demand_fn(bin_mid_points).sum()*bin_width\n",
"\texpenditures = q_l * p_effective\n",
"\treturn value - expenditures\n",
"\n",
"def print_best_responses(brl, brf):\n",
"\tdec_to_show = 3\n",
"\tpretty_brl\t= [(round(i[0],dec_to_show), round(i[1],dec_to_show)) for i in brl]\n",
"\tpretty_brf\t= [(round(i[0],dec_to_show), round(i[1],dec_to_show)) for i in brf]\n",
"\tprint \"\\n----------------------------------\"\n",
"\tprint \"Best response for legitimate firm:\"\n",
"\tfor i in pretty_brl:\n",
"\t\tprint i\n",
"\tprint \"----------------------------------\"\n",
"\tprint \"Best response for fraudster: \"\n",
"\tfor i in pretty_brf:\n",
"\t\tprint i\n",
"\tprint \"----------------------------------\\n\"\n",
"\n",
"def graph_best_responses(brl, brf):\n",
"\tdf_brl = DataFrame(brl, columns=[\"q_f\", \"q_l\"])\n",
"\tdf_brf = DataFrame(brf, columns=[\"q_l\", \"q_f\"])\n",
"\tdf_brl.plot(x=\"q_f\", y=\"q_l\", color='b')\n",
"\tdf_brf.plot(x=\"q_f\", y=\"q_l\", color='r')\n",
"\tplt.show()\n",
"\treturn\n",
"\t\n",
"\n",
"def describe_equilibrium(demand_fn, c_l, c_f):\n",
"\t\"\"\"calculates and prints best response functions and relevant outcomes given model primitives\"\"\"\n",
"\tdecimal_places = 3\n",
"\tbrl = all_best_resp(demand_fn, c_l, 'l')\n",
"\tbrf = all_best_resp(demand_fn, c_f, 'f')\n",
"\tmy_plt = graph_best_responses(brl, brf)\n",
"\t#print_best_responses(brl, brf)\n",
"\n",
"\tq_l, q_f = find_equilibrium(brl, brf)\n",
"\tif q_l==q_f==0:\n",
"\t\tprint \"NO EQUILIBRIUM.\"\n",
"\t\treturn\n",
"\tp_t\t= calc_p_t(demand_fn, q_l, q_f)\n",
"\tp_effective = p_t * (q_f+q_l) / q_l\n",
"\tprofit_l = q_l * (p_t - c_l)\n",
"\tprofit_f = q_f * (p_t - c_f)\n",
"\tconsumer_surplus = calc_consumer_surplus(demand_fn, q_l, p_effective)\n",
"\tprint \"Equilibrium outcomes: \"\n",
"\tfor varname in [\"q_l\", \"q_f\", \"p_t\", \"p_effective\", \"profit_l\", \"profit_f\", \"consumer_surplus\"]:\n",
"\t\tprint varname + \" = \" +str(round(eval(varname), decimal_places))\n",
"\treturn\n"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"################ MODIFY BELOW THIS LINE ####################\n",
"#marginal costs\n",
"c_f = 0.8\n",
"c_l = 1\n",
"\n",
"def demand_fn(q_l):\n",
" \"\"\"returns price that clears market when supplied qty is q_l\"\"\"\n",
" A = 10\n",
" B = 8\n",
" p = A-B*q_l\n",
" return (p>0)*p #floor at 0. This implementation is safe for vectorized calls\n",
"################ MODIFY ABOVE THIS LINE ####################\n",
"\n",
"# PRESS SHIFT-ENTER WHILE IN THIS WINDOW TO UPDATE RESULTS\n",
"describe_equilibrium(demand_fn, c_l, c_f) "
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Equilibrium outcomes: \n",
"q_l = 0.649\n",
"q_f = 0.942\n",
"p_t = 1.961\n",
"p_effective = 4.806\n",
"profit_l = 0.624\n",
"profit_f = 1.094\n",
"consumer_surplus = 1.686\n"
]
}
],
"prompt_number": 2
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"CALL OR EMAIL DAN IF YOU HAVE QUESTIONS"
]
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment