def nodeplot(xnode,figtitle): fig = demo.figure(figtitle,'', '',[-0.0001, 1.0001], [-0.05, 0.05],figsize=[6,1.5]) plt.plot(xnode, np.zeros_like(xnode),'bo',ms=8) plt.xticks([0,1]) plt.yticks([]) figures.append(fig)
def nodeplot(xnode, figtitle): fig = demo.figure(figtitle, '', '', [-0.0001, 1.0001], [-0.05, 0.05], figsize=[6, 1.5]) plt.plot(xnode, np.zeros_like(xnode), 'bo', ms=8) plt.xticks([0, 1]) plt.yticks([]) figures.append(fig)
def equiplot(method): x, w = qnwequi(2500, [0, 0], [1, 1], method[0]) fig = demo.figure(method[1], '$x_1$', '$x_2$', [0, 1], [0, 1], figsize=[5, 5]) plt.plot(*x, '.') plt.xticks([0, 1]) plt.yticks([0, 1]) plt.axis('equal') return fig
f'$p^*_{i:d} = {pcrit:.2f}$', 'wo', offs[i], fs=11, ms=12, ) print(f'{msgs[i]:12s} = {pcrit:5.2f}') # ### Plot Residual # # We normalize the residuals as percentage of the value function. Notice the spikes at the "Profit entry" and "Profit exit" points. # In[10]: S['resid2'] = 100 * (S.resid / S.value) fig2 = demo.figure('Bellman Equation Residual', 'Potential Profit', 'Percent Residual') demo.qplot('profit', 'resid2', 'i', S) plt.legend(dactions) # ## SIMULATION # We simulate the model 50000 times for a time horizon $T=50$, starting with an operating firm ($d=1$) at the long-term profit mean $\bar{\pi}$. To be able to reproduce these results, we set the random seed at an arbitrary value of 945. # In[11]: T = 50 nrep = 50000 p0 = np.tile(pbar, (1, nrep)) d0 = 1 data = model.simulate(T, p0, d0, seed=945)
vcrit = np.interp(pcrit, subdata.index, subdata['value[close]']) demo.annotate(pcrit, vcrit, f'$p^*_{i:d} = {pcrit:.2f}$', 'wo', offs[i], fs=11, ms=12,) print(f'{msgs[i]:12s} = {pcrit:5.2f}') # ### Plot Residual # # We normalize the residuals as percentage of the value function. Notice the spikes at the "Profit entry" and "Profit exit" points. # In[10]: S['resid2'] = 100 * (S.resid / S.value) fig2 = demo.figure('Bellman Equation Residual','Potential Profit','Percent Residual') demo.qplot('profit','resid2','i',S) plt.legend(dactions) # ## SIMULATION # We simulate the model 50000 times for a time horizon $T=50$, starting with an operating firm ($d=1$) at the long-term profit mean $\bar{\pi}$. To be able to reproduce these results, we set the random seed at an arbitrary value of 945. # In[11]: T = 50 nrep = 50000 p0 = np.tile(pbar, (1, nrep)) d0 = 1
def approx_error(true_func, appr_func, d=0, title=''): demo.figure(title, 'x', 'Error') plotzero() plt.plot(xgrid, appr_func(xgrid, d) - true_func(xgrid)) plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0)) figures.append(plt.gcf())
# #### * Using Broyden's method # In[4]: A.broyden(x0) err_broyden = err(A.x_sequence) # #### * Using function iteration # # This method finds a zero of $f(x)$ by looking for a fixpoint of $g(x) = x-f(x)$. # In[5]: A.funcit(x0) err_funcit = err(A.x_sequence) # ### Plot results # In[6]: demo.figure('Convergence rates', 'Iteration', 'Log10 Error', [0, 12], [-15, 2]) plt.plot(err_newton, label="Newton's Method") plt.plot(err_broyden, label="Broyden's Method") plt.plot(err_funcit, label="Function Iteration") plt.legend(loc='lower left') demo.savefig([plt.gcf()])
# Next, for each possible price shock, we compute next period log-price by adding the shock to current log-prices (the nodes of the Value object). Then, we use each next-period price to compute the expected value of an option with one-period to maturity (save the values in ```v```). We update the value function to reflect the new time-to-maturity and use ```broyden``` to solve for the critical value. We repeat this procedure until we reach the $T=300$ horizon. # In[8]: for t in range(T): v = np.zeros((1, n)) for k in range(m): pnext = Value.nodes + e[k] v += w[k] * np.maximum(K - np.exp(pnext), delta * Value(pnext)) Value[:] = v pcrit[t + 1] = f.broyden(pcrit[t]) # ### Print Critical Exercise Price 300 Periods to Expiration # In[9]: print('Critical Price = %5.2f' % np.exp(pcrit[-1])) # ### Plot Critical Exercise Prices # In[10]: fig1 = demo.figure('American Put Option Optimal Exercise Boundary', 'Periods Remaining Until Expiration', 'Exercise Price') plt.plot(np.exp(pcrit)) # In[ ]: demo.savefig([fig1])
# ### Plot setup # In[5]: n = 1000 x = np.linspace(a, b, n) r = resid(F.c) # ### Plot function inverse # In[6]: fig1 = demo.figure('Implicit Function', 'x', 'f(x)') plt.plot(x, F(x)) # ### Plot residual # In[7]: fig2 = demo.figure('Functional Equation Residual', 'x', 'Residual') plt.hlines(0, a, b, 'k', '--') plt.plot(x, r) # In[8]:
d2 = deriv_error(x-h, x+h) e2 = np.log10(eps**(1/3)) # ## Plot finite difference derivatives # In[6]: ylim = [-15, 5] xlim = [-15, 0] lcolor = [z['color'] for z in plt.rcParams['axes.prop_cycle']] demo.figure('Error in Numerical Derivatives','$\log_{10}(h)$','$\log_{10}$ Approximation Error',xlim,ylim) plt.plot(c,d1, label='One-Sided') plt.plot(c,d2, label='Two-Sided') plt.vlines([e1,e2],*ylim, lcolor,linestyle=':') plt.xticks(np.arange(-15,5,5)) plt.yticks(np.arange(-15,10,5)) demo.annotate(e1,2,'$\sqrt{\epsilon}$',color=lcolor[0],ms=0) demo.annotate(e2,2,'$\sqrt[3]{\epsilon}$',color=lcolor[1],ms=0) plt.legend(loc='lower left') # In[7]: demo.savefig([plt.gcf()])
# ## Analysis # # ### Plot Action-Contingent Value Functions # In[12]: # Compute and Plot Critical Unit Profit Contributions pcrit = [NLP(lambda s: model.Value_j(s)[i].dot([1,-1])).broyden(0.0)[0] for i in range(A)] vcrit = [model.Value(s)[i] for i, s in enumerate(pcrit)] # In[13]: fig1 = demo.figure('Action-Contingent Value Functions', 'Net Unit Profit','Value', figsize=[10,5]) cc = np.linspace(0.3,0.9,model.dims.ni) for a, i in enumerate(dstates): plt.plot(S.loc[i,'value[keep]'] ,color=plt.cm.Blues(cc[a]), label='Keep ' + i) if pmin < pcrit[a] < pmax: demo.annotate(pcrit[a], vcrit[a], f'$p^*_{a+1}$', 'wo',(0, 0), fs=11, ms=18) print(f'Age {a+1:d} Profit {pcrit[a]:5.2f}') plt.plot(S.loc['a=1','value[replace]'], color=plt.cm.Oranges(0.5),label='Replace') plt.legend() # ### Plot Residual
# ## Two-sided finite difference derivative # In[5]: d2 = deriv_error(x - h, x + h) e2 = np.log10(eps**(1 / 3)) # ## Plot finite difference derivatives # In[6]: ylim = [-15, 5] xlim = [-15, 0] lcolor = [z['color'] for z in plt.rcParams['axes.prop_cycle']] demo.figure('Error in Numerical Derivatives', '$\log_{10}(h)$', '$\log_{10}$ Approximation Error', xlim, ylim) plt.plot(c, d1, label='One-Sided') plt.plot(c, d2, label='Two-Sided') plt.vlines([e1, e2], *ylim, lcolor, linestyle=':') plt.xticks(np.arange(-15, 5, 5)) plt.yticks(np.arange(-15, 10, 5)) demo.annotate(e1, 2, '$\sqrt{\epsilon}$', color=lcolor[0], ms=0) demo.annotate(e2, 2, '$\sqrt[3]{\epsilon}$', color=lcolor[1], ms=0) plt.legend(loc='lower left') # In[7]: demo.savefig([plt.gcf()])
monopoly = NLP(resid) Q.c = monopoly.broyden(c0) # ### Setup plot # In[5]: nplot = 1000 p = np.linspace(a, b, nplot) rplot = resid(Q.c) # ### Plot effective supply # In[6]: demo.figure("Monopolist's Effective Supply Curve", 'Quantity', 'Price') plt.plot(Q(p), p) figures.append(plt.gcf()) # ### Plot residual # In[7]: demo.figure('Functional Equation Residual', 'Price', 'Residual') plt.hlines(0, a, b, 'k', '--') plt.plot(p, rplot) figures.append(plt.gcf()) # In[8]: demo.savefig(figures)
# Class `NLP` defines nonlinear problems. It can be used to solve `resid` by Broyden's method. # In[7]: cournot = NLP(resid) S.c = cournot.broyden(S.c, tol=1e-12) # ### Plot demand and effective supply for m=5 firms # In[8]: prices = np.linspace(a, b, 501) fig1 = demo.figure('Cournot Effective Firm Supply Function', 'Quantity', 'Price', [0, 4], [0.5, 2]) plt.plot(5 * S(prices), prices, D(prices), prices) plt.legend(('Supply','Demand')) # ### Plot residual # # Notice that `resid` does not take explicit parameters, so to evaluate it when prices are `prices` we need to assign `p = prices`. # In order to assess the quality of the approximation, one plots the residual function over the approximation domain. Here, the residual function is plotted by computing the residual at a refined grid of 501 equally spaced points. # In[9]: p = prices fig2 = demo.figure('Residual Function for Cournot Problem',
S[['j*']].plot(ax=plt.subplot(gs[1])) plt.title('Optimal Action') plt.ylabel('Action') plt.ylim([-0.25,1.25]) plt.yticks([0,1],options) plt.legend([]) # ### Plot Residuals # In[13]: S['resid2'] = 100*S.resid / S.value fig2 = demo.figure('Bellman Equation Residual','','Percent Residual') S['resid2'].plot(ax=plt.gca()) plt.hlines(0,0,smax,'k') # ### Simulation # # The path followed by the biomass is computed by the ```simulate()``` method. Here we simulate 32 periods starting with a biomass level $s_0 = 0$. # In[14]: H = model.simulate(32, 0.0) fig3 = demo.figure('Timber harvesting simulation','Period','Biomass') H['biomass'].plot(ax=plt.gca())
ywid = ymax - ymin ylims = [ymin - 0.5*ywid, ymax + 0.1*ywid] # In[4]: figs = [] for nnode in 3, 5, 9: F = BasisSpline(nnode, xmin, xmax, k=1, f=f) xnodes = F.nodes[0] xx = np.r_[x, xnodes] xx.sort() figs.append(demo.figure('Linear Spline with %d nodes' % nnode, '', '', xlims, ylims, figsize=[10,5])) plt.plot(xx, f(xx), lw=3) # true function plt.plot(xx, F(xx), 'r', lw=1) # approximation plt.yticks(ylims, ['', '']) xe = ['$x_{%d}$' % k for k in range(nnode)] xe[0], xe[-1] = '$x_0=a$', '$x_{%d}=b$' % (nnode-1) plt.xticks(xnodes, xe, fontsize=18) for i, xi in enumerate(xnodes): plt.vlines(xi, ylims[0], F(xi), 'gray','--') # In[5]: demo.savefig(figs)
# ## ANALYSIS # ### Compute refined state grid # In[9]: ss = np.linspace(0,smax,1000) # ### Plot Conditional Value Functions # In[10]: fig1 =demo.figure('Conditional Value Functions','Biomass','Value of Stand') plt.plot(ss,vhat0(cc,ss),label='Grow') plt.plot(ss,vhat1(cc,ss),label='Clear-Cut') plt.legend() vcrit = vhat(cc,scrit) ymin = plt.ylim()[0] plt.vlines(scrit, ymin,vcrit,'grey',linestyles='--') demo.annotate(scrit,ymin,'$s^*$',ms=10) demo.bullet(scrit,vcrit) print(f'Optimal Biomass Harvest Level = {scrit:.4f}') # ### Plot Value Function Residual # In[ ]:
# # ### Plot Action-Contingent Value Functions # In[12]: # Compute and Plot Critical Unit Profit Contributions pcrit = [ NLP(lambda s: model.Value_j(s)[i].dot([1, -1])).broyden(0.0)[0] for i in range(A) ] vcrit = [model.Value(s)[i] for i, s in enumerate(pcrit)] # In[13]: fig1 = demo.figure('Action-Contingent Value Functions', 'Net Unit Profit', 'Value', figsize=[10, 5]) cc = np.linspace(0.3, 0.9, model.dims.ni) for a, i in enumerate(dstates): plt.plot(S.loc[i, 'value[keep]'], color=plt.cm.Blues(cc[a]), label='Keep ' + i) if pmin < pcrit[a] < pmax: demo.annotate(pcrit[a], vcrit[a], f'$p^*_{a+1}$', 'wo', (0, 0), fs=11, ms=18)
# EMPLOYED demo.subplot(1,2,2,'Action-Contingent Value, Employed', 'Wage', 'Value') plt.plot(S.loc['employed',vv]) demo.annotate(wcrit1, vcrit1, f'$w^*_0 = {wcrit1:.1f}$', 'wo',(5, -5), fs=12) plt.legend(['Quit', 'Work'], loc='upper left') # ### Plot Residual # In[11]: S['resid2'] = 100 * (S['resid'] / S['value']) fig2 = demo.figure('Bellman Equation Residual', 'Wage', 'Percent Residual') plt.plot(S.loc['unemployed','resid2']) plt.plot(S.loc['employed','resid2']) plt.legend(model.labels.i) # ## SIMULATION # ### Simulate Model # # We simulate the model 10000 times for a time horizon $T=40$, starting with an unemployed worker ($i=0$) at the long-term wage rate mean $\bar{w}$. To be able to reproduce these results, we set the random seed at an arbitrary value of 945. # In[12]: T = 40
scrit # ## ANALYSIS # ### Compute refined state grid # In[9]: ss = np.linspace(0, smax, 1000) # ### Plot Conditional Value Functions # In[10]: fig1 = demo.figure('Conditional Value Functions', 'Biomass', 'Value of Stand') plt.plot(ss, vhat0(cc, ss), label='Grow') plt.plot(ss, vhat1(cc, ss), label='Clear-Cut') plt.legend() vcrit = vhat(cc, scrit) ymin = plt.ylim()[0] plt.vlines(scrit, ymin, vcrit, 'grey', linestyles='--') demo.annotate(scrit, ymin, '$s^*$', ms=10) demo.bullet(scrit, vcrit) print(f'Optimal Biomass Harvest Level = {scrit:.4f}') # ### Plot Value Function Residual # In[ ]:
plt.plot(S.loc['unemployed', vv]) demo.annotate(wcrit0, vcrit0, f'$w^*_0 = {wcrit0:.1f}$', 'wo', (5, -5), fs=12) plt.legend(['Do Not Search', 'Search'], loc='upper left') # EMPLOYED demo.subplot(1, 2, 2, 'Action-Contingent Value, Employed', 'Wage', 'Value') plt.plot(S.loc['employed', vv]) demo.annotate(wcrit1, vcrit1, f'$w^*_0 = {wcrit1:.1f}$', 'wo', (5, -5), fs=12) plt.legend(['Quit', 'Work'], loc='upper left') # ### Plot Residual # In[11]: S['resid2'] = 100 * (S['resid'] / S['value']) fig2 = demo.figure('Bellman Equation Residual', 'Wage', 'Percent Residual') plt.plot(S.loc['unemployed', 'resid2']) plt.plot(S.loc['employed', 'resid2']) plt.legend(model.labels.i) # ## SIMULATION # ### Simulate Model # # We simulate the model 10000 times for a time horizon $T=40$, starting with an unemployed worker ($i=0$) at the long-term wage rate mean $\bar{w}$. To be able to reproduce these results, we set the random seed at an arbitrary value of 945. # In[12]: T = 40 nrep = 10000 sinit = np.full((1, nrep), wbar)
# # Simulate time series using Monte Carlo Method # In[1]: import numpy as np from compecon import demo from scipy.stats import norm import matplotlib.pyplot as plt # In[2]: m, n = 3, 40 mu, sigma = 0.005, 0.02 e = norm.rvs(mu,sigma,size=[n,m]) logp = np.zeros([n+1,m]) logp[0] = np.log(2) for t in range(40): logp[t+1] = logp[t] + e[t] # In[3]: demo.figure('','Week','Price', [0,n]) plt.plot(np.exp(logp)) demo.savefig([plt.gcf()])
v += w[k] * np.maximum(K - np.exp(pnext), delta * Value(pnext)) Value[:] = v pcrit[t + 1] = f.broyden(pcrit[t]) # ### Print Critical Exercise Price 300 Periods to Expiration # In[9]: print('Critical Price = %5.2f' % np.exp(pcrit[-1])) # ### Plot Critical Exercise Prices # In[10]: fig1 = demo.figure('American Put Option Optimal Exercise Boundary', 'Periods Remaining Until Expiration', 'Exercise Price') plt.plot(np.exp(pcrit)) # In[ ]: demo.savefig([fig1])
def approx_error(true_func, appr_func, d=0, title=''): demo.figure(title, 'x', 'Error') plotzero() plt.plot(xgrid, appr_func(xgrid, d) - true_func(xgrid)) plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) figures.append(plt.gcf())
A.newton(x0) err_newton = err(A.x_sequence) # #### * Using Broyden's method # In[4]: A.broyden(x0) err_broyden = err(A.x_sequence) # #### * Using function iteration # # This method finds a zero of $f(x)$ by looking for a fixpoint of $g(x) = x-f(x)$. # In[5]: A.funcit(x0) err_funcit = err(A.x_sequence) # ### Plot results # In[6]: demo.figure('Convergence rates', 'Iteration', 'Log10 Error', [0, 12], [-15, 2]) plt.plot(err_newton, label="Newton's Method") plt.plot(err_broyden, label="Broyden's Method") plt.plot(err_funcit, label="Function Iteration") plt.legend(loc='lower left') demo.savefig([plt.gcf()])
# ### Setup plot # In[5]: nplot = 1000 p = np.linspace(a, b, nplot) rplot = resid(Q.c) # ### Plot effective supply # In[6]: demo.figure("Monopolist's Effective Supply Curve", 'Quantity', 'Price') plt.plot(Q(p), p) figures.append(plt.gcf()) # ### Plot residual # In[7]: demo.figure('Functional Equation Residual', 'Price', 'Residual') plt.hlines(0, a, b, 'k', '--') plt.plot(p, rplot) figures.append(plt.gcf())