def run_TPI(p, client=None): # unpack tuples of parameters initial_values, SS_values, baseline_values = get_initial_SS_values(p) (B0, b_sinit, b_splus1init, factor, initial_b, initial_n, D0) = initial_values (Kss, Bss, Lss, rss, wss, BQss, T_Hss, total_revenue_ss, bssmat_splus1, nssmat, Yss, Gss, theta) = SS_values (T_Hbaseline, Gbaseline) = baseline_values print('Government spending breakpoints are tG1: ', p.tG1, '; and tG2:', p.tG2) # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings domain = np.linspace(0, p.T, p.T) domain2 = np.tile(domain.reshape(p.T, 1, 1), (1, p.S, p.J)) ending_b = bssmat_splus1 guesses_b = (-1 / (domain2 + 1)) * (ending_b - initial_b) + ending_b ending_b_tail = np.tile(ending_b.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, p.T).reshape(p.T, 1, 1), (1, p.S, p.J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = guesses_b # np.zeros((p.T + p.S, p.S, p.J)) n_mat = guesses_n # np.zeros((p.T + p.S, p.S, p.J)) ind = np.arange(p.S) L_init = np.ones((p.T + p.S, )) * Lss B_init = np.ones((p.T + p.S, )) * Bss L_init[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B_init[1:p.T] = aggr.get_K(b_mat[:p.T], p, 'TPI', False)[:p.T - 1] B_init[0] = B0 if not p.small_open: if p.budget_balance: K_init = B_init else: K_init = B_init * Kss / Bss else: K_init = firm.get_K(L_init, p.firm_r, p, 'TPI') K = K_init L = L_init B = B_init Y = np.zeros_like(K) Y[:p.T] = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') Y[p.T:] = Yss r = np.zeros_like(Y) if not p.small_open: r[:p.T] = firm.get_r(Y[:p.T], K[:p.T], p, 'TPI') r[p.T:] = rss else: r = p.firm_r # compute w w = np.zeros_like(r) w[:p.T] = firm.get_w_from_r(r[:p.T], p, 'TPI') w[p.T:] = wss r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r else: r_hh = aggr.get_r_hh(r, r_gov, K, p.debt_ratio_ss * Y) if p.small_open: r_hh = p.hh_r BQ0 = aggr.get_BQ(r[0], initial_b, None, p, 'SS', True) if not p.use_zeta: BQ = np.zeros((p.T + p.S, p.J)) for j in range(p.J): BQ[:, j] = (list(np.linspace(BQ0[j], BQss[j], p.T)) + [BQss[j]] * p.S) BQ = np.array(BQ) else: BQ = (list(np.linspace(BQ0, BQss, p.T)) + [BQss] * p.S) BQ = np.array(BQ) if p.budget_balance: if np.abs(T_Hss) < 1e-13: T_Hss2 = 0.0 # sometimes SS is very small but not zero, # even if taxes are zero, this get's rid of the approximation # error, which affects the perc changes below else: T_Hss2 = T_Hss T_H = np.ones(p.T + p.S) * T_Hss2 total_revenue = T_H G = np.zeros(p.T + p.S) elif not p.baseline_spending: T_H = p.alpha_T * Y elif p.baseline_spending: T_H = T_Hbaseline T_H_new = p.T_H # Need to set T_H_new for later reference G = Gbaseline G_0 = Gbaseline[0] # Initialize some starting value if p.budget_balance: D = 0.0 * Y else: D = p.debt_ratio_ss * Y TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((p.T, 2 * p.S, p.J)) TPIdist_vec = np.zeros(p.maxiter) print('analytical mtrs in tpi = ', p.analytical_mtrs) print('tax function type in tpi = ', p.tax_func_type) # TPI loop while (TPIiter < p.maxiter) and (TPIdist >= p.mindist_TPI): r_gov[:p.T] = fiscal.get_r_gov(r[:p.T], p) if p.budget_balance: r_hh[:p.T] = r[:p.T] else: K[:p.T] = firm.get_K_from_Y(Y[:p.T], r[:p.T], p, 'TPI') r_hh[:p.T] = aggr.get_r_hh(r[:p.T], r_gov[:p.T], K[:p.T], D[:p.T]) if p.small_open: r_hh[:p.T] = p.hh_r[:p.T] outer_loop_vars = (r, w, r_hh, BQ, T_H, theta) euler_errors = np.zeros((p.T, 2 * p.S, p.J)) lazy_values = [] for j in range(p.J): guesses = (guesses_b[:, :, j], guesses_n[:, :, j]) lazy_values.append( delayed(inner_loop)(guesses, outer_loop_vars, initial_values, j, ind, p)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) for j, result in enumerate(results): euler_errors[:, :, j], b_mat[:, :, j], n_mat[:, :, j] = result bmat_s = np.zeros((p.T, p.S, p.J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:p.T - 1, :-1, :] bmat_splus1 = np.zeros((p.T, p.S, p.J)) bmat_splus1[:, :, :] = b_mat[:p.T, :, :] L[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B[1:p.T] = aggr.get_K(bmat_splus1[:p.T], p, 'TPI', False)[:p.T - 1] if np.any(B) < 0: print('B has negative elements. B[0:9]:', B[0:9]) print('B[T-2:T]:', B[p.T - 2, p.T]) etr_params_4D = np.tile( p.etr_params.reshape(p.T, p.S, 1, p.etr_params.shape[2]), (1, 1, p.J, 1)) bqmat = household.get_bq(BQ, None, p, 'TPI') tax_mat = tax.total_taxes(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], factor, T_H[:p.T], theta, 0, None, False, 'TPI', p.e, etr_params_4D, p) r_hh_path = utils.to_timepath_shape(r_hh, p) wpath = utils.to_timepath_shape(w, p) c_mat = household.get_cons(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s, bmat_splus1, n_mat[:p.T, :, :], bqmat[:p.T, :, :], tax_mat, p.e, p.tau_c[:p.T, :, :], p) if not p.small_open: if p.budget_balance: K[:p.T] = B[:p.T] else: if not p.baseline_spending: Y = T_H / p.alpha_T # maybe unecessary (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], c_mat[:p.T, :, :], Y[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue = np.array( list(total_rev) + [total_revenue_ss] * p.S) # set intial debt value if p.baseline: D_0 = p.initial_debt_ratio * Y[0] else: D_0 = D0 if not p.baseline_spending: G_0 = p.alpha_G[0] * Y[0] dg_fixed_values = (Y, total_revenue, T_H, D_0, G_0) Dnew, G = fiscal.D_G_path(r_gov, dg_fixed_values, Gbaseline, p) K[:p.T] = B[:p.T] - Dnew[:p.T] if np.any(K < 0): print('K has negative elements. Setting them ' + 'positive to prevent NAN.') K[:p.T] = np.fmax(K[:p.T], 0.05 * B[:p.T]) else: K[:p.T] = firm.get_K(L[:p.T], p.firm_r[:p.T], p, 'TPI') Ynew = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') if not p.small_open: rnew = firm.get_r(Ynew[:p.T], K[:p.T], p, 'TPI') else: rnew = r.copy() r_gov_new = fiscal.get_r_gov(rnew, p) if p.budget_balance: r_hh_new = rnew[:p.T] else: r_hh_new = aggr.get_r_hh(rnew, r_gov_new, K[:p.T], Dnew[:p.T]) if p.small_open: r_hh_new = p.hh_r[:p.T] # compute w wnew = firm.get_w_from_r(rnew[:p.T], p, 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, p.S, p.J)), b_mat[:p.T - 1, :, :], axis=0) BQnew = aggr.get_BQ(r_hh_new[:p.T], b_mat_shift, None, p, 'TPI', False) bqmat_new = household.get_bq(BQnew, None, p, 'TPI') (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh_new[:p.T], wnew[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat_new[:p.T, :, :], c_mat[:p.T, :, :], Ynew[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue = np.array(list(total_rev) + [total_revenue_ss] * p.S) if p.budget_balance: T_H_new = total_revenue elif not p.baseline_spending: T_H_new = p.alpha_T[:p.T] * Ynew[:p.T] # If baseline_spending==True, no need to update T_H, it's fixed if p.small_open and not p.budget_balance: # Loop through years to calculate debt and gov't spending. # This is done earlier when small_open=False. if p.baseline: D_0 = p.initial_debt_ratio * Y[0] else: D_0 = D0 if not p.baseline_spending: G_0 = p.alpha_G[0] * Ynew[0] dg_fixed_values = (Ynew, total_revenue, T_H, D_0, G_0) Dnew, G = fiscal.D_G_path(r_gov_new, dg_fixed_values, Gbaseline, p) if p.budget_balance: Dnew = D w[:p.T] = wnew[:p.T] r[:p.T] = utils.convex_combo(rnew[:p.T], r[:p.T], p.nu) BQ[:p.T] = utils.convex_combo(BQnew[:p.T], BQ[:p.T], p.nu) D = Dnew Y[:p.T] = utils.convex_combo(Ynew[:p.T], Y[:p.T], p.nu) if not p.baseline_spending: T_H[:p.T] = utils.convex_combo(T_H_new[:p.T], T_H[:p.T], p.nu) guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu) guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu) print('r diff: ', (rnew[:p.T] - r[:p.T]).max(), (rnew[:p.T] - r[:p.T]).min()) print('BQ diff: ', (BQnew[:p.T] - BQ[:p.T]).max(), (BQnew[:p.T] - BQ[:p.T]).min()) print('T_H diff: ', (T_H_new[:p.T] - T_H[:p.T]).max(), (T_H_new[:p.T] - T_H[:p.T]).min()) print('Y diff: ', (Ynew[:p.T] - Y[:p.T]).max(), (Ynew[:p.T] - Y[:p.T]).min()) if not p.baseline_spending: if T_H.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(utils.pct_diff_func(T_H_new[:p.T], T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(np.abs(T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(utils.pct_diff_func(Ynew[:p.T], Y[:p.T]))).max() TPIdist_vec[TPIiter] = TPIdist # After T=10, if cycling occurs, drop the value of nu # wait til after T=10 or so, because sometimes there is a jump up # in the first couple iterations # if TPIiter > 10: # if TPIdist_vec[TPIiter] - TPIdist_vec[TPIiter - 1] > 0: # nu /= 2 # print 'New Value of nu:', nu TPIiter += 1 print('Iteration:', TPIiter) print('\tDistance:', TPIdist) # Compute effective and marginal tax rates for all agents mtrx_params_4D = np.tile( p.mtrx_params.reshape(p.T, p.S, 1, p.mtrx_params.shape[2]), (1, 1, p.J, 1)) mtry_params_4D = np.tile( p.mtry_params.reshape(p.T, p.S, 1, p.mtry_params.shape[2]), (1, 1, p.J, 1)) e_3D = np.tile(p.e.reshape(1, p.S, p.J), (p.T, 1, 1)) mtry_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, True, e_3D, etr_params_4D, mtry_params_4D, p) mtrx_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, False, e_3D, etr_params_4D, mtrx_params_4D, p) etr_path = tax.ETR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, e_3D, etr_params_4D, p) C = aggr.get_C(c_mat, p, 'TPI') if not p.small_open: I = aggr.get_I(bmat_splus1[:p.T], K[1:p.T + 1], K[:p.T], p, 'TPI') rc_error = Y[:p.T] - C[:p.T] - I[:p.T] - G[:p.T] else: I = ((1 + np.squeeze(np.hstack( (p.g_n[1:p.T], p.g_n_ss)))) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) BI = aggr.get_I(bmat_splus1[:p.T], B[1:p.T + 1], B[:p.T], p, 'TPI') new_borrowing = (D[1:p.T] * (1 + p.g_n[1:p.T]) * np.exp(p.g_y) - D[:p.T - 1]) rc_error = (Y[:p.T - 1] + new_borrowing - (C[:p.T - 1] + BI[:p.T - 1] + G[:p.T - 1]) + (p.hh_r[:p.T - 1] * B[:p.T - 1] - (p.delta + p.firm_r[:p.T - 1]) * K[:p.T - 1] - p.hh_r[:p.T - 1] * D[:p.T - 1])) # Compute total investment (not just domestic) I_total = ((1 + p.g_n[:p.T]) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) rce_max = np.amax(np.abs(rc_error)) print('Max absolute value resource constraint error:', rce_max) print('Checking time path for violations of constraints.') for t in range(p.T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_mat[t], t, p.ltilde) eul_savings = euler_errors[:, :p.S, :].max(1).max(1) eul_laborleisure = euler_errors[:, p.S:, :].max(1).max(1) print('Max Euler error, savings: ', eul_savings) print('Max Euler error labor supply: ', eul_laborleisure) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Y': Y[:p.T], 'B': B, 'K': K, 'L': L, 'C': C, 'I': I, 'I_total': I_total, 'BQ': BQ, 'total_revenue': total_revenue, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Ipath, 'T_H': T_H, 'T_P': T_Ppath, 'T_BQ': T_BQpath, 'T_W': T_Wpath, 'T_C': T_Cpath, 'G': G, 'D': D, 'r': r, 'r_gov': r_gov, 'r_hh': r_hh, 'w': w, 'bmat_splus1': bmat_splus1, 'bmat_s': bmat_s[:p.T, :, :], 'n_mat': n_mat[:p.T, :, :], 'c_path': c_mat, 'bq_path': bqmat, 'tax_path': tax_mat, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'resource_constraint_error': rc_error, 'etr_path': etr_path, 'mtrx_path': mtrx_path, 'mtry_path': mtry_path } tpi_dir = os.path.join(p.output_base, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) if np.any(G) < 0: print('Government spending is negative along transition path' + ' to satisfy budget') if (((TPIiter >= p.maxiter) or (np.absolute(TPIdist) > p.mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found' + ' (TPIdist)') if ((np.any(np.absolute(rc_error) >= p.mindist_TPI * 10)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(rc_error)') if ((np.any(np.absolute(eul_savings) >= p.mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > p.mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(eulers)') return output
def test_get_r_gov(r, p, r_gov_expected): r_gov = fiscal.get_r_gov(r, p) assert np.allclose(r_gov, r_gov_expected)
def run_TPI(p, client=None): # unpack tuples of parameters initial_values, SS_values, baseline_values = get_initial_SS_values(p) (B0, b_sinit, b_splus1init, factor, initial_b, initial_n, D0) = initial_values (Kss, Bss, Lss, rss, wss, BQss, T_Hss, total_revenue_ss, bssmat_splus1, nssmat, Yss, Gss, theta) = SS_values (T_Hbaseline, Gbaseline) = baseline_values print('Government spending breakpoints are tG1: ', p.tG1, '; and tG2:', p.tG2) # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings domain = np.linspace(0, p.T, p.T) domain2 = np.tile(domain.reshape(p.T, 1, 1), (1, p.S, p.J)) ending_b = bssmat_splus1 guesses_b = (-1 / (domain2 + 1)) * (ending_b - initial_b) + ending_b ending_b_tail = np.tile(ending_b.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, p.T).reshape(p.T, 1, 1), (1, p.S, p.J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = guesses_b # np.zeros((p.T + p.S, p.S, p.J)) n_mat = guesses_n # np.zeros((p.T + p.S, p.S, p.J)) ind = np.arange(p.S) L_init = np.ones((p.T + p.S,)) * Lss B_init = np.ones((p.T + p.S,)) * Bss L_init[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B_init[1:p.T] = aggr.get_K(b_mat[:p.T], p, 'TPI', False)[:p.T - 1] B_init[0] = B0 if not p.small_open: if p.budget_balance: K_init = B_init else: K_init = B_init * Kss / Bss else: K_init = firm.get_K(L_init, p.firm_r, p, 'TPI') K = K_init L = L_init B = B_init Y = np.zeros_like(K) Y[:p.T] = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') Y[p.T:] = Yss r = np.zeros_like(Y) if not p.small_open: r[:p.T] = firm.get_r(Y[:p.T], K[:p.T], p, 'TPI') r[p.T:] = rss else: r = p.firm_r # compute w w = np.zeros_like(r) w[:p.T] = firm.get_w_from_r(r[:p.T], p, 'TPI') w[p.T:] = wss r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r else: r_hh = aggr.get_r_hh(r, r_gov, K, p.debt_ratio_ss * Y) if p.small_open: r_hh = p.hh_r BQ0 = aggr.get_BQ(r[0], initial_b, None, p, 'SS', True) if not p.use_zeta: BQ = np.zeros((p.T + p.S, p.J)) for j in range(p.J): BQ[:, j] = (list(np.linspace(BQ0[j], BQss[j], p.T)) + [BQss[j]] * p.S) BQ = np.array(BQ) else: BQ = (list(np.linspace(BQ0, BQss, p.T)) + [BQss] * p.S) BQ = np.array(BQ) if p.budget_balance: if np.abs(T_Hss) < 1e-13: T_Hss2 = 0.0 # sometimes SS is very small but not zero, # even if taxes are zero, this get's rid of the approximation # error, which affects the perc changes below else: T_Hss2 = T_Hss T_H = np.ones(p.T + p.S) * T_Hss2 total_revenue = T_H G = np.zeros(p.T + p.S) elif not p.baseline_spending: T_H = p.alpha_T * Y elif p.baseline_spending: T_H = T_Hbaseline T_H_new = p.T_H # Need to set T_H_new for later reference G = Gbaseline G_0 = Gbaseline[0] # Initialize some starting value if p.budget_balance: D = 0.0 * Y else: D = p.debt_ratio_ss * Y TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((p.T, 2 * p.S, p.J)) TPIdist_vec = np.zeros(p.maxiter) print('analytical mtrs in tpi = ', p.analytical_mtrs) print('tax function type in tpi = ', p.tax_func_type) # TPI loop while (TPIiter < p.maxiter) and (TPIdist >= p.mindist_TPI): r_gov[:p.T] = fiscal.get_r_gov(r[:p.T], p) if p.budget_balance: r_hh[:p.T] = r[:p.T] else: K[:p.T] = firm.get_K_from_Y(Y[:p.T], r[:p.T], p, 'TPI') r_hh[:p.T] = aggr.get_r_hh(r[:p.T], r_gov[:p.T], K[:p.T], D[:p.T]) if p.small_open: r_hh[:p.T] = p.hh_r[:p.T] outer_loop_vars = (r, w, r_hh, BQ, T_H, theta) euler_errors = np.zeros((p.T, 2 * p.S, p.J)) lazy_values = [] for j in range(p.J): guesses = (guesses_b[:, :, j], guesses_n[:, :, j]) lazy_values.append( delayed(inner_loop)(guesses, outer_loop_vars, initial_values, j, ind, p)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) for j, result in enumerate(results): euler_errors[:, :, j], b_mat[:, :, j], n_mat[:, :, j] = result bmat_s = np.zeros((p.T, p.S, p.J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:p.T-1, :-1, :] bmat_splus1 = np.zeros((p.T, p.S, p.J)) bmat_splus1[:, :, :] = b_mat[:p.T, :, :] L[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B[1:p.T] = aggr.get_K(bmat_splus1[:p.T], p, 'TPI', False)[:p.T - 1] if np.any(B) < 0: print('B has negative elements. B[0:9]:', B[0:9]) print('B[T-2:T]:', B[p.T - 2, p.T]) etr_params_4D = np.tile( p.etr_params.reshape(p.T, p.S, 1, p.etr_params.shape[2]), (1, 1, p.J, 1)) bqmat = household.get_bq(BQ, None, p, 'TPI') tax_mat = tax.total_taxes(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], factor, T_H[:p.T], theta, 0, None, False, 'TPI', p.e, etr_params_4D, p) r_hh_path = utils.to_timepath_shape(r_hh, p) wpath = utils.to_timepath_shape(w, p) c_mat = household.get_cons(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s, bmat_splus1, n_mat[:p.T, :, :], bqmat[:p.T, :, :], tax_mat, p.e, p.tau_c[:p.T, :, :], p) if not p.small_open: if p.budget_balance: K[:p.T] = B[:p.T] else: if not p.baseline_spending: Y = T_H / p.alpha_T # maybe unecessary (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], c_mat[:p.T, :, :], Y[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue = np.array(list(total_rev) + [total_revenue_ss] * p.S) # set intial debt value if p.baseline: D_0 = p.initial_debt_ratio * Y[0] else: D_0 = D0 if not p.baseline_spending: G_0 = p.alpha_G[0] * Y[0] dg_fixed_values = (Y, total_revenue, T_H, D_0, G_0) Dnew, G = fiscal.D_G_path(r_gov, dg_fixed_values, Gbaseline, p) K[:p.T] = B[:p.T] - Dnew[:p.T] if np.any(K < 0): print('K has negative elements. Setting them ' + 'positive to prevent NAN.') K[:p.T] = np.fmax(K[:p.T], 0.05 * B[:p.T]) else: K[:p.T] = firm.get_K(L[:p.T], p.firm_r[:p.T], p, 'TPI') Ynew = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') if not p.small_open: rnew = firm.get_r(Ynew[:p.T], K[:p.T], p, 'TPI') else: rnew = r.copy() r_gov_new = fiscal.get_r_gov(rnew, p) if p.budget_balance: r_hh_new = rnew[:p.T] else: r_hh_new = aggr.get_r_hh(rnew, r_gov_new, K[:p.T], Dnew[:p.T]) if p.small_open: r_hh_new = p.hh_r[:p.T] # compute w wnew = firm.get_w_from_r(rnew[:p.T], p, 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, p.S, p.J)), b_mat[:p.T - 1, :, :], axis=0) BQnew = aggr.get_BQ(r_hh_new[:p.T], b_mat_shift, None, p, 'TPI', False) bqmat_new = household.get_bq(BQnew, None, p, 'TPI') (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh_new[:p.T], wnew[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat_new[:p.T, :, :], c_mat[:p.T, :, :], Ynew[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue = np.array(list(total_rev) + [total_revenue_ss] * p.S) if p.budget_balance: T_H_new = total_revenue elif not p.baseline_spending: T_H_new = p.alpha_T[:p.T] * Ynew[:p.T] # If baseline_spending==True, no need to update T_H, it's fixed if p.small_open and not p.budget_balance: # Loop through years to calculate debt and gov't spending. # This is done earlier when small_open=False. if p.baseline: D_0 = p.initial_debt_ratio * Y[0] else: D_0 = D0 if not p.baseline_spending: G_0 = p.alpha_G[0] * Ynew[0] dg_fixed_values = (Ynew, total_revenue, T_H, D_0, G_0) Dnew, G = fiscal.D_G_path(r_gov_new, dg_fixed_values, Gbaseline, p) if p.budget_balance: Dnew = D w[:p.T] = wnew[:p.T] r[:p.T] = utils.convex_combo(rnew[:p.T], r[:p.T], p.nu) BQ[:p.T] = utils.convex_combo(BQnew[:p.T], BQ[:p.T], p.nu) D = Dnew Y[:p.T] = utils.convex_combo(Ynew[:p.T], Y[:p.T], p.nu) if not p.baseline_spending: T_H[:p.T] = utils.convex_combo(T_H_new[:p.T], T_H[:p.T], p.nu) guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu) guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu) print('r diff: ', (rnew[:p.T] - r[:p.T]).max(), (rnew[:p.T] - r[:p.T]).min()) print('BQ diff: ', (BQnew[:p.T] - BQ[:p.T]).max(), (BQnew[:p.T] - BQ[:p.T]).min()) print('T_H diff: ', (T_H_new[:p.T]-T_H[:p.T]).max(), (T_H_new[:p.T] - T_H[:p.T]).min()) print('Y diff: ', (Ynew[:p.T]-Y[:p.T]).max(), (Ynew[:p.T] - Y[:p.T]).min()) if not p.baseline_spending: if T_H.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(utils.pct_diff_func(T_H_new[:p.T], T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(np.abs(T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(wnew[:p.T], w[:p.T])) + list(utils.pct_diff_func(Ynew[:p.T], Y[:p.T]))).max() TPIdist_vec[TPIiter] = TPIdist # After T=10, if cycling occurs, drop the value of nu # wait til after T=10 or so, because sometimes there is a jump up # in the first couple iterations # if TPIiter > 10: # if TPIdist_vec[TPIiter] - TPIdist_vec[TPIiter - 1] > 0: # nu /= 2 # print 'New Value of nu:', nu TPIiter += 1 print('Iteration:', TPIiter) print('\tDistance:', TPIdist) # Compute effective and marginal tax rates for all agents mtrx_params_4D = np.tile( p.mtrx_params.reshape(p.T, p.S, 1, p.mtrx_params.shape[2]), (1, 1, p.J, 1)) mtry_params_4D = np.tile( p.mtry_params.reshape(p.T, p.S, 1, p.mtry_params.shape[2]), (1, 1, p.J, 1)) e_3D = np.tile(p.e.reshape(1, p.S, p.J), (p.T, 1, 1)) mtry_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, True, e_3D, etr_params_4D, mtry_params_4D, p) mtrx_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, False, e_3D, etr_params_4D, mtrx_params_4D, p) etr_path = tax.ETR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, e_3D, etr_params_4D, p) C = aggr.get_C(c_mat, p, 'TPI') if not p.small_open: I = aggr.get_I(bmat_splus1[:p.T], K[1:p.T + 1], K[:p.T], p, 'TPI') rc_error = Y[:p.T] - C[:p.T] - I[:p.T] - G[:p.T] else: I = ((1 + np.squeeze(np.hstack((p.g_n[1:p.T], p.g_n_ss)))) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) BI = aggr.get_I(bmat_splus1[:p.T], B[1:p.T + 1], B[:p.T], p, 'TPI') new_borrowing = (D[1:p.T] * (1 + p.g_n[1:p.T]) * np.exp(p.g_y) - D[:p.T - 1]) rc_error = (Y[:p.T - 1] + new_borrowing - ( C[:p.T - 1] + BI[:p.T - 1] + G[:p.T - 1]) + (p.hh_r[:p.T - 1] * B[:p.T - 1] - ( p.delta + p.firm_r[:p.T - 1]) * K[:p.T - 1] - p.hh_r[:p.T - 1] * D[:p.T - 1])) # Compute total investment (not just domestic) I_total = ((1 + p.g_n[:p.T]) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) rce_max = np.amax(np.abs(rc_error)) print('Max absolute value resource constraint error:', rce_max) print('Checking time path for violations of constraints.') for t in range(p.T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_mat[t], t, p.ltilde) eul_savings = euler_errors[:, :p.S, :].max(1).max(1) eul_laborleisure = euler_errors[:, p.S:, :].max(1).max(1) print('Max Euler error, savings: ', eul_savings) print('Max Euler error labor supply: ', eul_laborleisure) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = {'Y': Y[:p.T], 'B': B, 'K': K, 'L': L, 'C': C, 'I': I, 'I_total': I_total, 'BQ': BQ, 'total_revenue': total_revenue, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Ipath, 'T_H': T_H, 'T_P': T_Ppath, 'T_BQ': T_BQpath, 'T_W': T_Wpath, 'T_C': T_Cpath, 'G': G, 'D': D, 'r': r, 'r_gov': r_gov, 'r_hh': r_hh, 'w': w, 'bmat_splus1': bmat_splus1, 'bmat_s': bmat_s[:p.T, :, :], 'n_mat': n_mat[:p.T, :, :], 'c_path': c_mat, 'bq_path': bqmat, 'tax_path': tax_mat, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'resource_constraint_error': rc_error, 'etr_path': etr_path, 'mtrx_path': mtrx_path, 'mtry_path': mtry_path} tpi_dir = os.path.join(p.output_base, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) if np.any(G) < 0: print('Government spending is negative along transition path' + ' to satisfy budget') if (((TPIiter >= p.maxiter) or (np.absolute(TPIdist) > p.mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found' + ' (TPIdist)') if ((np.any(np.absolute(rc_error) >= p.mindist_TPI * 10)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(rc_error)') if ((np.any(np.absolute(eul_savings) >= p.mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > p.mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(eulers)') return output
def run_TPI(p, client=None): ''' Solve for transition path equilibrium of OG-USA. Args: p (OG-USA Specifications object): model parameters client (Dask client object): client Returns: output (dictionary): dictionary with transition path solution results ''' # unpack tuples of parameters initial_values, ss_vars, theta, baseline_values = get_initial_SS_values(p) (B0, b_sinit, b_splus1init, factor, initial_b, initial_n) =\ initial_values (TRbaseline, Gbaseline, D0_baseline) = baseline_values print('Government spending breakpoints are tG1: ', p.tG1, '; and tG2:', p.tG2) # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings guesses_b = utils.get_initial_path(initial_b, ss_vars['bssmat_splus1'], p, 'ratio') guesses_n = utils.get_initial_path(initial_n, ss_vars['nssmat'], p, 'ratio') b_mat = guesses_b n_mat = guesses_n ind = np.arange(p.S) # Get path for aggregate savings and labor supply` L_init = np.ones((p.T + p.S, )) * ss_vars['Lss'] B_init = np.ones((p.T + p.S, )) * ss_vars['Bss'] L_init[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B_init[1:p.T] = aggr.get_B(b_mat[:p.T], p, 'TPI', False)[:p.T - 1] B_init[0] = B0 K_init = B_init * ss_vars['Kss'] / ss_vars['Bss'] K = K_init K_d = K_init * ss_vars['K_d_ss'] / ss_vars['Kss'] K_f = K_init * ss_vars['K_f_ss'] / ss_vars['Kss'] L = L_init B = B_init Y = np.zeros_like(K) Y[:p.T] = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') Y[p.T:] = ss_vars['Yss'] r = np.zeros_like(Y) r[:p.T] = firm.get_r(Y[:p.T], K[:p.T], p, 'TPI') r[p.T:] = ss_vars['rss'] # For case where economy is small open econ r[p.zeta_K == 1] = p.world_int_rate[p.zeta_K == 1] # Compute other interest rates r_gov = fiscal.get_r_gov(r, p) r_hh = aggr.get_r_hh(r, r_gov, K, ss_vars['Dss']) # compute w w = np.zeros_like(r) w[:p.T] = firm.get_w_from_r(r[:p.T], p, 'TPI') w[p.T:] = ss_vars['wss'] # initial guesses at fiscal vars if p.budget_balance: if np.abs(ss_vars['TR_ss']) < 1e-13: TR_ss2 = 0.0 # sometimes SS is very small but not zero, # even if taxes are zero, this get's rid of the # approximation error, which affects the pct changes below else: TR_ss2 = ss_vars['TR_ss'] TR = np.ones(p.T + p.S) * TR_ss2 total_tax_revenue = TR - ss_vars['agg_pension_outlays'] G = np.zeros(p.T + p.S) D = np.zeros(p.T + p.S) D_d = np.zeros(p.T + p.S) D_f = np.zeros(p.T + p.S) else: if p.baseline_spending: TR = TRbaseline G = Gbaseline G[p.T:] = ss_vars['Gss'] else: TR = p.alpha_T * Y G = np.ones(p.T + p.S) * ss_vars['Gss'] D = np.ones(p.T + p.S) * ss_vars['Dss'] D_d = D * ss_vars['D_d_ss'] / ss_vars['Dss'] D_f = D * ss_vars['D_f_ss'] / ss_vars['Dss'] total_tax_revenue = np.ones(p.T + p.S) * ss_vars['total_tax_revenue'] # Initialize bequests BQ0 = aggr.get_BQ(r_hh[0], initial_b, None, p, 'SS', True) if not p.use_zeta: BQ = np.zeros((p.T + p.S, p.J)) for j in range(p.J): BQ[:, j] = (list(np.linspace(BQ0[j], ss_vars['BQss'][j], p.T)) + [ss_vars['BQss'][j]] * p.S) BQ = np.array(BQ) else: BQ = (list(np.linspace(BQ0, ss_vars['BQss'], p.T)) + [ss_vars['BQss']] * p.S) BQ = np.array(BQ) TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((p.T, 2 * p.S, p.J)) TPIdist_vec = np.zeros(p.maxiter) # TPI loop while (TPIiter < p.maxiter) and (TPIdist >= p.mindist_TPI): r_gov[:p.T] = fiscal.get_r_gov(r[:p.T], p) if not p.budget_balance: K[:p.T] = firm.get_K_from_Y(Y[:p.T], r[:p.T], p, 'TPI') r_hh[:p.T] = aggr.get_r_hh(r[:p.T], r_gov[:p.T], K[:p.T], D[:p.T]) outer_loop_vars = (r, w, r_hh, BQ, TR, theta) euler_errors = np.zeros((p.T, 2 * p.S, p.J)) lazy_values = [] for j in range(p.J): guesses = (guesses_b[:, :, j], guesses_n[:, :, j]) lazy_values.append( delayed(inner_loop)(guesses, outer_loop_vars, initial_values, j, ind, p)) if client: futures = client.compute(lazy_values, num_workers=p.num_workers) results = client.gather(futures) else: results = results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) for j, result in enumerate(results): euler_errors[:, :, j], b_mat[:, :, j], n_mat[:, :, j] = result bmat_s = np.zeros((p.T, p.S, p.J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:p.T - 1, :-1, :] bmat_splus1 = np.zeros((p.T, p.S, p.J)) bmat_splus1[:, :, :] = b_mat[:p.T, :, :] etr_params_4D = np.tile( p.etr_params.reshape(p.T, p.S, 1, p.etr_params.shape[2]), (1, 1, p.J, 1)) bqmat = household.get_bq(BQ, None, p, 'TPI') trmat = household.get_tr(TR, None, p, 'TPI') tax_mat = tax.net_taxes(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], factor, trmat[:p.T, :, :], theta, 0, None, False, 'TPI', p.e, etr_params_4D, p) r_hh_path = utils.to_timepath_shape(r_hh) wpath = utils.to_timepath_shape(w) c_mat = household.get_cons(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s, bmat_splus1, n_mat[:p.T, :, :], bqmat[:p.T, :, :], tax_mat, p.e, p.tau_c[:p.T, :, :], p) y_before_tax_mat = household.get_y(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], p) (total_tax_rev, iit_payroll_tax_revenue, agg_pension_outlays, bequest_tax_revenue, wealth_tax_revenue, cons_tax_revenue, business_tax_revenue, payroll_tax_revenue, iit_revenue) = aggr.revenue(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], c_mat[:p.T, :, :], Y[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_tax_revenue[:p.T] = total_tax_rev dg_fixed_values = (Y, total_tax_revenue, agg_pension_outlays, TR, Gbaseline, D0_baseline) (Dnew, G[:p.T], D_d[:p.T], D_f[:p.T], new_borrowing, debt_service, new_borrowing_f) =\ fiscal.D_G_path(r_gov, dg_fixed_values, p) L[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B[1:p.T] = aggr.get_B(bmat_splus1[:p.T], p, 'TPI', False)[:p.T - 1] K_demand_open = firm.get_K(L[:p.T], p.world_int_rate[:p.T], p, 'TPI') K[:p.T], K_d[:p.T], K_f[:p.T] = aggr.get_K_splits( B[:p.T], K_demand_open, D_d[:p.T], p.zeta_K[:p.T]) Ynew = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') rnew = r.copy() rnew[:p.T] = firm.get_r(Ynew[:p.T], K[:p.T], p, 'TPI') # For case where economy is small open econ r[p.zeta_K == 1] = p.world_int_rate[p.zeta_K == 1] r_gov_new = fiscal.get_r_gov(rnew, p) r_hh_new = aggr.get_r_hh(rnew[:p.T], r_gov_new[:p.T], K[:p.T], Dnew[:p.T]) # compute w wnew = firm.get_w_from_r(rnew[:p.T], p, 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, p.S, p.J)), b_mat[:p.T - 1, :, :], axis=0) BQnew = aggr.get_BQ(r_hh_new[:p.T], b_mat_shift, None, p, 'TPI', False) bqmat_new = household.get_bq(BQnew, None, p, 'TPI') (total_tax_rev, iit_payroll_tax_revenue, agg_pension_outlays, bequest_tax_revenue, wealth_tax_revenue, cons_tax_revenue, business_tax_revenue, payroll_tax_revenue, iit_revenue) = aggr.revenue(r_hh_new[:p.T], wnew[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat_new[:p.T, :, :], c_mat[:p.T, :, :], Ynew[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_tax_revenue[:p.T] = total_tax_rev TR_new = fiscal.get_TR(Ynew[:p.T], TR[:p.T], G[:p.T], total_tax_revenue[:p.T], agg_pension_outlays[:p.T], p, 'TPI') # update vars for next iteration w[:p.T] = wnew[:p.T] r[:p.T] = utils.convex_combo(rnew[:p.T], r[:p.T], p.nu) BQ[:p.T] = utils.convex_combo(BQnew[:p.T], BQ[:p.T], p.nu) D[:p.T] = Dnew[:p.T] Y[:p.T] = utils.convex_combo(Ynew[:p.T], Y[:p.T], p.nu) if not p.baseline_spending: TR[:p.T] = utils.convex_combo(TR_new[:p.T], TR[:p.T], p.nu) guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu) guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu) print('r diff: ', (rnew[:p.T] - r[:p.T]).max(), (rnew[:p.T] - r[:p.T]).min()) print('BQ diff: ', (BQnew[:p.T] - BQ[:p.T]).max(), (BQnew[:p.T] - BQ[:p.T]).min()) print('TR diff: ', (TR_new[:p.T] - TR[:p.T]).max(), (TR_new[:p.T] - TR[:p.T]).min()) print('Y diff: ', (Ynew[:p.T] - Y[:p.T]).max(), (Ynew[:p.T] - Y[:p.T]).min()) if not p.baseline_spending: if TR.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(TR_new[:p.T], TR[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(np.abs(TR[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(Ynew[:p.T], Y[:p.T]))).max() TPIdist_vec[TPIiter] = TPIdist # After T=10, if cycling occurs, drop the value of nu # wait til after T=10 or so, because sometimes there is a jump up # in the first couple iterations # if TPIiter > 10: # if TPIdist_vec[TPIiter] - TPIdist_vec[TPIiter - 1] > 0: # nu /= 2 # print 'New Value of nu:', nu TPIiter += 1 print('Iteration:', TPIiter) print('\tDistance:', TPIdist) # Compute effective and marginal tax rates for all agents mtrx_params_4D = np.tile( p.mtrx_params.reshape(p.T, p.S, 1, p.mtrx_params.shape[2]), (1, 1, p.J, 1)) mtry_params_4D = np.tile( p.mtry_params.reshape(p.T, p.S, 1, p.mtry_params.shape[2]), (1, 1, p.J, 1)) e_3D = np.tile(p.e.reshape(1, p.S, p.J), (p.T, 1, 1)) mtry_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, True, e_3D, etr_params_4D, mtry_params_4D, p) mtrx_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, False, e_3D, etr_params_4D, mtrx_params_4D, p) etr_path = tax.ETR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, e_3D, etr_params_4D, p) C = aggr.get_C(c_mat, p, 'TPI') # Note that implicity in this computation is that immigrants' # wealth is all in the form of private capital I_d = aggr.get_I(bmat_splus1[:p.T], K_d[1:p.T + 1], K_d[:p.T], p, 'TPI') I = aggr.get_I(bmat_splus1[:p.T], K[1:p.T + 1], K[:p.T], p, 'TPI') # solve resource constraint # foreign debt service costs debt_service_f = fiscal.get_debt_service_f(r_hh, D_f) RC_error = aggr.resource_constraint(Y[:p.T - 1], C[:p.T - 1], G[:p.T - 1], I_d[:p.T - 1], K_f[:p.T - 1], new_borrowing_f[:p.T - 1], debt_service_f[:p.T - 1], r_hh[:p.T - 1], p) # Compute total investment (not just domestic) I_total = aggr.get_I(None, K[1:p.T + 1], K[:p.T], p, 'total_tpi') # Compute resource constraint error rce_max = np.amax(np.abs(RC_error)) print('Max absolute value resource constraint error:', rce_max) print('Checking time path for violations of constraints.') for t in range(p.T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_mat[t], t, p.ltilde) eul_savings = euler_errors[:, :p.S, :].max(1).max(1) eul_laborleisure = euler_errors[:, p.S:, :].max(1).max(1) print('Max Euler error, savings: ', eul_savings) print('Max Euler error labor supply: ', eul_laborleisure) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Y': Y[:p.T], 'B': B, 'K': K, 'K_f': K_f, 'K_d': K_d, 'L': L, 'C': C, 'I': I, 'I_total': I_total, 'I_d': I_d, 'BQ': BQ, 'total_tax_revenue': total_tax_revenue, 'business_tax_revenue': business_tax_revenue, 'iit_payroll_tax_revenue': iit_payroll_tax_revenue, 'iit_revenue': iit_revenue, 'payroll_tax_revenue': payroll_tax_revenue, 'TR': TR, 'agg_pension_outlays': agg_pension_outlays, 'bequest_tax_revenue': bequest_tax_revenue, 'wealth_tax_revenue': wealth_tax_revenue, 'cons_tax_revenue': cons_tax_revenue, 'G': G, 'D': D, 'D_f': D_f, 'D_d': D_d, 'r': r, 'r_gov': r_gov, 'r_hh': r_hh, 'w': w, 'bmat_splus1': bmat_splus1, 'bmat_s': bmat_s[:p.T, :, :], 'n_mat': n_mat[:p.T, :, :], 'c_path': c_mat, 'bq_path': bqmat, 'tr_path': trmat, 'y_before_tax_mat': y_before_tax_mat, 'tax_path': tax_mat, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'resource_constraint_error': RC_error, 'new_borrowing_f': new_borrowing_f, 'debt_service_f': debt_service_f, 'etr_path': etr_path, 'mtrx_path': mtrx_path, 'mtry_path': mtry_path } tpi_dir = os.path.join(p.output_base, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") with open(tpi_vars, "wb") as f: pickle.dump(output, f) if np.any(G) < 0: print('Government spending is negative along transition path' + ' to satisfy budget') if (((TPIiter >= p.maxiter) or (np.absolute(TPIdist) > p.mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found' + ' (TPIdist)') if ((np.any(np.absolute(RC_error) >= p.mindist_TPI * 10)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(RC_error)') if ((np.any(np.absolute(eul_savings) >= p.mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > p.mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(eulers)') return output
def inner_loop(outer_loop_vars, p, client): ''' This function solves for the inner loop of the SS. That is, given the guesses of the outer loop variables (r, w, Y, factor) this function solves the households' problems in the SS. Inputs: r = [T,] vector, interest rate w = [T,] vector, wage rate b = [T,S,J] array, wealth holdings n = [T,S,J] array, labor supply BQ = [T,J] vector, bequest amounts factor = scalar, model income scaling factor Y = [T,] vector, lump sum transfer amount(s) Functions called: euler_equation_solver() aggr.get_K() aggr.get_L() firm.get_Y() firm.get_r() firm.get_w() aggr.get_BQ() tax.replacement_rate_vals() aggr.revenue() Objects in function: Returns: euler_errors, bssmat, nssmat, new_r, new_w new_T_H, new_factor, new_BQ ''' # unpack variables to pass to function if p.budget_balance: bssmat, nssmat, r, BQ, T_H, factor = outer_loop_vars else: bssmat, nssmat, r, BQ, Y, T_H, factor = outer_loop_vars euler_errors = np.zeros((2 * p.S, p.J)) w = firm.get_w_from_r(r, p, 'SS') r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r D = 0 else: D = p.debt_ratio_ss * Y K = firm.get_K_from_Y(Y, r, p, 'SS') r_hh = aggr.get_r_hh(r, r_gov, K, D) if p.small_open: r_hh = p.hh_r[-1] bq = household.get_bq(BQ, None, p, 'SS') lazy_values = [] for j in range(p.J): guesses = np.append(bssmat[:, j], nssmat[:, j]) euler_params = (r_hh, w, bq[:, j], T_H, factor, j, p) lazy_values.append(delayed(opt.fsolve)(euler_equation_solver, guesses * .9, args=euler_params, xtol=MINIMIZER_TOL, full_output=True)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) # for j, result in results.items(): for j, result in enumerate(results): [solutions, infodict, ier, message] = result euler_errors[:, j] = infodict['fvec'] bssmat[:, j] = solutions[:p.S] nssmat[:, j] = solutions[p.S:] L = aggr.get_L(nssmat, p, 'SS') B = aggr.get_K(bssmat, p, 'SS', False) K_demand_open = firm.get_K(L, p.firm_r[-1], p, 'SS') D_f = p.zeta_D[-1] * D D_d = D - D_f if not p.small_open: K_d = B - D_d K_f = p.zeta_K[-1] * (K_demand_open - B + D_d) K = K_f + K_d else: # can remove this else statement by making small open the case where zeta_K = 1 K_d = B - D_d K_f = K_demand_open - B + D_d K = K_f + K_d new_Y = firm.get_Y(K, L, p, 'SS') if p.budget_balance: Y = new_Y if not p.small_open: new_r = firm.get_r(Y, K, p, 'SS') else: new_r = p.firm_r[-1] new_w = firm.get_w_from_r(new_r, p, 'SS') b_s = np.array(list(np.zeros(p.J).reshape(1, p.J)) + list(bssmat[:-1, :])) new_r_gov = fiscal.get_r_gov(new_r, p) new_r_hh = aggr.get_r_hh(new_r, new_r_gov, K, D) average_income_model = ((new_r_hh * b_s + new_w * p.e * nssmat) * p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).sum() if p.baseline: new_factor = p.mean_income_data / average_income_model else: new_factor = factor new_BQ = aggr.get_BQ(new_r_hh, bssmat, None, p, 'SS', False) new_bq = household.get_bq(new_BQ, None, p, 'SS') theta = tax.replacement_rate_vals(nssmat, new_w, new_factor, None, p) if p.budget_balance: etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) taxss = tax.total_taxes(new_r_hh, new_w, b_s, nssmat, new_bq, factor, T_H, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(new_r_hh, new_w, b_s, bssmat, nssmat, new_bq, taxss, p.e, p.tau_c[-1, :, :], p) new_T_H, _, _, _, _, _, _ = aggr.revenue( new_r_hh, new_w, b_s, nssmat, new_bq, cssmat, new_Y, L, K, factor, theta, etr_params_3D, p, 'SS') elif p.baseline_spending: new_T_H = T_H else: new_T_H = p.alpha_T[-1] * new_Y return euler_errors, bssmat, nssmat, new_r, new_r_gov, new_r_hh, \ new_w, new_T_H, new_Y, new_factor, new_BQ, average_income_model
def SS_solver(bmat, nmat, r, BQ, T_H, factor, Y, p, client, fsolve_flag=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = length X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() aggr.get_K() aggr.get_L() firm.get_Y() firm.get_r() firm.get_w() aggr.get_BQ() tax.replacement_rate_vals() aggr.revenue() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption OBJECTS CREATED WITHIN FUNCTION - SMALL OPEN ONLY Bss = scalar, aggregate household wealth in the steady state BIss = scalar, aggregate household net investment in the steady state RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' # Rename the inputs if not p.budget_balance: if not p.baseline_spending: Y = T_H / p.alpha_T[-1] if p.small_open: r = p.hh_r[-1] dist = 10 iteration = 0 dist_vec = np.zeros(p.maxiter) maxiter_ss = p.maxiter nu_ss = p.nu if fsolve_flag: maxiter_ss = 1 while (dist > p.mindist_SS) and (iteration < maxiter_ss): # Solve for the steady state levels of b and n, given w, r, # Y and factor if p.budget_balance: outer_loop_vars = (bmat, nmat, r, BQ, T_H, factor) else: outer_loop_vars = (bmat, nmat, r, BQ, Y, T_H, factor) (euler_errors, new_bmat, new_nmat, new_r, new_r_gov, new_r_hh, new_w, new_T_H, new_Y, new_factor, new_BQ, average_income_model) =\ inner_loop(outer_loop_vars, p, client) r = utils.convex_combo(new_r, r, nu_ss) factor = utils.convex_combo(new_factor, factor, nu_ss) BQ = utils.convex_combo(new_BQ, BQ, nu_ss) # bmat = utils.convex_combo(new_bmat, bmat, nu_ss) # nmat = utils.convex_combo(new_nmat, nmat, nu_ss) if not p.baseline_spending: T_H = utils.convex_combo(new_T_H, T_H, nu_ss) dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() else: Y = utils.convex_combo(new_Y, Y, nu_ss) if Y != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_Y, Y)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If Y is zero (if there is no output), a percent difference # will throw NaN's, so we use an absolute difference dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [abs(new_Y - Y)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu_ss /= 2.0 print('New value of nu:', nu_ss) iteration += 1 print('Iteration: %02d' % iteration, ' Distance: ', dist) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1, p.J)), bmat[:-1, :], axis=0) bssmat_splus1 = bmat nssmat = nmat rss = r r_gov_ss = fiscal.get_r_gov(rss, p) if p.budget_balance: r_hh_ss = rss Dss = 0.0 else: Dss = p.debt_ratio_ss * Y Lss = aggr.get_L(nssmat, p, 'SS') Bss = aggr.get_K(bssmat_splus1, p, 'SS', False) K_demand_open_ss = firm.get_K(Lss, p.firm_r[-1], p, 'SS') D_f_ss = p.zeta_D[-1] * Dss D_d_ss = Dss - D_f_ss K_d_ss = Bss - D_d_ss if not p.small_open: K_f_ss = p.zeta_K[-1] * (K_demand_open_ss - Bss + D_d_ss) Kss = K_f_ss + K_d_ss # Note that implicity in this computation is that immigrants' # wealth is all in the form of private capital I_d_ss = aggr.get_I(bssmat_splus1, K_d_ss, K_d_ss, p, 'SS') Iss = aggr.get_I(bssmat_splus1, Kss, Kss, p, 'SS') else: K_d_ss = Bss - D_d_ss K_f_ss = K_demand_open_ss - Bss + D_d_ss Kss = K_f_ss + K_d_ss InvestmentPlaceholder = np.zeros(bssmat_splus1.shape) Iss = aggr.get_I(InvestmentPlaceholder, Kss, Kss, p, 'SS') BIss = aggr.get_I(bssmat_splus1, Bss, Bss, p, 'BI_SS') I_d_ss = aggr.get_I(bssmat_splus1, K_d_ss, K_d_ss, p, 'SS') r_hh_ss = aggr.get_r_hh(rss, r_gov_ss, Kss, Dss) wss = new_w BQss = new_BQ factor_ss = factor T_Hss = T_H bqssmat = household.get_bq(BQss, None, p, 'SS') Yss = firm.get_Y(Kss, Lss, p, 'SS') theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, None, p) # Compute effective and marginal tax rates for all agents etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) mtrx_params_3D = np.tile(np.reshape( p.mtrx_params[-1, :, :], (p.S, 1, p.mtrx_params.shape[2])), (1, p.J, 1)) mtry_params_3D = np.tile(np.reshape( p.mtry_params[-1, :, :], (p.S, 1, p.mtry_params.shape[2])), (1, p.J, 1)) mtry_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, True, p.e, etr_params_3D, mtry_params_3D, p) mtrx_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, False, p.e, etr_params_3D, mtrx_params_3D, p) etr_ss = tax.ETR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, p.e, etr_params_3D, p) taxss = tax.total_taxes(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, factor_ss, T_Hss, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(r_hh_ss, wss, bssmat_s, bssmat_splus1, nssmat, bqssmat, taxss, p.e, p.tau_c[-1, :, :], p) yss_before_tax_mat = r_hh_ss * bssmat_s + wss * p.e * nssmat Css = aggr.get_C(cssmat, p, 'SS') (total_revenue_ss, T_Iss, T_Pss, T_BQss, T_Wss, T_Css, business_revenue) =\ aggr.revenue(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, cssmat, Yss, Lss, Kss, factor, theta, etr_params_3D, p, 'SS') debt_service_ss = r_gov_ss * Dss new_borrowing = Dss * ((1 + p.g_n_ss) * np.exp(p.g_y) - 1) # government spends such that it expands its debt at the same rate as GDP if p.budget_balance: Gss = 0.0 else: Gss = total_revenue_ss + new_borrowing - (T_Hss + debt_service_ss) print('G components = ', new_borrowing, T_Hss, debt_service_ss) # Compute total investment (not just domestic) Iss_total = ((1 + p.g_n_ss) * np.exp(p.g_y) - 1 + p.delta) * Kss # solve resource constraint # net foreign borrowing print('Foreign debt holdings = ', D_f_ss) print('Foreign capital holdings = ', K_f_ss) new_borrowing_f = D_f_ss * (np.exp(p.g_y) * (1 + p.g_n_ss) - 1) debt_service_f = D_f_ss * r_hh_ss RC = aggr.resource_constraint(Yss, Css, Gss, I_d_ss, K_f_ss, new_borrowing_f, debt_service_f, r_hh_ss, p) print('resource constraint: ', RC) if Gss < 0: print('Steady state government spending is negative to satisfy' + ' budget') if ENFORCE_SOLUTION_CHECKS and (np.absolute(RC) > p.mindist_SS): print('Resource Constraint Difference:', RC) err = 'Steady state aggregate resource constraint not satisfied' raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat_splus1, nssmat, cssmat, p.ltilde) euler_savings = euler_errors[:p.S, :] euler_labor_leisure = euler_errors[p.S:, :] print('Maximum error in labor FOC = ', np.absolute(euler_labor_leisure).max()) print('Maximum error in savings FOC = ', np.absolute(euler_savings).max()) ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = {'Kss': Kss, 'K_f_ss': K_f_ss, 'K_d_ss': K_d_ss, 'Bss': Bss, 'Lss': Lss, 'Css': Css, 'Iss': Iss, 'Iss_total': Iss_total, 'I_d_ss': I_d_ss, 'nssmat': nssmat, 'Yss': Yss, 'Dss': Dss, 'D_f_ss': D_f_ss, 'D_d_ss': D_d_ss, 'wss': wss, 'rss': rss, 'r_gov_ss': r_gov_ss, 'r_hh_ss': r_hh_ss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'yss_before_tax_mat': yss_before_tax_mat, 'bqssmat': bqssmat, 'T_Hss': T_Hss, 'Gss': Gss, 'total_revenue_ss': total_revenue_ss, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Iss, 'T_Pss': T_Pss, 'T_BQss': T_BQss, 'T_Wss': T_Wss, 'T_Css': T_Css, 'euler_savings': euler_savings, 'debt_service_f': debt_service_f, 'new_borrowing_f': new_borrowing_f, 'debt_service_ss': debt_service_ss, 'new_borrowing': new_borrowing, 'euler_labor_leisure': euler_labor_leisure, 'resource_constraint_error': RC, 'etr_ss': etr_ss, 'mtrx_ss': mtrx_ss, 'mtry_ss': mtry_ss} return output
def inner_loop(outer_loop_vars, p, client): ''' This function solves for the inner loop of the SS. That is, given the guesses of the outer loop variables (r, w, TR, factor) this function solves the households' problems in the SS. Args: outer_loop_vars (tuple): tuple of outer loop variables, (bssmat, nssmat, r, BQ, TR, factor) or (bssmat, nssmat, r, BQ, Y, TR, factor) bssmat (Numpy array): initial guess at savings, size = SxJ nssmat (Numpy array): initial guess at labor supply, size = SxJ BQ (array_like): aggregate bequest amount(s) Y (scalar): real GDP TR (scalar): lump sum transfer amount factor (scalar): scaling factor converting model units to dollars w (scalar): real wage rate p (OG-USA Specifications object): model parameters client (Dask client object): client Returns: (tuple): results from household solution: * euler_errors (Numpy array): errors terms from FOCs, size = 2SxJ * bssmat (Numpy array): savings, size = SxJ * nssmat (Numpy array): labor supply, size = SxJ * new_r (scalar): real interest rate on firm capital * new_r_gov (scalar): real interest rate on government debt * new_r_hh (scalar): real interest rate on household portfolio * new_w (scalar): real wage rate * new_TR (scalar): lump sum transfer amount * new_Y (scalar): real GDP * new_factor (scalar): scaling factor converting model units to dollars * new_BQ (array_like): aggregate bequest amount(s) * average_income_model (scalar): average income in model units ''' # unpack variables to pass to function if p.budget_balance: bssmat, nssmat, r, BQ, TR, factor = outer_loop_vars else: bssmat, nssmat, r, BQ, Y, TR, factor = outer_loop_vars euler_errors = np.zeros((2 * p.S, p.J)) w = firm.get_w_from_r(r, p, 'SS') r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r D = 0 else: D = p.debt_ratio_ss * Y K = firm.get_K_from_Y(Y, r, p, 'SS') r_hh = aggr.get_r_hh(r, r_gov, K, D) if p.small_open: r_hh = p.hh_r[-1] bq = household.get_bq(BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') lazy_values = [] for j in range(p.J): guesses = np.append(bssmat[:, j], nssmat[:, j]) euler_params = (r_hh, w, bq[:, j], tr[:, j], factor, j, p) lazy_values.append(delayed(opt.fsolve)(euler_equation_solver, guesses * .9, args=euler_params, xtol=MINIMIZER_TOL, full_output=True)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) # for j, result in results.items(): for j, result in enumerate(results): [solutions, infodict, ier, message] = result euler_errors[:, j] = infodict['fvec'] bssmat[:, j] = solutions[:p.S] nssmat[:, j] = solutions[p.S:] L = aggr.get_L(nssmat, p, 'SS') B = aggr.get_B(bssmat, p, 'SS', False) K_demand_open = firm.get_K(L, p.firm_r[-1], p, 'SS') D_f = p.zeta_D[-1] * D D_d = D - D_f if not p.small_open: K_d = B - D_d K_f = p.zeta_K[-1] * (K_demand_open - B + D_d) K = K_f + K_d else: # can remove this else statement by making small open the case # where zeta_K = 1 K_d = B - D_d K_f = K_demand_open - B + D_d K = K_f + K_d new_Y = firm.get_Y(K, L, p, 'SS') if p.budget_balance: Y = new_Y if not p.small_open: new_r = firm.get_r(Y, K, p, 'SS') else: new_r = p.firm_r[-1] new_w = firm.get_w_from_r(new_r, p, 'SS') b_s = np.array(list(np.zeros(p.J).reshape(1, p.J)) + list(bssmat[:-1, :])) new_r_gov = fiscal.get_r_gov(new_r, p) new_r_hh = aggr.get_r_hh(new_r, new_r_gov, K, D) average_income_model = ((new_r_hh * b_s + new_w * p.e * nssmat) * p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).sum() if p.baseline: new_factor = p.mean_income_data / average_income_model else: new_factor = factor new_BQ = aggr.get_BQ(new_r_hh, bssmat, None, p, 'SS', False) new_bq = household.get_bq(new_BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') theta = tax.replacement_rate_vals(nssmat, new_w, new_factor, None, p) if p.budget_balance: etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) taxss = tax.total_taxes(new_r_hh, new_w, b_s, nssmat, new_bq, factor, tr, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(new_r_hh, new_w, b_s, bssmat, nssmat, new_bq, taxss, p.e, p.tau_c[-1, :, :], p) new_TR, _, _, _, _, _, _ = aggr.revenue( new_r_hh, new_w, b_s, nssmat, new_bq, cssmat, new_Y, L, K, factor, theta, etr_params_3D, p, 'SS') elif p.baseline_spending: new_TR = TR else: new_TR = p.alpha_T[-1] * new_Y return euler_errors, bssmat, nssmat, new_r, new_r_gov, new_r_hh, \ new_w, new_TR, new_Y, new_factor, new_BQ, average_income_model
def run_TPI(p, client=None): # unpack tuples of parameters initial_values, ss_vars, theta, baseline_values = get_initial_SS_values(p) (B0, b_sinit, b_splus1init, factor, initial_b, initial_n, D0) = initial_values (T_Hbaseline, Gbaseline) = baseline_values print('Government spending breakpoints are tG1: ', p.tG1, '; and tG2:', p.tG2) # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings domain = np.linspace(0, p.T, p.T) domain2 = np.tile(domain.reshape(p.T, 1, 1), (1, p.S, p.J)) ending_b = ss_vars['bssmat_splus1'] guesses_b = (-1 / (domain2 + 1)) * (ending_b - initial_b) + ending_b ending_b_tail = np.tile(ending_b.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, p.T).reshape(p.T, 1, 1), (1, p.S, p.J)) guesses_n = domain3 * (ss_vars['nssmat'] - initial_n) + initial_n ending_n_tail = np.tile(ss_vars['nssmat'].reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = guesses_b n_mat = guesses_n ind = np.arange(p.S) L_init = np.ones((p.T + p.S, )) * ss_vars['Lss'] B_init = np.ones((p.T + p.S, )) * ss_vars['Bss'] L_init[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B_init[1:p.T] = aggr.get_K(b_mat[:p.T], p, 'TPI', False)[:p.T - 1] B_init[0] = B0 if not p.small_open: if p.budget_balance: K_init = B_init else: K_init = B_init * ss_vars['Kss'] / ss_vars['Bss'] else: K_init = firm.get_K(L_init, p.firm_r, p, 'TPI') K = K_init K_d = K_init * ss_vars['K_d_ss'] / ss_vars['Kss'] K_f = K_init * ss_vars['K_f_ss'] / ss_vars['Kss'] L = L_init B = B_init Y = np.zeros_like(K) Y[:p.T] = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') Y[p.T:] = ss_vars['Yss'] r = np.zeros_like(Y) if not p.small_open: r[:p.T] = firm.get_r(Y[:p.T], K[:p.T], p, 'TPI') r[p.T:] = ss_vars['rss'] else: r = p.firm_r # compute w w = np.zeros_like(r) w[:p.T] = firm.get_w_from_r(r[:p.T], p, 'TPI') w[p.T:] = ss_vars['wss'] r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r else: r_hh = aggr.get_r_hh(r, r_gov, K, ss_vars['Dss']) if p.small_open: r_hh = p.hh_r BQ0 = aggr.get_BQ(r[0], initial_b, None, p, 'SS', True) if not p.use_zeta: BQ = np.zeros((p.T + p.S, p.J)) for j in range(p.J): BQ[:, j] = (list(np.linspace(BQ0[j], ss_vars['BQss'][j], p.T)) + [ss_vars['BQss'][j]] * p.S) BQ = np.array(BQ) else: BQ = (list(np.linspace(BQ0, ss_vars['BQss'], p.T)) + [ss_vars['BQss']] * p.S) BQ = np.array(BQ) if p.budget_balance: if np.abs(ss_vars['T_Hss']) < 1e-13: T_Hss2 = 0.0 # sometimes SS is very small but not zero, # even if taxes are zero, this get's rid of the approximation # error, which affects the perc changes below else: T_Hss2 = ss_vars['T_Hss'] T_H = np.ones(p.T + p.S) * T_Hss2 total_revenue = T_H G = np.zeros(p.T + p.S) elif not p.baseline_spending: T_H = p.alpha_T * Y G = np.ones(p.T + p.S) * ss_vars['Gss'] elif p.baseline_spending: T_H = T_Hbaseline T_H_new = p.T_H # Need to set T_H_new for later reference G = Gbaseline G_0 = Gbaseline[0] # Initialize some starting values if p.budget_balance: D = np.zeros(p.T + p.S) else: D = np.ones(p.T + p.S) * ss_vars['Dss'] if ss_vars['Dss'] == 0: D_d = np.zeros(p.T + p.S) D_f = np.zeros(p.T + p.S) else: D_d = D * ss_vars['D_d_ss'] / ss_vars['Dss'] D_f = D * ss_vars['D_f_ss'] / ss_vars['Dss'] total_revenue = np.ones(p.T + p.S) * ss_vars['total_revenue_ss'] TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((p.T, 2 * p.S, p.J)) TPIdist_vec = np.zeros(p.maxiter) # TPI loop while (TPIiter < p.maxiter) and (TPIdist >= p.mindist_TPI): r_gov[:p.T] = fiscal.get_r_gov(r[:p.T], p) if p.budget_balance: r_hh[:p.T] = r[:p.T] else: K[:p.T] = firm.get_K_from_Y(Y[:p.T], r[:p.T], p, 'TPI') r_hh[:p.T] = aggr.get_r_hh(r[:p.T], r_gov[:p.T], K[:p.T], D[:p.T]) if p.small_open: r_hh[:p.T] = p.hh_r[:p.T] outer_loop_vars = (r, w, r_hh, BQ, T_H, theta) euler_errors = np.zeros((p.T, 2 * p.S, p.J)) lazy_values = [] for j in range(p.J): guesses = (guesses_b[:, :, j], guesses_n[:, :, j]) lazy_values.append( delayed(inner_loop)(guesses, outer_loop_vars, initial_values, j, ind, p)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) for j, result in enumerate(results): euler_errors[:, :, j], b_mat[:, :, j], n_mat[:, :, j] = result bmat_s = np.zeros((p.T, p.S, p.J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:p.T - 1, :-1, :] bmat_splus1 = np.zeros((p.T, p.S, p.J)) bmat_splus1[:, :, :] = b_mat[:p.T, :, :] etr_params_4D = np.tile( p.etr_params.reshape(p.T, p.S, 1, p.etr_params.shape[2]), (1, 1, p.J, 1)) bqmat = household.get_bq(BQ, None, p, 'TPI') tax_mat = tax.total_taxes(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], factor, T_H[:p.T], theta, 0, None, False, 'TPI', p.e, etr_params_4D, p) r_hh_path = utils.to_timepath_shape(r_hh, p) wpath = utils.to_timepath_shape(w, p) c_mat = household.get_cons(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s, bmat_splus1, n_mat[:p.T, :, :], bqmat[:p.T, :, :], tax_mat, p.e, p.tau_c[:p.T, :, :], p) y_before_tax_mat = (r_hh_path[:p.T, :, :] * bmat_s[:p.T, :, :] + wpath[:p.T, :, :] * p.e * n_mat[:p.T, :, :]) if not p.baseline_spending and not p.budget_balance: Y[:p.T] = T_H[:p.T] / p.alpha_T[:p.T] # maybe unecessary (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], c_mat[:p.T, :, :], Y[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue[:p.T] = total_rev # set intial debt value if p.baseline: D0 = p.initial_debt_ratio * Y[0] if not p.baseline_spending: G_0 = p.alpha_G[0] * Y[0] dg_fixed_values = (Y, total_revenue, T_H, D0, G_0) Dnew, G[:p.T] = fiscal.D_G_path(r_gov, dg_fixed_values, Gbaseline, p) # Fix initial amount of foreign debt holding D_f[0] = p.initial_foreign_debt_ratio * Dnew[0] for t in range(1, p.T): D_f[t + 1] = (D_f[t] / (np.exp(p.g_y) * (1 + p.g_n[t + 1])) + p.zeta_D[t] * (Dnew[t + 1] - (Dnew[t] / (np.exp(p.g_y) * (1 + p.g_n[t + 1]))))) D_d[:p.T] = Dnew[:p.T] - D_f[:p.T] else: # if budget balance Dnew = np.zeros(p.T + 1) G[:p.T] = np.zeros(p.T) D_f[:p.T] = np.zeros(p.T) D_d[:p.T] = np.zeros(p.T) L[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B[1:p.T] = aggr.get_K(bmat_splus1[:p.T], p, 'TPI', False)[:p.T - 1] K_demand_open = firm.get_K(L[:p.T], p.firm_r[:p.T], p, 'TPI') K_d[:p.T] = B[:p.T] - D_d[:p.T] if np.any(K_d < 0): print('K_d has negative elements. Setting them ' + 'positive to prevent NAN.') K_d[:p.T] = np.fmax(K_d[:p.T], 0.05 * B[:p.T]) K_f[:p.T] = p.zeta_K[:p.T] * (K_demand_open - B[:p.T] + D_d[:p.T]) K = K_f + K_d if np.any(B) < 0: print('B has negative elements. B[0:9]:', B[0:9]) print('B[T-2:T]:', B[p.T - 2, p.T]) if p.small_open: K[:p.T] = K_demand_open Ynew = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') rnew = r.copy() if not p.small_open: rnew[:p.T] = firm.get_r(Ynew[:p.T], K[:p.T], p, 'TPI') else: rnew[:p.T] = r[:p.T].copy() r_gov_new = fiscal.get_r_gov(rnew, p) if p.budget_balance: r_hh_new = rnew[:p.T] else: r_hh_new = aggr.get_r_hh(rnew[:p.T], r_gov_new[:p.T], K[:p.T], Dnew[:p.T]) if p.small_open: r_hh_new = p.hh_r[:p.T] # compute w wnew = firm.get_w_from_r(rnew[:p.T], p, 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, p.S, p.J)), b_mat[:p.T - 1, :, :], axis=0) BQnew = aggr.get_BQ(r_hh_new[:p.T], b_mat_shift, None, p, 'TPI', False) bqmat_new = household.get_bq(BQnew, None, p, 'TPI') (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh_new[:p.T], wnew[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat_new[:p.T, :, :], c_mat[:p.T, :, :], Ynew[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue[:p.T] = total_rev if p.budget_balance: T_H_new = total_revenue elif not p.baseline_spending: T_H_new = p.alpha_T[:p.T] * Ynew[:p.T] # If baseline_spending==True, no need to update T_H, it's fixed # update vars for next iteration w[:p.T] = wnew[:p.T] r[:p.T] = utils.convex_combo(rnew[:p.T], r[:p.T], p.nu) BQ[:p.T] = utils.convex_combo(BQnew[:p.T], BQ[:p.T], p.nu) D[:p.T] = Dnew[:p.T] Y[:p.T] = utils.convex_combo(Ynew[:p.T], Y[:p.T], p.nu) if not p.baseline_spending: T_H[:p.T] = utils.convex_combo(T_H_new[:p.T], T_H[:p.T], p.nu) guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu) guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu) print('r diff: ', (rnew[:p.T] - r[:p.T]).max(), (rnew[:p.T] - r[:p.T]).min()) print('BQ diff: ', (BQnew[:p.T] - BQ[:p.T]).max(), (BQnew[:p.T] - BQ[:p.T]).min()) print('T_H diff: ', (T_H_new[:p.T] - T_H[:p.T]).max(), (T_H_new[:p.T] - T_H[:p.T]).min()) print('Y diff: ', (Ynew[:p.T] - Y[:p.T]).max(), (Ynew[:p.T] - Y[:p.T]).min()) if not p.baseline_spending: if T_H.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(T_H_new[:p.T], T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(np.abs(T_H[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(Ynew[:p.T], Y[:p.T]))).max() TPIdist_vec[TPIiter] = TPIdist # After T=10, if cycling occurs, drop the value of nu # wait til after T=10 or so, because sometimes there is a jump up # in the first couple iterations # if TPIiter > 10: # if TPIdist_vec[TPIiter] - TPIdist_vec[TPIiter - 1] > 0: # nu /= 2 # print 'New Value of nu:', nu TPIiter += 1 print('Iteration:', TPIiter) print('\tDistance:', TPIdist) # Compute effective and marginal tax rates for all agents mtrx_params_4D = np.tile( p.mtrx_params.reshape(p.T, p.S, 1, p.mtrx_params.shape[2]), (1, 1, p.J, 1)) mtry_params_4D = np.tile( p.mtry_params.reshape(p.T, p.S, 1, p.mtry_params.shape[2]), (1, 1, p.J, 1)) e_3D = np.tile(p.e.reshape(1, p.S, p.J), (p.T, 1, 1)) mtry_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, True, e_3D, etr_params_4D, mtry_params_4D, p) mtrx_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, False, e_3D, etr_params_4D, mtrx_params_4D, p) etr_path = tax.ETR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, e_3D, etr_params_4D, p) C = aggr.get_C(c_mat, p, 'TPI') # Note that implicity in this computation is that immigrants' # wealth is all in the form of private capital I_d = aggr.get_I(bmat_splus1[:p.T], K_d[1:p.T + 1], K_d[:p.T], p, 'TPI') I = aggr.get_I(bmat_splus1[:p.T], K[1:p.T + 1], K[:p.T], p, 'TPI') # solve resource constraint # net foreign borrowing new_borrowing_f = (D_f[1:p.T + 1] * np.exp(p.g_y) * (1 + p.g_n[1:p.T + 1]) - D_f[:p.T]) debt_service_f = D_f * r_hh RC_error = aggr.resource_constraint(Y[:p.T - 1], C[:p.T - 1], G[:p.T - 1], I_d[:p.T - 1], K_f[:p.T - 1], new_borrowing_f[:p.T - 1], debt_service_f[:p.T - 1], r_hh[:p.T - 1], p) # Compute total investment (not just domestic) I_total = ((1 + p.g_n[:p.T]) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) rce_max = np.amax(np.abs(RC_error)) print('Max absolute value resource constraint error:', rce_max) print('Checking time path for violations of constraints.') for t in range(p.T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_mat[t], t, p.ltilde) eul_savings = euler_errors[:, :p.S, :].max(1).max(1) eul_laborleisure = euler_errors[:, p.S:, :].max(1).max(1) print('Max Euler error, savings: ', eul_savings) print('Max Euler error labor supply: ', eul_laborleisure) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Y': Y[:p.T], 'B': B, 'K': K, 'K_f': K_f, 'K_d': K_d, 'L': L, 'C': C, 'I': I, 'I_total': I_total, 'I_d': I_d, 'BQ': BQ, 'total_revenue': total_revenue, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Ipath, 'T_H': T_H, 'T_P': T_Ppath, 'T_BQ': T_BQpath, 'T_W': T_Wpath, 'T_C': T_Cpath, 'G': G, 'D': D, 'D_f': D_f, 'D_d': D_d, 'r': r, 'r_gov': r_gov, 'r_hh': r_hh, 'w': w, 'bmat_splus1': bmat_splus1, 'bmat_s': bmat_s[:p.T, :, :], 'n_mat': n_mat[:p.T, :, :], 'c_path': c_mat, 'bq_path': bqmat, 'y_before_tax_mat': y_before_tax_mat, 'tax_path': tax_mat, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'resource_constraint_error': RC_error, 'new_borrowing_f': new_borrowing_f, 'debt_service_f': debt_service_f, 'etr_path': etr_path, 'mtrx_path': mtrx_path, 'mtry_path': mtry_path } tpi_dir = os.path.join(p.output_base, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) if np.any(G) < 0: print('Government spending is negative along transition path' + ' to satisfy budget') if (((TPIiter >= p.maxiter) or (np.absolute(TPIdist) > p.mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found' + ' (TPIdist)') if ((np.any(np.absolute(RC_error) >= p.mindist_TPI * 10)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(RC_error)') if ((np.any(np.absolute(eul_savings) >= p.mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > p.mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(eulers)') return output
def SS_solver(bmat, nmat, r, BQ, TR, factor, Y, p, client, fsolve_flag=False): ''' Solves for the steady state distribution of capital, labor, as well as w, r, TR and the scaling factor, using functional iteration. Args: bmat (Numpy array): initial guess at savings, size = SxJ nmat (Numpy array): initial guess at labor supply, size = SxJ r (scalar): real interest rate BQ (array_like): aggregate bequest amount(s) TR (scalar): lump sum transfer amount factor (scalar): scaling factor converting model units to dollars Y (scalar): real GDP p (OG-USA Specifications object): model parameters client (Dask client object): client Returns: output (dictionary): dictionary with steady state solution results ''' # Rename the inputs if not p.budget_balance: if not p.baseline_spending: Y = TR / p.alpha_T[-1] if p.small_open: r = p.hh_r[-1] dist = 10 iteration = 0 dist_vec = np.zeros(p.maxiter) maxiter_ss = p.maxiter nu_ss = p.nu if fsolve_flag: maxiter_ss = 1 while (dist > p.mindist_SS) and (iteration < maxiter_ss): # Solve for the steady state levels of b and n, given w, r, # Y and factor if p.budget_balance: outer_loop_vars = (bmat, nmat, r, BQ, TR, factor) else: outer_loop_vars = (bmat, nmat, r, BQ, Y, TR, factor) (euler_errors, new_bmat, new_nmat, new_r, new_r_gov, new_r_hh, new_w, new_TR, new_Y, new_factor, new_BQ, average_income_model) =\ inner_loop(outer_loop_vars, p, client) r = utils.convex_combo(new_r, r, nu_ss) factor = utils.convex_combo(new_factor, factor, nu_ss) BQ = utils.convex_combo(new_BQ, BQ, nu_ss) # bmat = utils.convex_combo(new_bmat, bmat, nu_ss) # nmat = utils.convex_combo(new_nmat, nmat, nu_ss) if not p.baseline_spending: TR = utils.convex_combo(new_TR, TR, nu_ss) dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_TR, TR)] + [utils.pct_diff_func(new_factor, factor)]).max() else: Y = utils.convex_combo(new_Y, Y, nu_ss) if Y != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_Y, Y)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If Y is zero (if there is no output), a percent difference # will throw NaN's, so we use an absolute difference dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [abs(new_Y - Y)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu_ss /= 2.0 print('New value of nu:', nu_ss) iteration += 1 print('Iteration: %02d' % iteration, ' Distance: ', dist) # Generate the SS values of variables, including euler errors bssmat_s = np.append(np.zeros((1, p.J)), bmat[:-1, :], axis=0) bssmat_splus1 = bmat nssmat = nmat rss = r r_gov_ss = fiscal.get_r_gov(rss, p) if p.budget_balance: r_hh_ss = rss Dss = 0.0 else: Dss = p.debt_ratio_ss * Y Lss = aggr.get_L(nssmat, p, 'SS') Bss = aggr.get_B(bssmat_splus1, p, 'SS', False) K_demand_open_ss = firm.get_K(Lss, p.firm_r[-1], p, 'SS') D_f_ss = p.zeta_D[-1] * Dss D_d_ss = Dss - D_f_ss K_d_ss = Bss - D_d_ss if not p.small_open: K_f_ss = p.zeta_K[-1] * (K_demand_open_ss - Bss + D_d_ss) Kss = K_f_ss + K_d_ss # Note that implicity in this computation is that immigrants' # wealth is all in the form of private capital I_d_ss = aggr.get_I(bssmat_splus1, K_d_ss, K_d_ss, p, 'SS') Iss = aggr.get_I(bssmat_splus1, Kss, Kss, p, 'SS') else: K_d_ss = Bss - D_d_ss K_f_ss = K_demand_open_ss - Bss + D_d_ss Kss = K_f_ss + K_d_ss InvestmentPlaceholder = np.zeros(bssmat_splus1.shape) Iss = aggr.get_I(InvestmentPlaceholder, Kss, Kss, p, 'SS') I_d_ss = aggr.get_I(bssmat_splus1, K_d_ss, K_d_ss, p, 'SS') r_hh_ss = aggr.get_r_hh(rss, r_gov_ss, Kss, Dss) wss = new_w BQss = new_BQ factor_ss = factor TR_ss = TR bqssmat = household.get_bq(BQss, None, p, 'SS') trssmat = household.get_tr(TR_ss, None, p, 'SS') Yss = firm.get_Y(Kss, Lss, p, 'SS') theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, None, p) # Compute effective and marginal tax rates for all agents etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) mtrx_params_3D = np.tile(np.reshape( p.mtrx_params[-1, :, :], (p.S, 1, p.mtrx_params.shape[2])), (1, p.J, 1)) mtry_params_3D = np.tile(np.reshape( p.mtry_params[-1, :, :], (p.S, 1, p.mtry_params.shape[2])), (1, p.J, 1)) mtry_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, True, p.e, etr_params_3D, mtry_params_3D, p) mtrx_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, False, p.e, etr_params_3D, mtrx_params_3D, p) etr_ss = tax.ETR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, p.e, etr_params_3D, p) taxss = tax.total_taxes(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, factor_ss, trssmat, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(r_hh_ss, wss, bssmat_s, bssmat_splus1, nssmat, bqssmat, taxss, p.e, p.tau_c[-1, :, :], p) yss_before_tax_mat = r_hh_ss * bssmat_s + wss * p.e * nssmat Css = aggr.get_C(cssmat, p, 'SS') (total_revenue_ss, T_Iss, T_Pss, T_BQss, T_Wss, T_Css, business_revenue) =\ aggr.revenue(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, cssmat, Yss, Lss, Kss, factor, theta, etr_params_3D, p, 'SS') debt_service_ss = r_gov_ss * Dss new_borrowing = Dss * ((1 + p.g_n_ss) * np.exp(p.g_y) - 1) # government spends such that it expands its debt at the same rate as GDP if p.budget_balance: Gss = 0.0 else: Gss = total_revenue_ss + new_borrowing - (TR_ss + debt_service_ss) print('G components = ', new_borrowing, TR_ss, debt_service_ss) # Compute total investment (not just domestic) Iss_total = ((1 + p.g_n_ss) * np.exp(p.g_y) - 1 + p.delta) * Kss # solve resource constraint # net foreign borrowing print('Foreign debt holdings = ', D_f_ss) print('Foreign capital holdings = ', K_f_ss) new_borrowing_f = D_f_ss * (np.exp(p.g_y) * (1 + p.g_n_ss) - 1) debt_service_f = D_f_ss * r_hh_ss RC = aggr.resource_constraint(Yss, Css, Gss, I_d_ss, K_f_ss, new_borrowing_f, debt_service_f, r_hh_ss, p) print('resource constraint: ', RC) if Gss < 0: print('Steady state government spending is negative to satisfy' + ' budget') if ENFORCE_SOLUTION_CHECKS and (np.absolute(RC) > p.mindist_SS): print('Resource Constraint Difference:', RC) err = 'Steady state aggregate resource constraint not satisfied' raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat_splus1, nssmat, cssmat, p.ltilde) euler_savings = euler_errors[:p.S, :] euler_labor_leisure = euler_errors[p.S:, :] print('Maximum error in labor FOC = ', np.absolute(euler_labor_leisure).max()) print('Maximum error in savings FOC = ', np.absolute(euler_savings).max()) # Return dictionary of SS results output = {'Kss': Kss, 'K_f_ss': K_f_ss, 'K_d_ss': K_d_ss, 'Bss': Bss, 'Lss': Lss, 'Css': Css, 'Iss': Iss, 'Iss_total': Iss_total, 'I_d_ss': I_d_ss, 'nssmat': nssmat, 'Yss': Yss, 'Dss': Dss, 'D_f_ss': D_f_ss, 'D_d_ss': D_d_ss, 'wss': wss, 'rss': rss, 'r_gov_ss': r_gov_ss, 'r_hh_ss': r_hh_ss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'yss_before_tax_mat': yss_before_tax_mat, 'bqssmat': bqssmat, 'TR_ss': TR_ss, 'trssmat': trssmat, 'Gss': Gss, 'total_revenue_ss': total_revenue_ss, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Iss, 'T_Pss': T_Pss, 'T_BQss': T_BQss, 'T_Wss': T_Wss, 'T_Css': T_Css, 'euler_savings': euler_savings, 'debt_service_f': debt_service_f, 'new_borrowing_f': new_borrowing_f, 'debt_service_ss': debt_service_ss, 'new_borrowing': new_borrowing, 'euler_labor_leisure': euler_labor_leisure, 'resource_constraint_error': RC, 'etr_ss': etr_ss, 'mtrx_ss': mtrx_ss, 'mtry_ss': mtry_ss} return output
def SS_solver(bmat, nmat, r, BQ, T_H, factor, Y, p, client, fsolve_flag=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = length X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() aggr.get_K() aggr.get_L() firm.get_Y() firm.get_r() firm.get_w() aggr.get_BQ() tax.replacement_rate_vals() aggr.revenue() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption OBJECTS CREATED WITHIN FUNCTION - SMALL OPEN ONLY Bss = scalar, aggregate household wealth in the steady state BIss = scalar, aggregate household net investment in the steady state RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' # Rename the inputs if not p.budget_balance: if not p.baseline_spending: Y = T_H / p.alpha_T[-1] if p.small_open: r = p.hh_r[-1] dist = 10 iteration = 0 dist_vec = np.zeros(p.maxiter) maxiter_ss = p.maxiter nu_ss = p.nu if fsolve_flag: maxiter_ss = 1 while (dist > p.mindist_SS) and (iteration < maxiter_ss): # Solve for the steady state levels of b and n, given w, r, # Y and factor if p.budget_balance: outer_loop_vars = (bmat, nmat, r, BQ, T_H, factor) else: outer_loop_vars = (bmat, nmat, r, BQ, Y, T_H, factor) (euler_errors, new_bmat, new_nmat, new_r, new_r_gov, new_r_hh, new_w, new_T_H, new_Y, new_factor, new_BQ, average_income_model) =\ inner_loop(outer_loop_vars, p, client) r = utils.convex_combo(new_r, r, nu_ss) factor = utils.convex_combo(new_factor, factor, nu_ss) BQ = utils.convex_combo(new_BQ, BQ, nu_ss) # bmat = utils.convex_combo(new_bmat, bmat, nu_ss) # nmat = utils.convex_combo(new_nmat, nmat, nu_ss) if p.budget_balance: T_H = utils.convex_combo(new_T_H, T_H, nu_ss) dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() else: Y = utils.convex_combo(new_Y, Y, nu_ss) if Y != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [utils.pct_diff_func(new_Y, Y)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If Y is zero (if there is no output), a percent difference # will throw NaN's, so we use an absoluate difference dist = np.array([utils.pct_diff_func(new_r, r)] + list(utils.pct_diff_func(new_BQ, BQ)) + [abs(new_Y - Y)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu_ss /= 2.0 print('New value of nu:', nu_ss) iteration += 1 print('Iteration: %02d' % iteration, ' Distance: ', dist) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1, p.J)), bmat[:-1, :], axis=0) bssmat_splus1 = bmat nssmat = nmat rss = r r_gov_ss = fiscal.get_r_gov(rss, p) if p.budget_balance: r_hh_ss = rss debt_ss = 0.0 else: debt_ss = p.debt_ratio_ss * Y Lss = aggr.get_L(nssmat, p, 'SS') if not p.small_open: Bss = aggr.get_K(bssmat_splus1, p, 'SS', False) Kss = Bss - debt_ss Iss = aggr.get_I(bssmat_splus1, Kss, Kss, p, 'SS') else: # Compute capital (K) and wealth (B) separately Kss = firm.get_K(Lss, p.firm_r[-1], p, 'SS') InvestmentPlaceholder = np.zeros(bssmat_splus1.shape) Iss = aggr.get_I(InvestmentPlaceholder, Kss, Kss, p, 'SS') Bss = aggr.get_K(bssmat_splus1, p, 'SS', False) BIss = aggr.get_I(bssmat_splus1, Bss, Bss, p, 'BI_SS') if p.budget_balance: r_hh_ss = rss else: r_hh_ss = aggr.get_r_hh(rss, r_gov_ss, Kss, debt_ss) if p.small_open: r_hh_ss = p.hh_r[-1] wss = new_w BQss = new_BQ factor_ss = factor T_Hss = T_H bqssmat = household.get_bq(BQss, None, p, 'SS') Yss = firm.get_Y(Kss, Lss, p, 'SS') theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, None, p) # Compute effective and marginal tax rates for all agents etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) mtrx_params_3D = np.tile(np.reshape( p.mtrx_params[-1, :, :], (p.S, 1, p.mtrx_params.shape[2])), (1, p.J, 1)) mtry_params_3D = np.tile(np.reshape( p.mtry_params[-1, :, :], (p.S, 1, p.mtry_params.shape[2])), (1, p.J, 1)) mtry_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, True, p.e, etr_params_3D, mtry_params_3D, p) mtrx_ss = tax.MTR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, False, p.e, etr_params_3D, mtrx_params_3D, p) etr_ss = tax.ETR_income(r_hh_ss, wss, bssmat_s, nssmat, factor, p.e, etr_params_3D, p) taxss = tax.total_taxes(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, factor_ss, T_Hss, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(r_hh_ss, wss, bssmat_s, bssmat_splus1, nssmat, bqssmat, taxss, p.e, p.tau_c[-1, :, :], p) Css = aggr.get_C(cssmat, p, 'SS') (total_revenue_ss, T_Iss, T_Pss, T_BQss, T_Wss, T_Css, business_revenue) =\ aggr.revenue(r_hh_ss, wss, bssmat_s, nssmat, bqssmat, cssmat, Yss, Lss, Kss, factor, theta, etr_params_3D, p, 'SS') debt_service_ss = r_gov_ss * p.debt_ratio_ss * Yss new_borrowing = p.debt_ratio_ss * Yss * ((1 + p.g_n_ss) * np.exp(p.g_y) - 1) # government spends such that it expands its debt at the same rate as GDP if p.budget_balance: Gss = 0.0 else: Gss = total_revenue_ss + new_borrowing - (T_Hss + debt_service_ss) print('G components = ', new_borrowing, T_Hss, debt_service_ss) # Compute total investment (not just domestic) Iss_total = p.delta * Kss # solve resource constraint if p.small_open: # include term for current account resource_constraint = (Yss + new_borrowing - (Css + BIss + Gss) + (p.hh_r[-1] * Bss - (p.delta + p.firm_r[-1]) * Kss - debt_service_ss)) print('Yss= ', Yss, '\n', 'Css= ', Css, '\n', 'Bss = ', Bss, '\n', 'BIss = ', BIss, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'T_H = ', T_H, '\n', 'Gss= ', Gss) print('D/Y:', debt_ss / Yss, 'T/Y:', T_Hss / Yss, 'G/Y:', Gss / Yss, 'Rev/Y:', total_revenue_ss / Yss, 'Int payments to GDP:', (r_gov_ss * debt_ss) / Yss) print('resource constraint: ', resource_constraint) else: resource_constraint = Yss - (Css + Iss + Gss) print('Yss= ', Yss, '\n', 'Gss= ', Gss, '\n', 'Css= ', Css, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'Debt service = ', debt_service_ss) print('D/Y:', debt_ss / Yss, 'T/Y:', T_Hss / Yss, 'G/Y:', Gss / Yss, 'Rev/Y:', total_revenue_ss / Yss, 'business rev/Y: ', business_revenue / Yss, 'Int payments to GDP:', (r_gov_ss * debt_ss) / Yss) print('Check SS budget: ', Gss - (np.exp(p.g_y) * (1 + p.g_n_ss) - 1 - r_gov_ss) * debt_ss - total_revenue_ss + T_Hss) print('resource constraint: ', resource_constraint) if Gss < 0: print('Steady state government spending is negative to satisfy' + ' budget') if ENFORCE_SOLUTION_CHECKS and (np.absolute(resource_constraint) > p.mindist_SS): print('Resource Constraint Difference:', resource_constraint) err = 'Steady state aggregate resource constraint not satisfied' raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat_splus1, nssmat, cssmat, p.ltilde) euler_savings = euler_errors[:p.S, :] euler_labor_leisure = euler_errors[p.S:, :] print('Maximum error in labor FOC = ', np.absolute(euler_labor_leisure).max()) print('Maximum error in savings FOC = ', np.absolute(euler_savings).max()) ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = {'Kss': Kss, 'Bss': Bss, 'Lss': Lss, 'Css': Css, 'Iss': Iss, 'Iss_total': Iss_total, 'nssmat': nssmat, 'Yss': Yss, 'Dss': debt_ss, 'wss': wss, 'rss': rss, 'r_gov_ss': r_gov_ss, 'r_hh_ss': r_hh_ss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'bqssmat': bqssmat, 'T_Hss': T_Hss, 'Gss': Gss, 'total_revenue_ss': total_revenue_ss, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Iss, 'T_Pss': T_Pss, 'T_BQss': T_BQss, 'T_Wss': T_Wss, 'T_Css': T_Css, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'resource_constraint_error': resource_constraint, 'etr_ss': etr_ss, 'mtrx_ss': mtrx_ss, 'mtry_ss': mtry_ss} return output
def inner_loop(outer_loop_vars, p, client): ''' This function solves for the inner loop of the SS. That is, given the guesses of the outer loop variables (r, w, Y, factor) this function solves the households' problems in the SS. Inputs: r = [T,] vector, interest rate w = [T,] vector, wage rate b = [T,S,J] array, wealth holdings n = [T,S,J] array, labor supply BQ = [T,J] vector, bequest amounts factor = scalar, model income scaling factor Y = [T,] vector, lump sum transfer amount(s) Functions called: euler_equation_solver() aggr.get_K() aggr.get_L() firm.get_Y() firm.get_r() firm.get_w() aggr.get_BQ() tax.replacement_rate_vals() aggr.revenue() Objects in function: Returns: euler_errors, bssmat, nssmat, new_r, new_w new_T_H, new_factor, new_BQ ''' # unpack variables to pass to function if p.budget_balance: bssmat, nssmat, r, BQ, T_H, factor = outer_loop_vars else: bssmat, nssmat, r, BQ, Y, T_H, factor = outer_loop_vars euler_errors = np.zeros((2 * p.S, p.J)) w = firm.get_w_from_r(r, p, 'SS') r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r D = 0 else: D = p.debt_ratio_ss * Y K = firm.get_K_from_Y(Y, r, p, 'SS') r_hh = aggr.get_r_hh(r, r_gov, K, D) if p.small_open: r_hh = p.hh_r[-1] bq = household.get_bq(BQ, None, p, 'SS') lazy_values = [] for j in range(p.J): guesses = np.append(bssmat[:, j], nssmat[:, j]) euler_params = (r_hh, w, bq[:, j], T_H, factor, j, p) lazy_values.append(delayed(opt.fsolve)(euler_equation_solver, guesses * .9, args=euler_params, xtol=MINIMIZER_TOL, full_output=True)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) # for j, result in results.items(): for j, result in enumerate(results): [solutions, infodict, ier, message] = result euler_errors[:, j] = infodict['fvec'] bssmat[:, j] = solutions[:p.S] nssmat[:, j] = solutions[p.S:] L = aggr.get_L(nssmat, p, 'SS') if not p.small_open: B = aggr.get_K(bssmat, p, 'SS', False) if p.budget_balance: K = B else: K = B - D else: K = firm.get_K(L, r, p, 'SS') new_Y = firm.get_Y(K, L, p, 'SS') if p.budget_balance: Y = new_Y if not p.small_open: new_r = firm.get_r(Y, K, p, 'SS') else: new_r = p.firm_r[-1] new_w = firm.get_w_from_r(new_r, p, 'SS') print('inner factor prices: ', new_r, new_w) b_s = np.array(list(np.zeros(p.J).reshape(1, p.J)) + list(bssmat[:-1, :])) new_r_gov = fiscal.get_r_gov(new_r, p) if p.small_open: new_r_hh = p.hh_r[-1] else: new_r_hh = aggr.get_r_hh(new_r, new_r_gov, K, D) average_income_model = ((new_r_hh * b_s + new_w * p.e * nssmat) * p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).sum() if p.baseline: new_factor = p.mean_income_data / average_income_model else: new_factor = factor new_BQ = aggr.get_BQ(new_r_hh, bssmat, None, p, 'SS', False) new_bq = household.get_bq(new_BQ, None, p, 'SS') theta = tax.replacement_rate_vals(nssmat, new_w, new_factor, None, p) if p.budget_balance: etr_params_3D = np.tile(np.reshape( p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) taxss = tax.total_taxes(new_r_hh, new_w, b_s, nssmat, new_bq, factor, T_H, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(new_r_hh, new_w, b_s, bssmat, nssmat, new_bq, taxss, p.e, p.tau_c[-1, :, :], p) new_T_H, _, _, _, _, _, _ = aggr.revenue( new_r_hh, new_w, b_s, nssmat, new_bq, cssmat, new_Y, L, K, factor, theta, etr_params_3D, p, 'SS') elif p.baseline_spending: new_T_H = T_H else: new_T_H = p.alpha_T[-1] * new_Y return euler_errors, bssmat, nssmat, new_r, new_r_gov, new_r_hh, \ new_w, new_T_H, new_Y, new_factor, new_BQ, average_income_model
def inner_loop(outer_loop_vars, p, client): ''' This function solves for the inner loop of the SS. That is, given the guesses of the outer loop variables (r, w, TR, factor) this function solves the households' problems in the SS. Args: outer_loop_vars (tuple): tuple of outer loop variables, (bssmat, nssmat, r, BQ, TR, factor) or (bssmat, nssmat, r, BQ, Y, TR, factor) bssmat (Numpy array): initial guess at savings, size = SxJ nssmat (Numpy array): initial guess at labor supply, size = SxJ BQ (array_like): aggregate bequest amount(s) Y (scalar): real GDP TR (scalar): lump sum transfer amount factor (scalar): scaling factor converting model units to dollars w (scalar): real wage rate p (OG-USA Specifications object): model parameters client (Dask client object): client Returns: (tuple): results from household solution: * euler_errors (Numpy array): errors terms from FOCs, size = 2SxJ * bssmat (Numpy array): savings, size = SxJ * nssmat (Numpy array): labor supply, size = SxJ * new_r (scalar): real interest rate on firm capital * new_r_gov (scalar): real interest rate on government debt * new_r_hh (scalar): real interest rate on household portfolio * new_w (scalar): real wage rate * new_TR (scalar): lump sum transfer amount * new_Y (scalar): real GDP * new_factor (scalar): scaling factor converting model units to dollars * new_BQ (array_like): aggregate bequest amount(s) * average_income_model (scalar): average income in model units ''' # unpack variables to pass to function if p.budget_balance: bssmat, nssmat, r, BQ, TR, factor = outer_loop_vars r_hh = r Y = 1.0 # placeholder K = 1.0 # placeholder else: bssmat, nssmat, r, BQ, Y, TR, factor = outer_loop_vars K = firm.get_K_from_Y(Y, r, p, 'SS') # initialize array for euler errors euler_errors = np.zeros((2 * p.S, p.J)) w = firm.get_w_from_r(r, p, 'SS') r_gov = fiscal.get_r_gov(r, p) D, D_d, D_f, new_borrowing, debt_service, new_borrowing_f =\ fiscal.get_D_ss(r_gov, Y, p) r_hh = aggr.get_r_hh(r, r_gov, K, D) bq = household.get_bq(BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') lazy_values = [] for j in range(p.J): guesses = np.append(bssmat[:, j], nssmat[:, j]) euler_params = (r_hh, w, bq[:, j], tr[:, j], factor, j, p) lazy_values.append(delayed(opt.fsolve)(euler_equation_solver, guesses * .9, args=euler_params, xtol=MINIMIZER_TOL, full_output=True)) if client: futures = client.compute(lazy_values, num_workers=p.num_workers) results = client.gather(futures) else: results = results = compute( *lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) # for j, result in results.items(): for j, result in enumerate(results): [solutions, infodict, ier, message] = result euler_errors[:, j] = infodict['fvec'] bssmat[:, j] = solutions[:p.S] nssmat[:, j] = solutions[p.S:] L = aggr.get_L(nssmat, p, 'SS') B = aggr.get_B(bssmat, p, 'SS', False) K_demand_open = firm.get_K(L, p.world_int_rate[-1], p, 'SS') K, K_d, K_f = aggr.get_K_splits(B, K_demand_open, D_d, p.zeta_K[-1]) Y = firm.get_Y(K, L, p, 'SS') if p.zeta_K[-1] == 1.0: new_r = p.world_int_rate[-1] else: new_r = firm.get_r(Y, K, p, 'SS') new_w = firm.get_w_from_r(new_r, p, 'SS') b_s = np.array(list(np.zeros(p.J).reshape(1, p.J)) + list(bssmat[:-1, :])) new_r_gov = fiscal.get_r_gov(new_r, p) new_r_hh = aggr.get_r_hh(new_r, new_r_gov, K, D) average_income_model = ((new_r_hh * b_s + new_w * p.e * nssmat) * p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).sum() if p.baseline: new_factor = p.mean_income_data / average_income_model else: new_factor = factor new_BQ = aggr.get_BQ(new_r_hh, bssmat, None, p, 'SS', False) new_bq = household.get_bq(new_BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') theta = tax.replacement_rate_vals(nssmat, new_w, new_factor, None, p) etr_params_3D = np.tile( np.reshape(p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) taxss = tax.net_taxes( new_r_hh, new_w, b_s, nssmat, new_bq, factor, tr, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons( new_r_hh, new_w, b_s, bssmat, nssmat, new_bq, taxss, p.e, p.tau_c[-1, :, :], p) total_tax_revenue, _, agg_pension_outlays, _, _, _, _, _, _ =\ aggr.revenue(new_r_hh, new_w, b_s, nssmat, new_bq, cssmat, Y, L, K, factor, theta, etr_params_3D, p, 'SS') G = fiscal.get_G_ss(Y, total_tax_revenue, agg_pension_outlays, TR, new_borrowing, debt_service, p) new_TR = fiscal.get_TR(Y, TR, G, total_tax_revenue, agg_pension_outlays, p, 'SS') return euler_errors, bssmat, nssmat, new_r, new_r_gov, new_r_hh, \ new_w, new_TR, Y, new_factor, new_BQ, average_income_model