You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When solving a model with two types of heterogenous households (in this case, two different levels of permanent income), it seems that the solve_impulse_nonlinear doesn't compute the proper consumption path for the two types of households.
For example, in this simple one-asset Krusell-Smith model, the variable C_low following a TFP shock is not equal to distribution * policy function. It doesn't converge back to zero and is very different from the same variable computed through solve_impulse_linear, whereas the model should be approximately linear for a small shock. I suspect it's an issue with the initial distribution used to compute the transition. I tried imposing manually ss.internals['hh_low']['Dbeg'] = ss.internals['hh_low']['D'] , etc, but it didn't solve the issue.
It also seems that the aggregate variables td_nonlin['C'] and td_lin['C'] match and are accurate, so I'm unsure where the issue comes from.
I also noted that there is no issue when setting Z_low = Z_high = 1.
import numpy as np
from sequence_jacobian import simple, create_model
from sequence_jacobian.blocks.het_block import het
from sequence_jacobian import grids, interpolate, misc
import matplotlib.pyplot as plt
def make_grid_one_asset(amax, nA, nE, rho_e, sig_e):
e_grid, pi_e, Pi = grids.markov_rouwenhorst(rho=rho_e, sigma=sig_e, N=nE)
a_grid = grids.agrid(amax=amax, n=nA)
Dbeg = np.zeros((nE, nA))
Dbeg[:,0] = pi_e
Dbeg_low = Dbeg
Dbeg_high = Dbeg
Pi_low = Pi
Pi_high = Pi
return a_grid, e_grid, Pi, Pi_low, Pi_high
def hh_init_oa(a_grid, Z, z_grid, r, sigma):
coh = (1 + r) * a_grid[np.newaxis,:] + Z * z_grid[:,np.newaxis]
Va = (1 + r) * (0.1 * coh) ** (-sigma)
return Va
@het(exogenous=['Pi'], policy='a', backward='Va', backward_init=hh_init_oa)
def hh_one_asset(Va_p, a_grid, Z, z_grid, r, beta, sigma):
uc_nextgrid = beta * Va_p
c_nextgrid = uc_nextgrid ** (-1/sigma)
coh = (1 + r) * a_grid[np.newaxis, :] + Z * z_grid[:,np.newaxis]
a = interpolate.interpolate_y(c_nextgrid + a_grid, coh, a_grid)
misc.setmin(a, a_grid[0])
c = coh - a
Va = (1 + r) * c ** (-sigma)
return Va, a, c
'''Part 1: Blocks'''
@simple
def firm(K, delta, alpha, tfp):
Y = tfp * K(-1)**alpha
r = alpha * Y / K(-1) - delta
w = (1-alpha) * Y
I = K - (1-delta) * K(-1)
return Y, r, w, I
@simple
def mkt_clearing(A, K, C, Y, I, verbose, beta):
asset_mkt = A - K
goods_mkt = Y - C - I
if verbose == True:
print('asset_mkt = ', float(asset_mkt))
print('A = ', float(A))
print('beta = ', float(beta))
print(' ')
return asset_mkt, goods_mkt
@simple
def aggregate(A_low, A_high, C_low, C_high, share_low, share_high):
A = A_low * share_low + A_high * share_high
C = C_low * share_low + C_high * share_high
return A, C
def income(e_grid, w):
z_grid = w * e_grid
return z_grid
# Combine Blocks
hh_one_asset = hh_one_asset.add_hetinputs([income, make_grid_one_asset])
to_map = ['Z', *hh_one_asset.outputs]
hh_low = hh_one_asset.remap({k: k + '_low' for k in to_map}).rename('hh_low')
hh_high = hh_one_asset.remap({k: k + '_high' for k in to_map}).rename('hh_high')
blocks = [hh_low, hh_high, firm, mkt_clearing, aggregate]
one_asset_model = create_model(blocks, name='One-Asset HANK')
calibration = {'tfp': 1,
'nE': 11, 'nA': 500, 'sigma':1,
'amax': 5_000, 'rho_e': 0.91, 'sig_e': 0.9,
'alpha':1/3, "delta":0.09,
'verbose': True, 'share_low':0.9, 'share_high':0.1}
calibration['K'] = ((0.05+calibration['delta']) / (calibration['alpha']))**(1/(calibration['alpha']-1))
calibration['Z_high'] = 1.8
# Normalize total endowment in permanent productivity to 1
calibration['Z_low'] = (1 - calibration['Z_high'] * calibration['share_high']) / calibration['share_low']
# Steady state
ss = one_asset_model.solve_steady_state(calibration, {'beta':(0.8,0.95)}, {'asset_mkt':0})
print(ss['goods_mkt']) # Check Walras law
ss['verbose']=False
# Transition
unknowns = ['K']
targets = ['asset_mkt']
T = 300
sig = 0.0005
rho = 0.15
dtfp = sig * rho ** np.arange(T)
td_nonlin = one_asset_model.solve_impulse_nonlinear(ss, unknowns, targets, {"tfp": dtfp}, internals=['hh_low', 'hh_high'])
td_lin = one_asset_model.solve_impulse_linear(ss, unknowns, targets, {"tfp": dtfp})
# This should be the same as td_nonlin['C_low'] : distribution * policy function
dC_low = np.sum(td_nonlin.internals['hh_low']['c']*(ss.internals['hh_low']['D'] + td_nonlin.internals['hh_low']['D']), axis = (1,2))
error = np.max(np.abs(dC_low - td_nonlin['C_low']))
print(error)
# Difference between solve_impulse_nonlinear and policy function * distribution
plt.plot(td_nonlin['C_low'], label = 'solve_impulse_nonlinear')
plt.plot(dC_low, linestyle = ':', label = 'policy function * distribution')
plt.legend()
plt.show()
# Difference beteen nonlinear and linear: should be approximately the same for a small shock
plt.plot(td_nonlin['C_low'],label = 'nonlinear')
plt.plot(td_lin['C_low'], linestyle = ':', label = 'linear')
plt.legend()
plt.show()
# Aggregate consumption match for linear and nonlinear
plt.plot(td_nonlin['C'],label = 'nonlinear')
plt.plot(td_lin['C'], linestyle = ':', label = 'linear')
plt.legend()
plt.show()
The text was updated successfully, but these errors were encountered:
raphaelhuleux
changed the title
Problem will solve_impulse_nonlinear with permanent type
Problem with solve_impulse_nonlinear with permanent type
May 27, 2024
Hi Raphael (infering),
I also had some problems with remap, did you try to not use remap but instead just define two independent Hh blocks (in case it's still a problem)?
Hello,
When solving a model with two types of heterogenous households (in this case, two different levels of permanent income), it seems that the
solve_impulse_nonlinear
doesn't compute the proper consumption path for the two types of households.For example, in this simple one-asset Krusell-Smith model, the variable
C_low
following a TFP shock is not equal todistribution * policy function
. It doesn't converge back to zero and is very different from the same variable computed throughsolve_impulse_linear
, whereas the model should be approximately linear for a small shock. I suspect it's an issue with the initial distribution used to compute the transition. I tried imposing manuallyss.internals['hh_low']['Dbeg'] = ss.internals['hh_low']['D']
, etc, but it didn't solve the issue.It also seems that the aggregate variables
td_nonlin['C']
andtd_lin['C']
match and are accurate, so I'm unsure where the issue comes from.I also noted that there is no issue when setting
Z_low = Z_high = 1
.The text was updated successfully, but these errors were encountered: