by Fedor Iskhakov, ANU
Description: Fastest and most accurate solution methods for consumption-savings model. Class of models solvable by EGM. Generalizations of EGM method.
Most accurate solution method for consumption-savings problem we have so far?
EGM on the other hand: no root-finding operations!
FOC: $ \quad u'(c^\star) - \beta R \mathbb{E}_{y} V'\big(R(M-c^\star)+\tilde{y}\big) = 0 $
Envelope theorem: $ \quad V'(M) = \beta R \mathbb{E}_{y} V'\big(R(M-c^\star)+\tilde{y}\big) $
Euler equation:
$$ u'\big(c^\star(M)\big) = \beta R \mathbb{E}_{y} u'\big(c^\star\big(\underset{=M'}{\underbrace{R[M-c^\star(M)]+\tilde{y}}}\big)\big) $$(see video 39)
Let $ A $ denote end-of-period wealth = wealth after consumption (savings)
Timing of the model:
$$ M \rightarrow c(M) \rightarrow A = M-c(M) \rightarrow M' = R(M-c(M)) + \tilde{y} = RA + \tilde{y} $$$$ 0 \le c \le M \; \Rightarrow \; 0 \le A = M-c \le M $$Recall Coleman-Reffett operator $ K(c)(M) : \mathcal{P} \rightarrow \mathcal{P} $
Standard implementation:
EGM is time iterations solver with a much more efficient implementation of Coleman-Reffett operator
consumption $ c_j $ and the endogenous point of wealth $ M_j = A_j+c_j $
updated policy function $ c_i(M) $
Given point $ A_j $ on the grid over $ A $:
%clear # clear notebook memory
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
%matplotlib inline
beta,R,y = 0.95,1.,0. # fundamentals (cake eating)
Mbar,ngrid = 10,5 # technical parameters
u = lambda c: np.log(c) # utility function
mu = lambda c: 1/c # marginal utility function
imu = lambda u: 1/u # inverse marginal utility function
A = np.linspace(0,Mbar,ngrid) # What are the bounds of A?
c0 = np.array([0,Mbar])
M0 = np.array([0,Mbar])
# set up plotting
fig, ax = plt.subplots(1,3,figsize=(14,6))
for axi in ax:
axi.grid(b=True, which='both', color='0.65', linestyle='-')
ax[0].set_title('consumption c(A)')
ax[1].set_title('wealth M(A)')
ax[2].set_title('consumption c(M)')
ax[0].set_xlabel('Savings (post decision state) A')
ax[1].set_xlabel('Savings (post decision state) A')
ax[2].set_xlabel('Wealth M')
# make colors generator
# https://stackoverflow.com/questions/37890412/increment-matplotlib-color-cycle
from itertools import cycle
prop_cycle = plt.rcParams['axes.prop_cycle']
colors = cycle(prop_cycle.by_key()['color'])
def plot_iter(a,m,c):
color = next(colors)
ax[0].plot(a,c,linewidth=0.5,c=color)
ax[1].plot(a,m,linewidth=0.5,c=color)
ax[2].plot(m,c,linewidth=0.5,c=color)
ax[0].scatter(a,c,s=11,c=color)
ax[1].scatter(a,m,s=11,c=color)
ax[2].scatter(m,c,s=11,c=color)
return fig
# Iteration 0
plot_iter(np.full(2,np.nan),M0,c0)
# Iteration 1
policy = interpolate.interp1d(M0,c0,kind='slinear',fill_value="extrapolate") # interpolation function for policy
M1 = np.full(ngrid,np.nan)
c1 = np.full(ngrid,np.nan)
for j,aj in enumerate(A):
Mpr = max(R*aj+y,1e-10) # next period wealth
cpr = policy(Mpr) # next period consumption
c1[j] = imu( beta*R*mu(cpr) ) # inverse Euler
M1[j] = aj + c1[j] # endogenous wealth
plot_iter(A,M1,c1) # returns fig object, plotted automatically
# Iteration 2
policy = interpolate.interp1d(M1,c1,kind='slinear',fill_value="extrapolate") # interpolation function for policy
M2 = np.full(ngrid,np.nan)
c2 = np.full(ngrid,np.nan)
for j,aj in enumerate(A):
Mpr = max(R*aj+y,1e-10) # next period wealth
cpr = policy(Mpr) # next period consumption
c2[j] = imu( beta*R*mu(cpr) ) # inverse Euler
M2[j] = aj + c2[j] # endogenous wealth
plot_iter(A,M2,c2) # returns fig object, plotted automatically
Proposition If utility function $ u(c) $ in the consumption-savings model is monotone and concave, then end-of-period wealth $ A=M-c $ is non-decreasing in M.
%clear # clear notebook memory
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
%matplotlib inline
beta,R,y = 0.95,1.05,1 # fundamentals
Mbar,ngrid = 10,5 # technical parameters
u = lambda c: np.log(c) # utility function
mu = lambda c: 1/c # marginal utility function
imu = lambda u: 1/u # inverse marginal utility function
A = np.linspace(0,Mbar,ngrid) # What are the bounds of A?
c0 = np.array([0,Mbar])
M0 = np.array([0,Mbar])
# set up plotting
fig, ax = plt.subplots(1,3,figsize=(14,6))
for axi in ax:
axi.grid(b=True, which='both', color='0.65', linestyle='-')
ax[0].set_title('consumption c(A)')
ax[1].set_title('wealth M(A)')
ax[2].set_title('consumption c(M)')
ax[0].set_xlabel('Savings (post decision state) A')
ax[1].set_xlabel('Savings (post decision state) A')
ax[2].set_xlabel('Wealth M')
# make colors generator
# https://stackoverflow.com/questions/37890412/increment-matplotlib-color-cycle
from itertools import cycle
prop_cycle = plt.rcParams['axes.prop_cycle']
colors = cycle(prop_cycle.by_key()['color'])
def plot_iter(a,m,c):
color = next(colors)
ax[0].plot(a,c,linewidth=0.5,c=color)
ax[1].plot(a,m,linewidth=0.5,c=color)
ax[2].plot(m,c,linewidth=0.5,c=color)
ax[0].scatter(a,c,s=11,c=color)
ax[1].scatter(a,m,s=11,c=color)
ax[2].scatter(m,c,s=11,c=color)
return fig
# Iteration 0
plot_iter(np.full(2,np.nan),M0,c0)
# Iteration function
Aex = np.full(ngrid+1,np.nan)
Aex[1:] = A
def iter(M0,c0):
policy = interpolate.interp1d(M0,c0,kind='slinear',fill_value="extrapolate") # interpolation function for policy
M1 = np.full(ngrid+1,np.nan)
c1 = np.full(ngrid+1,np.nan)
M1[0] = c1[0] = 0 # add one point at the origin!
for j,aj in enumerate(A):
Mpr = max(R*aj+y,1e-10) # next period wealth
cpr = policy(Mpr) # next period consumption
c = imu( beta*R*mu(cpr) ) # inverse Euler
M = aj + c # endogenous wealth
M1[j+1] = M # save to array
c1[j+1] = c
pt = plot_iter(Aex,M1,c1) # returns fig object, plotted automatically
return M1,c1,pt
M1,c1,pt = iter(M0,c0)
pt
M,c,pt = iter(M1,c1)
pt
for i in range(10):
M,c,pt = iter(M,c)
pt
Rather small class, although many important models in micro and macro economics are included
Multiple dimensions: hard because irregular grids in multiple dimensions
Non-convex problems: hard because Euler equation is not a sufficient condition any longer