def spline_basis(x, knots_dict): knots = knots_dict[0] n_a = len(x) n_knots = len(knots) first_interp_mat = np.zeros([n_a, n_knots + 1]) aux_mat = np.zeros([n_a, n_knots]) for i in range(n_a): loc = sum(knots <= x[i]) if loc == n_knots: loc = n_knots - 1 first_interp_mat[i, loc - 1] = 1 - (x[i] - knots[loc - 1])**2 / ( knots[loc] - knots[loc - 1])**2 first_interp_mat[i, loc] = (x[i] - knots[loc - 1])**2 / ( knots[loc] - knots[loc - 1])**2 aux_mat[i, loc - 1] = (x[i] - knots[loc - 1]) - ( x[i] - knots[loc - 1])**2 / (knots[loc] - knots[loc - 1]) aux_mat2 = spdiag(np.ones(n_knots), offsets=0, shape=(n_knots, n_knots), format="csc") \ +spdiag(np.ones(n_knots), offsets=1, shape=(n_knots, n_knots), format="csc") aux_mat2[-1, -1] = 0 aux_mat2[n_knots - 1, 0] = 1 aux_mat3 = spdiag(np.hstack([-2/np.diff(knots), 0.0]), offsets=0, shape=(n_knots, n_knots+1), format="csc") \ +spdiag(np.hstack([ 2/np.diff(knots), 1.0]), offsets=1, shape=(n_knots, n_knots+1), format="csc") from_knots = csc_matrix(first_interp_mat) + csc_matrix(aux_mat) * (spsolve( aux_mat2, aux_mat3)) to_knots = spsolve((from_knots.conj().T * from_knots), from_knots.conj().T) * speye(n_a, format="csc") return from_knots, to_knots
def projection_for_subset(from_small, to_small, n_pre, n_post): n_full, n_red = from_small.shape spdiag_internal = lambda n: (*spdiag(np.ones(n)).nonzero(), np.ones(n)) I, J, V = spdiag_internal(n_red + n_pre) from_approx = csc_matrix((V, (I, J)), shape=(n_full + n_pre, n_pre + n_red)) I, J, V = spdiag_internal(n_red + n_pre) to_approx = csc_matrix((V, (I, J)), shape=(n_pre + n_red, n_full + n_pre)) from_approx[n_pre:n_pre + n_full, n_pre:n_pre + n_red] = from_small to_approx[n_pre:n_pre + n_red, n_pre:n_pre + n_full] = to_small # Expand matrices and add needed values dim1_from_approx, dim2_from_approx = from_approx.shape from_approx = hstack([ from_approx, csc_matrix(np.zeros((dim1_from_approx, n_post)), dtype=float) ], format='csc') from_approx = vstack([ from_approx, csc_matrix(np.zeros((n_post, dim2_from_approx + n_post)), dtype=float) ], format='csc') to_approx = hstack([ to_approx, csc_matrix(np.zeros((dim2_from_approx, n_post)), dtype=float) ], format='csc') to_approx = vstack([ to_approx, csc_matrix(np.zeros((n_post, dim1_from_approx + n_post)), dtype=float) ], format='csc') from_approx[dim1_from_approx:, dim2_from_approx:] = speye(n_post) to_approx[dim2_from_approx:, dim1_from_approx:] = speye(n_post) return from_approx, to_approx
def _get_residuals(x): #x = x.toarray().flatten() # Prepare steady state deviations V = (x[:n_v - 1] + V_ss).reshape(I, J, order='F') inflation = x[n_v - 1] + inflation_ss gg = x[n_v:n_v + n_g - 1] + g_ss[:-1] MP = x[n_v + n_g - 1] w = x[n_v + n_g] + w_ss hours = x[n_v + n_g + 1] + N_ss consumption = x[n_v + n_g + 2] + C_ss output = x[n_v + n_g + 3] + Y_ss assets = x[n_v + n_g + 4] + B_ss #government = x[n_v + n_g + 5] + G_ss V_dot = x[nstates:nstates + n_v - 1] inflation_dot = x[nstates + n_v - 1] g_dot = x[nstates + n_v:nstates + n_v + n_g - 1] mp_dot = x[nstates + n_g + n_v - 1] #fp_dot = x[nstates + n_g + n_v + 5] #ps_dot = x[nstates + n_g + n_v + 3] VEErrors = x[2 * nstates:2 * nstates + n_v - 1] inflation_error = x[2 * nstates + n_v - 1] mp_shock = x[2 * nstates + n_v] #fp_shock = x[2*nstates + n_v + 1] #ps_shock = x[2*nstates + n_v + 2] g_end = (1 - gg @ azdelta[:-1]) / azdelta[-1] g = np.append(gg, g_end) g[g < 1e-19] = 0.0 #----------------------------------------------------------------- # Get equilibrium values, given steady state values normalized_wage = w / TFP profshare = (zz / meanlabeff) * ((1.0 - normalized_wage) * output) r_nominal = r_ss + taylor_inflation * inflation \ + taylor_outputgap * (np.log(output)-np.log(Y_ss)) + MP r = r_nominal - inflation lumptransfer = labtax * w * hours - G_ss - \ (r_nominal - (1-govbcrule_fixnomB) * inflation) * assets #----------------------------------------------------------------- # Compute one iteration of the HJB ## Get flow utility, income, and labor hour functions util, income, labor = \ aux.construct_household_problem_functions(V, w, coefrra, frisch, labtax, labdisutil) ## Initialize other variables, using V to ensure everything is a dual number Vaf = np.copy(V) Vab = np.copy(V) #h0 = np.array([h_ss[i, j] for i in range(I) for j in range(J)]).reshape(I, J) h0 = np.copy(h_ss) #----------------------------------------------------------------- # Construct Initial Difference Matrices # hf = np.empty_like(V) # hb = np.empty_like(V) Vaf[-1, :] = income(h_ss[-1, :], zz[-1, :], profshare[-1, :], lumptransfer, r, amax)**(-coefrra) Vab[-1, :] = (V[-1, :] - V[-2, :]) / dab[-1] Vaf[0, :] = (V[1, :] - V[0, :]) / daf[0] Vab[0, :] = income(h_ss[0, :], zz[0, :], profshare[0, :], lumptransfer, r, amin)**(-coefrra) Vaf[1:-1] = (V[2:, :] - V[1:-1, :]) / daf[0] Vab[1:-1] = (V[1:-1, :] - V[:-2, :]) / dab[0] # idx = ((i,j) for i in range(I) for j in range(J)) # for t in idx: # hf[t] = min(abs(labor(zz[t], Vaf[t])), maxhours) # hb[t] = min(abs(labor(zz[t], Vab[t])), maxhours) hf = np.minimum(abs(labor(zz, Vaf)), maxhours) hb = np.minimum(abs(labor(zz, Vab)), maxhours) cf = Vaf**(-1 / coefrra) cb = Vab**(-1 / coefrra) #----------------------------------------------------------------- # Hours Iteration idx = ((i, j) for i in range(I) for j in range(J)) for ih in range(niter_hours): for t in idx: if t[0] == I - 1: cf[t] = income(hf[t], zz[t], profshare[t], lumptransfer, r, aa[t]) hf[t] = labor(zz[t], cf[t]**(-coefrra)) hf[t] = min(abs(hf[t]), maxhours) if ih == niter_hours - 1: Vaf[t] = cf[t]**(-coefrra) elif t[0] == 0: cb[t] = income(hb[t], zz[t], profshare[t], lumptransfer, r, aa[t]) hb[t] = labor(zz[t], cb[t]**(-coefrra)) hb[t] = min(abs(hb[t]), maxhours) if ih == niter_hours: Vab[t] = cb[t]**(-coefrra) c0 = income(h0, zz, profshare, lumptransfer, r, aa) h0 = labor(zz, c0**(-coefrra)) h0 = np.minimum(abs(h0.flatten()), maxhours).reshape(I, J) c0 = income(h0, zz, profshare, lumptransfer, r, aa) sf = income(hf, zz, profshare, lumptransfer, r, aa) - cf sb = income(hb, zz, profshare, lumptransfer, r, aa) - cb #----------------------------------------------------------------- # Upwind #T = sb[0,0].dtype Vf = (cf > 0) * (util(cf, hf) + sf * Vaf) + (cf <= 0) * (-1e12) Vb = (cb > 0) * (util(cb, hb) + sb * Vab) + (cb <= 0) * (-1e12) V0 = (c0 > 0) * util(c0, h0) + (c0 <= 0) * (-1e12) Iunique = (sb < 0) * (1 - (sf > 0)) + (1 - (sb < 0)) * (sf > 0) Iboth = (sb < 0) * (sf > 0) Ib = Iunique * (sb < 0) * (Vb > V0) + Iboth * (Vb == np.maximum( np.maximum(Vb, Vf), V0)) If = Iunique * (sf > 0) * (Vf > V0) + Iboth * (Vf == np.maximum( np.maximum(Vb, Vf), V0)) I0 = 1 - Ib - If h = hf * If + hb * Ib + h0 * I0 c = cf * If + cb * Ib + c0 * I0 s = sf * If + sb * Ib u = util(c, h) X = -Ib * sb / np.array([dab, dab]).reshape(I, J) Z = If * sf / np.array([daf, daf]).reshape(I, J) Y = -Z - X X[0, :] = 0. Z[I - 1, :] = 0. A = spdiag([ X.reshape(I * J, order='F')[1:], Y.reshape(I * J, order='F'), Z.reshape(I * J, order='F')[:I * J - 1] ], offsets=[-1, 0, 1], shape=(I * J, I * J), format='csc') + A_switch #----------------------------------------------------------------- # Collect/calculate Residuals hjb_residual = u.flatten(order='F') + A * V.flatten(order='F') \ + V_dot + VEErrors - rho_ss * V.flatten(order='F') pc_residual = -((r - 0) * inflation - (ceselast / priceadjust * \ (w / TFP - (ceselast-1) / ceselast) + \ inflation_dot - inflation_error)) g_azdelta = g.flatten() * azdelta.flatten() g_intermediate = spdiag(1 / azdelta) * A.T @ g_azdelta g_residual = g_dot - g_intermediate[:-1] mp_residual = mp_dot - (-theta_MP * MP + sig_MP * mp_shock) realsav = sum( aa.flatten(order='F') * g.flatten(order='F') * azdelta.flatten(order='F')) realsav_dot = sum( s.flatten(order='F') * g.flatten(order='F') * azdelta.flatten(order='F')) bondmarket_residual = realsav_dot / realsav + govbcrule_fixnomB * inflation labmarket_residual = sum(zz.flatten(order='F') * h.flatten(order='F') \ * g.flatten(order='F') * azdelta.flatten(order='F')) - hours consumption_residual = sum(c.flatten(order='F') * g.flatten(order='F') \ * azdelta.flatten(order='F')) - consumption output_residual = TFP * hours - output #output_residual = TFP * hours - (-theta_PS * output + sig_PS * ps_shock) assets_residual = assets - realsav #government_residual = fp_dot - (-theta_FP * government + sig_FP * fp_shock) # Return equilibrium conditions return np.hstack( (hjb_residual, pc_residual, g_residual, mp_residual, bondmarket_residual, labmarket_residual, consumption_residual, output_residual, assets_residual))
def steadystate(model): # Read in parameters coefrra = model.params['coefrra'].value frisch = model.params['frisch'].value meanlabeff = model.params['meanlabeff'].value maxhours = model.params['maxhours'].value ceselast = model.params['ceselast'].value labtax = model.params['labtax'].value govbondtarget = model.params['govbondtarget'].value labdisutil = model.params['labdisutil'].value lumptransferpc = model.params['lumptransferpc'].value # Read in grids I = model.settings['I'].value J = model.settings['J'].value a = model.settings['a'].value g_z = model.settings['g_z'].value zz = model.settings['zz'].value ymarkov_combined = model.settings['ymarkov_combined'].value # Set necessary variables aa = np.repeat(a.reshape(-1, 1), J, axis=1) amax = np.max(a) amin = np.min(a) # Read in initial rates iterate_r = model.settings['iterate_r'].value r = model.settings['r0'].value rmin = model.settings['rmin'].value rmax = model.settings['rmax'].value iterate_rho = model.settings['iterate_rho'].value rho = model.settings['rho0'].value rhomin = model.settings['rhomin'].value rhomax = model.settings['rhomax'].value # Read in approximation parameters Ir = model.settings['Ir'].value maxit_HJB = model.settings['maxit_HJB'].value tol_HJB = model.settings['tol_HJB'].value d_HJB = model.settings['d_HJB'].value maxit_kfe = model.settings['maxit_kfe'].value tol_kfe = model.settings['tol_kfe'].value d_kfe = model.settings['d_kfe'].value niter_hours = model.settings['niter_hours'].value crit_S = model.settings['crit_S'].value # Initializing equilibrium objects labor_share_ss = (ceselast - 1) / ceselast w = w_ss = labor_share_ss # compute initial guesses at steady state values given zz, labor_share_ss, etc. N_ss, Y_ss, B_ss, profit_ss, profshare, lumptransfer = \ aux.calculate_ss_equil_vars_init(zz, labor_share_ss, meanlabeff, lumptransferpc, govbondtarget) # Initialize matrices for finite differences Vaf = np.empty((I, J), dtype=np.complex64) Vab = np.empty((I, J), dtype=np.complex64) cf = np.empty((I, J), dtype=np.complex64) # forward consumption difference hf = np.empty((I, J), dtype=np.complex64) # forward hours difference sf = np.empty((I, J), dtype=np.complex64) # forward saving difference cb = np.empty((I, J), dtype=np.complex64) # backward consumption difference hb = np.empty((I, J), dtype=np.complex64) # backward hours difference sb = np.empty((I, J), dtype=np.complex64) # backward saving difference c0 = np.empty((I, J), dtype=np.complex64) A = np.empty((I * J, J * J), dtype=np.complex64) Aswitch = spkron(ymarkov_combined, speye(I, dtype='complex64')) # Initialize steady state variables V = np.empty((I, J), dtype=np.complex64) # value function u = np.empty((I, J), dtype=np.complex64) # flow utility across state space s = np.empty((I, J), dtype=np.complex64) # savings across state space c = np.empty((I, J), dtype=np.complex64) # flow consumption h = np.empty((I, J), dtype=np.complex64) # flow hours of labor h0 = np.empty((I, J), dtype=np.complex64) # guess of what h will be # Creates functions for computing flow utility, income earned, and labor done given # CRRA + frisch elasticity style labor disutility util, income, labor = \ aux.construct_household_problem_functions(V, w, coefrra, frisch, labtax, labdisutil) # Setting up forward/backward difference grids for a. daf, dab, azdelta = aux.initialize_diff_grids(a, I, J) for ir in range(Ir): c.fill(np.complex(0.)) h.fill(np.complex(1 / 3)) h0.fill(np.complex(1.)) # Initial guess inc = income(h, zz, profshare, lumptransfer, r, aa) # get income v = util(inc, h) / rho # value function guess # Iterate HJB for ihjb in range(maxit_HJB): V = v Vaf, Vab, cf, hf, cb, hb = aux.construct_initial_diff_matrices( V, Vaf, Vab, income, labor, h, h0, zz, profshare, lumptransfer, amax, amin, coefrra, r, daf, dab, maxhours) # Iterative method to find consistent forward/backward/neutral # difference matrices for c and h cf, hf, cb, hb, c0, h0 = aux.hours_iteration( income, labor, zz, profshare, lumptransfer, aa, coefrra, r, cf, hf, cb, hb, c0, h0, maxhours, niter_hours) c0 = income(h0, zz, profshare, lumptransfer, r, aa) sf = income(hf, zz, profshare, lumptransfer, r, aa) - cf sb = income(hb, zz, profshare, lumptransfer, r, aa) - cb Vaf[I - 1, :] = cf[I - 1, :]**( -coefrra ) # Forward difference for value function w.r.t. wealth Vab[0, :] = cb[0, :]**( -coefrra ) # Backward difference for value function w.r.t. wealth V, A, u, h, c, s = aux.upwind(rho, V, util, Aswitch, cf, cb, c0, hf, hb, h0, sf, sb, Vaf, Vab, daf, dab, d_HJB=d_HJB) # Check for convergence Vchange = V - v v = V err_HJB = np.max(np.abs(Vchange)) if err_HJB < tol_HJB: break # Create initial guess for g0 g0 = np.zeros((I, J), dtype=np.complex64) # Assign stationary income distribution weight at a = 0, zero elsewhere g0[a == 0, :] = g_z # g_z is marginal distribution, so re-weight by some multiplier of Lebesgue measure g0 = g0 / azdelta.reshape(I, J) # Solve for distribution g = aux.solve_kfe(A, g0, spdiag(azdelta), maxit_kfe=maxit_kfe, tol_kfe=tol_kfe, d_kfe=d_kfe) # Back out static conditions/steady state values given our value function and distribution N_ss, Y_ss, B_ss, profit_ss, profshare, lumptransfer, bond_err = \ aux.calculate_ss_equil_vars(zz, h, g, azdelta, aa, labor_share_ss, meanlabeff, lumptransferpc, govbondtarget) # Check bond market for market clearing r, rmin, rmax, rho, rhomin, rhomax, clear_cond = \ aux.check_bond_market_clearing(bond_err, crit_S, r, rmin, rmax, rho, rhomin, rhomax, iterate_r, iterate_rho) if clear_cond: # Set steady state values model.steady_state['V_ss'].value = np.real(V.flatten(order='F')) model.steady_state['inflation_ss'].value = 0. model.steady_state['g_ss'].value = np.real(g.flatten(order='F')) model.steady_state['r_ss'].value = r model.steady_state['u_ss'].value = np.real(u.flatten(order='F')) model.steady_state['c_ss'].value = np.real(c.flatten(order='F')) model.steady_state['h_ss'].value = np.real(h.flatten(order='F')) model.steady_state['s_ss'].value = np.real(s.flatten(order='F')) model.steady_state['rnom_ss'].value = model.steady_state['r_ss'].value \ + model.steady_state['inflation_ss'].value model.steady_state['B_ss'].value = sum( model.steady_state['g_ss'].value * aa.flatten(order='F') * azdelta) model.steady_state['N_ss'].value = np.real(sum(zz.flatten(order='F') * model.steady_state['h_ss'].value \ * model.steady_state['g_ss'].value * azdelta)) model.steady_state['Y_ss'].value = model.steady_state['N_ss'].value model.steady_state['labor_share_ss'].value = (ceselast - 1) / ceselast model.steady_state['w_ss'].value = model.steady_state[ 'labor_share_ss'].value model.steady_state['profit_ss'].value = (1 - model.steady_state['labor_share_ss'].value) \ * model.steady_state['Y_ss'].value model.steady_state['C_ss'].value = sum( model.steady_state['c_ss'].value * model.steady_state['g_ss'].value * azdelta) model.steady_state['T_ss'].value = np.real(lumptransfer) model.steady_state['rho_ss'].value = rho model.steady_state['G_ss'].value = labtax * model.steady_state['w_ss'].value * model.steady_state['N_ss'].value \ - model.steady_state['T_ss'].value - model.steady_state['r_ss'].value * model.steady_state['B_ss'].value break return model
def upwind(rho: float, V: np.ndarray, util: object, A_switch: spmatrix, cf: np.ndarray, cb: np.ndarray, c0: np.ndarray, hf: np.ndarray, hb: np.ndarray, h0: np.ndarray, sf: np.ndarray, sb: np.ndarray, Vaf: np.ndarray, Vab: np.ndarray, daf: np.ndarray, dab: np.ndarray, d_HJB: float = 1e6): T = sb[0, 0].dtype I, J = sb.shape # h = np.empty_like(sb) # c = np.empty_like(sb) # s = np.empty_like(sb) # u = np.empty_like(sb) # X = np.empty_like(sb) # Z = np.empty_like(sb) # Y = np.empty_like(sb) Vf = (cf > 0) * (util(cf, hf) + sf * Vaf) + (cf <= 0) * (-1e12) Vb = (cb > 0) * (util(cb, hb) + sb * Vab) + (cb <= 0) * (-1e12) V0 = (c0 > 0) * util(c0, h0) + (c0 <= 0) * (-1e12) Iunique = (sb < 0) * (1 - (sf > 0)) + (1 - (sb < 0)) * (sf > 0) Iboth = (sb < 0) * (sf > 0) Ib = Iunique * (sb < 0) * (Vb > V0) + Iboth * (Vb == np.maximum( np.maximum(Vb, Vf), V0)) If = Iunique * (sf > 0) * (Vf > V0) + Iboth * (Vf == np.maximum( np.maximum(Vb, Vf), V0)) I0 = 1 - Ib - If h = hf * If + hb * Ib + h0 * I0 c = cf * If + cb * Ib + c0 * I0 s = sf * If + sb * Ib u = util(c, h) X = -Ib * sb / np.array([dab, dab]).reshape(I, J) Z = If * sf / np.array([daf, daf]).reshape(I, J) Y = -Z - X X[0, :] = complex(0.) if T == np.complex else 0 Z[I - 1, :] = complex(0.) if T == np.complex else 0 A = spdiag([ X.reshape(I * J, order='F')[1:], Y.reshape(I * J, order='F'), Z.reshape(I * J, order='F')[:I * J - 1] ], offsets=[-1, 0, 1], shape=(I * J, I * J)) + A_switch I, J = u.shape B = (1 / d_HJB + rho) * speye(I * J, dtype=T) - A b = u.reshape(I * J, order='F') + V.reshape(I * J, order='F') / d_HJB V = spsolve(B, b).reshape(I, J, order='F') #V = scipy.sparse.linalg.lsqr(B,b)[0].reshape(I, J,order='F') return V, A, u, h, c, s
def E(self): return spdiag(np.ones(len(self._poles)))
def A(self): return spdiag(self._poles)
def gensys_hank(GAM1, C, PSI, PI, check_existence=True, check_uniqueness=True, eps = np.sqrt(np.finfo(float).eps)*10, div=-1.0): """ Solve a liner rational expectations model by Sims(2002) Generate state-space solution to DSGE model system given as: GAM0 s(t) = GAM1 s(t-1) + c + PSI eps(t) + PI eta(t) Return system is: s(t) = G1 * s(t-1) + c + impact * eps(t) Input ----- GAM0: n x n matrix GAM1: n x n matrix PSI: n x m matrix PI: n x p Return ----- G1: n x n matrix impact: n x m matrix eu: eu[0] = 1 for existence eu[1] = 1 for uniqueness eu = [-2, -2] for coincident zeros """ eu = [0, 0] T, U = schur(GAM1) n = U.shape[0] g_eigs = np.real(eigvals(T)) stable_eigs = lambda eigs :eigs <= 0 nunstab = n - sum(stable_eigs(g_eigs)) T, U, _ = schur(GAM1, sort=stable_eigs) U1 = U[:, :n - nunstab].T U2 = U[:, n - nunstab : n].T etawt = U2 @ PI _, ueta, deta, veta = decomposition_svdct(etawt, eps=eps) if check_existence: zwt = U2 @ PSI bigev, uz, dz, vz = decomposition_svdct(zwt, eps=eps) if all(bigev) == False: eu[0] = 1 else: eu[0] = np.linalg.norm(uz-(ueta @ ueta.conj().T) @ uz) < eps * n # if (eu[0] == 0) & (div == -1): # warnings.warn('Solution does not exist') impact = np. real(-PI @ veta @ solve(deta, ueta.T) @ uz @ dz @ vz.T + PSI) else: eu[0] = 1 impact = np. real(-PI @ veta @ solve(deta, ueta.T) @ U2 + PSI) if check_uniqueness: etawt1 = U1 @ PI bigev, _, deta1, veta1 = decomposition_svdct(etawt1) if all(bigev) == False: eu[1] = 1 else: eu[1] = np.linalg.norm(veta1 - (veta @ veta.conj().T) @ veta1) < eps * n # spdiag_internal = lambda n1, n2: (*spdiag(np.hstack([np.ones(n1),np.zeros(n2)])).nonzero(), \ # np.hstack([np.ones(n1),np.zeros(n2)])) # I, J, V = spdiag_internal(n-nunstab, nunstab) # diag_m = csc_matrix((V, (I, J)), shape=(n, n)) diag_m = spdiag(np.hstack([np.ones(n-nunstab),np.zeros(nunstab)])) G1 = np.real(U @ T @ diag_m @ U.T) F = U1[:, :nunstab].T @ np.linalg.inv(U1[:, nunstab:].T) impact = np.vstack([F @ PSI[nunstab:, :], PSI[nunstab:, :]]) C = np.real(U @ C) * np.ones([U.shape[0], 1]) return G1, C, impact, U, T, eu