def solve_egm(self): # Initialize par = self.par sol = self.sol_egm # Shape parameter for the solution vector shape = (np.size(par.y), 1) # Initial guess is like a 'last period' choice - consume everything sol.m = np.tile( np.linspace(par.a_min, par.a_max, par.Na + 1), shape) # a is pre descision, so for any state consume everything. sol.c = sol.m.copy() # Consume everyting - this could be improved sol.v = util.u(sol.c, par) # Utility of consumption sol.it = 0 # Iteration counter sol.delta = 1000.0 # Difference between iterations # Iterate value function until convergence or break if no convergence while (sol.delta >= par.tol_egm and sol.it < par.max_iter): # Use last iteration to compute the continuation value # therefore, copy c and a grid from last iteration. c_next = sol.c.copy() m_next = sol.m.copy() # Call EGM function here sol = egm.solve(sol, par, c_next, m_next) # add zero consumption sol.m[:, 0] = 1.0e-4 sol.c[:, 0] = 1.0e-4
def solve_vfi(self): # Initialize par = self.par sol = self.sol_vfi # Initialize shape = (np.size(par.y), 1) # Shape to fit nr of income states sol.c = np.tile(par.grid_a.copy(), shape) # Initial guess - consume all sol.v = util.u(sol.c, par) # Utility of consumption sol.m = par.grid_m.copy( ) # Copy the exogenous asset grid for consistency (with EGM algortihm) state1 = 0 # UNEMPLOYMENT STATE state2 = 1 # EMPLOYMENT STATE sol.it = 0 # Iteration counters sol.delta = 1000.0 # Distance between iterations # Iterate untill convergence while (sol.delta >= par.tol_vfi and sol.it < par.max_iter): # Use last iteration as the continuation value. See slides if confused v_next = sol.v.copy() # Find optimal c given v_next sol = vfi.solve(sol, par, v_next, state1, state2) # Update iteration parameters sol.it += 1 sol.delta = max(max(abs(sol.v[0] - v_next[0])), max(abs(sol.v[1] - v_next[1]))) # Update this maybe
def solve_vfi(self): # Initialize par = self.par sol = self.sol_vfi # Initialize shape = (np.size(par.y), 1) # Shape to fit nr of income states sol.c = np.tile(par.grid_m.copy(), shape) # Initial guess - consume all sol.v = util.u(sol.c, par) # Utility of consumption sol.m = par.grid_m sol.it = 0 # Iteration counters sol.delta = 1000.0 # Distance between iterations # Iterate untill convergence while (sol.delta >= par.tol_vfi and sol.it < par.max_iter): # Use last iteration as the continuation value. v_next = sol.v.copy() # Find optimal c given v_next sol = vfi.solve(sol, par, v_next) # Update iteration parameters sol.it += 1 sol.delta = max(max(abs(sol.v[0] - v_next[0])), max(abs(sol.v[1] - v_next[1]))) # Update this maybe
def solve_VFI_2d(par): # Initialize solution class class sol: pass shape = (np.size(par.y), 1) sol.c = np.tile( par.grid_a.copy(), shape) # Initial guess is to consume everything for each state sol.v = util.u(sol.c, par) # Utility of consumption sol.a = par.grid_a.copy( ) # Copy the exogenous asset grid for consistency (with EGM algortihm) state1 = 1 # UNEMPLOYMENT STATE Used as boolean in "value_of_choice" - Defined here for readability state2 = 0 # EMPLOYMENT STATE Used as boolean in "value_of_choice" - Defined here for readability sol.it = 0 # Iteration counter sol.delta = 1000.0 # Difference between two iterations # Iterate value function until convergence or break if no convergence while (sol.delta >= par.tol_vfi and sol.it < par.max_iter): # Use last iteration as the continuation value. See slides if confused v_next = sol.v.copy() # Loop over asset grid for i_a, a in enumerate(par.grid_a): # FUNCTIONS BELOW CAN BE WRITTEN AS LOOP - for i=0,1 - AND BE STORED IN AN ARRAY/LIST WITH TWO ENTRIES - a la res[i]=optimize.minimize.... # Minimize the minus the value function wrt consumption conditional on unemployment state obj_fun = lambda x: -value_of_choice_2d(x, a, par.grid_a, v_next[ 0, :], par, state1) res_1 = optimize.minimize_scalar(obj_fun, bounds=[0, a + 1.0e-4], method='bounded') # Minimize the minus the value function wrt consumption conditional on employment state obj_fun = lambda x: -value_of_choice_2d(x, a, par.grid_a, v_next[ 1, :], par, state2) res_2 = optimize.minimize_scalar(obj_fun, bounds=[0, a + 1.0e-4], method='bounded') # Unpack solutions # State 1 sol.v[0, i_a] = -res_1.fun sol.c[0, i_a] = res_1.x # State 2 sol.v[1, i_a] = -res_2.fun sol.c[1, i_a] = res_2.x # Update iteration parameters sol.it += 1 sol.delta = max(max(abs(sol.v[0] - v_next[0])), max(abs(sol.v[1] - v_next[1]))) # check this, is this optimal return sol
def solve(sol, par, c_next, m_next): # Copy last iteration of the value function v_old = sol.v.copy() # Expand exogenous asset grid a = np.tile(par.grid_a, np.size(par.y)) # 2d end-of-period asset grid # m_plus = (1+par.r) # Loop over exogneous states (post decision states) for a_i, a in enumerate(par.grid_a): #Next periods assets and consumption m_plus = (1 + par.r) * a + np.transpose( par.y) # Transpose for dimension to fit # Interpolate next periods consumption - can this be combined? c_plus_1 = tools.interp_linear_1d(m_next[0, :], c_next[0, :], m_plus) # State 1 c_plus_2 = tools.interp_linear_1d(m_next[1, :], c_next[1, :], m_plus) # State 2 #Combine into a vector. Rows indicate income state, columns indicate asset state c_plus = np.vstack((c_plus_1, c_plus_2)) # Marginal utility marg_u_plus = util.marg_u(c_plus, par) # Compute expectation below av_marg_u_plus = np.array([ par.P[0, 0] * marg_u_plus[0, 0] + par.P[0, 1] * marg_u_plus[1, 1], par.P[1, 1] * marg_u_plus[1, 1] + par.P[1, 0] * marg_u_plus[0, 0] ]) # Add optimal consumption and endogenous state sol.c[:, a_i + 1] = util.inv_marg_u( (1 + par.r) * par.beta * av_marg_u_plus, par) sol.m[:, a_i + 1] = a + sol.c[:, a_i + 1] sol.v = util.u(sol.c, par) #Compute value function and update iteration parameters sol.delta = max(max(abs(sol.v[0] - v_old[0])), max(abs(sol.v[1] - v_old[1]))) sol.it += 1 # sol.delta = max( max(abs(sol.c[0] - c_next[0])), max(abs(sol.c[1] - c_next[1]))) return sol
def value_of_choice_2d(x, a, a_next, v_next, par, state): # Unpack consumption (choice variable) c = x # Intialize expected continuation value Ev_next = 0.0 # Compute value of choice conditional on being in state 1 (unemployment state) ###### VECTORIZE THIS if state == 1: # Loop over each possible state for i in [0, 1]: # Next periods state for each income level a_plus = par.y[i] + (1 + par.r) * (a - c) #Interpolate continuation given state a_plus v_plus = tools.interp_linear_1d_scalar(a_next, v_next, a_plus) # Append continuation value to calculate expected value Ev_next += par.P[0, i] * v_plus # Compute value of choice conditional on being in state 2 (employment state) else: # Loop over each possible state ###### VECTORIZE THIS for i in [0, 1]: # Next periods state for each income level a_plus = par.y[i] + (1 + par.r) * (a - c) #Interpolate continuation given state a_plus v_plus = tools.interp_linear_1d_scalar(a_next, v_next, a_plus) # Append continuation value to calculate expected value Ev_next += par.P[1, i] * v_plus # Value of choice v_guess = util.u(c, par) + par.beta * Ev_next return v_guess
def solve_VFI(par): # Initialize solution class class sol: pass sol.c = par.grid_a.copy() # Initial guess is to consume everything sol.v = util.u(sol.c, par) # Utility of consumption sol.a = par.grid_a.copy( ) # Copy the exogenous asset grid for consistency (with EGM algortihm) -- Jeg kan se, at denne initialisering er nødvendig for at kunne # plotte på et a-grid, men vi initialisere jo allerede griddet i setup(), så måske kan man kalde par.grid_a direkte, når der plottes? Har prøvet, men den klager. sol.it = 0 # Iteration counter sol.delta = 1000.0 # Difference between two iterations # Iterate value function until convergence or break if no convergence while (sol.delta >= par.tol_vfi and sol.it < par.max_iter): # Use last iteration as the continuation value. See slides if confused v_next = sol.v.copy() # Loop over asset grid for i_a, a in enumerate(par.grid_a): # Minimize the minus the value function wrt consumption obj_fun = lambda x: -value_of_choice(x, a, par.grid_a, v_next, par) res = optimize.minimize_scalar(obj_fun, bounds=[0, a + 1.0e-4], method='bounded') # Unpack solution sol.v[i_a] = -res.fun sol.c[i_a] = res.x # Update iteration parameters sol.it += 1 sol.delta = max(abs(sol.v - v_next)) return sol
def value_of_choice(x, a, a_next, v_next, par): # Unpack consumption (choice variable) c = x # Intialize expected continuation value Ev_next = 0.0 # Loop over each possible state for i in [0, 1]: # Next periods state for each income level a_plus = par.y[i] + (1 + par.r) * (a - c) #Interpolate continuation given state a_plus v_plus = tools.interp_linear_1d_scalar(a_next, v_next, a_plus) # Append continuation value to calculate expected value Ev_next += par.Pi[i] * v_plus # Value of choice v_guess = util.u(c, par) + par.beta * Ev_next return v_guess
def solve(par, sol): ## SETUP ## # Asst grid N = par.Nm m = par.grid_m.transpose() # N x 1 vector dm = (par.m_max - par.m_min) / (par.Nm - 1) # Stepsize on m grid mm = np.tile(np.array([m]), (2, 1)) mm = mm.transpose() # Write this better # Income y = par.y yy = y * np.ones((N, 2)) # 2 dimensional income grid Delta_step = 1000 # Stepsize delta = 1000 # Distance between iterations - MADS it = 0 # Iteration counter # Initialize v0 = np.zeros((N, 2)) dVf = np.zeros((N, 2)) dVb = np.zeros((N, 2)) c = np.zeros((N, 2)) u = np.zeros((N, 2)) V_n = np.zeros((N, 2, par.max_iter)) A = sparse.eye(2 * N, format='csr') # Transition matrix # Transition matrix for income y_transition = sparse.kron(par.pi, sparse.eye(par.Nm), format="csr") # Initial guess of value function v0[:, 0] = util.u(yy[:, 0] + par.r * mm[:, 0], par) / par.rho v0[:, 1] = util.u(yy[:, 1] + par.r * mm[:, 1], par) / par.rho v = v0 while (delta >= par.tol_fd and it < par.max_iter): # Redefine V = v V_n[:, :, it] = V # Forward difference dVf[:N - 1, :] = (V[1:N, :] - V[0:N - 1, :]) / dm dVf[N - 1, :] = util.marg_u( y + par.r * mm[N - 1, :], par ) #will never be used, but impose state constraint a<=amax just in case # Backward difference dVb[1:, :] = ((V[1:N, :] - V[0:N - 1, :])) / dm dVb[0, :] = util.marg_u(y + par.r * mm[0, :], par) # state constraint boundary condition I_concave = dVb > dVf #consumption and savings with forward difference cf = util.inv_marg_u( dVf, par) # Take inverse marginal utility of value function (c foc) ssf = yy + par.r * mm - cf # Savings from forward difference #consumption and savings with backward difference cb = util.inv_marg_u(dVb, par) ssb = yy + par.r * mm - cb #consumption and derivative of value function at steady state c0 = yy + par.r * mm dV0 = util.marg_u(c0, par) # Upwind method makes a choice of forward or backward differences based on the sign of the drift If = ssf > 0 #positive drift --> forward difference Ib = ssb < 0 #negative drift --> backward difference I0 = (1 - If - Ib) #at steady state dV_upwind = dVf * If + dVb * Ib + dV0 * I0 c = util.inv_marg_u(dV_upwind, par) # Utility of choice u = util.u(c, par) # Utility without car # Terms to be put into the A matrix X = -np.minimum(ssb, 0) / dm Y = -np.maximum(ssf, 0) / dm + np.minimum(ssb, 0) / dm Z = np.maximum(ssf, 0) / dm Z_helper = np.vstack((np.array([0, 0]), Z)) # Construct A matrix A1 = sparse.eye(N, format='csr') * 0 # Intialize sparse zero mat A1 += sparse.spdiags(Y[:, 0], 0, N, N) A1 += sparse.spdiags(X[1:, 0], -1, N, N) A1 += sparse.spdiags(Z_helper[:N - 2, 0], 1, N, N) A2 = sparse.eye(N, format='csr') * 0 # Intialize sparse zero mat A2 += sparse.spdiags(Y[:, 1], 0, N, N) A2 += sparse.spdiags(X[1:, 1], -1, N, N) A2 += sparse.spdiags(Z_helper[:N - 2, 1], 1, N, N) # Stack A1 and A2 block_helper = sparse.eye(N, format='csr') * 0 A_upper = sparse.hstack([A1, block_helper], format='csr') A_lower = sparse.hstack([block_helper, A2], format='csr') A = sparse.vstack( [A_upper, A_lower], format='csr' ) + y_transition # This is the transition matrix used for the problem # Write a check for the row sum of A, should be zero # B matrix B = (par.rho + 1 / Delta_step) * sparse.eye(2 * N) - A # Stack utility vector into one long column vector u_stacked = np.hstack(([u[:, 0]], [u[:, 1]])).transpose() V_stacked = np.hstack(([V[:, 0]], [V[:, 1]])).transpose() b = u_stacked + V_stacked / Delta_step # Solve system V_stacked = spsolve(B, b) V_old = V.copy() V[:, 0] = V_stacked[:N] V[:, 1] = V_stacked[N:2 * N] # np.hstack((V_stacked[:N], V_stacked[N:2*N-1])) Vchange = V - V_old v = V delta = abs( max(max(Vchange[0, :], key=abs), max(Vchange[1, :], key=abs))) it += 1 # Unpack solution sol.dV = dV_upwind.transpose() sol.v = v.transpose() sol.c = c.transpose() sol.m = m return sol
def solve(sol, par, c_next, m_next): # Copy last iteration of the value function v_old = sol.v.copy() # Expand exogenous asset grid a = np.tile(par.grid_a, np.size(par.y)) # does this work? m_plus = (1 + par.r) # Loop over exogneous states (post decision states) for a_i, a in enumerate(par.grid_a): #Next periods assets and consumption m_plus = (1 + par.r) * a + np.transpose( par.y) # Transpose for dimension to fit # Interpolate next periods consumption - can this be combined? c_plus_1 = tools.interp_linear_1d(m_next[0, :], c_next[0, :], m_plus) # State 1 c_plus_2 = tools.interp_linear_1d(m_next[1, :], c_next[1, :], m_plus) # State 2 #Combine into a vector. Rows indicate income state, columns indicate asset state c_plus = np.vstack((c_plus_1, c_plus_2)) # 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) # Add optimal consumption and endogenous state sol.c[:, a_i + 1] = util.inv_marg_u( (1 + par.r) * par.beta * av_marg_u_plus, par) sol.m[:, a_i + 1] = a + sol.c[:, a_i + 1] sol.v = util.u(sol.c, par) #Compute valu function and update iteration parameters sol.delta = max(max(abs(sol.v[0] - v_old[0])), max(abs(sol.v[1] - v_old[1]))) sol.it += 1 # sol.delta = max( max(abs(sol.c[0] - c_next[0])), max(abs(sol.c[1] - c_next[1]))) return sol ## Attempt at vectorizing the code # def solve_vec(sol, par, c_next, m_next): # # Copy last iteration of the value function # v_old = sol.v.copy() # # Expand exogenous asset grid # shape = (np.size(par.y),1) # a = np.tile(par.grid_a, shape) # does this work? # y_help = np.array([par.y]) # y_help = np.transpose(y_help) # y = np.tile(y_help, (1,par.Na)) # m_plus = (1+par.r)*a + y # # m_plus = (1+par.r)*a + np.transpose(par.y) # # Interpolate next periods consumption # c_plus_1 = tools.interp_linear_1d(m_next[0,:], c_next[0,:], m_plus[0,:]) # State 1 # c_plus_2 = tools.interp_linear_1d(m_next[1,:], c_next[1,:], m_plus[1,:]) # State 2 # #Combine into a vector. Rows indicate income state, columns indicate asset state # c_plus = np.vstack((c_plus_1, c_plus_2)) # # Marginal utility # marg_u_plus = util.marg_u(c_plus,par) # av_marg_u_plus = np.sum(par.P*marg_u_plus) # av_marg_u_plus = np.sum(par.P*marg_u_plus, axis = 1) # Dot product by row (axis = 1) # # Add optimal consumption and endogenous state # sol.c = util.inv_marg_u((1+par.r)*par.beta*av_marg_u_plus,par) # sol.m = a + sol.c[:,a_i+1] # sol.v = util.u(sol.c,par) # Loop over exogneous states (post decision states) for a_i, a in enumerate(par.grid_a): #Next periods assets and consumption m_plus = (1 + par.r) * a + np.transpose( par.y) # Transpose for dimension to fit # Interpolate next periods consumption - can this be combined? c_plus_1 = tools.interp_linear_1d(m_next[0, :], c_next[0, :], m_plus) # State 1 c_plus_2 = tools.interp_linear_1d(m_next[1, :], c_next[1, :], m_plus) # State 2 #Combine into a vector. Rows indicate income state, columns indicate asset state c_plus = np.vstack((c_plus_1, c_plus_2)) # 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) # Add optimal consumption and endogenous state sol.c[:, a_i + 1] = util.inv_marg_u( (1 + par.r) * par.beta * av_marg_u_plus, par) sol.m[:, a_i + 1] = a + sol.c[:, a_i + 1] sol.v = util.u(sol.c, par) #Compute valu function and update iteration parameters sol.delta = max(max(abs(sol.v[0] - v_old[0])), max(abs(sol.v[1] - v_old[1]))) sol.it += 1 # sol.delta = max( max(abs(sol.c[0] - c_next[0])), max(abs(sol.c[1] - c_next[1]))) return sol