def income_tax_liab(r, w, b, n, factor, t, j, method, e, etr_params, p): ''' Calculate income and payroll tax liability for each household Args: r (array_like): real interest rate w (array_like): real wage rate b (Numpy array): savings n (Numpy array): labor supply factor (scalar): scaling factor converting model units to dollars t (int): time period j (int): index of lifetime income group method (str): adjusts calculation dimensions based on 'SS' or 'TPI' e (Numpy array): effective labor units etr_params (Numpy array): effective tax rate function parameters p (OG-USA Specifications object): model parameters Returns: T_I (Numpy array): total income and payroll taxes paid for each household ''' if j is not None: if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) else: if method == 'TPI': r = utils.to_timepath_shape(r) w = utils.to_timepath_shape(w) income = r * b + w * e * n labor_income = w * e * n T_I = ETR_income(r, w, b, n, factor, e, etr_params, p) * income if method == 'SS': T_P = p.tau_payroll[-1] * labor_income elif method == 'TPI': length = w.shape[0] if len(b.shape) == 1: T_P = p.tau_payroll[t:t + length] * labor_income elif len(b.shape) == 2: T_P = (p.tau_payroll[t:t + length].reshape(length, 1) * labor_income) else: T_P = (p.tau_payroll[t:t + length].reshape(length, 1, 1) * labor_income) elif method == 'TPI_scalar': T_P = p.tau_payroll[0] * labor_income income_payroll_tax_liab = T_I + T_P return income_payroll_tax_liab
def test_to_timepath_shape(): ''' Test of function that converts vector to time path conformable array ''' in_array = np.ones(40) test_array = utils.to_timepath_shape(in_array) assert test_array.shape == (40, 1, 1)
def get_bq(BQ, j, p, method): ''' Calculation of bequests to each lifetime income group. Inputs: r = [T,] vector, interest rates b_splus1 = [T,S,J] array, distribution of wealth/capital holdings one period ahead params = length 5 tuple, (omega, lambdas, rho, g_n, method) omega = [S,T] array, population weights lambdas = [J,] vector, fraction in each lifetime income group rho = [S,] vector, mortality rates g_n = scalar, population growth rate method = string, 'SS' or 'TPI' Functions called: None Objects in function: BQ_presum = [T,S,J] array, weighted distribution of wealth/capital holdings one period ahead BQ = [T,J] array, aggregate bequests by lifetime income group Returns: BQ ''' if p.use_zeta: if j is not None: if method == 'SS': bq = (p.zeta[:, j] * BQ) / (p.lambdas[j] * p.omega_SS) else: len_T = BQ.shape[0] bq = ((np.reshape(p.zeta[:, j], (1, p.S)) * BQ.reshape( (len_T, 1))) / (p.lambdas[j] * p.omega[:len_T, :])) else: if method == 'SS': bq = ((p.zeta * BQ) / (p.lambdas.reshape( (1, p.J)) * p.omega_SS.reshape((p.S, 1)))) else: len_T = BQ.shape[0] bq = ((np.reshape(p.zeta, (1, p.S, p.J)) * utils.to_timepath_shape(BQ, p)) / (p.lambdas.reshape( (1, 1, p.J)) * p.omega[:len_T, :].reshape( (len_T, p.S, 1)))) else: if j is not None: if method == 'SS': bq = np.tile(BQ[j], p.S) / p.lambdas[j] if method == 'TPI': len_T = BQ.shape[0] bq = np.tile(np.reshape(BQ[:, j] / p.lambdas[j], (len_T, 1)), (1, p.S)) else: if method == 'SS': BQ_per = BQ / np.squeeze(p.lambdas) bq = np.tile(np.reshape(BQ_per, (1, p.J)), (p.S, 1)) if method == 'TPI': len_T = BQ.shape[0] BQ_per = BQ / p.lambdas.reshape(1, p.J) bq = np.tile(np.reshape(BQ_per, (len_T, 1, p.J)), (1, p.S, 1)) return bq
def get_bq(BQ, j, p, method): r''' Calculate bequests to each household. .. math:: bq_{j,s,t} = zeta_{j,s}\frac{BQ_{t}}{\lambda_{j}\omega_{s,t}} Args: BQ (array_like): aggregate bequests j (int): index of lifetime ability group p (OG-USA Specifications object): model parameters method (str): adjusts calculation dimensions based on 'SS' or 'TPI' Returns: bq (array_like): bequests received by each household ''' if p.use_zeta: if j is not None: if method == 'SS': bq = (p.zeta[:, j] * BQ) / (p.lambdas[j] * p.omega_SS) else: len_T = BQ.shape[0] bq = ((np.reshape(p.zeta[:, j], (1, p.S)) * BQ.reshape( (len_T, 1))) / (p.lambdas[j] * p.omega[:len_T, :])) else: if method == 'SS': bq = ((p.zeta * BQ) / (p.lambdas.reshape( (1, p.J)) * p.omega_SS.reshape((p.S, 1)))) else: len_T = BQ.shape[0] bq = ( (np.reshape(p.zeta, (1, p.S, p.J)) * utils.to_timepath_shape(BQ)) / (p.lambdas.reshape( (1, 1, p.J)) * p.omega[:len_T, :].reshape( (len_T, p.S, 1)))) else: if j is not None: if method == 'SS': bq = np.tile(BQ[j], p.S) / p.lambdas[j] if method == 'TPI': len_T = BQ.shape[0] bq = np.tile(np.reshape(BQ[:, j] / p.lambdas[j], (len_T, 1)), (1, p.S)) else: if method == 'SS': BQ_per = BQ / np.squeeze(p.lambdas) bq = np.tile(np.reshape(BQ_per, (1, p.J)), (p.S, 1)) if method == 'TPI': len_T = BQ.shape[0] BQ_per = BQ / p.lambdas.reshape(1, p.J) bq = np.tile(np.reshape(BQ_per, (len_T, 1, p.J)), (1, p.S, 1)) return bq
def wealth_tax_liab(r, b, t, j, method, p): ''' Calculate wealth tax liability for each household. Args: r (array_like): real interest rate b (Numpy array): savings t (int): time period j (int): index of lifetime income group method (str): adjusts calculation dimensions based on 'SS' or 'TPI' p (OG-USA Specifications object): model parameters Returns: T_W (Numpy array): wealth tax liability for each household ''' if j is not None: if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) else: if method == 'TPI': r = utils.to_timepath_shape(r) if method == 'SS': T_W = (ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) elif method == 'TPI': length = r.shape[0] if len(b.shape) == 1: T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) elif len(b.shape) == 2: T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) else: T_W = (ETR_wealth(b, p.h_wealth[t:t + length].reshape( length, 1, 1), p.m_wealth[t:t + length].reshape(length, 1, 1), p.p_wealth[t:t + length].reshape(length, 1, 1)) * b) elif method == 'TPI_scalar': T_W = (ETR_wealth(b, p.h_wealth[0], p.m_wealth[0], p.p_wealth[0]) * b) return T_W
def bequest_tax_liab(r, b, bq, t, j, method, p): ''' Calculate liability due from taxes on bequests for each household. Args: r (array_like): real interest rate b (Numpy array): savings bq (Numpy array): bequests received t (int): time period j (int): index of lifetime income group method (str): adjusts calculation dimensions based on 'SS' or 'TPI' p (OG-USA Specifications object): model parameters Returns: T_BQ (Numpy array): bequest tax liability for each household ''' if j is not None: lambdas = p.lambdas[j] if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) else: lambdas = np.transpose(p.lambdas) if method == 'TPI': r = utils.to_timepath_shape(r) if method == 'SS': T_BQ = p.tau_bq[-1] * bq elif method == 'TPI': length = r.shape[0] if len(b.shape) == 1: T_BQ = p.tau_bq[t:t + length] * bq elif len(b.shape) == 2: T_BQ = p.tau_bq[t:t + length].reshape(length, 1) * bq / lambdas else: T_BQ = p.tau_bq[t:t + length].reshape(length, 1, 1) * bq elif method == 'TPI_scalar': # The above methods won't work if scalars are used. This option # is only called by the SS_TPI_firstdoughnutring function in TPI. T_BQ = p.tau_bq[0] * bq return T_BQ
def get_tr(TR, j, p, method): r''' Calculate transfers to each household. .. math:: tr_{j,s,t} = zeta_{j,s}\frac{TR_{t}}{\lambda_{j}\omega_{s,t}} Args: TR (array_like): aggregate transfers j (int): index of lifetime ability group p (OG-USA Specifications object): model parameters method (str): adjusts calculation dimensions based on 'SS' or 'TPI' Returns: tr (array_like): bequests received by each household ''' if j is not None: if method == 'SS': tr = (p.eta[-1, :, j] * TR) / (p.lambdas[j] * p.omega_SS) else: len_T = TR.shape[0] tr = ((p.eta[:len_T, :, j] * TR.reshape((len_T, 1))) / (p.lambdas[j] * p.omega[:len_T, :])) else: if method == 'SS': tr = ((p.eta[-1, :, :] * TR) / (p.lambdas.reshape((1, p.J)) * p.omega_SS.reshape((p.S, 1)))) else: len_T = TR.shape[0] tr = ((p.eta[:len_T, :, :] * utils.to_timepath_shape(TR)) / (p.lambdas.reshape((1, 1, p.J)) * p.omega[:len_T, :].reshape((len_T, p.S, 1)))) return tr
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 FOC_savings(r, w, b, b_splus1, n, bq, factor, tr, theta, e, rho, tau_c, etr_params, mtry_params, t, j, p, method): r''' Computes Euler errors for the FOC for savings in the steady state. This function is usually looped through over J, so it does one lifetime income group at a time. .. math:: c_{j,s,t}^{-\sigma} = e^{-\sigma g_y}\biggl[\chi^b_j\rho_s(b_{j,s+1,t+1})^{-\sigma} + \beta\bigl(1 - \rho_s\bigr)\Bigl(1 + r_{t+1}\bigl[1 - \tau^{mtry}_{s+1,t+1}\bigr]\Bigr)(c_{j,s+1,t+1})^{-\sigma}\biggr] Args: r (array_like): the real interest rate w (array_like): the real wage rate b (Numpy array): household savings b_splus1 (Numpy array): household savings one period ahead b_splus2 (Numpy array): household savings two periods ahead n (Numpy array): household labor supply bq (Numpy array): household bequests received factor (scalar): scaling factor converting model units to dollars tr (Numpy array): government tranfers to household theta (Numpy array): social security replacement rate for each lifetime income group e (Numpy array): effective labor units rho (Numpy array): mortality rates tau_c (array_like): consumption tax rates etr_params (Numpy array): parameters of the effective tax rate functions mtry_params (Numpy array): parameters of the marginal tax rate on capital income functions t (int): model period j (int): index of ability type p (OG-USA Specifications object): model parameters method (str): adjusts calculation dimensions based on 'SS' or 'TPI' Returns: euler (Numpy array): Euler error from FOC for savings ''' if j is not None: chi_b = p.chi_b[j] else: chi_b = p.chi_b if method == 'TPI': r = utils.to_timepath_shape(r) w = utils.to_timepath_shape(w) if method == 'SS': h_wealth = p.h_wealth[-1] m_wealth = p.m_wealth[-1] p_wealth = p.p_wealth[-1] else: h_wealth = p.h_wealth[t] m_wealth = p.m_wealth[t] p_wealth = p.p_wealth[t] taxes = tax.total_taxes(r, w, b, n, bq, factor, tr, theta, t, j, False, method, e, etr_params, p) cons = get_cons(r, w, b, b_splus1, n, bq, taxes, e, tau_c, p) deriv = ((1 + r) - ( r * tax.MTR_income(r, w, b, n, factor, True, e, etr_params, mtry_params, p)) - tax.MTR_wealth(b, h_wealth, m_wealth, p_wealth)) savings_ut = (rho * np.exp(-p.sigma * p.g_y) * chi_b * b_splus1 ** (-p.sigma)) euler_error = np.zeros_like(n) if n.shape[0] > 1: euler_error[:-1] = (marg_ut_cons(cons[:-1], p.sigma) * (1 / (1 + tau_c[:-1])) - p.beta * (1 - rho[:-1]) * deriv[1:] * marg_ut_cons(cons[1:], p.sigma) * (1 / (1 + tau_c[1:])) * np.exp(-p.sigma * p.g_y) - savings_ut[:-1]) euler_error[-1] = (marg_ut_cons(cons[-1], p.sigma) * (1 / (1 + tau_c[-1])) - savings_ut[-1]) else: euler_error[-1] = (marg_ut_cons(cons[-1], p.sigma) * (1 / (1 + tau_c[-1])) - savings_ut[-1]) return euler_error
def pension_amount(w, n, theta, t, j, shift, method, e, p): ''' Calculate public pension benefit amounts for each household. Args: w (array_like): real wage rate n (Numpy array): labor supply theta (Numpy array): social security replacement rate value for lifetime income group j t (int): time period j (int): index of lifetime income group shift (bool): whether computing for periods 0--s or 1--(s+1), =True for 1--(s+1) method (str): adjusts calculation dimensions based on 'SS' or 'TPI' e (Numpy array): effective labor units p (OG-USA Specifications object): model parameters Returns: pension (Numpy array): pension amount for each household ''' if j is not None: if method == 'TPI': if n.ndim == 2: w = w.reshape(w.shape[0], 1) else: if method == 'TPI': w = utils.to_timepath_shape(w) pension = np.zeros_like(n) if method == 'SS': # Depending on if we are looking at b_s or b_s+1, the # entry for retirement will change (it shifts back one). # The shift boolean makes sure we start replacement rates # at the correct age. if shift is False: pension[p.retire[-1]:] = theta * w else: pension[p.retire[-1] - 1:] = theta * w elif method == 'TPI': length = w.shape[0] if not shift: # retireTPI is different from retire, because in TP income # we are counting backwards with different length lists. # This will always be the correct location of retirement, # depending on the shape of the lists. retireTPI = (p.retire[t:t + length] - p.S) else: retireTPI = (p.retire[t:t + length] - 1 - p.S) if len(n.shape) == 1: if not shift: retireTPI = p.retire[t] - p.S else: retireTPI = p.retire[t] - 1 - p.S pension[retireTPI:] = (theta[j] * p.replacement_rate_adjust[t] * w[retireTPI:]) elif len(n.shape) == 2: for tt in range(pension.shape[0]): pension[tt, retireTPI[tt]:] = (theta * p.replacement_rate_adjust[t + tt] * w[tt]) else: for tt in range(pension.shape[0]): pension[tt, retireTPI[tt]:, :] = ( theta.reshape(1, p.J) * p.replacement_rate_adjust[t + tt] * w[tt]) elif method == 'TPI_scalar': # The above methods won't work if scalars are used. This option # is only called by the SS_TPI_firstdoughnutring function in TPI. pension = theta * p.replacement_rate_adjust[0] * w return pension
def FOC_labor(r, w, b, b_splus1, n, bq, factor, tr, theta, chi_n, e, tau_c, etr_params, mtrx_params, t, j, p, method): r''' Computes errors for the FOC for labor supply in the steady state. This function is usually looped through over J, so it does one lifetime income group at a time. .. math:: w_t e_{j,s}\bigl(1 - \tau^{mtrx}_{s,t}\bigr)(c_{j,s,t})^{-\sigma} = \chi^n_{s}\biggl(\frac{b}{\tilde{l}}\biggr)\biggl(\frac{n_{j,s,t}}{\tilde{l}}\biggr)^{\upsilon-1}\Biggl[1 - \biggl(\frac{n_{j,s,t}}{\tilde{l}}\biggr)^\upsilon\Biggr]^{\frac{1-\upsilon}{\upsilon}} Args: r (array_like): the real interest rate w (array_like): the real wage rate b (Numpy array): household savings b_splus1 (Numpy array): household savings one period ahead n (Numpy array): household labor supply bq (Numpy array): household bequests received factor (scalar): scaling factor converting model units to dollars tr (Numpy array): government tranfers to household theta (Numpy array): social security replacement rate for each lifetime income group chi_n (Numpy array): utility weight on the disutility of labor supply e (Numpy array): effective labor units tau_c (array_like): consumption tax rates etr_params (Numpy array): parameters of the effective tax rate functions mtrx_params (Numpy array): parameters of the marginal tax rate on labor income functions t (int): model period j (int): index of ability type p (OG-USA Specifications object): model parameters method (str): adjusts calculation dimensions based on 'SS' or 'TPI' Returns: FOC_error (Numpy array): error from FOC for labor supply ''' if method == 'SS': tau_payroll = p.tau_payroll[-1] elif method == 'TPI_scalar': # for 1st donut ring onlye tau_payroll = p.tau_payroll[0] else: length = r.shape[0] tau_payroll = p.tau_payroll[t:t + length] if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) tau_payroll = tau_payroll.reshape(tau_payroll.shape[0], 1) elif b.ndim == 3: r = utils.to_timepath_shape(r) w = utils.to_timepath_shape(w) tau_payroll = utils.to_timepath_shape(tau_payroll) taxes = tax.total_taxes(r, w, b, n, bq, factor, tr, theta, t, j, False, method, e, etr_params, p) cons = get_cons(r, w, b, b_splus1, n, bq, taxes, e, tau_c, p) deriv = (1 - tau_payroll - tax.MTR_income(r, w, b, n, factor, False, e, etr_params, mtrx_params, p)) FOC_error = (marg_ut_cons(cons, p.sigma) * (1 / (1 + tau_c)) * w * deriv * e - marg_ut_labor(n, chi_n, p)) return FOC_error
def total_taxes(r, w, b, n, bq, factor, T_H, theta, t, j, shift, method, e, etr_params, p): ''' Gives net taxes paid values. 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 T_H = [T,] vector, lump sum transfer amount(s) j = integer, lifetime incoem group being computed shift = boolean, computing for periods 0--s or 1--(s+1) (bool) (True for 1--(s+1)) params = length 13 tuple, (e, lambdas, method, retire, etr_params, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) e = [T,S,J] array, effective labor units lambdas = [J,] vector, population weights by lifetime income group method = string, 'SS' or 'TPI' retire = integer, retirement age etr_params = [T,S,J] array, effective tax rate function parameters h_wealth = scalar, wealth tax function parameter p_wealth = scalar, wealth tax function parameter m_wealth = scalar, wealth tax function parameter tau_payroll = scalar, payroll tax rate theta = [J,] vector, replacement rate values by lifetime income group tau_bq = scalar, bequest tax rate S = integer, number of age groups J = integer, number of lifetime income groups Functions called: ETR_income ETR_wealth Objects in function: income = [T,S,J] array, total income T_I = [T,S,J] array, total income taxes T_P = [T,S,J] array, total payroll taxes T_W = [T,S,J] array, total wealth taxes T_BQ = [T,S,J] array, total bequest taxes retireTPI = integer, =(retire - S) total_taxes = [T,] vector, net taxes Returns: total_taxes ''' if j is not None: lambdas = p.lambdas[j] if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) T_H = T_H.reshape(T_H.shape[0], 1) else: lambdas = np.transpose(p.lambdas) if method == 'TPI': r = utils.to_timepath_shape(r, p) w = utils.to_timepath_shape(w, p) T_H = utils.to_timepath_shape(T_H, p) income = r * b + w * e * n T_I = ETR_income(r, w, b, n, factor, e, etr_params, p) * income if method == 'SS': # Depending on if we are looking at b_s or b_s+1, the # entry for retirement will change (it shifts back one). # The shift boolean makes sure we start replacement rates # at the correct age. T_P = p.tau_payroll[-1] * w * e * n if shift is False: T_P[p.retire[-1]:] -= theta * w else: T_P[p.retire[-1] - 1:] -= theta * w T_BQ = p.tau_bq[-1] * bq T_W = (ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) elif method == 'TPI': length = w.shape[0] if not shift: # retireTPIis different from retire, because in TPincomewe are # counting backwards with different length lists. This will # always be the correct location of retirement, depending # on the shape of the lists. retireTPI = (p.retire[t:t + length] - p.S) else: retireTPI = (p.retire[t:t + length] - 1 - p.S) if len(b.shape) == 1: T_P = p.tau_payroll[t:t + length] * w * e * n if not shift: retireTPI = p.retire[t] - p.S else: retireTPI = p.retire[t] - 1 - p.S T_P[retireTPI:] -= (theta[j] * p.replacement_rate_adjust[t] * w[retireTPI:]) T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) T_BQ = p.tau_bq[t:t + length] * bq elif len(b.shape) == 2: T_P = p.tau_payroll[t:t + length].reshape(length, 1) * w * e * n for tt in range(T_P.shape[0]): T_P[tt, retireTPI[tt]:] -= (theta * p.replacement_rate_adjust[t + tt] * w[tt]) T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) T_BQ = p.tau_bq[t:t + length].reshape(length, 1) * bq / lambdas else: T_P = p.tau_payroll[t:t + length].reshape(length, 1, 1) * w * e * n for tt in range(T_P.shape[0]): T_P[tt, retireTPI[tt]:, :] -= (theta.reshape(1, p.J) * p.replacement_rate_adjust[t + tt] * w[tt]) T_W = (ETR_wealth(b, p.h_wealth[t:t + length].reshape( length, 1, 1), p.m_wealth[t:t + length].reshape(length, 1, 1), p.p_wealth[t:t + length].reshape(length, 1, 1)) * b) T_BQ = p.tau_bq[t:t + length].reshape(length, 1, 1) * bq elif method == 'TPI_scalar': # The above methods won't work if scalars are used. This option # is only called by the SS_TPI_firstdoughnutring function in TPI. T_P = p.tau_payroll[0] * w * e * n T_P -= theta * p.replacement_rate_adjust[0] * w T_BQ = p.tau_bq[0] * bq T_W = (ETR_wealth(b, p.h_wealth[0], p.m_wealth[0], p.p_wealth[0]) * b) total_tax = T_I + T_P + T_BQ + T_W - T_H return total_tax
def FOC_labor(r, w, b, b_splus1, n, bq, factor, T_H, theta, chi_n, e, tau_c, etr_params, mtrx_params, t, j, p, method): ''' Computes Euler errors for the FOC for labor supply in the steady state. This function is usually looped through over J, so it does one lifetime income group at a time. Inputs: r = scalar, interest rate w = scalar, wage rate b = [S,J] array, distribution of wealth/capital holdings b_splus1 = [S,J] array, distribution of wealth/capital holdings one period ahead n = [S,J] array, distribution of labor supply BQ = [J,] vector, aggregate bequests by lifetime income group factor = scalar, scaling factor to convert model income to dollars T_H = scalar, lump sum transfer params = length 19 tuple (e, sigma, g_y, theta, b_ellipse, upsilon, ltilde, chi_n, tau_bq, lambdas, J, S, etr_params, mtrx_params, h_wealth, p_wealth, m_wealth, tau_payroll, tau_bq) e = [S,J] array, effective labor units sigma = scalar, coefficient of relative risk aversion g_y = scalar, exogenous labor augmenting technological growth theta = [J,] vector, replacement rate for each lifetime income group b_ellipse = scalar, scaling parameter in elliptical utility function upsilon = curvature parameter in elliptical utility function chi_n = [S,] vector, utility weights on disutility of labor ltilde = scalar, upper bound of household labor supply tau_bq = scalar, bequest tax rate (scalar) lambdas = [J,] vector, ability weights J = integer, number of lifetime income groups S = integer, number of economically active periods in lifetime etr_params = [S,10] array, parameters of effective income tax rate function mtrx_params = [S,10] array, parameters of marginal tax rate on labor income function h_wealth = scalar, parameter in wealth tax function p_wealth = scalar, parameter in wealth tax function m_wealth = scalar, parameter in wealth tax function tau_payroll = scalar, payroll tax rate tau_bq = scalar, bequest tax rate Functions called: get_cons marg_ut_cons marg_ut_labor tax.total_taxes tax.MTR_income Objects in function: tax = [S,J] array, net taxes in the current period cons = [S,J] array, consumption in the current period deriv = [S,J] array, net of tax share of labor income euler = [S,J] array, Euler error from FOC for labor supply Returns: euler if j is not None: chi_b = p.chi_b[j] if method == 'TPI': r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) T_H = T_H.reshape(T_H.shape[0], 1) else: chi_b = p.chi_b if method == 'TPI': r = utils.to_timepath_shape(r, p) w = utils.to_timepath_shape(w, p) T_H = utils.to_timepath_shape(T_H, p) ''' if method == 'SS': tau_payroll = p.tau_payroll[-1] elif method == 'TPI_scalar': # for 1st donut ring onlye tau_payroll = p.tau_payroll[0] else: length = r.shape[0] tau_payroll = p.tau_payroll[t:t + length] if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) T_H = T_H.reshape(T_H.shape[0], 1) tau_payroll = tau_payroll.reshape(tau_payroll.shape[0], 1) elif b.ndim == 3: r = utils.to_timepath_shape(r, p) w = utils.to_timepath_shape(w, p) T_H = utils.to_timepath_shape(T_H, p) tau_payroll = utils.to_timepath_shape(tau_payroll, p) taxes = tax.total_taxes(r, w, b, n, bq, factor, T_H, theta, t, j, False, method, e, etr_params, p) cons = get_cons(r, w, b, b_splus1, n, bq, taxes, e, tau_c, p) deriv = (1 - tau_payroll - tax.MTR_income(r, w, b, n, factor, False, e, etr_params, mtrx_params, p)) FOC_error = (marg_ut_cons(cons, p.sigma) * (1 / (1 + tau_c)) * w * deriv * e - marg_ut_labor(n, chi_n, p)) return FOC_error
def FOC_savings(r, w, b, b_splus1, n, bq, factor, T_H, theta, e, rho, tau_c, etr_params, mtry_params, t, j, p, method): ''' Computes Euler errors for the FOC for savings in the steady state. This function is usually looped through over J, so it does one lifetime income group at a time. Inputs: r = scalar, interest rate w = scalar, wage rate b = [S,J] array, distribution of wealth/capital b_splus1 = [S,J] array, distribution of wealth/capital, one period ahead b_splus2 = [S,J] array, distribution of wealth/capital, two periods ahead n = [S,J] array, distribution of labor supply BQ = [J,] vector, aggregate bequests by lifetime income group factor = scalar, scaling factor to convert model income to dollars T_H = scalar, lump sum transfer params = length 18 tuple (e, sigma, beta, g_y, chi_b, theta, tau_bq, rho, lambdas, J, S, etr_params, mtry_params, h_wealth, p_wealth, m_wealth, tau_payroll, tau_bq) e = [S,J] array, effective labor units sigma = scalar, coefficient of relative risk aversion beta = scalar, discount factor g_y = scalar, exogenous labor augmenting technological growth chi_b = [J,] vector, utility weight on bequests for each lifetime income group theta = [J,] vector, replacement rate for each lifetime income group tau_bq = scalar, bequest tax rate (scalar) rho = [S,] vector, mortality rates lambdas = [J,] vector, ability weights J = integer, number of lifetime income groups S = integer, number of economically active periods in lifetime etr_params = [S,12] array, parameters of effective income tax rate function mtry_params = [S,12] array, parameters of marginal tax rate on capital income function h_wealth = scalar, parameter in wealth tax function p_wealth = scalar, parameter in wealth tax function m_wealth = scalar, parameter in wealth tax function tau_payroll = scalar, payroll tax rate tau_bq = scalar, bequest tax rate Functions called: get_cons marg_ut_cons tax.total_taxes tax.MTR_income Objects in function: tax1 = [S,J] array, net taxes in the current period tax2 = [S,J] array, net taxes one period ahead cons1 = [S,J] array, consumption in the current period cons2 = [S,J] array, consumption one period ahead deriv = [S,J] array, after-tax return on capital savings_ut = [S,J] array, marginal utility from savings euler = [S,J] array, Euler error from FOC for savings Returns: euler ''' if j is not None: chi_b = p.chi_b[j] else: chi_b = p.chi_b if method == 'TPI': r = utils.to_timepath_shape(r, p) w = utils.to_timepath_shape(w, p) T_H = utils.to_timepath_shape(T_H, p) taxes = tax.total_taxes(r, w, b, n, bq, factor, T_H, theta, t, j, False, method, e, etr_params, p) cons = get_cons(r, w, b, b_splus1, n, bq, taxes, e, tau_c, p) deriv = ((1 + r) - r * (tax.MTR_income(r, w, b, n, factor, True, e, etr_params, mtry_params, p))) savings_ut = (rho * np.exp(-p.sigma * p.g_y) * chi_b * b_splus1**(-p.sigma)) euler_error = np.zeros_like(n) if n.shape[0] > 1: euler_error[:-1] = ( marg_ut_cons(cons[:-1], p.sigma) * (1 / (1 + tau_c[:-1])) - p.beta * (1 - rho[:-1]) * deriv[1:] * marg_ut_cons(cons[1:], p.sigma) * (1 / (1 + tau_c[1:])) * np.exp(-p.sigma * p.g_y) - savings_ut[:-1]) euler_error[-1] = (marg_ut_cons(cons[-1], p.sigma) * (1 / (1 + tau_c[-1])) - savings_ut[-1]) else: euler_error[-1] = (marg_ut_cons(cons[-1], p.sigma) * (1 / (1 + tau_c[-1])) - savings_ut[-1]) return euler_error
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 total_taxes(r, w, b, n, bq, factor, tr, theta, t, j, shift, method, e, etr_params, p): ''' Calculate net taxes paid for each household. Args: r (array_like): real interest rate w (array_like): real wage rate b (Numpy array): savings n (Numpy array): labor supply bq (Numpy array): bequests received factor (scalar): scaling factor converting model units to dollars tr (Numpy array): government transfers to the household theta (Numpy array): social security replacement rate value for lifetime income group j t (int): time period j (int): index of lifetime income group shift (bool): whether computing for periods 0--s or 1--(s+1), =True for 1--(s+1) method (str): adjusts calculation dimensions based on 'SS' or 'TPI' e (Numpy array): effective labor units etr_params (Numpy array): effective tax rate function parameters p (OG-USA Specifications object): model parameters Returns: total_taxes (Numpy array): net taxes paid for each household ''' if j is not None: lambdas = p.lambdas[j] if method == 'TPI': if b.ndim == 2: r = r.reshape(r.shape[0], 1) w = w.reshape(w.shape[0], 1) else: lambdas = np.transpose(p.lambdas) if method == 'TPI': r = utils.to_timepath_shape(r) w = utils.to_timepath_shape(w) income = r * b + w * e * n T_I = ETR_income(r, w, b, n, factor, e, etr_params, p) * income if method == 'SS': # Depending on if we are looking at b_s or b_s+1, the # entry for retirement will change (it shifts back one). # The shift boolean makes sure we start replacement rates # at the correct age. T_P = p.tau_payroll[-1] * w * e * n if shift is False: T_P[p.retire[-1]:] -= theta * w else: T_P[p.retire[-1] - 1:] -= theta * w T_BQ = p.tau_bq[-1] * bq T_W = (ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) elif method == 'TPI': length = w.shape[0] if not shift: # retireTPIis different from retire, because in TPincomewe are # counting backwards with different length lists. This will # always be the correct location of retirement, depending # on the shape of the lists. retireTPI = (p.retire[t: t + length] - p.S) else: retireTPI = (p.retire[t: t + length] - 1 - p.S) if len(b.shape) == 1: T_P = p.tau_payroll[t: t + length] * w * e * n if not shift: retireTPI = p.retire[t] - p.S else: retireTPI = p.retire[t] - 1 - p.S T_P[retireTPI:] -= (theta[j] * p.replacement_rate_adjust[t] * w[retireTPI:]) T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) T_BQ = p.tau_bq[t:t + length] * bq elif len(b.shape) == 2: T_P = p.tau_payroll[t: t + length].reshape(length, 1) * w * e * n for tt in range(T_P.shape[0]): T_P[tt, retireTPI[tt]:] -= ( theta * p.replacement_rate_adjust[t + tt] * w[tt]) T_W = (ETR_wealth(b, p.h_wealth[t:t + length], p.m_wealth[t:t + length], p.p_wealth[t:t + length]) * b) T_BQ = p.tau_bq[t:t + length].reshape(length, 1) * bq / lambdas else: T_P = p.tau_payroll[t:t + length].reshape(length, 1, 1) * w * e * n for tt in range(T_P.shape[0]): T_P[tt, retireTPI[tt]:, :] -= ( theta.reshape(1, p.J) * p.replacement_rate_adjust[t + tt] * w[tt]) T_W = (ETR_wealth( b, p.h_wealth[t:t + length].reshape(length, 1, 1), p.m_wealth[t:t + length].reshape(length, 1, 1), p.p_wealth[t:t + length].reshape(length, 1, 1)) * b) T_BQ = p.tau_bq[t:t + length].reshape(length, 1, 1) * bq elif method == 'TPI_scalar': # The above methods won't work if scalars are used. This option # is only called by the SS_TPI_firstdoughnutring function in TPI. T_P = p.tau_payroll[0] * w * e * n T_P -= theta * p.replacement_rate_adjust[0] * w T_BQ = p.tau_bq[0] * bq T_W = (ETR_wealth(b, p.h_wealth[0], p.m_wealth[0], p.p_wealth[0]) * b) total_tax = T_I + T_P + T_BQ + T_W - tr return total_tax
def revenue(r, w, b, n, bq, c, Y, L, K, factor, theta, etr_params, p, method): r''' Calculate aggregate tax revenue. .. math:: R_{t} = \sum_{s=E}^{E+S}\sum_{j=0}^{J}\omega_{s,t}\lambda_{j}(T_{j,s,t} + \tau^{p}_{t}w_{t}e_{j,s}n_{j,s,t} - \theta_{j}w_{t} + \tau^{bq}bq_{j,s,t} + \tau^{c}_{s,t}c_{j,s,t} + \tau^{w}_{t}b_{j,s,t}) + \tau^{b}_{t}(Y_{t}-w_{t}L_{t}) - \tau^{b}_{t}\delta^{\tau}_{t}K^{\tau}_{t} Args: r (array_like): the real interest rate w (array_like): the real wage rate b (Numpy array): household savings n (Numpy array): household labor supply bq (Numpy array): household bequests received c (Numpy array): household consumption Y (array_like): aggregate output L (array_like): aggregate labor K (array_like): aggregate capital factor (scalar): factor (scalar): scaling factor converting model units to dollars theta (Numpy array): social security replacement rate for each lifetime income group etr_params (Numpy array): paramters of the effective tax rate functions p (OG-USA Specifications object): model parameters method (str): adjusts calculation dimensions based on 'SS' or 'TPI' Returns: REVENUE (array_like): aggregate tax revenue T_I (array_like): aggregate income tax revenue T_P (array_like): aggregate net payroll tax revenue, revenues minus social security benefits paid T_BQ (array_like): aggregate bequest tax revenue T_W (array_like): aggregate wealth tax revenue T_C (array_like): aggregate consumption tax revenue business_revenue (array_like): aggregate business tax revenue ''' if method == 'SS': I = r * b + w * p.e * n T_I = np.zeros_like(I) T_I = tax.ETR_income(r, w, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[-1] * w * p.e * n T_P[p.retire[-1]:] -= theta * w T_W = (tax.ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) T_BQ = p.tau_bq[-1] * bq T_C = p.tau_c[-1, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((np.transpose(p.omega_SS * p.lambdas) * (T_I + T_P + T_BQ + T_W + T_C)).sum() + business_revenue) elif method == 'TPI': r_array = utils.to_timepath_shape(r) w_array = utils.to_timepath_shape(w) I = r_array * b + w_array * n * p.e T_I = np.zeros_like(I) T_I = tax.ETR_income(r_array, w_array, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[:p.T].reshape(p.T, 1, 1) * w_array * n * p.e for t in range(T_P.shape[0]): T_P[t, p.retire[t]:, :] -= (theta.reshape(1, p.J) * p.replacement_rate_adjust[t] * w_array[t]) T_W = (tax.ETR_wealth(b, p.h_wealth[:p.T].reshape(p.T, 1, 1), p.m_wealth[:p.T].reshape(p.T, 1, 1), p.p_wealth[:p.T].reshape(p.T, 1, 1)) * b) T_BQ = p.tau_bq[:p.T].reshape(p.T, 1, 1) * bq T_C = p.tau_c[:p.T, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((((np.squeeze(p.lambdas)) * np.tile(np.reshape(p.omega[:p.T, :], (p.T, p.S, 1)), (1, 1, p.J))) * (T_I + T_P + T_BQ + T_W + T_C)).sum(1).sum(1) + business_revenue) return REVENUE, T_I, T_P, T_BQ, T_W, T_C, business_revenue
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 revenue(r, w, b, n, bq, c, Y, L, K, factor, theta, etr_params, p, method): ''' Gives lump sum transfer value. 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] array, bequest amounts factor = scalar, model income scaling factor params = length 12 tuple, (e, lambdas, omega, method, etr_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) e = [T,S,J] array, effective labor units lambdas = [J,] vector, population weights by lifetime income group omega = [T,S] array, population weights by age method = string, 'SS' or 'TPI' etr_params = [T,S,J] array, effective tax rate function parameters tax_func_types = string, type of tax function used theta = [J,] vector, replacement rate values by lifetime income group tau_bq = scalar, bequest tax rate h_wealth = scalar, wealth tax function parameter p_wealth = scalar, wealth tax function parameter m_wealth = scalar, wealth tax function parameter tau_payroll = scalar, payroll tax rate retire = integer, retirement age T = integer, number of periods in transition path S = integer, number of age groups J = integer, number of lifetime income groups Functions called: ETR_income ETR_wealth Objects in function: I = [T,S,J] array, total income T_I = [T,S,J] array, total income taxes T_P = [T,S,J] array, total payroll taxes T_W = [T,S,J] array, total wealth taxes T_BQ = [T,S,J] array, total bequest taxes T_H = [T,] vector, lump sum transfer amount(s) Returns: T_H ''' if method == 'SS': I = r * b + w * p.e * n T_I = np.zeros_like(I) T_I = tax.ETR_income(r, w, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[-1] * w * p.e * n T_P[p.retire[-1]:] -= theta * w T_W = ( tax.ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) T_BQ = p.tau_bq[-1] * bq T_C = p.tau_c[-1, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((np.transpose(p.omega_SS * p.lambdas) * (T_I + T_P + T_BQ + T_W + T_C)).sum() + business_revenue) elif method == 'TPI': r_array = utils.to_timepath_shape(r, p) w_array = utils.to_timepath_shape(w, p) I = r_array * b + w_array * n * p.e T_I = np.zeros_like(I) T_I = tax.ETR_income(r_array, w_array, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[:p.T].reshape(p.T, 1, 1) * w_array * n * p.e for t in range(T_P.shape[0]): T_P[t, p.retire[t]:, :] -= (theta.reshape(1, p.J) * p.replacement_rate_adjust[t] * w_array[t]) T_W = (tax.ETR_wealth( b, p.h_wealth[:p.T].reshape(p.T, 1, 1), p.m_wealth[:p.T].reshape( p.T, 1, 1), p.p_wealth[:p.T].reshape(p.T, 1, 1)) * b) T_BQ = p.tau_bq[:p.T].reshape(p.T, 1, 1) * bq T_C = p.tau_c[:p.T, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((((np.squeeze(p.lambdas)) * np.tile(np.reshape(p.omega[:p.T, :], (p.T, p.S, 1)), (1, 1, p.J))) * (T_I + T_P + T_BQ + T_W + T_C)).sum(1).sum(1) + business_revenue) return REVENUE, T_I, T_P, T_BQ, T_W, T_C, business_revenue
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 revenue(r, w, b, n, bq, c, Y, L, K, factor, theta, etr_params, p, method): ''' Gives lump sum transfer value. 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] array, bequest amounts factor = scalar, model income scaling factor params = length 12 tuple, (e, lambdas, omega, method, etr_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) e = [T,S,J] array, effective labor units lambdas = [J,] vector, population weights by lifetime income group omega = [T,S] array, population weights by age method = string, 'SS' or 'TPI' etr_params = [T,S,J] array, effective tax rate function parameters tax_func_types = string, type of tax function used theta = [J,] vector, replacement rate values by lifetime income group tau_bq = scalar, bequest tax rate h_wealth = scalar, wealth tax function parameter p_wealth = scalar, wealth tax function parameter m_wealth = scalar, wealth tax function parameter tau_payroll = scalar, payroll tax rate retire = integer, retirement age T = integer, number of periods in transition path S = integer, number of age groups J = integer, number of lifetime income groups Functions called: ETR_income ETR_wealth Objects in function: I = [T,S,J] array, total income T_I = [T,S,J] array, total income taxes T_P = [T,S,J] array, total payroll taxes T_W = [T,S,J] array, total wealth taxes T_BQ = [T,S,J] array, total bequest taxes T_H = [T,] vector, lump sum transfer amount(s) Returns: T_H ''' if method == 'SS': I = r * b + w * p.e * n T_I = np.zeros_like(I) T_I = tax.ETR_income(r, w, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[-1] * w * p.e * n T_P[p.retire[-1]:] -= theta * w T_W = (tax.ETR_wealth(b, p.h_wealth[-1], p.m_wealth[-1], p.p_wealth[-1]) * b) T_BQ = p.tau_bq[-1] * bq T_C = p.tau_c[-1, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((np.transpose(p.omega_SS * p.lambdas) * (T_I + T_P + T_BQ + T_W + T_C)).sum() + business_revenue) elif method == 'TPI': r_array = utils.to_timepath_shape(r, p) w_array = utils.to_timepath_shape(w, p) I = r_array * b + w_array * n * p.e T_I = np.zeros_like(I) T_I = tax.ETR_income(r_array, w_array, b, n, factor, p.e, etr_params, p) * I T_P = p.tau_payroll[:p.T].reshape(p.T, 1, 1) * w_array * n * p.e for t in range(T_P.shape[0]): T_P[t, p.retire[t]:, :] -= (theta.reshape(1, p.J) * p.replacement_rate_adjust[t] * w_array[t]) T_W = (tax.ETR_wealth(b, p.h_wealth[:p.T].reshape(p.T, 1, 1), p.m_wealth[:p.T].reshape(p.T, 1, 1), p.p_wealth[:p.T].reshape(p.T, 1, 1)) * b) T_BQ = p.tau_bq[:p.T].reshape(p.T, 1, 1) * bq T_C = p.tau_c[:p.T, :, :] * c business_revenue = tax.get_biz_tax(w, Y, L, K, p, method) REVENUE = ((((np.squeeze(p.lambdas)) * np.tile(np.reshape(p.omega[:p.T, :], (p.T, p.S, 1)), (1, 1, p.J))) * (T_I + T_P + T_BQ + T_W + T_C)).sum(1).sum(1) + business_revenue) return REVENUE, T_I, T_P, T_BQ, T_W, T_C, business_revenue