def backward_iterate_olg(ucp, a, Pi, coh, r, beta, sigma): """One-step backward iteration function.""" # Implied consumption today consistent with Euler equation (on tomorrow's grid for assets a') c_nextgrid = (beta * (1 + r) * (Pi @ ucp))**(-1 / sigma) # We have consumption today for each a' tomorrow (a mapping from total cash on hand today c''+a' to a' tomorrow) # Interpolate to get mapping of actual cash on hand in each state to assets tomorrow a' a_pol = interpolate_y(c_nextgrid + a, coh, a) # Derive the consumption policy function using the above mapping from cash-on-hand today to a' tomorrow and the # mapping from consumption today to a' (c_nextgrid) c_pol = interpolate_y(a, a_pol, c_nextgrid) # Replace constrained agents with minimum asset level (bottom of grid) cstr_i = a_pol < a[0] # index of constrained bins if np.any(cstr_i): a_pol[cstr_i], c_pol[cstr_i] = constrained(coh[cstr_i], a) # Replace zeros by 1E-10 to compute marginal utility without dividing by zero c_pol[c_pol <= 0] = 1E-10 # Calculate marginal utility uc = c_pol**(-sigma) return a_pol, c_pol, uc
def household(Va_p, Pi_p, a_grid, e_grid, T, w, r, beta, eis, frisch, vphi, c_const, n_const, ssflag=False): """Single backward iteration step using endogenous gridpoint method for households with separable CRRA utility. Order of returns matters! backward_var, assets, others """ # this one is useful to do internally ws = w * e_grid # uc(z_t, a_t) uc_nextgrid = (beta * Pi_p) @ Va_p # c(z_t, a_t) and n(z_t, a_t) c_nextgrid, n_nextgrid = cn(uc_nextgrid, ws[:, np.newaxis], eis, frisch, vphi) # c(z_t, a_{t-1}) and n(z_t, a_{t-1}) lhs = c_nextgrid - ws[:, np.newaxis] * n_nextgrid + a_grid[ np.newaxis, :] - T[:, np.newaxis] rhs = (1 + r) * a_grid c = utils.interpolate_y(lhs, rhs, c_nextgrid) n = utils.interpolate_y(lhs, rhs, n_nextgrid) # test constraints, replace if needed a = rhs + ws[:, np.newaxis] * n + T[:, np.newaxis] - c iconst = np.nonzero(a < a_grid[0]) a[iconst] = a_grid[0] if ssflag: # use precomputed values c[iconst] = c_const[iconst] n[iconst] = n_const[iconst] else: # have to solve again if in transition uc_seed = c_const[iconst]**(-1 / eis) c[iconst], n[iconst] = solve_cn( ws[iconst[0]], rhs[iconst[1]] + T[iconst[0]] - a_grid[0], eis, frisch, vphi, uc_seed) # calculate marginal utility to go backward Va = (1 + r) * c**(-1 / eis) # efficiency units of labor which is what really matters ns = e_grid[:, np.newaxis] * n return Va, a, c, n, ns
def step6(ap_endo, c_endo, z_grid, b_grid, a_grid, ra, rb, chi0, chi1, chi2): # b(z, k, a) zzz = z_grid[:, np.newaxis, np.newaxis] aaa = a_grid[np.newaxis, np.newaxis, :] b_endo = (c_endo + ap_endo + b_grid[0] - (1 + ra) * aaa + Psi_fun(ap_endo, aaa, ra, chi0, chi1, chi2) - zzz) / (1 + rb) # b'(z, b, a), a'(z, b, a) # assert np.min(np.diff(b_endo, axis=1)) < 0, 'b(kappa) is not decreasing' # assert np.min(np.diff(ap_endo, axis=1)) < 0, 'ap(kappa) is not decreasing' ap = utils.interpolate_y(b_endo[:, ::-1, :].swapaxes(1, 2), b_grid, ap_endo[:, ::-1, :].swapaxes(1, 2)).swapaxes(1, 2) return ap
def backward_iterate(Va_p, Pi_p, a_grid, e_grid, r, w, beta, eis): """Single backward iteration step using endogenous gridpoint method for households with CRRA utility. Order of returns matters! backward_var, assets, others Parameters ---------- Va_p : np.ndarray marginal value of assets tomorrow Pi_p : np.ndarray Markov transition matrix for skills tomorrow a_grid : np.ndarray asset grid e_grid : np.ndarray skill grid r : float ex-post interest rate w : float wage beta : float discount rate today eis : float elasticity of intertemporal substitution Returns ---------- Va : np.ndarray, shape(nS, nA) marginal value of assets today a : np.ndarray, shape(nS, nA) asset policy today c : np.ndarray, shape(nS, nA) consumption policy today """ uc_nextgrid = (beta * Pi_p) @ Va_p c_nextgrid = uc_nextgrid**(-eis) coh = (1 + r) * a_grid[np.newaxis, :] + w * e_grid[:, np.newaxis] a = utils.interpolate_y(c_nextgrid + a_grid, coh, a_grid) utils.setmin(a, a_grid[0]) c = coh - a Va = (1 + r) * c**(-1 / eis) return Va, a, c
def time_iteration(sigma, theta, alpha, delta, r, lump, beta, Pi_e, d_grid, z_grid, b_grid, k_grid, zzz, lll, bbb, ddd, Ne, Nb, Nd, Nk, rhs, Vb, Vd, P_n_p, P_d_p): # output containers sol_shape = (Ne, Nb, Nd) Wb = np.zeros(sol_shape) Wd = np.zeros(sol_shape) d_unc = np.zeros(sol_shape) b_unc = np.zeros(sol_shape) d_con = np.zeros(sol_shape) ''' computes one backward EGM step ''' # a. pre-compute post-decision value functions and LHS offirst-order optimality equation # i. post-decision functions Wb[:, :, :] = (Vb.T @ (beta * Pi_e.T)).T Wd[:, :, :] = (Vd.T @ (beta * Pi_e.T)).T # ii. LHS of FOC optimality equation in unconstrained and constrained case lhs_unc = Wd / Wb lhs_con = lhs_unc[:, 0, :] lhs_con = lhs_con[:, np.newaxis, :] / (1 + k_grid[np.newaxis, :, np.newaxis]) # b. get unconstrained solution to d'(z,b,d), a'(z,b,d), c(z,b,d) # i. get d'(z,b',d), b(z,b',d), c(z,b,d) with EGM dp_endo_unc, _, b_endo_unc, _ = solve_unconstrained( sigma, theta, alpha, delta, r, d_grid, b_grid, z_grid, lump, Ne, Nb, Nd, lhs_unc, rhs, Wb, P_d_p, P_n_p) # ii. use d'(z,b',d), b(z,b',d) to interpolate to d'(z,b,d), b'(z,b,d) i, pi = utils.interpolate_coord(b_endo_unc.swapaxes( 1, 2), b_grid) # gives interpolation weights from a' grid to a grid d_unc[:, :, :] = utils.apply_coord(i, pi, dp_endo_unc.swapaxes( 1, 2)).swapaxes(1, 2) # apply weights to d'(z,a',d)->d'(z,a,d) b_unc[:, :, :] = utils.apply_coord(i, pi, b_grid).swapaxes( 1, 2) # apply weights to a'(z,a',d)->a'(z,a,d) # c. get constrained solution to d'(z,0,d), b'(z,0,d), c(z,0,d) # i. get d'(z,k,d), b(z,k,d), c(z,k,d) with EGM dp_endo_con, _, b_endo_con, _ = solve_constrained(sigma, theta, alpha, delta, r, d_grid, b_grid, k_grid, z_grid, lump, Ne, Nk, Nd, lhs_con, rhs, Wb, P_n_p, P_d_p) # ii. get d'(z,b,d) by interpolating using b'(z,k,d) d_con[:] = utils.interpolate_y(b_endo_con[:, ::-1, :].swapaxes(1, 2), b_grid, dp_endo_con[:, ::-1, :].swapaxes( 1, 2)).swapaxes(1, 2) # d. collect policy functions d',b',c by combining unconstrained and constrained solutions d, b, c = collect_policy(delta, alpha, r, Ne, Nb, Nd, b_grid, zzz, lll, ddd, bbb, d_unc, b_unc, d_con, P_n_p, P_d_p) c_d = d - (1 - delta) * ddd # durable investment policy fuctions # e. update Vb, Vd # i. compute marginal utilities c[c < 0] = 1e-8 # for numerical stability while converging uc = theta * c**(theta - 1) * (ddd)**(1 - theta) * ( (c**theta * (ddd)**(1 - theta)))**(-sigma) ud = (1 - theta) * c**theta * (ddd)**(-theta) * ( (c**theta * (ddd)**(1 - theta)))**(-sigma) # ii. compute Vb, Vd using envelope conditions Vb = (1 / P_n_p) * (1 + r) * uc Vd = ud + (1 / P_n_p) * uc * (P_d_p * (1 - delta) - 0.5 * alpha * ((1 - delta)**2 - (d / ddd)**2)) return Vb, Vd, d, b, c, c_d
def EGMhousehold( EVa_p, Pi_p, Pi_ern, a_grid, Pi_seed, rstar, sBorrow, P, hss, kappa, ssN, e_grid,pi_e, pi_ern, w, ra, beta, eis, Eq, N_, destr_L, destrO_L, b, Benefit_type, T_dist, pi_beta, wss, Tss, Ttd, Tuni, ssAvgInc, VAT, nPoints, cs_avg, ttd_inf, frisch, ssflag=False): """Single backward iteration step using endogenous gridpoint method for households with separable CRRA utility.""" x = a_grid >= 0 x = x.astype(int) R = 1 + ra * x + (1- x) * (ra + kappa) nBeta = nPoints[0] ne = nPoints[1] nA = nPoints[2] nN = 2 e_grid_alt = e_grid sol = {'N' : {}, 'S' : {}} # create dict containing vars for each employment state # reshape some input EVa_p = np.reshape(EVa_p, (nBeta, ne, nN, nA)) U_inc, _ = Unemp_benefit(Benefit_type, b, e_grid, pi_ern, ne, wss) T = transfers(pi_ern, Tss, e_grid, T_dist) Ttd_ = transfers_td_e(pi_ern, Ttd, e_grid) T_agg = np.broadcast_to(T[np.newaxis, :, np.newaxis] + Ttd_[np.newaxis, :, np.newaxis] + Tuni , (nBeta,ne, nA)) # u'c(z_t, a_t) sol['N']['uc_nextgrid'] = np.ones([nBeta, ne, nA]) * np.nan sol['S']['uc_nextgrid'] = np.ones([nBeta, ne, nA]) * np.nan sol['N']['tInc'] = np.ones([nBeta, ne, nA]) * np.nan sol['S']['tInc'] = np.ones([nBeta, ne, nA]) * np.nan a_grid_org = a_grid dN = N_ / ssN dU = (1-N_) / (1-ssN) for j in range(nBeta): sol['N']['uc_nextgrid'][j,:,:] = (beta[j] * Pi_ern) @ EVa_p[j,:,0, :] sol['S']['uc_nextgrid'][j,:,:] = (beta[j] * Pi_ern) @ EVa_p[j,:,1, :] for h in sol: if h == 'N': a_grid = a_grid_org if h == 'S': a_grid = a_grid_org sol[h]['c_nextgrid'] = inv_mu(sol[h]['uc_nextgrid'], eis) if h == 'N': tax_IN = avgTaxf(w * e_grid, ssAvgInc, cs_avg) sol[h]['tInc'] = np.broadcast_to(tax_IN[np.newaxis, :, np.newaxis], (nBeta,ne, nA)) sol[h]['I'] = (1 - sol[h]['tInc']) * w * e_grid[np.newaxis, :, np.newaxis] * dN + T_agg if h == 'S': tax_IS = avgTaxf(U_inc, ssAvgInc, cs_avg) sol[h]['tInc'] = np.broadcast_to(tax_IS[np.newaxis, :, np.newaxis], (nBeta,ne, nA)) sol[h]['I'] = (1 - sol[h]['tInc']) * U_inc[np.newaxis,:, np.newaxis] * dU + T_agg # interpolate for each beta sol[h]['c'] = np.empty([nBeta, ne, nA]) for j in range(nBeta): lhs = sol[h]['c_nextgrid'][j,:,:] * (1+VAT) + a_grid[np.newaxis, :] - sol[h]['I'][j,:,:] rhs = R * a_grid sol[h]['c'][j,:,:] = utils.interpolate_y(lhs, rhs, sol[h]['c_nextgrid'][j,:,:]) sol[h]['a'] = R * a_grid[np.newaxis, np.newaxis, :] + sol[h]['I'] - sol[h]['c'] * (1+VAT) # check borrowing constraint sol[h]['a'], sol[h]['c'] = constr(sol[h]['a'], sol[h]['c'], a_grid[0], 'a', R, a_grid, VAT, sol[h]['I']) # unpack from dict and aggregate cN = np.reshape(sol['N']['c'] , (ne*nBeta, nA)) cS = np.reshape(sol['S']['c'] , (ne*nBeta, nA)) aN = np.reshape(sol['N']['a'] , (ne*nBeta, nA)) aS = np.reshape(sol['S']['a'] , (ne*nBeta, nA)) dN = N_ / ssN dU = (1-N_) / (1-ssN) IncN = np.reshape(sol['N']['I'], (ne*nBeta, nA)) IncS = np.reshape(sol['S']['I'], (ne*nBeta, nA)) IncNpretax = np.reshape(sol['N']['I'] + sol['N']['tInc'] * w * e_grid[np.newaxis, :, np.newaxis] , (ne*nBeta, nA)) IncSpretax = np.reshape(sol['S']['I'] + sol['S']['tInc'] * U_inc[np.newaxis, :, np.newaxis] , (ne*nBeta, nA)) Ntaxes = sol['N']['tInc'] * w * e_grid[np.newaxis, :, np.newaxis] Ntaxes = np.reshape(np.broadcast_to(Ntaxes, (nBeta,ne, nA)), (ne*nBeta, nA)) Staxes = np.reshape(sol['S']['tInc'] * U_inc[np.newaxis, :, np.newaxis] , (ne*nBeta, nA)) mu_N = cN ** (-1 / eis) mu_S = cS ** (-1 / eis) # EnVa = R[np.newaxis, :] * (destr * (1-Eq) * mu_S + (1 - destr * (1-Eq)) * mu_N) # EuVa = R[np.newaxis, :] * ((1-Eq* (1-destrO)) * mu_S + Eq * (1-destrO) * mu_N) EnVa = R[np.newaxis, :] * (destr_L * (1-Eq) * mu_S + (1 - destr_L * (1-Eq)) * mu_N) EuVa = R[np.newaxis, :] * ((1-Eq* (1-destrO_L)) * mu_S + Eq * (1-destrO_L) * mu_N) Incagg = N_ * IncN + (1-N_) * IncS # Aggregate EVa = np.reshape( np.stack((EnVa, EuVa), axis=-2), (ne*nBeta*nN, nA)) # a = np.reshape( np.stack((aN * dN, aS * dU), axis=-2), (ne*nBeta*nN, nA)) # c = np.reshape( np.stack((cN* dN, cS* dU), axis=-2), (ne*nBeta*nN, nA)) a = np.reshape( np.stack((aN , aS ), axis=-2), (ne*nBeta*nN, nA)) c = np.reshape( np.stack((cN, cS), axis=-2), (ne*nBeta*nN, nA)) UincAgg = np.reshape(np.broadcast_to( U_inc[np.newaxis, :, np.newaxis], (nBeta,ne, nA)), (ne*nBeta, nA)) zeromat = np.zeros([ne*nBeta, nA]) tInc = np.reshape( np.stack((Ntaxes * dN, dU * Staxes), axis=-2), (ne*nBeta*nN, nA)) UincAgg =np.reshape( np.stack((zeromat, UincAgg), axis=-2), (ne*nBeta*nN, nA)) Inc = np.reshape( np.stack((IncN * dN, IncS* dU), axis=-2), (ne*nBeta*nN, nA)) IncN = np.reshape( np.stack((IncN , zeromat), axis=-2), (ne*nBeta*nN, nA)) IncS = np.reshape( np.stack((zeromat, IncS), axis=-2), (ne*nBeta*nN, nA)) #print(N) #print(dU) # ctd = np.reshape( np.stack((cN* N + cS* (1-N), cN* N + cS* (1-N) ), axis=-2), (ne*nBeta*nN, nA)) # atd = np.reshape( np.stack((aN* N + aS* (1-N) , aN* N + aS* (1-N) ), axis=-2), (ne*nBeta*nN, nA)) ctd = np.reshape( np.stack((cN, cS ), axis=-2), (ne*nBeta*nN, nA)) atd = np.reshape( np.stack((aN , aS), axis=-2), (ne*nBeta*nN, nA)) cN = np.reshape( np.stack((cN , zeromat ), axis=-2), (ne*nBeta*nN, nA)) cS = np.reshape( np.stack((zeromat , cS ), axis=-2), (ne*nBeta*nN, nA)) aN = np.reshape( np.stack((aN , zeromat ), axis=-2), (ne*nBeta*nN, nA)) aS = np.reshape( np.stack((zeromat , aS ), axis=-2), (ne*nBeta*nN, nA)) taxN = np.reshape( np.stack((Ntaxes , zeromat ), axis=-2), (ne*nBeta*nN, nA)) taxS = np.reshape( np.stack((zeromat , Staxes ), axis=-2), (ne*nBeta*nN, nA)) a_debt = np.reshape(np.broadcast_to( (1-x) * a_grid[np.newaxis, np.newaxis, :], (nBeta,ne, nA)), (ne*nBeta, nA)) a_debtN = np.reshape( np.stack(( a_debt ,zeromat ), axis=-2), (ne*nBeta*nN, nA)) a_debtS = np.reshape( np.stack((zeromat, a_debt ), axis=-2), (ne*nBeta*nN, nA)) a_debt = np.reshape( np.stack((dN * a_debt ,dU * a_debt ), axis=-2), (ne*nBeta*nN, nA)) return EVa, a, c, tInc, UincAgg, Inc, cN, cS, aN, aS, ctd, atd, taxN, taxS, a_debt, a_debtN, a_debtS, IncN, IncS