Created
December 17, 2012 17:50
-
-
Save dansbecker/4320314 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
{ | |
"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