def test_get_BQ(): """ Simulate data similar to observed """ T = 160 S, J = 40, 2 r = 0.5 + 0.5 * np.random.rand(T).reshape(T, 1) b_splus1 = 0.06 + 7 * np.random.rand(T, S, J) # normalize across S and J axes omega = 0.5 * np.random.rand(T * S).reshape(T, S, 1) omega = omega / omega.sum(axis=1).reshape(T, 1, 1) lambdas = 0.4 + 0.2 * np.random.rand(J).reshape(1, 1, J) lambdas = lambdas / lambdas.sum() assert np.allclose(lambdas.sum(), 1.0) assert np.allclose(omega.sum(), T) rho = np.random.rand(S).reshape(1, S, 1) g_n = 0.1 * np.random.rand(T).reshape(T, 1) BQ_presum = b_splus1 * omega * rho * lambdas factor = (1.0 + r) / (1.0 + g_n) # test SS BQ = aggr.get_BQ(r[0], b_splus1[0], (omega[0], lambdas[0], rho[0], g_n[0], "SS")) assert np.allclose(BQ_presum[0].sum(0) * factor[0], BQ) # test TPI BQ = aggr.get_BQ(r, b_splus1, (omega, lambdas, rho, g_n, "TPI")) assert np.allclose(BQ_presum.sum(1) * factor, BQ)
def test_SS_solver(baseline, param_updates, filename, dask_client): # Test SS.SS_solver function. Provide inputs to function and # ensure that output returned matches what it has been before. p = Specifications(baseline=baseline, client=dask_client, num_workers=NUM_WORKERS) p.update_specifications(param_updates) p.output_base = CUR_PATH p.get_tax_function_parameters(None, run_micro=False) b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .35 * p.ltilde if p.zeta_K[-1] == 1.0: rguess = p.world_int_rate[-1] else: rguess = 0.06483431412921253 TRguess = 0.05738932081035772 factorguess = 139355.1547340256 BQguess = aggregates.get_BQ(rguess, b_guess, None, p, 'SS', False) Yguess = 0.6376591201150815 test_dict = SS.SS_solver(b_guess, n_guess, rguess, BQguess, TRguess, factorguess, Yguess, p, None, False) expected_dict = utils.safe_read_pickle( os.path.join(CUR_PATH, 'test_io_data', filename)) for k, v in expected_dict.items(): print('Testing ', k) assert (np.allclose(test_dict[k], v, atol=1e-07, equal_nan=True))
def find_moments(p, client): b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .4 * p.ltilde rguess = 0.08961277823002804 # 0.09 T_Hguess = 0.12 factorguess = 12.73047710050195 # 7.7 #70000 # Modified BQguess = aggr.get_BQ(rguess, b_guess, None, p, 'SS', False) exit_early = [0, -1] # 2nd value gives number of valid labor moments to consider before exiting SS_fsolve # Put -1 to run to SS ss_params_baseline = (b_guess, n_guess, None, None, p, client, exit_early) guesses = [rguess] + list(BQguess) + [T_Hguess, factorguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS.SS_fsolve, guesses, args=ss_params_baseline, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-2] T_Hss = solutions_fsolve[-2] factor_ss = solutions_fsolve[-1] Yss = T_Hss/p.alpha_T[-1] fsolve_flag = True try: output = SS.SS_solver(b_guess, n_guess, rss, BQss, T_Hss, factor_ss, Yss, p, client, fsolve_flag) except: print('RuntimeError: Steady state aggregate resource constraint not satisfied') print('Luckily we caught the error, so minstat_init_calibrate will continue') return 1e10 model_moments = np.array(output['nssmat'].mean(axis=1)[:45]) # calc_moments(output, p.omega_SS, p.lambdas, p.S, p.J) return model_moments
def minstat_init_calibrate(params, *args): a0, a1, a2, a3, a4 = params p, client, data_moments, W, ages = args chi_n = np.ones(p.S) chi_n[:p.S // 2 + 5] = chebyshev_func(ages, a0, a1, a2, a3, a4) slope = chi_n[p.S // 2 + 5 - 1] - chi_n[p.S // 2 + 5 - 2] chi_n[p.S // 2 + 5 - 1:] = (np.linspace(65, 100, 36) - 65) * slope + chi_n[p.S // 2 + 5 - 1] chi_n[chi_n < 0.5] = 0.5 p.chi_n = chi_n print("-----------------------------------------------------") print('PARAMS AT START' + str(params)) print("-----------------------------------------------------") b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .4 * p.ltilde rguess = 0.09 T_Hguess = 0.12 factorguess = 7.7 #70000 # Modified BQguess = aggr.get_BQ(rguess, b_guess, None, p, 'SS', False) exit_early = [ 0, 2 ] # 2nd value gives number of valid labor moments to consider before exiting SS_fsolve ss_params_baseline = (b_guess, n_guess, None, None, p, client, exit_early) guesses = [rguess] + list(BQguess) + [T_Hguess, factorguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS.SS_fsolve, guesses, args=ss_params_baseline, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-2] T_Hss = solutions_fsolve[-2] factor_ss = solutions_fsolve[-1] Yss = T_Hss / p.alpha_T[-1] fsolve_flag = True try: output = SS.SS_solver(b_guess, n_guess, rss, BQss, T_Hss, factor_ss, Yss, p, client, fsolve_flag) except: print( 'RuntimeError: Steady state aggregate resource constraint not satisfied' ) print( 'Luckily we caught the error, so minstat_init_calibrate will continue' ) return 1e10 model_moments = calc_moments(output, p.omega_SS, p.lambdas, p.S, p.J) print('Model moments:', model_moments) print("-----------------------------------------------------") distance = np.dot( np.dot((np.array(model_moments[:9]) - np.array(data_moments)).T, W), np.array(model_moments[:9]) - np.array(data_moments)) print('DATA and MODEL DISTANCE: ', distance) return distance
def test_euler_equation_solver(): # Test SS.inner_loop function. Provide inputs to function and # ensure that output returned matches what it has been before. input_tuple = utils.safe_read_pickle( os.path.join(CUR_PATH, 'test_io_data/euler_eqn_solver_inputs.pkl')) (guesses, params) = input_tuple p = Specifications() (r, w, T_H, factor, j, p.J, p.S, p.beta, p.sigma, p.ltilde, p.g_y, p.g_n_ss, tau_payroll, retire, p.mean_income_data, h_wealth, p_wealth, m_wealth, p.b_ellipse, p.upsilon, j, p.chi_b, p.chi_n, tau_bq, p.rho, lambdas, p.omega_SS, p.e, p.analytical_mtrs, etr_params, mtrx_params, mtry_params) = params p.tau_bq = np.ones(p.T + p.S) * 0.0 p.tau_payroll = np.ones(p.T + p.S) * tau_payroll p.h_wealth = np.ones(p.T + p.S) * h_wealth p.p_wealth = np.ones(p.T + p.S) * p_wealth p.m_wealth = np.ones(p.T + p.S) * m_wealth p.retire = (np.ones(p.T + p.S) * retire).astype(int) p.etr_params = np.transpose(etr_params.reshape( p.S, 1, etr_params.shape[-1]), (1, 0, 2)) p.mtrx_params = np.transpose(mtrx_params.reshape( p.S, 1, mtrx_params.shape[-1]), (1, 0, 2)) p.mtry_params = np.transpose(mtry_params.reshape( p.S, 1, mtry_params.shape[-1]), (1, 0, 2)) p.tax_func_type = 'DEP' p.lambdas = lambdas.reshape(p.J, 1) b_splus1 = np.array(guesses[:p.S]).reshape(p.S, 1) + 0.005 BQ = aggregates.get_BQ(r, b_splus1, j, p, 'SS', False) bq = household.get_bq(BQ, j, p, 'SS') args = (r, w, bq, T_H, factor, j, p) test_list = SS.euler_equation_solver(guesses, *args) expected_list = np.array([ -3.62741663e+00, -6.30068841e+00, -6.76592886e+00, -6.97731223e+00, -7.05777777e+00, -6.57305440e+00, -7.11553046e+00, -7.30569622e+00, -7.45808107e+00, -7.89984062e+00, -8.11466111e+00, -8.28230086e+00, -8.79253862e+00, -8.86994311e+00, -9.31299476e+00, -9.80834199e+00, -9.97333771e+00, -1.08349979e+01, -1.13199826e+01, -1.22890930e+01, -1.31550471e+01, -1.42753713e+01, -1.55721098e+01, -1.73811490e+01, -1.88856303e+01, -2.09570569e+01, -2.30559500e+01, -2.52127149e+01, -2.76119605e+01, -3.03141128e+01, -3.30900203e+01, -3.62799730e+01, -3.91169706e+01, -4.24246421e+01, -4.55740527e+01, -4.92914871e+01, -5.30682805e+01, -5.70043846e+01, -6.06075991e+01, -6.45251018e+01, -6.86128365e+01, -7.35896515e+01, -7.92634608e+01, -8.34733231e+01, -9.29802390e+01, -1.01179788e+02, -1.10437881e+02, -1.20569527e+02, -1.31569973e+02, -1.43633399e+02, -1.57534056e+02, -1.73244610e+02, -1.90066728e+02, -2.07980863e+02, -2.27589046e+02, -2.50241670e+02, -2.76314755e+02, -3.04930986e+02, -3.36196973e+02, -3.70907934e+02, -4.10966644e+02, -4.56684022e+02, -5.06945218e+02, -5.61838645e+02, -6.22617808e+02, -6.90840503e+02, -7.67825713e+02, -8.54436805e+02, -9.51106365e+02, -1.05780305e+03, -1.17435473e+03, -1.30045062e+03, -1.43571221e+03, -1.57971603e+03, -1.73204264e+03, -1.88430524e+03, -2.03403679e+03, -2.17861987e+03, -2.31532884e+03, -8.00654731e+03, -5.21487172e-02, -2.80234170e-01, 4.93894552e-01, 3.11884938e-01, 6.55799607e-01, 5.62182419e-01, 3.86074983e-01, 3.43741491e-01, 4.22461089e-01, 3.63707951e-01, 4.93150010e-01, 4.72813688e-01, 4.07390308e-01, 4.94974186e-01, 4.69900128e-01, 4.37562389e-01, 5.67370182e-01, 4.88965362e-01, 6.40728461e-01, 6.14619979e-01, 4.97173823e-01, 6.19549666e-01, 6.51193557e-01, 4.48906118e-01, 7.93091492e-01, 6.51249363e-01, 6.56307713e-01, 1.12948552e+00, 9.50018058e-01, 6.79613030e-01, 9.51359123e-01, 6.31059147e-01, 7.97896887e-01, 8.44620817e-01, 7.43683837e-01, 1.56693187e+00, 2.75630011e-01, 5.32956891e-01, 1.57110727e+00, 1.22674610e+00, 4.63932928e-01, 1.47225464e+00, 1.16948107e+00, 1.07965795e+00, -3.20557791e-01, -1.17064127e+00, -7.84880649e-01, -7.60851182e-01, -1.61415945e+00, -8.30363975e-01, -1.68459409e+00, -1.49260581e+00, -1.84257084e+00, -1.72143079e+00, -1.43131579e+00, -1.63719219e+00, -1.43874851e+00, -1.57207905e+00, -1.72909159e+00, -1.98778122e+00, -1.80843826e+00, -2.12828312e+00, -2.24768762e+00, -2.36961877e+00, -2.49117258e+00, -2.59914065e+00, -2.82309085e+00, -2.93613362e+00, -3.34446991e+00, -3.45445086e+00, -3.74962140e+00, -3.78113417e+00, -4.55643800e+00, -4.86929016e+00, -5.08657898e+00, -5.22054177e+00, -5.54606515e+00, -5.78478304e+00, -5.93652041e+00, -6.11519786e+00]) assert(np.allclose(np.array(test_list), np.array(expected_list)))
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 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
def test_get_BQ(r, b_splus1, j, p, method, PreTP, expected): """ Test of aggregate bequest function. """ BQ = aggr.get_BQ(r, b_splus1, j, p, method, PreTP) assert np.allclose(BQ, expected)
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 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_SS(p, client=None): ''' -------------------------------------------------------------------- Solve for SS of OG-USA. -------------------------------------------------------------------- INPUTS: p = Specifications class with parameterization of model income_tax_parameters = length 5 tuple, (tax_func_type, analytical_mtrs, etr_params, mtrx_params, mtry_params) ss_parameters = length 21 tuple, (J, S, T, BW, beta, sigma, alpha, gamma, epsilon, Z, delta, ltilde, nu, g_y, g_n_ss, tau_payroll, retire, mean_income_data, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon) iterative_params = [2,] vector, vector with max iterations and tolerance for SS solution baseline = boolean, =True if run is for baseline tax policy calibrate_model = boolean, =True if run calibration of chi parameters output_dir = string, path to save output from current model run baseline_dir = string, path where baseline results located OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: SS_fsolve() SS_fsolve_reform() SS_solver OBJECTS CREATED WITHIN FUNCTION: chi_params = [J+S,] vector, chi_b and chi_n stacked together b_guess = [S,J] array, initial guess at savings n_guess = [S,J] array, initial guess at labor supply wguess = scalar, initial guess at SS real wage rate rguess = scalar, initial guess at SS real interest rate T_Hguess = scalar, initial guess at SS lump sum transfers factorguess = scalar, initial guess at SS factor adjustment (to scale model units to dollars) output RETURNS: output OUTPUT: None -------------------------------------------------------------------- ''' # For initial guesses of w, r, T_H, and factor, we use values that # are close to some steady state values. if p.baseline: b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .4 * p.ltilde if p.small_open: rguess = p.firm_r[-1] else: rguess = 0.09 T_Hguess = 0.12 factorguess = 70000 BQguess = aggr.get_BQ(rguess, b_guess, None, p, 'SS', False) ss_params_baseline = (b_guess, n_guess, None, None, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [T_Hguess, factorguess] else: guesses = [rguess] + list(BQguess) + [T_Hguess, factorguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_baseline, xtol=p.mindist_SS, full_output=True) if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-2] T_Hss = solutions_fsolve[-2] factor_ss = solutions_fsolve[-1] Yss = T_Hss/p.alpha_T[-1] # may not be right - if budget_balance # = True, but that's ok - will be fixed in SS_solver fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, T_Hss, factor_ss, Yss, p, client, fsolve_flag) else: # Use the baseline solution to get starting values for the reform baseline_ss_dir = os.path.join(p.baseline_dir, 'SS/SS_vars.pkl') ss_solutions = pickle.load(open(baseline_ss_dir, 'rb'), encoding='latin1') (b_guess, n_guess, rguess, BQguess, T_Hguess, Yguess, factor) =\ (ss_solutions['bssmat_splus1'], ss_solutions['nssmat'], ss_solutions['rss'], ss_solutions['BQss'], ss_solutions['T_Hss'], ss_solutions['Yss'], ss_solutions['factor_ss']) if p.baseline_spending: T_Hss = T_Hguess ss_params_reform = (b_guess, n_guess, T_Hss, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [Yguess] else: guesses = [rguess] + list(BQguess) + [Yguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] Yss = solutions_fsolve[-1] else: ss_params_reform = (b_guess, n_guess, None, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [T_Hguess] else: guesses = [rguess] + list(BQguess) + [T_Hguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] T_Hss = solutions_fsolve[-1] Yss = T_Hss/p.alpha_T[-1] # may not be right - if # budget_balance = True, but that's ok - will be fixed in # SS_solver if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') # Return SS values of variables fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, T_Hss, factor, Yss, p, client, fsolve_flag) if output['Gss'] < 0.: warnings.warn('Warning: The combination of the tax policy ' + 'you specified and your target debt-to-GDP ' + 'ratio results in an infeasible amount of ' + 'government spending in order to close the ' + 'budget (i.e., G < 0)') 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 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 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_SS(p, client=None): ''' Solve for steady-state equilibrium of OG-USA. Args: p (OG-USA Specifications object): model parameters client (Dask client object): client Returns: output (dictionary): dictionary with steady-state solution results ''' # For initial guesses of w, r, TR, and factor, we use values that # are close to some steady state values. if p.baseline: b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .4 * p.ltilde if p.small_open: rguess = p.firm_r[-1] else: rguess = 0.09 TRguess = 0.12 factorguess = 70000 BQguess = aggr.get_BQ(rguess, b_guess, None, p, 'SS', False) ss_params_baseline = (b_guess, n_guess, None, None, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [TRguess, factorguess] else: guesses = [rguess] + list(BQguess) + [TRguess, factorguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_baseline, xtol=p.mindist_SS, full_output=True) if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-2] TR_ss = solutions_fsolve[-2] factor_ss = solutions_fsolve[-1] Yss = TR_ss/p.alpha_T[-1] # may not be right - if budget_balance # = True, but that's ok - will be fixed in SS_solver fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, TR_ss, factor_ss, Yss, p, client, fsolve_flag) else: # Use the baseline solution to get starting values for the reform baseline_ss_dir = os.path.join(p.baseline_dir, 'SS/SS_vars.pkl') ss_solutions = pickle.load(open(baseline_ss_dir, 'rb'), encoding='latin1') (b_guess, n_guess, rguess, BQguess, TRguess, Yguess, factor) =\ (ss_solutions['bssmat_splus1'], ss_solutions['nssmat'], ss_solutions['rss'], ss_solutions['BQss'], ss_solutions['TR_ss'], ss_solutions['Yss'], ss_solutions['factor_ss']) if p.baseline_spending: TR_ss = TRguess ss_params_reform = (b_guess, n_guess, TR_ss, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [Yguess] else: guesses = [rguess] + list(BQguess) + [Yguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] Yss = solutions_fsolve[-1] else: ss_params_reform = (b_guess, n_guess, None, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [TRguess] else: guesses = [rguess] + list(BQguess) + [TRguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] TR_ss = solutions_fsolve[-1] Yss = TR_ss/p.alpha_T[-1] # may not be right - if # budget_balance = True, but that's ok - will be fixed in # SS_solver if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') # Return SS values of variables fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, TR_ss, factor, Yss, p, client, fsolve_flag) if output['Gss'] < 0.: warnings.warn('Warning: The combination of the tax policy ' + 'you specified and your target debt-to-GDP ' + 'ratio results in an infeasible amount of ' + 'government spending in order to close the ' + 'budget (i.e., G < 0)') 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