def solve(sol, par): grid_last = np.linspace(par.m_min, par.m_max, par.Nm + par.N_bottom) if np.size(sol.c[0, :]) >= (par.Nm + par.N_bottom - 1): grid = grid_last else: grid = par.grid_m for n in range(2): # Loop over housing state for m_i, m in enumerate(grid): # Loop over exogeneous asset grid if n == 0: # Cannot buy a house if m < par.ph: sol.c[n, m_i] = m sol.h[n, m_i] = 0 # Can buy a house else: u_dif = util.u_h(m, 0, par) - util.u_h( m - par.ph, 1, par) # dif in utility from choice if u_dif >= 0: # If not buying a house is optimal sol.c[n, m_i] = m sol.h[n, m_i] = 0 else: # If buying a house is optimal sol.c[n, m_i] = m - par.ph sol.h[n, m_i] = 1 if n == 1: u_dif = util.u_h(m, 1, par) - util.u_h( m + par.ph, 0, par) # dif in utility from choice if u_dif >= 0: sol.c[n, m_i] = m sol.h[n, m_i] = 1 else: sol.c[n, m_i] = m + par.ph sol.h[n, m_i] = 0 # Compute value of choice sol.v[n, m_i] = util.u_h(sol.c[n, m_i], sol.h[n, m_i], par)
def solve(sol, par): for n in range(2): # Loop over housing state for m_i, m in enumerate(par.grid_m): # Loop over exogeneous asset grid if n == 0: # Cannot buy a house if m < par.ph: sol.c[n, m_i] = m sol.h[n, m_i] = 0 # Can buy a house else: u_dif = util.u_h(m, 0, par) - util.u_h( m - par.ph, 1, par) # dif in utility from choice if u_dif >= 0: # If not buying a house is optimal sol.c[n, m_i] = m sol.h[n, m_i] = 0 else: # If buying a house is optimal sol.c[n, m_i] = m - par.ph sol.h[n, m_i] = 1 if n == 1: u_dif = util.u_h(m, 1, par) - util.u_h( m + par.ph, 0, par) # dif in utility from choice if u_dif >= 0: sol.c[n, m_i] = m sol.h[n, m_i] = 1 else: sol.c[n, m_i] = m + par.ph sol.h[n, m_i] = 0 # Compute value of choice sol.v[n, m_i] = util.u_h(sol.c[n, m_i], sol.h[n, m_i], par)
def obj_keep( arg, n, m, v_next, par, m_next ): # I have added m_next to the interpolation since it changes throughout iterations # Unpack c = arg # End of period assets m_plus = (1 + par.r) * (m - c) + par.y1 # Continuation value v_plus = tools.interp_linear_1d_scalar(m_next, v_next, m_plus) # Value of choice value = util.u_h(c, n, par) + par.beta * v_plus return value
def obj_keep(arg, n, m, v_next, par): # Unpack c = arg # End of period assets m_plus = (1 + par.r) * (m - c) + par.y1 # Continuation value v_plus = tools.interp_linear_1d_scalar(par.grid_m, v_next, m_plus) # Value of choice value = util.u_h(c, n, par) + par.beta * v_plus return value #def solve_NEGM(par,sol): # a. next-period cash-on-hand m_plus = par['R'] * par['grid_a'] + par['y'] # b. post-decision value function sol['w_vec'] = np.empty(m_plus.size) linear_interp.interp_1d_vec(par['grid_m'], sol['v_next'], m_plus, sol['w_vec']) # c. post-decision marginal value of cash c_next_interp = np.empty(m_plus.size) linear_interp.interp_1d_vec(par['grid_m'], sol['c_next'], m_plus, c_next_interp) q = par['beta'] * par['R'] * marg_u(c_next_interp, par) # d. EGM sol['c_vec'] = inv_marg_u(q, par) sol['m_vec'] = par['grid_a'] + sol['c_vec'] myupperenvelope = upperenvelope.create(u) # where is the utility function # b. apply upperenvelope c_ast_vec = np.empty(par['grid_m'].size) # output v_ast_vec = np.empty(par['grid_m'].size) # output myupperenvelope(par['grid_a'], sol['m_vec'], sol['c_vec'], sol['w_vec'], par['grid_m'], c_ast_vec, v_ast_vec, par['rho']) return #sol from upperenvelope
def solve_dc(sol, par, v_next, c_next, h_next, m_next): # a. Solve the keeper problem shape = ( 2, np.size(par.grid_a) ) # Row for each state of housing and colums for exogenous end-of-period assets grid # Intialize v_keep = np.zeros(shape) + np.nan c_keep = np.zeros(shape) + np.nan h_keep = np.zeros(shape) + np.nan # Loop over housing states for n in range(2): # Loop over exogenous states (post decision states) for a_i, a in enumerate(par.grid_a): #Next periods assets and consumption m_plus = (1 + par.r) * a + par.y1 # Interpolate next periods consumption c_plus = tools.interp_linear_1d_scalar(m_next[n, :], c_next[n, :], m_plus) # Marginal utility marg_u_plus = util.marg_u(c_plus, par) #av_marg_u_plus = np.sum(par.P*marg_u_plus, axis = 1) # Dot product by row (axis = 1) #### no average # Add optimal consumption and endogenous state using Euler equation c_keep[n, a_i] = util.inv_marg_u( (1 + par.r) * par.beta * marg_u_plus, par) #### no average # v_keep[n,a_i] = obj_keep(c_keep[n,a_i], n, c_keep[n,a_i] + a, v_next[n,:], par, m_next[n, :]) # The line below is faster and more precise as it avoids numerical errors v_keep[n, a_i] = util.u_h( c_keep[n, a_i], n, par) + par.beta * tools.interp_linear_1d_scalar( m_next[n, :], v_next[n, :], m_plus) h_keep[n, a_i] = n ### UPPER ENVELOPE ### c_keep, v_keep, m_grid = upper_envelope(c_keep, v_keep, v_next, m_next, shape, par) ### Add points at the constraints ### m_con = np.array([ np.linspace(0 + 1e-8, m_grid[0, 0] - 1e-4, par.N_bottom), np.linspace(0 + 1e-8, m_grid[1, 0] - 1e-4, par.N_bottom) ]) c_con = m_con.copy() v_con_0 = [ obj_keep(c_con[0, i], 0, m_con[0, i], v_next[0, :], par, m_next[0, :]) for i in range(par.N_bottom) ] # From N_bottom or whole v_con_1 = [ obj_keep(c_con[1, i], 1, m_con[1, i], v_next[1, :], par, m_next[1, :]) for i in range(par.N_bottom) ] # From N_bottom or whole v_con = np.array([v_con_0, v_con_1]) # initialize new larger keeper containers new_shape = (2, np.size(par.grid_a) + par.N_bottom) c_keep_append = np.zeros(new_shape) + np.nan v_keep_append = np.zeros(new_shape) + np.nan m_grid_append = np.zeros(new_shape) + np.nan # append for i in range(2): c_keep_append[i, :] = np.append(c_con[i, :], c_keep[i, :]) v_keep_append[i, :] = np.append(v_con[i, :], v_keep[i, :]) m_grid_append[i, :] = np.append(m_con[i, :], m_grid[i, :]) # b. Solve the adjuster problem # Initialize v_adj = np.zeros(new_shape) + np.nan c_adj = np.zeros(new_shape) + np.nan h_adj = np.zeros(new_shape) + np.nan # Loop over housing state for n in range(2): # Housing choice is reverse of state n if adjusting h = 1 - n # Loop over asset grid for a_i, m in enumerate(m_grid_append[n]): # endogenous grid # If adjustment is not possible if n == 0 and m < par.ph: v_adj[n, a_i] = -np.inf c_adj[n, a_i] = 0 h_adj[n, a_i] = np.nan else: # Assets available after adjusting if n == 1: p = par.p1 else: p = par.ph x = m - p * (h - n) # Value of choice v_adj[n, a_i] = tools.interp_linear_1d_scalar( m_grid_append[h], v_keep_append[h, :], x) c_adj[n, a_i] = tools.interp_linear_1d_scalar( m_grid_append[h], c_keep_append[h, :], x) h_adj[n, a_i] = h # c. Combine solutions # Loop over asset grid again for n in range(2): for a_i, m in enumerate(m_grid_append[n]): # endogenous grid # If keeping is optimal if v_keep_append[n, a_i] > v_adj[n, a_i]: sol.v[n, a_i] = v_keep_append[n, a_i] sol.c[n, a_i] = c_keep_append[n, a_i] sol.h[n, a_i] = n sol.m[n, a_i] = m_grid_append[n, a_i] # added # If adjusting is optimal else: sol.v[n, a_i] = v_adj[n, a_i] sol.c[n, a_i] = c_adj[n, a_i] sol.h[n, a_i] = 1 - n sol.m[n, a_i] = m_grid_append[n, a_i] # added for i in range(2): sol.delta_save[i, sol.it] = max(abs(sol.v[i] - v_next[i])) return sol