def house(sol,z_plus,t,par): # Prepare a = np.repeat(par.grid_a[t],par.Nxi) # Compute a grid for each node for integration - remove # Next period states m_plus = par.R*a + par.W # Here, not considering housing shape = (2,m_plus.size) # One row for each choice of housing # Intialize v_plus = np.nan+np.zeros(shape) c_plus = np.nan+np.zeros(shape) marg_u_plus = np.nan+np.zeros(shape) for i in range(2): # Range keeping house (i = 1) and selling house (i = 0) # Choice specific house gain gain = (1-i)*par.ph # Choice specific value v_plus[i,:]=tools.interp_linear_1d(sol.m[t+1,i,par.N_bottom:],sol.v[t+1,i,par.N_bottom:], m_plus + gain) #Choice specific consumption c_plus[i,:] = tools.interp_linear_1d(sol.m[t+1,i,par.N_bottom:],sol.c[t+1,i,par.N_bottom:], m_plus + gain) # Choice specific Marginal utility marg_u_plus[i,:] = marg_util(c_plus[i,:],par) # Expected value V_plus, prob = logsum(v_plus[0],v_plus[1],par.sigma_eta) # logsum computes the optimal of housing in the next period w_raw = V_plus avg_marg_u_plus = prob[0,:]*marg_u_plus[0] + prob[1,:]*marg_u_plus[1] #Expected margnal utility dependend on choice probabilities return w_raw, avg_marg_u_plus
def retired(sol, z_plus, t, par): # Prepare w = np.ones((par.Na)) a = par.grid_a[t, :] xi = np.zeros(par.Na) # Next period states m_plus = par.R * a + par.W * xi #value w_raw = tools.interp_linear_1d(sol.m[t + 1, z_plus, par.N_bottom:], sol.v[t + 1, z_plus, par.N_bottom:], m_plus) # Consumption c_plus = tools.interp_linear_1d(sol.m[t + 1, z_plus, par.N_bottom:], sol.c[t + 1, z_plus, par.N_bottom:], m_plus) #Marginal utility marg_u_plus = marg_util(c_plus, par) #Expected average marginal utility avg_marg_u_plus = marg_u_plus * w return w_raw, avg_marg_u_plus
def value_of_choice(m, c, h, t, sol, par): # Next period ressources a = np.repeat(m - c, (par.xi.size)) m_plus = par.R * a + par.W # Note: Siden vi laver upper-envelope på både house og no-house, så skal vi indføre et if-statement. # Next-period value if you choose no-house today if h == 0: v_plus0 = tools.interp_linear_1d(sol.m[t + 1, 0, par.N_bottom:], sol.v[t + 1, 0, par.N_bottom:], m_plus) # No house v_plus1 = tools.interp_linear_1d(sol.m[t + 1, 1, par.N_bottom:], sol.v[t + 1, 1, par.N_bottom:], m_plus - par.ph) # House # Next-period value if you choose house today. else: v_plus0 = tools.interp_linear_1d(sol.m[t + 1, 0, par.N_bottom:], sol.v[t + 1, 0, par.N_bottom:], m_plus + par.ph) # No house v_plus1 = tools.interp_linear_1d(sol.m[t + 1, 1, par.N_bottom:], sol.v[t + 1, 1, par.N_bottom:], m_plus) # House V_plus, _ = logsum(v_plus0, v_plus1, par.sigma_eta) # Find the maximum of v0 and v1 # This period value v = util(c, h, par) + par.beta * V_plus return v
def simulate(par, sol): # Initialize class sim: pass shape = (par.simT, par.simN) sim.m = np.nan + np.zeros(shape) sim.c1 = np.nan + np.zeros(shape) sim.c2 = np.nan + np.zeros(shape) sim.a = np.nan + np.zeros(shape) sim.p = np.nan + np.zeros(shape) sim.y = np.nan + np.zeros(shape) # Shocks shocki = np.random.choice( par.Nshocks, (par.T, par.simN), replace=True, p=par.w) #draw values between 0 and Nshocks-1, with probability w sim.psi = par.psi_vec[shocki] sim.xi = par.xi_vec[shocki] #check it has a mean of 1 assert (abs(1 - np.mean(sim.xi)) < 1e-4), 'The mean is not 1 in the simulation of xi' assert (abs(1 - np.mean(sim.psi)) < 1e-4), 'The mean is not 1 in the simulation of psi' # Initial values sim.m[0, :] = par.sim_mini sim.p[0, :] = 0.0 # Simulation for t in range(par.simT): sim.c1[t, :] = tools.interp_linear_1d(sol.m[t, :], sol.c1[t, :], sim.m[t, :]) sim.c2[t, :] = tools.interp_linear_1d(sol.m[t, :], sol.c2[t, :], sim.m[t, :]) sim.a[t, :] = sim.m[t, :] - sim.c1[t, :] - sim.c2[t, :] if t < par.simT - 1: if t + 1 > par.Tr: #after pension sim.m[t + 1, :] = par.R * sim.a[t, :] / (par.G) + 1 sim.p[t + 1, :] = np.log(par.G) + sim.p[t, :] sim.y[t + 1, :] = sim.p[t + 1, :] else: #before pension sim.m[t + 1, :] = par.R * sim.a[t, :] / ( par.G * sim.psi[t + 1, :]) + sim.xi[t + 1, :] sim.p[t + 1, :] = np.log(par.G) + sim.p[t, :] + np.log( sim.psi[t + 1, :]) sim.y[t + 1, :] = sim.p[t + 1, :] + np.log(sim.xi[t + 1, :]) #Renormalize sim.P = sim.p sim.Y = sim.y sim.M = sim.m * sim.P sim.C1 = sim.c1 * sim.P sim.C2 = sim.c2 * sim.P sim.A = sim.a * sim.P return sim
def simulate (self): par = self.par sol = self.sol sim = self.sim # Initialize shape = (par.simT, par.simN) sim.m = np.nan +np.zeros(shape) sim.c = np.nan +np.zeros(shape) sim.a = np.nan +np.zeros(shape) sim.p = np.nan +np.zeros(shape) sim.y = np.nan +np.zeros(shape) # Shocks shocki = np.random.choice(par.Nshocks,(par.T,par.simN),replace=True,p=par.w) #draw values between 0 and Nshocks-1, with probability w sim.psi = par.psi_vec[shocki] sim.xi = par.xi_vec[shocki] #check it has a mean of 1 assert (abs(1-np.mean(sim.xi)) < 1e-4), 'The mean is not 1 in the simulation of xi' assert (abs(1-np.mean(sim.psi)) < 1e-4), 'The mean is not 1 in the simulation of psi' # Initial values sim.m[0,:] = par.sim_mini sim.p[0,:] = 0.0 # Simulation for t in range(par.simT): if par.simlifecycle == 0: sim.c[t,:] = tools.interp_linear_1d(sol.m[0,:],sol.c[0,:], sim.m[t,:]) else: sim.c[t,:] = tools.interp_linear_1d(sol.m[t,:],sol.c[t,:], sim.m[t,:]) sim.a[t,:] = sim.m[t,:] - sim.c[t,:] if t< par.simT-1: if t+1 > par.Tr: #after pension sim.m[t+1,:] = par.R*sim.a[t,:]/(par.G*par.L[t])+1 sim.p[t+1,:] = np.log(par.G)+np.log(par.L[t])+sim.p[t,:] sim.y[t+1,:] = sim.p[t+1,:] else: #before pension sim.m[t+1,:] = par.R*sim.a[t,:]/(par.G*par.L[t]*sim.psi[t+1,:])+sim.xi[t+1,:] sim.p[t+1,:] = np.log(par.G)+np.log(par.L[t])+sim.p[t,:]+np.log(sim.psi[t+1,:]) sim.y[t+1,:] = sim.p[t+1,:]+np.log(sim.xi[t+1,:]) #Renormalize sim.P = np.exp(sim.p) sim.Y = np.exp(sim.y) sim.M = sim.m*sim.P sim.C = sim.c*sim.P sim.A = sim.a*sim.P
def value_of_choice(m,c,h,t,sol,par): # Next period ressources a = np.repeat(m-c,(par.xi.size)) m_plus = par.R * a + par.W # Next-period value v_plus0 = tools.interp_linear_1d(sol.m[t+1,0,par.N_bottom:],sol.v[t+1,0,par.N_bottom:], m_plus) v_plus1 = tools.interp_linear_1d(sol.m[t+1,1,par.N_bottom:],sol.v[t+1,1,par.N_bottom:], m_plus) V_plus, _ = logsum(v_plus0,v_plus1,par.sigma_eta) # Find the maximum of v0 and v1 # This period value v = util(c,h,par) + par.beta*V_plus return v
def EGM_vec(sol, t, par): if t + 1 <= par.Tr: fac = np.tile(par.G * par.L[t] * par.psi_vec, par.Na) xi = np.tile(par.xi_vec, par.Na) a = np.repeat(par.grid_a[t], par.Nshocks) w = np.tile(par.w, (par.Na, 1)) dim = par.Nshocks else: fac = par.G * par.L[t] * np.ones((par.Na)) xi = np.ones((par.Na)) a = par.grid_a[t, :] w = np.ones((par.Na, 1)) dim = 1 inv_fac = 1 / fac # Futute m and c m_plus = inv_fac * par.R * a + xi c_plus = tools.interp_linear_1d(sol.m[t + 1, :], sol.c[t + 1, :], m_plus) # Future marginal utility marg_u_plus = marg_util(fac * c_plus, par) marg_u_plus = np.reshape(marg_u_plus, (par.Na, dim)) avg_marg_u_plus = np.sum(w * marg_u_plus, 1) # Currect C and m sol.c[t, 1:] = inv_marg_util(par.beta * par.R * avg_marg_u_plus, par) sol.m[t, 1:] = par.grid_a[t, :] + sol.c[t, 1:] return sol
def EGM_loop(sol, t, par): for i_a, a in enumerate(par.grid_a[t, :]): if t + 1 <= par.Tr: # No pension in the next period fac = par.G * par.L[t] * par.psi_vec w = par.w xi = par.xi_vec inv_fac = 1 / fac # Futute m and c m_plus = inv_fac * par.R * a + xi c_plus = tools.interp_linear_1d(sol.m[t + 1, :], sol.c[t + 1, :], m_plus) else: fac = par.G * par.L[t] w = 1 xi = 1 inv_fac = 1 / fac # Futute m and c m_plus = inv_fac * par.R * a + xi c_plus = tools.interp_linear_1d_scalar(sol.m[t + 1, :], sol.c[t + 1, :], m_plus) # Future marginal utility marg_u_plus = marg_util(fac * c_plus, par) avg_marg_u_plus = np.sum(w * marg_u_plus) # Currect C and m sol.c[t, i_a + 1] = inv_marg_util(par.beta * par.R * avg_marg_u_plus, par) sol.m[t, i_a + 1] = a + sol.c[t, i_a + 1] return sol
def log_likelihood(theta, model, est_par, data): #Update parameters par = model.par sol = model.sol par = updatepar(par, est_par, theta) # Solve the model model.create_grids() model.solve() # Predict consumption t = data.t c_predict = tools.interp_linear_1d(sol.m[t, :], sol.c[t, :], data.m) C_predict = c_predict * data.P #Renormalize # Calculate errors error = data.logC - np.log(C_predict) # Calculate log-likelihood log_lik_vec = -0.5 * np.log(2 * np.pi * par.sigma_eta**2) log_lik_vec += (-(error**2) / (2 * par.sigma_eta**2)) return np.mean(log_lik_vec)
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 solve_EGM(par): # Initialize solution class class sol: pass # Initial guess is like a 'last period' choice - consume everything # **** Jeg tænker ikke, at vi behøver at kalde linspace-funktionen nedenunder igen, da vi jo allerede har oprettet griddet i # model.py klassen. Måske kan man bare slette linjen nedenunder, og erstatte # "sol.c = sol.a.copy()" med "sol.c = par.grid_a.copy()" sol.a = np.linspace( par.a_min, par.a_max, par.num_a) # a is pre descision, so for any state consume everything sol.c = sol.a.copy() # Consume everyting - this could be improved 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() a_next = sol.a.copy() # Loop over exogneous states (post decision states) for a_i, s in enumerate(par.grid_s): #Next periods assets and consumption m_plus = (1 + par.r) * s + par.y # post decision state. Note vector c_plus = tools.interp_linear_1d(a_next, c_next, m_plus) # Marginal utility of next periods consumption marg_u_plus = util.marg_u(c_plus, par) av_marg_u_plus = np.sum( par.Pi * marg_u_plus) # Compute expected utility in next period # Optimal c in current period from inverted euler # +1 in indexation as we add zero consumption afterwards sol.c[a_i + 1] = util.inv_marg_u( (1 + par.r) * par.beta * av_marg_u_plus, par) sol.a[a_i + 1] = s + sol.c[a_i + 1] # Endogenous state # add zero consumption sol.a[0] = 0 sol.c[0] = 0 # Update iteration parameters sol.it += 1 sol.delta = max(abs(sol.c - c_next)) # Uncomment for debugging # sol.test = abs(sol.c - c_next) return sol
def value_of_choice(m, c, L, t, sol, par): xi_w_mat = np.tile(par.xi_w, (c.size, 1)) xi_mat = np.tile(par.xi, (c.size)) # Next period ressources a = np.repeat(m - c, (par.xi.size)) m_plus = par.R * a + par.W * xi_mat # Next-period value v_plus0 = tools.interp_linear_1d(sol.m[t + 1, 0, par.N_bottom:], sol.v[t + 1, 0, par.N_bottom:], m_plus) v_plus1 = tools.interp_linear_1d(sol.m[t + 1, 1, par.N_bottom:], sol.v[t + 1, 1, par.N_bottom:], m_plus) V_plus, _ = logsum(v_plus0, v_plus1, par.sigma_eta) V_plus = np.reshape(V_plus, (c.size, par.xi_w.size)) V_plus = np.sum(xi_w_mat * V_plus, 1) # This period value v = util(c, L, par) + par.beta * V_plus return v
def working(sol, z_plus, t, par): # Prepare xi = np.tile(par.xi, par.Na) a = np.repeat(par.grid_a[t], par.Nxi) w = np.tile(par.xi_w, (par.Na, 1)) # Next period states m_plus = par.R * a + par.W * xi shape = (2, m_plus.size) v_plus = np.nan + np.zeros(shape) c_plus = np.nan + np.zeros(shape) marg_u_plus = np.nan + np.zeros(shape) for i in range(2): #Range over working and not working next period # Choice specific value v_plus[i, :] = tools.interp_linear_1d(sol.m[t + 1, i, par.N_bottom:], sol.v[t + 1, i, par.N_bottom:], m_plus) #Choice specific consumption c_plus[i, :] = tools.interp_linear_1d(sol.m[t + 1, i, par.N_bottom:], sol.c[t + 1, i, par.N_bottom:], m_plus) # Choice specific Marginal utility marg_u_plus[i, :] = marg_util(c_plus[i, :], par) # Expected value V_plus, prob = logsum(v_plus[0], v_plus[1], par.sigma_eta) w_raw = w * np.reshape(V_plus, (par.Na, par.Nxi)) w_raw = np.sum(w_raw, 1) marg_u_plus = prob[0, :] * marg_u_plus[0] + prob[1, :] * marg_u_plus[1] #Expected average marg. utility avg_marg_u_plus = w * np.reshape(marg_u_plus, (par.Na, par.Nxi)) avg_marg_u_plus = np.sum(avg_marg_u_plus, 1) return w_raw, avg_marg_u_plus
def no_house(sol, z_plus, t, par): # Prepare a = np.repeat(par.grid_a[t], par.Nxi) # Next period states m_plus = par.R * a + par.W shape = (2, m_plus.size) v_plus = np.nan + np.zeros(shape) c_plus = np.nan + np.zeros(shape) marg_u_plus = np.nan + np.zeros(shape) for i in range(2): # Range over buying house (i = 1) and no house (i = 0) # Choice specific cost of the house cost = i * par.ph # Choice specific value v_plus[i, :] = tools.interp_linear_1d(sol.m[t + 1, i, par.N_bottom:], sol.v[t + 1, i, par.N_bottom:], m_plus - cost) #Choice specific consumption c_plus[i, :] = tools.interp_linear_1d(sol.m[t + 1, i, par.N_bottom:], sol.c[t + 1, i, par.N_bottom:], m_plus - cost) # Choice specific Marginal utility marg_u_plus[i, :] = marg_util(c_plus[i, :], par) # Expected value V_plus, prob = logsum(v_plus[0], v_plus[1], par.sigma_eta) w_raw = V_plus avg_marg_u_plus = prob[0, :] * marg_u_plus[0] + prob[1, :] * marg_u_plus[ 1] #Expected margnal utility dependend on choice probabilities return w_raw, avg_marg_u_plus
def EGM (sol,t,par): for i_a,a in enumerate(par.grid_a[t,:]): if t+1<= par.Tr: # No pension in the next period fac = par.G*par.psi_vec w = par.w xi = par.xi_vec inv_fac = 1/fac # Future m and c m_plus = inv_fac*par.R*a+xi c1_plus = tools.interp_linear_1d(sol.m[t+1,:],sol.c1[t+1,:], m_plus) c2_plus = tools.interp_linear_1d(sol.m[t+1,:],sol.c2[t+1,:], m_plus) else: fac = par.G w = 1 xi = 1 inv_fac = 1/fac # Future m and c m_plus = inv_fac*par.R*a+xi c1_plus = tools.interp_linear_1d_scalar(sol.m[t+1,:],sol.c1[t+1,:], m_plus) c2_plus = tools.interp_linear_1d_scalar(sol.m[t+1,:],sol.c2[t+1,:], m_plus) # Future marginal utility marg_u_plus1 = marg_util_c1(fac*c1_plus,par) marg_u_plus2 = marg_util_c2(fac*c2_plus,par) avg_marg_u_plus1 = np.sum(w*marg_u_plus1) avg_marg_u_plus2 = np.sum(w*marg_u_plus2) # Current C and m sol.c1[t,i_a+1]=inv_marg_util(par.beta*par.R*avg_marg_u_plus1,par) sol.c2[t,i_a+1]=inv_marg_util(par.beta*par.R*avg_marg_u_plus2,par) sol.m[t,i_a+1]=a+sol.c1[t,i_a+1]+sol.c2[t,i_a+1] return sol
# break V_stacked = z + Vstar_stacked # calculate value function V = np.hstack([V_stacked[:I], V_stacked[I:2 * I]]) Vchange = V - v v = V delta = np.max(np.absolute(Vchange[:, :])) it += 1 ###################### ## Measure accuracy ## ###################### # Unpack true policy c_true = c[5:-5, :].copy() m_true = a[5:-5].copy() # Interpolate on 'true' grid c_interp_1 = tools.interp_linear_1d(sol_m, sol_c[:, 0], m_true) c_interp_2 = tools.interp_linear_1d(sol_m, sol_c[:, 1], m_true) error_1 = 100 * 1 / 2 * 1 / 6000 * np.sum( np.abs(c_interp_1 - c_true[:, 0]) / c_true[:, 0]) error_2 = 100 * 1 / 2 * 1 / 6000 * np.sum( np.abs(c_interp_2 - c_true[:, 1]) / c_true[:, 1]) error = error_1 + error_2 print(error)
def solve_EGM_2d(par): # Initialize solution class class sol: pass # Shape parameter for the solution vector shape = (np.size(par.y), 1) # Initial guess is like a 'last period' choice - consume everything sol.a = np.tile( np.linspace(par.a_min, par.a_max, par.num_a + 1), shape) # a is pre descision, so for any state consume everything. sol.c = sol.a.copy() # Consume everyting - this could be improved 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() a_next = sol.a.copy() # Loop over exogneous states (post decision states) for a_i, s in enumerate(par.grid_s): #Next periods assets and consumption m_plus = (1 + par.r) * s + np.transpose( par.y) # Transpose for dimension to fit # Interpolate next periods consumption - can this be combined? c_plus_1 = tools.interp_linear_1d(a_next[0, :], c_next[0, :], m_plus) # State 1 c_plus_2 = tools.interp_linear_1d(a_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.a[:, a_i + 1] = s + sol.c[:, a_i + 1] # Update iteration parameters sol.it += 1 sol.delta = max(max(abs(sol.c[0] - c_next[0])), max(abs(sol.c[1] - c_next[1]))) # check this, is this optimal # add zero consumption sol.a[:, 0] = 0 sol.c[:, 0] = 0 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