def run_TPI(income_tax_params, tpi_params, iterative_params, initial_values, SS_values, output_dir="./OUTPUT"): # unpack tuples of parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params maxiter, mindist_SS, mindist_TPI = iterative_params J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_vector, tau_payroll, tau_bq, rho, omega, N_tilde, lambdas, e, retire, mean_income_data,\ factor, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon, chi_b, chi_n = tpi_params K0, b_sinit, b_splus1init, L0, Y0,\ w0, r0, BQ0, T_H_0, factor, tax0, c0, initial_b, initial_n = initial_values Kss, Lss, rss, wss, BQss, T_Hss, bssmat_splus1, nssmat = SS_values TPI_FIG_DIR = output_dir # Initialize guesses at time paths domain = np.linspace(0, T, T) K_init = (-1 / (domain + 1)) * (Kss - K0) + Kss K_init[-1] = Kss K_init = np.array(list(K_init) + list(np.ones(S) * Kss)) L_init = np.ones(T + S) * Lss K = K_init L = L_init Y_params = (alpha, Z) Y = firm.get_Y(K, L, Y_params) w = firm.get_w(Y, L, alpha) r_params = (alpha, delta) r = firm.get_r(Y, K, r_params) BQ = np.zeros((T + S, J)) for j in xrange(J): BQ[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQ = np.array(BQ) if T_Hss < 1e-13 and T_Hss > 0.0: 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(T + S) * T_Hss2 # Make array of initial guesses for labor supply and savings domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = np.zeros((T + S, S, J)) n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) TPIiter = 0 TPIdist = 10 PLOT_TPI = False euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: K_plot = list(K) + list(np.ones(10) * Kss) L_plot = list(L) + list(np.ones(10) * Lss) plt.figure() plt.axhline(y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange(T + 10), Kpath_plot[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) # Uncomment the following print statements to make sure all euler equations are converging. # If they don't, then you'll have negative consumption or consumption spikes. If they don't, # it is the initial guesses. You might need to scale them differently. It is rather delicate for the first # few periods and high ability groups. # theta_params = (e[-1, j], 1, omega[0].reshape(S, 1), lambdas[j]) # theta = tax.replacement_rate_vals(n, w, factor, theta_params) theta = np.zeros((J, )) guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, theta, ind) # Solve HH problem in inner loop euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) # if euler_errors.max() > 1e-6: # print 't-loop:', euler_errors.max() # Force the initial distribution of capital to be as given above. b_mat[0, :, :] = initial_b K_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') K[:T] = household.get_K(b_mat[:T], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) wnew = firm.get_w(Ynew[:T], L[:T], alpha) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) BQ_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat[:T, :, :], BQ_params) bmat_s = np.zeros((T, S, J)) bmat_s[:, 1:, :] = b_mat[:T, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[1:T + 1, :, :] TH_tax_params = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): TH_tax_params[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) T_H_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', TH_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) T_H_new = np.array( list( tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1), ( 1, S, J)), np.tile(wnew[:T].reshape(T, 1, 1), ( 1, S, J)), bmat_s, n_mat[:T, :, :], BQnew[:T].reshape( T, 1, J), factor, T_H_params)) + [T_Hss] * S) w[:T] = utils.convex_combo(wnew[:T], w[:T], nu) r[:T] = utils.convex_combo(rnew[:T], r[:T], nu) BQ[:T] = utils.convex_combo(BQnew[:T], BQ[:T], nu) T_H[:T] = utils.convex_combo(T_H_new[:T], T_H[:T], nu) guesses_b = utils.convex_combo(b_mat, guesses_b, nu) guesses_n = utils.convex_combo(n_mat, guesses_n, nu) if T_H.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(utils.pct_diff_func(wnew[:T], w[:T])) + list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(utils.pct_diff_func(wnew[:T], w[:T])) + list(np.abs(T_H_new[:T], T_H[: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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist if ((TPIiter >= maxiter) or (np.absolute(TPIdist) > mindist_TPI)) and ENFORCE_SOLUTION_CHECKS: raise RuntimeError("Transition path equlibrium not found") Y[:T] = Ynew # Solve HH problem in inner loop guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, theta, ind) euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) b_mat[0, :, :] = initial_b K_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') K[:T] = household.get_K( b_mat[:T], K_params) # this is what old code does, but it's strange - why use # b_mat -- what is going on with initial period, etc. etr_params_path = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) tax_path_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1), (1, S, J)), np.tile(w[:T].reshape(T, 1, 1), (1, S, J)), bmat_s, n_mat[:T, :, :], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), bmat_s, bmat_splus1, n_mat[:T, :, :], BQ[:T].reshape(T, 1, J), tax_path, cons_params) C_params = (omega[:T].reshape(T, S, 1), lambdas, 'TPI') C = household.get_C(c_path, C_params) I_params = (delta, g_y, g_n_vector[:T]) I = firm.get_I(K[1:T + 1], K[:T], I_params) print 'Resource Constraint Difference:', Y[:T] - C[:T] - I[:T] print 'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_path[t], t, ltilde) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, S:, :].max(1).max(1) print 'Max Euler error, savings: ', eul_savings print 'Max Euler error labor supply: ', eul_laborleisure if ((np.any(np.absolute(eul_savings) >= mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError("Transition path equlibrium not found") ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'T_H': T_H, 'r': r, 'w': w, 'b_mat': b_mat, 'n_mat': n_mat, 'c_path': c_path, 'tax_path': tax_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure } tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) macro_output = { 'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'T_H': T_H, 'r': r, 'w': w, 'tax_path': tax_path } # Non-stationary output # macro_ns_output = {'K_ns_path': K_ns_path, 'C_ns_path': C_ns_path, 'I_ns_path': I_ns_path, # 'L_ns_path': L_ns_path, 'BQ_ns_path': BQ_ns_path, # 'rinit': rinit, 'Y_ns_path': Y_ns_path, 'T_H_ns_path': T_H_ns_path, # 'w_ns_path': w_ns_path} return output, macro_output
def SS_solver(b_guess_init, n_guess_init, rss, wss, T_Hss, factor_ss, Yss, params, baseline, fsolve_flag=False, baseline_spending=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = length X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() household.get_K() firm.get_L() firm.get_Y() firm.get_r() firm.get_w() household.get_BQ() tax.replacement_rate_vals() tax.revenue() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption OBJECTS CREATED WITHIN FUNCTION - SMALL OPEN ONLY Bss = scalar, aggregate household wealth in the steady state BIss = scalar, aggregate household net investment in the steady state RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' bssmat, nssmat, chi_params, ss_params, income_tax_params, iterative_params, small_open_params = params J, S, T, BW, beta, sigma, alpha, gamma, epsilon, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, tau_bq, rho, omega_SS, budget_balance, \ alpha_T, debt_ratio_ss, tau_b, delta_tau,\ lambdas, imm_rates, e, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_params analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params chi_b, chi_n = chi_params maxiter, mindist_SS = iterative_params small_open, ss_firm_r, ss_hh_r = small_open_params # Rename the inputs r = rss w = wss T_H = T_Hss factor = factor_ss if budget_balance == False: if baseline_spending == True: Y = Yss else: Y = T_H / alpha_T if small_open == True: r = ss_hh_r dist = 10 iteration = 0 dist_vec = np.zeros(maxiter) if fsolve_flag == True: maxiter = 1 while (dist > mindist_SS) and (iteration < maxiter): # Solve for the steady state levels of b and n, given w, r, Y and # factor if budget_balance: outer_loop_vars = (bssmat, nssmat, r, w, T_H, factor) else: outer_loop_vars = (bssmat, nssmat, r, w, Y, T_H, factor) inner_loop_params = (ss_params, income_tax_params, chi_params, small_open_params) euler_errors, bssmat, nssmat, new_r, new_w, \ new_T_H, new_Y, new_factor, new_BQ, average_income_model = inner_loop(outer_loop_vars, inner_loop_params, baseline, baseline_spending) r = utils.convex_combo(new_r, r, nu) w = utils.convex_combo(new_w, w, nu) factor = utils.convex_combo(new_factor, factor, nu) if budget_balance: T_H = utils.convex_combo(new_T_H, T_H, nu) dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() else: Y = utils.convex_combo(new_Y, Y, nu) if Y != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_Y, Y)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If Y is zero (if there is no output), a percent difference # will throw NaN's, so we use an absoluate difference dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [abs(new_Y - Y)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu /= 2.0 print 'New value of nu:', nu iteration += 1 print "Iteration: %02d" % iteration, " Distance: ", dist ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1,J)),bssmat[:-1,:],axis=0) bssmat_splus1 = bssmat rss = r wss = w factor_ss = factor T_Hss = T_H Lss_params = (e, omega_SS.reshape(S, 1), lambdas, 'SS') Lss = firm.get_L(nssmat, Lss_params) if small_open == False: Kss_params = (omega_SS.reshape(S, 1), lambdas, imm_rates, g_n_ss, 'SS') Bss = household.get_K(bssmat_splus1, Kss_params) if budget_balance: debt_ss = 0.0 else: debt_ss = debt_ratio_ss*Y Kss = Bss - debt_ss Iss_params = (delta, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') Iss = firm.get_I(bssmat_splus1, Kss, Kss, Iss_params) else: # Compute capital (K) and wealth (B) separately Kss_params = (Z, gamma, epsilon, delta, tau_b, delta_tau) Kss = firm.get_K(Lss, ss_firm_r, Kss_params) Iss_params = (delta, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') InvestmentPlaceholder = np.zeros(bssmat_splus1.shape) Iss = firm.get_I(InvestmentPlaceholder, Kss, Kss, Iss_params) Bss_params = (omega_SS.reshape(S, 1), lambdas, imm_rates, g_n_ss, 'SS') Bss = household.get_K(bssmat_splus1, Bss_params) BIss_params = (0.0, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') BIss = firm.get_I(bssmat_splus1, Bss, Bss, BIss_params) if budget_balance: debt_ss = 0.0 else: debt_ss = debt_ratio_ss*Y # Yss_params = (alpha, Z) Yss_params = (Z, gamma, epsilon) Yss = firm.get_Y(Kss, Lss, Yss_params) # Verify that T_Hss = alpha_T*Yss # transfer_error = T_Hss - alpha_T*Yss # if np.absolute(transfer_error) > mindist_SS: # print 'Transfers exceed alpha_T percent of GDP by:', transfer_error # err = "Transfers do not match correct share of GDP in SS_solver" # raise RuntimeError(err) BQss = new_BQ theta_params = (e, S, retire) theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, theta_params) # Next 5 lines pulled out of inner_loop where they are used to calculate tax revenue. Now calculating G to balance gov't budget. b_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat[:-1, :])) lump_sum_params = (e, lambdas.reshape(1, J), omega_SS.reshape(S, 1), 'SS', etr_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) revenue_ss = tax.revenue(new_r, new_w, b_s, nssmat, new_BQ, Yss, Lss, Kss, factor, lump_sum_params) r_gov_ss = rss debt_service_ss = r_gov_ss*debt_ratio_ss*Yss new_borrowing = debt_ratio_ss*Yss*((1+g_n_ss)*np.exp(g_y)-1) # government spends such that it expands its debt at the same rate as GDP if budget_balance: Gss = 0.0 else: Gss = revenue_ss + new_borrowing - (T_Hss + debt_service_ss) # solve resource constraint etr_params_3D = np.tile(np.reshape(etr_params,(S,1,etr_params.shape[1])),(1,J,1)) mtrx_params_3D = np.tile(np.reshape(mtrx_params,(S,1,mtrx_params.shape[1])),(1,J,1)) ''' ------------------------------------------------------------------------ The code below is to calulate and save model MTRs - only exists to help debug ------------------------------------------------------------------------ ''' # etr_params_extended = np.append(etr_params,np.reshape(etr_params[-1,:],(1,etr_params.shape[1])),axis=0)[1:,:] # etr_params_extended_3D = np.tile(np.reshape(etr_params_extended,(S,1,etr_params_extended.shape[1])),(1,J,1)) # mtry_params_extended = np.append(mtry_params,np.reshape(mtry_params[-1,:],(1,mtry_params.shape[1])),axis=0)[1:,:] # mtry_params_extended_3D = np.tile(np.reshape(mtry_params_extended,(S,1,mtry_params_extended.shape[1])),(1,J,1)) # e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) # nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) # mtry_ss_params = (e_extended[1:,:], etr_params_extended_3D, mtry_params_extended_3D, analytical_mtrs) # mtry_ss = tax.MTR_capital(rss, wss, bssmat_splus1, nss_extended[1:,:], factor_ss, mtry_ss_params) # mtrx_ss_params = (e, etr_params_3D, mtrx_params_3D, analytical_mtrs) # mtrx_ss = tax.MTR_labor(rss, wss, bssmat_s, nssmat, factor_ss, mtrx_ss_params) # np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") # np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") # solve resource constraint taxss_params = (e, lambdas, 'SS', retire, etr_params_3D, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) taxss = tax.total_taxes(rss, wss, bssmat_s, nssmat, BQss, factor_ss, T_Hss, None, False, taxss_params) css_params = (e, lambdas.reshape(1, J), g_y) cssmat = household.get_cons(rss, wss, bssmat_s, bssmat_splus1, nssmat, BQss.reshape( 1, J), taxss, css_params) biz_params = (tau_b, delta_tau) business_revenue = tax.get_biz_tax(wss, Yss, Lss, Kss, biz_params) Css_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css = household.get_C(cssmat, Css_params) if small_open == False: resource_constraint = Yss - (Css + Iss + Gss) print 'Yss= ', Yss, '\n', 'Gss= ', Gss, '\n', 'Css= ', Css, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'Debt service = ', debt_service_ss print 'D/Y:', debt_ss/Yss, 'T/Y:', T_Hss/Yss, 'G/Y:', Gss/Yss, 'Rev/Y:', revenue_ss/Yss, 'business rev/Y: ', business_revenue/Yss, 'Int payments to GDP:', (rss*debt_ss)/Yss print 'Check SS budget: ', Gss - (np.exp(g_y)*(1+g_n_ss)-1-rss)*debt_ss - revenue_ss + T_Hss print 'resource constraint: ', resource_constraint else: # include term for current account resource_constraint = Yss + new_borrowing - (Css + BIss + Gss) + (ss_hh_r * Bss - (delta + ss_firm_r) * Kss - debt_service_ss) print 'Yss= ', Yss, '\n', 'Css= ', Css, '\n', 'Bss = ', Bss, '\n', 'BIss = ', BIss, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'T_H = ', T_H,'\n', 'Gss= ', Gss print 'D/Y:', debt_ss/Yss, 'T/Y:', T_Hss/Yss, 'G/Y:', Gss/Yss, 'Rev/Y:', revenue_ss/Yss, 'Int payments to GDP:', (rss*debt_ss)/Yss print 'resource constraint: ', resource_constraint if Gss < 0: print 'Steady state government spending is negative to satisfy budget' if ENFORCE_SOLUTION_CHECKS and np.absolute(resource_constraint) > mindist_SS: print 'Resource Constraint Difference:', resource_constraint err = "Steady state aggregate resource constraint not satisfied" raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat, nssmat, cssmat, ltilde) euler_savings = euler_errors[:S,:] euler_labor_leisure = euler_errors[S:,:] ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = {'Kss': Kss, 'bssmat': bssmat, 'Bss': Bss, 'Lss': Lss, 'Css':Css, 'Iss':Iss, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'Gss': Gss, 'revenue_ss': revenue_ss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b} return output
def run_time_path_iteration(Kss, Lss, Yss, BQss, theta, parameters, g_n_vector, omega_stationary, K0, b_sinit, b_splus1init, L0, Y0, r0, BQ0, T_H_0, tax0, c0, initial_b, initial_n, factor_ss, tau_bq, chi_b, chi_n, get_baseline=False, output_dir="./OUTPUT", **kwargs): TPI_FIG_DIR = output_dir # Initialize Time paths domain = np.linspace(0, T, T) Kinit = (-1 / (domain + 1)) * (Kss - K0) + Kss Kinit[-1] = Kss Kinit = np.array(list(Kinit) + list(np.ones(S) * Kss)) Linit = np.ones(T + S) * Lss Yinit = firm.get_Y(Kinit, Linit, parameters) winit = firm.get_w(Yinit, Linit, parameters) rinit = firm.get_r(Yinit, Kinit, parameters) BQinit = np.zeros((T + S, J)) for j in xrange(J): BQinit[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQinit = np.array(BQinit) T_H_init = np.ones(T + S) * T_Hss # Make array of initial guesses domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = np.zeros((T + S, S, J)) n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): Kpath_TPI = list(Kinit) + list(np.ones(10) * Kss) Lpath_TPI = list(Linit) + list(np.ones(10) * Lss) # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: plt.figure() plt.axhline( y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange( T + 10), Kpath_TPI[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) # Uncomment the following print statements to make sure all euler equations are converging. # If they don't, then you'll have negative consumption or consumption spikes. If they don't, # it is the initial guesses. You might need to scale them differently. It is rather delicate for the first # few periods and high ability groups. for j in xrange(J): b_mat[1, -1, j], n_mat[0, -1, j] = np.array(opt.fsolve(SS_TPI_firstdoughnutring, [guesses_b[1, -1, j], guesses_n[0, -1, j]], args=(winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq), xtol=1e-13)) # if np.array(SS_TPI_firstdoughnutring([b_mat[1, -1, j], n_mat[0, -1, j]], winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq)).max() > 1e-6: # print 'minidoughnut:', # np.array(SS_TPI_firstdoughnutring([b_mat[1, -1, j], n_mat[0, -1, # j]], winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, # factor_ss, j, parameters, theta, tau_bq)).max() for s in xrange(S - 2): # Upper triangle ind2 = np.arange(s + 2) b_guesses_to_use = np.diag( guesses_b[1:S + 1, :, j], S - (s + 2)) n_guesses_to_use = np.diag(guesses_n[:S, :, j], S - (s + 2)) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:len(solutions) / 2] b_mat[1 + ind2, S - (s + 2) + ind2, j] = b_vec n_vec = solutions[len(solutions) / 2:] n_mat[ind2, S - (s + 2) + ind2, j] = n_vec # if abs(np.array(Steady_state_TPI_solver(solutions, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n))).max() > 1e-6: # print 's-loop:', # abs(np.array(Steady_state_TPI_solver(solutions, winit, rinit, # BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, # theta, tau_bq, rho, lambdas, e, initial_b, chi_b, # chi_n))).max() for t in xrange(0, T): b_guesses_to_use = .75 * \ np.diag(guesses_b[t + 1:t + S + 1, :, j]) n_guesses_to_use = np.diag(guesses_n[t:t + S, :, j]) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:S] b_mat[t + 1 + ind, ind, j] = b_vec n_vec = solutions[S:] n_mat[t + ind, ind, j] = n_vec inputs = list(solutions) euler_errors[t, :, j] = np.abs(Steady_state_TPI_solver( inputs, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n)) # if euler_errors.max() > 1e-6: # print 't-loop:', euler_errors.max() # Force the initial distribution of capital to be as given above. b_mat[0, :, :] = initial_b Kinit = household.get_K(b_mat[:T], omega_stationary[:T].reshape( T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') Linit = firm.get_L(e.reshape(1, S, J), n_mat[:T], omega_stationary[ :T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') Ynew = firm.get_Y(Kinit, Linit, parameters) wnew = firm.get_w(Ynew, Linit, parameters) rnew = firm.get_r(Ynew, Kinit, parameters) # the following needs a g_n term BQnew = household.get_BQ(rnew.reshape(T, 1), b_mat[:T], omega_stationary[:T].reshape( T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') bmat_s = np.zeros((T, S, J)) bmat_s[:, 1:, :] = b_mat[:T, :-1, :] T_H_new = np.array(list(tax.get_lump_sum(rnew.reshape(T, 1, 1), bmat_s, wnew.reshape( T, 1, 1), e.reshape(1, S, J), n_mat[:T], BQnew.reshape(T, 1, J), lambdas.reshape( 1, 1, J), factor_ss, omega_stationary[:T].reshape(T, S, 1), 'TPI', parameters, theta, tau_bq)) + [T_Hss] * S) winit[:T] = utils.convex_combo(wnew, winit[:T], parameters) rinit[:T] = utils.convex_combo(rnew, rinit[:T], parameters) BQinit[:T] = utils.convex_combo(BQnew, BQinit[:T], parameters) T_H_init[:T] = utils.convex_combo( T_H_new[:T], T_H_init[:T], parameters) guesses_b = utils.convex_combo(b_mat, guesses_b, parameters) guesses_n = utils.convex_combo(n_mat, guesses_n, parameters) if T_H_init.all() != 0: TPIdist = np.array(list(utils.perc_dif_func(rnew, rinit[:T])) + list(utils.perc_dif_func(BQnew, BQinit[:T]).flatten()) + list( utils.perc_dif_func(wnew, winit[:T])) + list(utils.perc_dif_func(T_H_new, T_H_init))).max() else: TPIdist = np.array(list(utils.perc_dif_func(rnew, rinit[:T])) + list(utils.perc_dif_func(BQnew, BQinit[:T]).flatten()) + list( utils.perc_dif_func(wnew, winit[:T])) + list(np.abs(T_H_new, T_H_init))).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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist print 'Computing final solutions' # As in SS, you need the final distributions of b and n to match the final # w, r, BQ, etc. Otherwise the euler errors are large. You need one more # fsolve. for j in xrange(J): b_mat[1, -1, j], n_mat[0, -1, j] = np.array(opt.fsolve(SS_TPI_firstdoughnutring, [guesses_b[1, -1, j], guesses_n[0, -1, j]], args=(winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq), xtol=1e-13)) for s in xrange(S - 2): # Upper triangle ind2 = np.arange(s + 2) b_guesses_to_use = np.diag(guesses_b[1:S + 1, :, j], S - (s + 2)) n_guesses_to_use = np.diag(guesses_n[:S, :, j], S - (s + 2)) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:len(solutions) / 2] b_mat[1 + ind2, S - (s + 2) + ind2, j] = b_vec n_vec = solutions[len(solutions) / 2:] n_mat[ind2, S - (s + 2) + ind2, j] = n_vec for t in xrange(0, T): b_guesses_to_use = .75 * np.diag(guesses_b[t + 1:t + S + 1, :, j]) n_guesses_to_use = np.diag(guesses_n[t:t + S, :, j]) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:S] b_mat[t + 1 + ind, ind, j] = b_vec n_vec = solutions[S:] n_mat[t + ind, ind, j] = n_vec inputs = list(solutions) euler_errors[t, :, j] = np.abs(Steady_state_TPI_solver( inputs, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n)) b_mat[0, :, :] = initial_b ''' ------------------------------------------------------------------------ Generate variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' Kpath_TPI = np.array(list(Kinit) + list(np.ones(10) * Kss)) Lpath_TPI = np.array(list(Linit) + list(np.ones(10) * Lss)) BQpath_TPI = np.array(list(BQinit) + list(np.ones((10, J)) * BQss)) b_s = np.zeros((T, S, J)) b_s[:, 1:, :] = b_mat[:T, :-1, :] b_splus1 = np.zeros((T, S, J)) b_splus1[:, :, :] = b_mat[1:T + 1, :, :] tax_path = tax.total_taxes(rinit[:T].reshape(T, 1, 1), b_s, winit[:T].reshape(T, 1, 1), e.reshape( 1, S, J), n_mat[:T], BQinit[:T, :].reshape(T, 1, J), lambdas, factor_ss, T_H_init[:T].reshape(T, 1, 1), None, 'TPI', False, parameters, theta, tau_bq) c_path = household.get_cons(rinit[:T].reshape(T, 1, 1), b_s, winit[:T].reshape(T, 1, 1), e.reshape( 1, S, J), n_mat[:T], BQinit[:T].reshape(T, 1, J), lambdas.reshape(1, 1, J), b_splus1, parameters, tax_path) Y_path = firm.get_Y(Kpath_TPI[:T], Lpath_TPI[:T], parameters) C_path = household.get_C(c_path, omega_stationary[ :T].reshape(T, S, 1), lambdas, 'TPI') I_path = firm.get_I(Kpath_TPI[1:T + 1], Kpath_TPI[:T], delta, g_y, g_n_vector[:T]) print 'Resource Constraint Difference:', Y_path - C_path - I_path print'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_path[t], t, parameters) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, S:, :].max(1).max(1) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = {'Kpath_TPI': Kpath_TPI, 'b_mat': b_mat, 'c_path': c_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'Lpath_TPI': Lpath_TPI, 'BQpath_TPI': BQpath_TPI, 'n_mat': n_mat, 'rinit': rinit, 'Yinit': Yinit, 'T_H_init': T_H_init, 'tax_path': tax_path, 'winit': winit} if get_baseline: tpi_init_dir = os.path.join(output_dir, "TPIinit") utils.mkdirs(tpi_init_dir) tpi_init_vars = os.path.join(tpi_init_dir, "TPIinit_vars.pkl") pickle.dump(output, open(tpi_init_vars, "wb")) else: tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb"))
def SS_solver(b_guess_init, n_guess_init, rss, wss, T_Hss, factor_ss, Yss, params, baseline, fsolve_flag=False, baseline_spending=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = length X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() household.get_K() firm.get_L() firm.get_Y() firm.get_r() firm.get_w() household.get_BQ() tax.replacement_rate_vals() tax.revenue() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption OBJECTS CREATED WITHIN FUNCTION - SMALL OPEN ONLY Bss = scalar, aggregate household wealth in the steady state BIss = scalar, aggregate household net investment in the steady state RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' bssmat, nssmat, chi_params, ss_params, income_tax_params, iterative_params, small_open_params = params J, S, T, BW, beta, sigma, alpha, gamma, epsilon, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, tau_bq, rho, omega_SS, budget_balance, \ alpha_T, debt_ratio_ss, tau_b, delta_tau,\ lambdas, imm_rates, e, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_params analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params chi_b, chi_n = chi_params maxiter, mindist_SS = iterative_params small_open, ss_firm_r, ss_hh_r = small_open_params # Rename the inputs r = rss w = wss T_H = T_Hss factor = factor_ss if budget_balance == False: if baseline_spending == True: Y = Yss else: Y = T_H / alpha_T if small_open == True: r = ss_hh_r dist = 10 iteration = 0 dist_vec = np.zeros(maxiter) if fsolve_flag == True: maxiter = 1 while (dist > mindist_SS) and (iteration < maxiter): # Solve for the steady state levels of b and n, given w, r, Y and # factor if budget_balance: outer_loop_vars = (bssmat, nssmat, r, w, T_H, factor) else: outer_loop_vars = (bssmat, nssmat, r, w, Y, T_H, factor) inner_loop_params = (ss_params, income_tax_params, chi_params, small_open_params) euler_errors, bssmat, nssmat, new_r, new_w, \ new_T_H, new_Y, new_factor, new_BQ, average_income_model = inner_loop(outer_loop_vars, inner_loop_params, baseline, baseline_spending) r = utils.convex_combo(new_r, r, nu) w = utils.convex_combo(new_w, w, nu) factor = utils.convex_combo(new_factor, factor, nu) if budget_balance: T_H = utils.convex_combo(new_T_H, T_H, nu) dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() else: Y = utils.convex_combo(new_Y, Y, nu) if Y != 0: dist = np.array( [utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_Y, Y)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If Y is zero (if there is no output), a percent difference # will throw NaN's, so we use an absoluate difference dist = np.array( [utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [abs(new_Y - Y)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu /= 2.0 print 'New value of nu:', nu iteration += 1 print "Iteration: %02d" % iteration, " Distance: ", dist ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1, J)), bssmat[:-1, :], axis=0) bssmat_splus1 = bssmat rss = r wss = w factor_ss = factor T_Hss = T_H Lss_params = (e, omega_SS.reshape(S, 1), lambdas, 'SS') Lss = firm.get_L(nssmat, Lss_params) if small_open == False: Kss_params = (omega_SS.reshape(S, 1), lambdas, imm_rates, g_n_ss, 'SS') Bss = household.get_K(bssmat_splus1, Kss_params) if budget_balance: debt_ss = 0.0 else: debt_ss = debt_ratio_ss * Y Kss = Bss - debt_ss Iss_params = (delta, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') Iss = firm.get_I(bssmat_splus1, Kss, Kss, Iss_params) else: # Compute capital (K) and wealth (B) separately Kss_params = (Z, gamma, epsilon, delta, tau_b, delta_tau) Kss = firm.get_K(Lss, ss_firm_r, Kss_params) Iss_params = (delta, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') InvestmentPlaceholder = np.zeros(bssmat_splus1.shape) Iss = firm.get_I(InvestmentPlaceholder, Kss, Kss, Iss_params) Bss_params = (omega_SS.reshape(S, 1), lambdas, imm_rates, g_n_ss, 'SS') Bss = household.get_K(bssmat_splus1, Bss_params) BIss_params = (0.0, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') BIss = firm.get_I(bssmat_splus1, Bss, Bss, BIss_params) if budget_balance: debt_ss = 0.0 else: debt_ss = debt_ratio_ss * Y # Yss_params = (alpha, Z) Yss_params = (Z, gamma, epsilon) Yss = firm.get_Y(Kss, Lss, Yss_params) # Verify that T_Hss = alpha_T*Yss # transfer_error = T_Hss - alpha_T*Yss # if np.absolute(transfer_error) > mindist_SS: # print 'Transfers exceed alpha_T percent of GDP by:', transfer_error # err = "Transfers do not match correct share of GDP in SS_solver" # raise RuntimeError(err) BQss = new_BQ theta_params = (e, S, retire) theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, theta_params) # Next 5 lines pulled out of inner_loop where they are used to calculate tax revenue. Now calculating G to balance gov't budget. b_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat[:-1, :])) lump_sum_params = (e, lambdas.reshape(1, J), omega_SS.reshape(S, 1), 'SS', etr_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) revenue_ss = tax.revenue(new_r, new_w, b_s, nssmat, new_BQ, Yss, Lss, Kss, factor, lump_sum_params) r_gov_ss = rss debt_service_ss = r_gov_ss * debt_ratio_ss * Yss new_borrowing = debt_ratio_ss * Yss * ((1 + g_n_ss) * np.exp(g_y) - 1) # government spends such that it expands its debt at the same rate as GDP if budget_balance: Gss = 0.0 else: Gss = revenue_ss + new_borrowing - (T_Hss + debt_service_ss) # solve resource constraint etr_params_3D = np.tile( np.reshape(etr_params, (S, 1, etr_params.shape[1])), (1, J, 1)) mtrx_params_3D = np.tile( np.reshape(mtrx_params, (S, 1, mtrx_params.shape[1])), (1, J, 1)) ''' ------------------------------------------------------------------------ The code below is to calulate and save model MTRs - only exists to help debug ------------------------------------------------------------------------ ''' # etr_params_extended = np.append(etr_params,np.reshape(etr_params[-1,:],(1,etr_params.shape[1])),axis=0)[1:,:] # etr_params_extended_3D = np.tile(np.reshape(etr_params_extended,(S,1,etr_params_extended.shape[1])),(1,J,1)) # mtry_params_extended = np.append(mtry_params,np.reshape(mtry_params[-1,:],(1,mtry_params.shape[1])),axis=0)[1:,:] # mtry_params_extended_3D = np.tile(np.reshape(mtry_params_extended,(S,1,mtry_params_extended.shape[1])),(1,J,1)) # e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) # nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) # mtry_ss_params = (e_extended[1:,:], etr_params_extended_3D, mtry_params_extended_3D, analytical_mtrs) # mtry_ss = tax.MTR_capital(rss, wss, bssmat_splus1, nss_extended[1:,:], factor_ss, mtry_ss_params) # mtrx_ss_params = (e, etr_params_3D, mtrx_params_3D, analytical_mtrs) # mtrx_ss = tax.MTR_labor(rss, wss, bssmat_s, nssmat, factor_ss, mtrx_ss_params) # np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") # np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") # solve resource constraint taxss_params = (e, lambdas, 'SS', retire, etr_params_3D, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) taxss = tax.total_taxes(rss, wss, bssmat_s, nssmat, BQss, factor_ss, T_Hss, None, False, taxss_params) css_params = (e, lambdas.reshape(1, J), g_y) cssmat = household.get_cons(rss, wss, bssmat_s, bssmat_splus1, nssmat, BQss.reshape(1, J), taxss, css_params) biz_params = (tau_b, delta_tau) business_revenue = tax.get_biz_tax(wss, Yss, Lss, Kss, biz_params) Css_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css = household.get_C(cssmat, Css_params) if small_open == False: resource_constraint = Yss - (Css + Iss + Gss) print 'Yss= ', Yss, '\n', 'Gss= ', Gss, '\n', 'Css= ', Css, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'Debt service = ', debt_service_ss print 'D/Y:', debt_ss / Yss, 'T/Y:', T_Hss / Yss, 'G/Y:', Gss / Yss, 'Rev/Y:', revenue_ss / Yss, 'business rev/Y: ', business_revenue / Yss, 'Int payments to GDP:', ( rss * debt_ss) / Yss print 'Check SS budget: ', Gss - (np.exp(g_y) * (1 + g_n_ss) - 1 - rss) * debt_ss - revenue_ss + T_Hss print 'resource constraint: ', resource_constraint else: # include term for current account resource_constraint = Yss + new_borrowing - (Css + BIss + Gss) + ( ss_hh_r * Bss - (delta + ss_firm_r) * Kss - debt_service_ss) print 'Yss= ', Yss, '\n', 'Css= ', Css, '\n', 'Bss = ', Bss, '\n', 'BIss = ', BIss, '\n', 'Kss = ', Kss, '\n', 'Iss = ', Iss, '\n', 'Lss = ', Lss, '\n', 'T_H = ', T_H, '\n', 'Gss= ', Gss print 'D/Y:', debt_ss / Yss, 'T/Y:', T_Hss / Yss, 'G/Y:', Gss / Yss, 'Rev/Y:', revenue_ss / Yss, 'Int payments to GDP:', ( rss * debt_ss) / Yss print 'resource constraint: ', resource_constraint if Gss < 0: print 'Steady state government spending is negative to satisfy budget' if ENFORCE_SOLUTION_CHECKS and np.absolute( resource_constraint) > mindist_SS: print 'Resource Constraint Difference:', resource_constraint err = "Steady state aggregate resource constraint not satisfied" raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat, nssmat, cssmat, ltilde) euler_savings = euler_errors[:S, :] euler_labor_leisure = euler_errors[S:, :] ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = { 'Kss': Kss, 'bssmat': bssmat, 'Bss': Bss, 'Lss': Lss, 'Css': Css, 'Iss': Iss, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'Gss': Gss, 'revenue_ss': revenue_ss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b } return output
beq_ut = chi_b.reshape(1, J) * (rho.reshape(S, 1)) * \ (savings**(1 - sigma) - 1) / (1 - sigma) utility = ((cssmat_init ** (1 - sigma) - 1) / (1 - sigma)) + chi_n.reshape(S, 1) * \ (b_ellipse * (1 - (nssmat_init / ltilde)**upsilon) ** (1 / upsilon) + k_ellipse) utility += beq_ut utility_init = utility.sum(0) T_Hss_init = T_Hss Kss_init = Kss Lss_init = Lss c_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css_init = household.get_C(cssmat, c_params) i_params = (delta, g_y, omega_SS.reshape(1,S), lambdas, imm_rates, g_n_ss, 'SS') iss_init = firm.get_I(bssmat_splus1, Kss_init, Kss_init, i_params) income_init = cssmat + iss_init # print (income_init*omega_SS).sum() # print Css + delta * Kss # print Kss # print Lss # print Css_init # print (utility_init * omega_SS).sum() the_inequalizer(income_init, omega_SS, lambdas, S, J) ''' ------------------------------------------------------------------------ SS baseline graphs ------------------------------------------------------------------------ '''
def run_time_path_iteration(Kss, Lss, Yss, BQss, theta, parameters, g_n_vector, omega_stationary, K0, b_sinit, b_splus1init, L0, Y0, r0, BQ0, T_H_0, tax0, c0, initial_b, initial_n, factor_ss, tau_bq, chi_b, chi_n, get_baseline=False, output_dir="./OUTPUT", **kwargs): TPI_FIG_DIR = output_dir # Initialize Time paths domain = np.linspace(0, T, T) Kinit = (-1 / (domain + 1)) * (Kss - K0) + Kss Kinit[-1] = Kss Kinit = np.array(list(Kinit) + list(np.ones(S) * Kss)) Linit = np.ones(T + S) * Lss Yinit = firm.get_Y(Kinit, Linit, parameters) winit = firm.get_w(Yinit, Linit, parameters) rinit = firm.get_r(Yinit, Kinit, parameters) BQinit = np.zeros((T + S, J)) for j in xrange(J): BQinit[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQinit = np.array(BQinit) T_H_init = np.ones(T + S) * T_Hss # Make array of initial guesses domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = np.zeros((T + S, S, J)) n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): Kpath_TPI = list(Kinit) + list(np.ones(10) * Kss) Lpath_TPI = list(Linit) + list(np.ones(10) * Lss) # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: plt.figure() plt.axhline(y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange(T + 10), Kpath_TPI[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) # Uncomment the following print statements to make sure all euler equations are converging. # If they don't, then you'll have negative consumption or consumption spikes. If they don't, # it is the initial guesses. You might need to scale them differently. It is rather delicate for the first # few periods and high ability groups. for j in xrange(J): b_mat[1, -1, j], n_mat[0, -1, j] = np.array( opt.fsolve(SS_TPI_firstdoughnutring, [guesses_b[1, -1, j], guesses_n[0, -1, j]], args=(winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq), xtol=1e-13)) # if np.array(SS_TPI_firstdoughnutring([b_mat[1, -1, j], n_mat[0, -1, j]], winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq)).max() > 1e-6: # print 'minidoughnut:', # np.array(SS_TPI_firstdoughnutring([b_mat[1, -1, j], n_mat[0, -1, # j]], winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, # factor_ss, j, parameters, theta, tau_bq)).max() for s in xrange(S - 2): # Upper triangle ind2 = np.arange(s + 2) b_guesses_to_use = np.diag(guesses_b[1:S + 1, :, j], S - (s + 2)) n_guesses_to_use = np.diag(guesses_n[:S, :, j], S - (s + 2)) solutions = opt.fsolve( Steady_state_TPI_solver, list(b_guesses_to_use) + list(n_guesses_to_use), args=(winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:len(solutions) / 2] b_mat[1 + ind2, S - (s + 2) + ind2, j] = b_vec n_vec = solutions[len(solutions) / 2:] n_mat[ind2, S - (s + 2) + ind2, j] = n_vec # if abs(np.array(Steady_state_TPI_solver(solutions, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n))).max() > 1e-6: # print 's-loop:', # abs(np.array(Steady_state_TPI_solver(solutions, winit, rinit, # BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, # theta, tau_bq, rho, lambdas, e, initial_b, chi_b, # chi_n))).max() for t in xrange(0, T): b_guesses_to_use = .75 * \ np.diag(guesses_b[t + 1:t + S + 1, :, j]) n_guesses_to_use = np.diag(guesses_n[t:t + S, :, j]) solutions = opt.fsolve( Steady_state_TPI_solver, list(b_guesses_to_use) + list(n_guesses_to_use), args=(winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:S] b_mat[t + 1 + ind, ind, j] = b_vec n_vec = solutions[S:] n_mat[t + ind, ind, j] = n_vec inputs = list(solutions) euler_errors[t, :, j] = np.abs( Steady_state_TPI_solver(inputs, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n)) # if euler_errors.max() > 1e-6: # print 't-loop:', euler_errors.max() # Force the initial distribution of capital to be as given above. b_mat[0, :, :] = initial_b Kinit = household.get_K(b_mat[:T], omega_stationary[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') Linit = firm.get_L(e.reshape(1, S, J), n_mat[:T], omega_stationary[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') Ynew = firm.get_Y(Kinit, Linit, parameters) wnew = firm.get_w(Ynew, Linit, parameters) rnew = firm.get_r(Ynew, Kinit, parameters) # the following needs a g_n term BQnew = household.get_BQ(rnew.reshape(T, 1), b_mat[:T], omega_stationary[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') bmat_s = np.zeros((T, S, J)) bmat_s[:, 1:, :] = b_mat[:T, :-1, :] T_H_new = np.array( list( tax.get_lump_sum( rnew.reshape(T, 1, 1), bmat_s, wnew.reshape(T, 1, 1), e.reshape(1, S, J), n_mat[:T], BQnew.reshape(T, 1, J), lambdas.reshape(1, 1, J), factor_ss, omega_stationary[:T]. reshape(T, S, 1), 'TPI', parameters, theta, tau_bq)) + [T_Hss] * S) winit[:T] = utils.convex_combo(wnew, winit[:T], parameters) rinit[:T] = utils.convex_combo(rnew, rinit[:T], parameters) BQinit[:T] = utils.convex_combo(BQnew, BQinit[:T], parameters) T_H_init[:T] = utils.convex_combo(T_H_new[:T], T_H_init[:T], parameters) guesses_b = utils.convex_combo(b_mat, guesses_b, parameters) guesses_n = utils.convex_combo(n_mat, guesses_n, parameters) if T_H_init.all() != 0: TPIdist = np.array( list(utils.perc_dif_func(rnew, rinit[:T])) + list(utils.perc_dif_func(BQnew, BQinit[:T]).flatten()) + list(utils.perc_dif_func(wnew, winit[:T])) + list(utils.perc_dif_func(T_H_new, T_H_init))).max() else: TPIdist = np.array( list(utils.perc_dif_func(rnew, rinit[:T])) + list(utils.perc_dif_func(BQnew, BQinit[:T]).flatten()) + list(utils.perc_dif_func(wnew, winit[:T])) + list(np.abs(T_H_new, T_H_init))).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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist print 'Computing final solutions' # As in SS, you need the final distributions of b and n to match the final # w, r, BQ, etc. Otherwise the euler errors are large. You need one more # fsolve. for j in xrange(J): b_mat[1, -1, j], n_mat[0, -1, j] = np.array( opt.fsolve(SS_TPI_firstdoughnutring, [guesses_b[1, -1, j], guesses_n[0, -1, j]], args=(winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, parameters, theta, tau_bq), xtol=1e-13)) for s in xrange(S - 2): # Upper triangle ind2 = np.arange(s + 2) b_guesses_to_use = np.diag(guesses_b[1:S + 1, :, j], S - (s + 2)) n_guesses_to_use = np.diag(guesses_n[:S, :, j], S - (s + 2)) solutions = opt.fsolve( Steady_state_TPI_solver, list(b_guesses_to_use) + list(n_guesses_to_use), args=(winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:len(solutions) / 2] b_mat[1 + ind2, S - (s + 2) + ind2, j] = b_vec n_vec = solutions[len(solutions) / 2:] n_mat[ind2, S - (s + 2) + ind2, j] = n_vec for t in xrange(0, T): b_guesses_to_use = .75 * np.diag(guesses_b[t + 1:t + S + 1, :, j]) n_guesses_to_use = np.diag(guesses_n[t:t + S, :, j]) solutions = opt.fsolve( Steady_state_TPI_solver, list(b_guesses_to_use) + list(n_guesses_to_use), args=(winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:S] b_mat[t + 1 + ind, ind, j] = b_vec n_vec = solutions[S:] n_mat[t + ind, ind, j] = n_vec inputs = list(solutions) euler_errors[t, :, j] = np.abs( Steady_state_TPI_solver(inputs, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n)) b_mat[0, :, :] = initial_b ''' ------------------------------------------------------------------------ Generate variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' Kpath_TPI = np.array(list(Kinit) + list(np.ones(10) * Kss)) Lpath_TPI = np.array(list(Linit) + list(np.ones(10) * Lss)) BQpath_TPI = np.array(list(BQinit) + list(np.ones((10, J)) * BQss)) b_s = np.zeros((T, S, J)) b_s[:, 1:, :] = b_mat[:T, :-1, :] b_splus1 = np.zeros((T, S, J)) b_splus1[:, :, :] = b_mat[1:T + 1, :, :] tax_path = tax.total_taxes(rinit[:T].reshape(T, 1, 1), b_s, winit[:T].reshape(T, 1, 1), e.reshape(1, S, J), n_mat[:T], BQinit[:T, :].reshape(T, 1, J), lambdas, factor_ss, T_H_init[:T].reshape(T, 1, 1), None, 'TPI', False, parameters, theta, tau_bq) c_path = household.get_cons(rinit[:T].reshape(T, 1, 1), b_s, winit[:T].reshape(T, 1, 1), e.reshape(1, S, J), n_mat[:T], BQinit[:T].reshape(T, 1, J), lambdas.reshape(1, 1, J), b_splus1, parameters, tax_path) Y_path = firm.get_Y(Kpath_TPI[:T], Lpath_TPI[:T], parameters) C_path = household.get_C(c_path, omega_stationary[:T].reshape(T, S, 1), lambdas, 'TPI') I_path = firm.get_I(Kpath_TPI[1:T + 1], Kpath_TPI[:T], delta, g_y, g_n_vector[:T]) print 'Resource Constraint Difference:', Y_path - C_path - I_path print 'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_path[t], t, parameters) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, S:, :].max(1).max(1) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Kpath_TPI': Kpath_TPI, 'b_mat': b_mat, 'c_path': c_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'Lpath_TPI': Lpath_TPI, 'BQpath_TPI': BQpath_TPI, 'n_mat': n_mat, 'rinit': rinit, 'Yinit': Yinit, 'T_H_init': T_H_init, 'tax_path': tax_path, 'winit': winit } if get_baseline: tpi_init_dir = os.path.join(output_dir, "TPIinit") utils.mkdirs(tpi_init_dir) tpi_init_vars = os.path.join(tpi_init_dir, "TPIinit_vars.pkl") pickle.dump(output, open(tpi_init_vars, "wb")) else: tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb"))
def run_TPI(income_tax_params, tpi_params, iterative_params, initial_values, SS_values, output_dir="./OUTPUT"): # unpack tuples of parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params maxiter, mindist_SS, mindist_TPI = iterative_params J, S, T, BQ_dist, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_vector, tau_payroll, tau_bq, rho, omega, N_tilde, lambdas, e, retire, mean_income_data,\ factor, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon, chi_b, chi_n = tpi_params K0, b_sinit, b_splus1init, L0, Y0,\ w0, r0, BQ0, T_H_0, factor, tax0, c0, initial_b, initial_n = initial_values Kss, Lss, rss, wss, BQss, T_Hss, bssmat_splus1, nssmat = SS_values TPI_FIG_DIR = output_dir # Initialize guesses at time paths domain = np.linspace(0, T, T) K_init = (-1 / (domain + 1)) * (Kss - K0) + Kss K_init[-1] = Kss K_init = np.array(list(K_init) + list(np.ones(S) * Kss)) L_init = np.ones(T + S) * Lss K = K_init L = L_init Y_params = (alpha, Z) Y = firm.get_Y(K, L, Y_params) w = firm.get_w(Y, L, alpha) r_params = (alpha, delta) r = firm.get_r(Y, K, r_params) BQ = np.zeros((T + S, J)) for j in xrange(J): BQ[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQ = np.array(BQ) if T_Hss < 1e-13 and T_Hss > 0.0 : 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(T + S) * T_Hss2 # Make array of initial guesses for labor supply and savings domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = np.zeros((T + S, S, J)) n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) TPIiter = 0 TPIdist = 10 PLOT_TPI = False euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: K_plot = list(K) + list(np.ones(10) * Kss) L_plot = list(L) + list(np.ones(10) * Lss) plt.figure() plt.axhline( y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange( T + 10), Kpath_plot[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) # Uncomment the following print statements to make sure all euler equations are converging. # If they don't, then you'll have negative consumption or consumption spikes. If they don't, # it is the initial guesses. You might need to scale them differently. It is rather delicate for the first # few periods and high ability groups. # theta_params = (e[-1, j], 1, omega[0].reshape(S, 1), lambdas[j]) # theta = tax.replacement_rate_vals(n, w, factor, theta_params) theta = np.zeros((J,)) guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, theta, ind) # Solve HH problem in inner loop euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) # if euler_errors.max() > 1e-6: # print 't-loop:', euler_errors.max() # Force the initial distribution of capital to be as given above. b_mat[0, :, :] = initial_b K_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') K[:T] = household.get_K(b_mat[:T], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) wnew = firm.get_w(Ynew[:T], L[:T], alpha) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) BQ_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat[:T,:,:], BQ_params) bmat_s = np.zeros((T, S, J)) bmat_s[:, 1:, :] = b_mat[:T, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[1:T + 1, :, :] TH_tax_params = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): TH_tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) T_H_params = (np.tile(e.reshape(1, S, J),(T,1,1)), BQ_dist, lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', TH_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) T_H_new = np.array(list(tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1),(1,S,J)), np.tile(wnew[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQnew[:T].reshape(T, 1, J), factor, T_H_params)) + [T_Hss] * S) w[:T] = utils.convex_combo(wnew[:T], w[:T], nu) r[:T] = utils.convex_combo(rnew[:T], r[:T], nu) BQ[:T] = utils.convex_combo(BQnew[:T], BQ[:T], nu) T_H[:T] = utils.convex_combo(T_H_new[:T], T_H[:T], nu) guesses_b = utils.convex_combo(b_mat, guesses_b, nu) guesses_n = utils.convex_combo(n_mat, guesses_n, nu) if T_H.all() != 0: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( utils.pct_diff_func(wnew[:T], w[:T])) + list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() else: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( utils.pct_diff_func(wnew[:T], w[:T])) + list(np.abs(T_H_new[:T], T_H[: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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist if ((TPIiter >= maxiter) or (np.absolute(TPIdist) > mindist_TPI)) and ENFORCE_SOLUTION_CHECKS : raise RuntimeError("Transition path equlibrium not found") Y[:T] = Ynew # Solve HH problem in inner loop guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, theta, ind) euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) b_mat[0, :, :] = initial_b K_params = (omega[:T].reshape(T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') K[:T] = household.get_K(b_mat[:T], K_params) # this is what old code does, but it's strange - why use # b_mat -- what is going on with initial period, etc. etr_params_path = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_path_params = (np.tile(e.reshape(1, S, J),(T,1,1)), BQ_dist, lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1),(1,S,J)), np.tile(w[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) cons_params = (e.reshape(1, S, J), BQ_dist, lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(omega[:T].reshape(T,S,1), r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), bmat_s, bmat_splus1, n_mat[:T,:,:], BQ[:T].reshape(T, 1, J), tax_path, cons_params) C_params = (omega[:T].reshape(T, S, 1), lambdas, 'TPI') C = household.get_C(c_path, C_params) I_params = (delta, g_y, g_n_vector[:T]) I = firm.get_I(K[1:T+1], K[:T], I_params) print 'Resource Constraint Difference:', Y[:T] - C[:T] - I[:T] print'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_path[t], t, ltilde) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, S:, :].max(1).max(1) print 'Max Euler error, savings: ', eul_savings print 'Max Euler error labor supply: ', eul_laborleisure if ((np.any(np.absolute(eul_savings) >= mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError("Transition path equlibrium not found") ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = {'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'T_H': T_H, 'r': r, 'w': w, 'b_mat': b_mat, 'n_mat': n_mat, 'c_path': c_path, 'tax_path': tax_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure} tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) macro_output = {'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'T_H': T_H, 'r': r, 'w': w, 'tax_path': tax_path} # Non-stationary output # macro_ns_output = {'K_ns_path': K_ns_path, 'C_ns_path': C_ns_path, 'I_ns_path': I_ns_path, # 'L_ns_path': L_ns_path, 'BQ_ns_path': BQ_ns_path, # 'rinit': rinit, 'Y_ns_path': Y_ns_path, 'T_H_ns_path': T_H_ns_path, # 'w_ns_path': w_ns_path} return output, macro_output
def run_TPI(income_tax_params, tpi_params, iterative_params, small_open_params, initial_values, SS_values, fiscal_params, biz_tax_params, output_dir="./OUTPUT", baseline_spending=False): # unpack tuples of parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params maxiter, mindist_SS, mindist_TPI = iterative_params J, S, T, BW, beta, sigma, alpha, gamma, epsilon, Z, delta, ltilde, nu, g_y,\ g_n_vector, tau_payroll, tau_bq, rho, omega, N_tilde, lambdas, imm_rates, e, retire, mean_income_data,\ factor, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon, chi_b, chi_n, theta = tpi_params # K0, b_sinit, b_splus1init, L0, Y0,\ # w0, r0, BQ0, T_H_0, factor, tax0, c0, initial_b, initial_n, omega_S_preTP = initial_values small_open, tpi_firm_r, tpi_hh_r = small_open_params B0, b_sinit, b_splus1init, factor, initial_b, initial_n, omega_S_preTP, initial_debt = initial_values Kss, Bss, Lss, rss, wss, BQss, T_Hss, revenue_ss, bssmat_splus1, nssmat, Yss, Gss = SS_values tau_b, delta_tau = biz_tax_params if baseline_spending==False: budget_balance, ALPHA_T, ALPHA_G, tG1, tG2, rho_G, debt_ratio_ss = fiscal_params else: budget_balance, ALPHA_T, ALPHA_G, tG1, tG2, rho_G, debt_ratio_ss, T_Hbaseline, Gbaseline = fiscal_params print 'Government spending breakpoints are tG1: ', tG1, '; and tG2:', tG2 TPI_FIG_DIR = output_dir # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings domain = np.linspace(0, T, T) domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = guesses_b#np.zeros((T + S, S, J)) n_mat = guesses_n#np.zeros((T + S, S, J)) ind = np.arange(S) L_init = np.ones((T+S,))*Lss B_init = np.ones((T+S,))*Bss L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L_init[:T] = firm.get_L(n_mat[:T], L_params) B_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1,S,1), g_n_vector[1:T], 'TPI') B_init[1:T] = household.get_K(b_mat[:T-1], B_params) B_init[0] = B0 if small_open == False: if budget_balance: K_init = B_init else: K_init = B_init * Kss/Bss else: K_params = (Z, gamma, epsilon, delta, tau_b, delta_tau) K_init = firm.get_K(L_init, tpi_firm_r, K_params) K = K_init # if np.any(K < 0): # print 'K_init has negative elements. Setting them positive to prevent NAN.' # K[:T] = np.fmax(K[:T], 0.05*B[:T]) L = L_init B = B_init Y_params = (Z, gamma, epsilon) Y = firm.get_Y(K, L, Y_params) w_params = (Z, gamma, epsilon) w = firm.get_w(Y, L, w_params) if small_open == False: r_params = (Z, gamma, epsilon, delta, tau_b, delta_tau) r = firm.get_r(Y, K, r_params) else: r = tpi_hh_r BQ = np.zeros((T + S, J)) BQ0_params = (omega_S_preTP.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_vector[0], 'SS') BQ0 = household.get_BQ(r[0], initial_b, BQ0_params) for j in xrange(J): BQ[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQ = np.array(BQ) if 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(T + S) * T_Hss2 REVENUE = T_H G = np.zeros(T + S) elif baseline_spending==False: T_H = ALPHA_T * Y elif baseline_spending==True: T_H = T_Hbaseline T_H_new = T_H # Need to set T_H_new for later reference G = Gbaseline G_0 = Gbaseline[0] # Initialize some inputs # D = np.zeros(T + S) D = debt_ratio_ss*Y omega_shift = np.append(omega_S_preTP.reshape(1,S),omega[:T-1,:],axis=0) BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') tax_params = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) REVENUE_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) # print 'D/Y:', D[:T]/Y[:T] # print 'T/Y:', T_H[:T]/Y[:T] # print 'G/Y:', G[:T]/Y[:T] # print 'Int payments to GDP:', (r[:T]*D[:T])/Y[:T] # quit() TPIiter = 0 TPIdist = 10 PLOT_TPI = False report_tG1 = False euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) print 'analytical mtrs in tpi = ', analytical_mtrs while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: #K_plot = list(K) + list(np.ones(10) * Kss) D_plot = list(D) + list(np.ones(10) * Yss * debt_ratio_ss) plt.figure() plt.axhline( y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange( T + 10), D_plot[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_D")) if report_tG1 is True: print '\tAt time tG1-1:' print '\t\tG = ', G[tG1-1] print '\t\tK = ', K[tG1-1] print '\t\tr = ', r[tG1-1] print '\t\tD = ', D[tG1-1] guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) # Solve HH problem in inner loop euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T-1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] #L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') # defined above L[:T] = firm.get_L(n_mat[:T], L_params) #B_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1,S,1), g_n_vector[1:T], 'TPI') # defined above B[1:T] = household.get_K(bmat_splus1[:T-1], B_params) if np.any(B) < 0: print 'B has negative elements. B[0:9]:', B[0:9] print 'B[T-2:T]:', B[T-2,T] if small_open == False: if budget_balance: K[:T] = B[:T] else: if baseline_spending == False: Y = T_H/ALPHA_T #SBF 3/3: This seems totally unnecessary as both these variables are defined above. # tax_params = np.zeros((T,S,J,etr_params.shape[2])) # for i in range(etr_params.shape[2]): # tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) # REVENUE_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', # tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) # define above REVENUE = np.array(list(tax.revenue(np.tile(r[:T].reshape(T, 1, 1),(1,S,J)), np.tile(w[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQ[:T].reshape(T, 1, J), Y[:T], L[:T], K[:T], factor, REVENUE_params)) + [revenue_ss] * S) D_0 = initial_debt * Y[0] other_dg_params = (T, r, g_n_vector, g_y) if baseline_spending==False: G_0 = ALPHA_G[0] * Y[0] dg_fixed_values = (Y, REVENUE, T_H, D_0,G_0) Dnew, G = fiscal.D_G_path(dg_fixed_values, fiscal_params, other_dg_params, baseline_spending=baseline_spending) K[:T] = B[:T] - Dnew[:T] if np.any(K < 0): print 'K has negative elements. Setting them positive to prevent NAN.' K[:T] = np.fmax(K[:T], 0.05*B[:T]) else: # K_params previously set to = (Z, gamma, epsilon, delta, tau_b, delta_tau) K[:T] = firm.get_K(L[:T], tpi_firm_r[:T], K_params) Y_params = (Z, gamma, epsilon) Ynew = firm.get_Y(K[:T], L[:T], Y_params) Y = Ynew w_params = (Z, gamma, epsilon) wnew = firm.get_w(Ynew[:T], L[:T], w_params) if small_open == False: r_params = (Z, gamma, epsilon, delta, tau_b, delta_tau) rnew = firm.get_r(Ynew[:T], K[:T], r_params) else: rnew = r.copy() print 'Y and T_H: ', Y[3], T_H[3] # omega_shift = np.append(omega_S_preTP.reshape(1,S),omega[:T-1,:],axis=0) # defined above # BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), # g_n_vector[:T].reshape(T, 1), 'TPI') # defined above b_mat_shift = np.append(np.reshape(initial_b,(1,S,J)),b_mat[:T-1,:,:],axis=0) BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) # tax_params = np.zeros((T,S,J,etr_params.shape[2])) # for i in range(etr_params.shape[2]): # tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) # REVENUE_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', # tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) # defined above REVENUE = np.array(list(tax.revenue(np.tile(rnew[:T].reshape(T, 1, 1),(1,S,J)), np.tile(wnew[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQnew[:T].reshape(T, 1, J), Y[:T], L[:T], K[:T], factor, REVENUE_params)) + [revenue_ss] * S) if budget_balance: T_H_new = REVENUE elif baseline_spending==False: T_H_new = ALPHA_T[:T] * Y[:T] # If baseline_spending==True, no need to update T_H, which remains fixed. if small_open==True and budget_balance==False: # Loop through years to calculate debt and gov't spending. This is done earlier when small_open=False. D_0 = initial_debt * Y[0] other_dg_params = (T, r, g_n_vector, g_y) if baseline_spending==False: G_0 = ALPHA_G[0] * Y[0] dg_fixed_values = (Y, REVENUE, T_H, D_0,G_0) Dnew, G = fiscal.D_G_path(dg_fixed_values, fiscal_params, other_dg_params, baseline_spending=baseline_spending) w[:T] = utils.convex_combo(wnew[:T], w[:T], nu) r[:T] = utils.convex_combo(rnew[:T], r[:T], nu) BQ[:T] = utils.convex_combo(BQnew[:T], BQ[:T], nu) # D[:T] = utils.convex_combo(Dnew[:T], D[:T], nu) D = Dnew Y[:T] = utils.convex_combo(Ynew[:T], Y[:T], nu) if baseline_spending==False: T_H[:T] = utils.convex_combo(T_H_new[:T], T_H[:T], nu) guesses_b = utils.convex_combo(b_mat, guesses_b, nu) guesses_n = utils.convex_combo(n_mat, guesses_n, nu) print 'r diff: ', (rnew[:T]-r[:T]).max(), (rnew[:T]-r[:T]).min() print 'w diff: ', (wnew[:T]-w[:T]).max(), (wnew[:T]-w[:T]).min() print 'BQ diff: ', (BQnew[:T]-BQ[:T]).max(), (BQnew[:T]-BQ[:T]).min() print 'T_H diff: ', (T_H_new[:T]-T_H[:T]).max(), (T_H_new[:T]-T_H[:T]).min() if baseline_spending==False: if T_H.all() != 0: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( utils.pct_diff_func(wnew[:T], w[:T])) + list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() else: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( utils.pct_diff_func(wnew[:T], w[:T])) + list(np.abs(T_H[:T]))).max() else: # TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( # utils.pct_diff_func(wnew[:T], w[:T])) + list(utils.pct_diff_func(Dnew[:T], D[:T]))).max() TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list( utils.pct_diff_func(wnew[:T], w[:T])) + list(utils.pct_diff_func(Ynew[:T], Y[: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 # print 'D/Y:', (D[:T]/Ynew[:T]).max(), (D[:T]/Ynew[:T]).min(), np.median(D[:T]/Ynew[:T]) # print 'T/Y:', (T_H_new[:T]/Ynew[:T]).max(), (T_H_new[:T]/Ynew[:T]).min(), np.median(T_H_new[:T]/Ynew[:T]) # print 'G/Y:', (G[:T]/Ynew[:T]).max(), (G[:T]/Ynew[:T]).min(), np.median(G[:T]/Ynew[:T]) # print 'Int payments to GDP:', ((r[:T]*D[:T])/Ynew[:T]).max(), ((r[:T]*D[:T])/Ynew[:T]).min(), np.median((r[:T]*D[:T])/Ynew[:T]) # # print 'D/Y:', (D[:T]/Ynew[:T]) # print 'T/Y:', (T_H_new[:T]/Ynew[:T]) # print 'G/Y:', (G[:T]/Ynew[:T]) # # print 'deficit: ', REVENUE[:T] - T_H_new[:T] - G[:T] # Loop through years to calculate debt and gov't spending. The re-assignment of G0 & D0 is necessary because Y0 may change in the TPI loop. if budget_balance == False: D_0 = initial_debt * Y[0] other_dg_params = (T, r, g_n_vector, g_y) if baseline_spending==False: G_0 = ALPHA_G[0] * Y[0] dg_fixed_values = (Y, REVENUE, T_H, D_0,G_0) D, G = fiscal.D_G_path(dg_fixed_values, fiscal_params, other_dg_params, baseline_spending=baseline_spending) # Solve HH problem in inner loop guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, K, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T-1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] #L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') # defined above L[:T] = firm.get_L(n_mat[:T], L_params) #B_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1,S,1), g_n_vector[1:T], 'TPI') # defined above B[1:T] = household.get_K(bmat_splus1[:T-1], B_params) if small_open == False: K[:T] = B[:T] - D[:T] else: # K_params previously set to = (Z, gamma, epsilon, delta, tau_b, delta_tau) K[:T] = firm.get_K(L[:T], tpi_firm_r[:T], K_params) # Y_params previously set to = (Z, gamma, epsilon) Ynew = firm.get_Y(K[:T], L[:T], Y_params) # testing for change in Y ydiff = Ynew[:T] - Y[:T] ydiff_max = np.amax(np.abs(ydiff)) print 'ydiff_max = ', ydiff_max w_params = (Z, gamma, epsilon) wnew = firm.get_w(Ynew[:T], L[:T], w_params) if small_open == False: # r_params previously set to = (Z, gamma, epsilon, delta, tau_b, delta_tau) rnew = firm.get_r(Ynew[:T], K[:T], r_params) else: rnew = r # Note: previously, Y was not reassigned to equal Ynew at this point. Y = Ynew[:] # omega_shift = np.append(omega_S_preTP.reshape(1,S),omega[:T-1,:],axis=0) # BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), # g_n_vector[:T].reshape(T, 1), 'TPI') b_mat_shift = np.append(np.reshape(initial_b,(1,S,J)),b_mat[:T-1,:,:],axis=0) BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) # tax_params = np.zeros((T,S,J,etr_params.shape[2])) # for i in range(etr_params.shape[2]): # tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) # REVENUE_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', # tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J, tau_b, delta_tau) REVENUE = np.array(list(tax.revenue(np.tile(rnew[:T].reshape(T, 1, 1),(1,S,J)), np.tile(wnew[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQnew[:T].reshape(T, 1, J), Ynew[:T], L[:T], K[:T], factor, REVENUE_params)) + [revenue_ss] * S) etr_params_path = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_path_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1),(1,S,J)), np.tile(w[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), bmat_s, bmat_splus1, n_mat[:T,:,:], BQ[:T].reshape(T, 1, J), tax_path, cons_params) C_params = (omega[:T].reshape(T, S, 1), lambdas, 'TPI') C = household.get_C(c_path, C_params) if budget_balance==False: D_0 = initial_debt * Y[0] other_dg_params = (T, r, g_n_vector, g_y) if baseline_spending==False: G_0 = ALPHA_G[0] * Y[0] dg_fixed_values = (Y, REVENUE, T_H, D_0,G_0) D, G = fiscal.D_G_path(dg_fixed_values, fiscal_params, other_dg_params, baseline_spending=baseline_spending) if small_open == False: I_params = (delta, g_y, omega[:T].reshape(T, S, 1), lambdas, imm_rates[:T].reshape(T, S, 1), g_n_vector[1:T+1], 'TPI') I = firm.get_I(bmat_splus1[:T], K[1:T+1], K[:T], I_params) rc_error = Y[:T] - C[:T] - I[:T] - G[:T] else: #InvestmentPlaceholder = np.zeros(bmat_splus1[:T].shape) #I_params = (delta, g_y, omega[:T].reshape(T, S, 1), lambdas, imm_rates[:T].reshape(T, S, 1), g_n_vector[1:T+1], 'TPI') I = (1+g_n_vector[:T])*np.exp(g_y)*K[1:T+1] - (1.0 - delta) * K[:T] #firm.get_I(InvestmentPlaceholder, K[1:T+1], K[:T], I_params) BI_params = (0.0, g_y, omega[:T].reshape(T, S, 1), lambdas, imm_rates[:T].reshape(T, S, 1), g_n_vector[1:T+1], 'TPI') BI = firm.get_I(bmat_splus1[:T], B[1:T+1], B[:T], BI_params) new_borrowing = D[1:T]*(1+g_n_vector[1:T])*np.exp(g_y) - D[:T-1] rc_error = Y[:T-1] + new_borrowing - (C[:T-1] + BI[:T-1] + G[:T-1] ) + (tpi_hh_r[:T-1] * B[:T-1] - (delta + tpi_firm_r[:T-1])*K[:T-1] - tpi_hh_r[:T-1]*D[:T-1]) #print 'Y(T-1):', Y[T-1], '\n','C(T-1):', C[T-1], '\n','K(T-1):', K[T-1], '\n','B(T-1):', B[T-1], '\n','BI(T-1):', BI[T-1], '\n','I(T-1):', I[T-1] 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 xrange(T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_path[t], t, ltilde) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, 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, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'REVENUE': REVENUE, 'T_H': T_H, 'G': G, 'D': D, 'r': r, 'w': w, 'b_mat': b_mat, 'n_mat': n_mat, 'c_path': c_path, 'tax_path': tax_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure} tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) macro_output = {'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'T_H': T_H, 'r': r, 'w': w, 'tax_path': tax_path} growth = (1+g_n_vector)*np.exp(g_y) with open('TPI_output.csv', 'wb') as csvfile: tpiwriter = csv.writer(csvfile) tpiwriter.writerow(Y) tpiwriter.writerow(D) tpiwriter.writerow(REVENUE) tpiwriter.writerow(G) tpiwriter.writerow(T_H) tpiwriter.writerow(C) tpiwriter.writerow(K) tpiwriter.writerow(I) tpiwriter.writerow(r) if small_open == True: tpiwriter.writerow(B) tpiwriter.writerow(BI) tpiwriter.writerow(new_borrowing) tpiwriter.writerow(growth) tpiwriter.writerow(rc_error) tpiwriter.writerow(ydiff) if np.any(G) < 0: print 'Government spending is negative along transition path to satisfy budget' if ((TPIiter >= maxiter) or (np.absolute(TPIdist) > mindist_TPI)) and ENFORCE_SOLUTION_CHECKS : raise RuntimeError("Transition path equlibrium not found (TPIdist)") if ((np.any(np.absolute(rc_error) >= mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError("Transition path equlibrium not found (rc_error)") if ((np.any(np.absolute(eul_savings) >= mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError("Transition path equlibrium not found (eulers)") # Non-stationary output # macro_ns_output = {'K_ns_path': K_ns_path, 'C_ns_path': C_ns_path, 'I_ns_path': I_ns_path, # 'L_ns_path': L_ns_path, 'BQ_ns_path': BQ_ns_path, # 'rinit': rinit, 'Y_ns_path': Y_ns_path, 'T_H_ns_path': T_H_ns_path, # 'w_ns_path': w_ns_path} return output, macro_output
def run_TPI(income_tax_params, tpi_params, iterative_params, initial_values, SS_values, fix_transfers=False, output_dir="./OUTPUT"): # unpack tuples of parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params maxiter, mindist_SS, mindist_TPI = iterative_params J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_vector, tau_payroll, tau_bq, rho, omega, N_tilde, lambdas, imm_rates, e, retire, mean_income_data,\ factor, T_H_baseline, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon, chi_b, chi_n, theta = tpi_params K0, b_sinit, b_splus1init, factor, initial_b, initial_n, omega_S_preTP = initial_values Kss, Lss, rss, wss, BQss, T_Hss, Gss, bssmat_splus1, nssmat = SS_values TPI_FIG_DIR = output_dir # Initialize guesses at time paths domain = np.linspace(0, T, T) r = np.ones(T + S) * rss BQ = np.zeros((T + S, J)) BQ0_params = (omega_S_preTP.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_vector[0], 'SS') BQ0 = household.get_BQ(r[0], initial_b, BQ0_params) for j in xrange(J): BQ[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQ = np.array(BQ) # print "BQ values = ", BQ[0, :], BQ[100, :], BQ[-1, :], BQss # print "K0 vs Kss = ", K0-Kss if fix_transfers: T_H = T_H_baseline else: 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(T + S) * T_Hss2 * (r / rss) G = np.ones(T + S) * Gss # # print "T_H values = ", T_H[0], T_H[100], T_H[-1], T_Hss # # print "omega diffs = ", (omega_S_preTP-omega[-1]).max(), (omega[10]-omega[-1]).max() # # Make array of initial guesses for labor supply and savings domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) # print 'diff btwn start and end b: ', (guesses_b[0]-guesses_b[-1]).max() # domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) # b_mat = np.zeros((T + S, S, J)) # n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) # # print 'diff btwn start and end n: ', (guesses_n[0]-guesses_n[-1]).max() # # # find economic aggregates K = np.zeros(T + S) L = np.zeros(T + S) K[0] = K0 K_params = (omega[:T - 1].reshape(T - 1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T - 1].reshape(T - 1, S, 1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(guesses_b[:T - 1], K_params) K[T:] = Kss L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(guesses_n[:T], L_params) L[T:] = Lss Y_params = (alpha, Z) Y = firm.get_Y(K, L, Y_params) r_params = (alpha, delta) r[:T] = firm.get_r(Y[:T], K[:T], r_params) # uncomment lines below if want to use starting values from prior run r = TPI_START_VALUES['r'] K = TPI_START_VALUES['K'] L = TPI_START_VALUES['L'] Y = TPI_START_VALUES['Y'] T_H = TPI_START_VALUES['T_H'] BQ = TPI_START_VALUES['BQ'] G = TPI_START_VALUES['G'] guesses_b = TPI_START_VALUES['b_mat'] guesses_n = TPI_START_VALUES['n_mat'] TPIiter = 0 TPIdist = 10 PLOT_TPI = False euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) # print 'analytical mtrs in tpi = ', analytical_mtrs while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: K_plot = list(K) + list(np.ones(10) * Kss) L_plot = list(L) + list(np.ones(10) * Lss) plt.figure() plt.axhline(y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange(T + 10), Kpath_plot[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) guesses = (guesses_b, guesses_n) w_params = (Z, alpha, delta) w = firm.get_w_from_r(r, w_params) # print 'r and rss diff = ', r-rss # print 'w and wss diff = ', w-wss # print 'BQ and BQss diff = ', BQ-BQss # print 'T_H and T_Hss diff = ', T_H - T_Hss # print 'guess b and bss = ', (bssmat_splus1 - guesses_b).max() # print 'guess n and nss = ', (nssmat - guesses_n).max() outer_loop_vars = (r, w, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) # Solve HH problem in inner loop euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) # print 'guess b and bss = ', (b_mat - guesses_b).max() # print 'guess n and nss over time = ', (n_mat - guesses_n).max(axis=2).max(axis=1) # print 'guess n and nss over age = ', (n_mat - guesses_n).max(axis=0).max(axis=1) # print 'guess n and nss over ability = ', (n_mat - guesses_n).max(axis=0).max(axis=0) # quit() print 'Max Euler error: ', (np.abs(euler_errors)).max() bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T - 1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] K[0] = K0 K_params = (omega[:T - 1].reshape(T - 1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T - 1].reshape(T - 1, S, 1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(bmat_splus1[:T - 1], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) # print 'K diffs = ', K-K0 # print 'L diffs = ', L-L[0] Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) wnew = firm.get_w_from_r(rnew, w_params) omega_shift = np.append(omega_S_preTP.reshape(1, S), omega[:T - 1, :], axis=0) BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') # b_mat_shift = np.append(np.reshape(initial_b, (1, S, J)), # b_mat[:T-1, :, :], axis=0) b_mat_shift = bmat_splus1[:T, :, :] # print 'b diffs = ', (bmat_splus1[100, :, :] - initial_b).max(), (bmat_splus1[0, :, :] - initial_b).max(), (bmat_splus1[1, :, :] - initial_b).max() # print 'r diffs = ', rnew[1]-r[1], rnew[100]-r[100], rnew[-1]-r[-1] BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) BQss2 = np.empty(J) for j in range(J): BQss_params = (omega[1, :], lambdas[j], rho, g_n_vector[1], 'SS') BQss2[j] = household.get_BQ(rnew[1], bmat_splus1[1, :, j], BQss_params) # print 'BQ test = ', BQss2-BQss, BQss-BQnew[1], BQss-BQnew[100], BQss-BQnew[-1] total_tax_params = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): total_tax_params[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) tax_receipt_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', total_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) net_tax_receipts = np.array( list( tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1), ( 1, S, J)), np.tile(wnew[:T].reshape(T, 1, 1), ( 1, S, J)), bmat_s, n_mat[:T, :, :], BQnew[:T].reshape( T, 1, J), factor, tax_receipt_params)) + [T_Hss] * S) r[:T] = utils.convex_combo(rnew[:T], r[:T], nu) BQ[:T] = utils.convex_combo(BQnew[:T], BQ[:T], nu) if fix_transfers: T_H_new = T_H G[:T] = net_tax_receipts[:T] - T_H[:T] else: T_H_new = net_tax_receipts T_H[:T] = utils.convex_combo(T_H_new[:T], T_H[:T], nu) G[:T] = 0.0 etr_params_path = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) tax_path_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) b_to_use = np.zeros((T, S, J)) b_to_use[0, 1:, :] = initial_b[:-1, :] b_to_use[1:, 1:, :] = b_mat[:T - 1, :-1, :] tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1), (1, S, J)), np.tile(w[:T].reshape(T, 1, 1), (1, S, J)), b_to_use, n_mat[:T, :, :], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) y_path = (np.tile(r[:T].reshape(T, 1, 1), (1, S, J)) * b_to_use[:T, :, :] + np.tile(w[:T].reshape(T, 1, 1), (1, S, J)) * np.tile(e.reshape(1, S, J), (T, 1, 1)) * n_mat[:T, :, :]) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), b_to_use[:T, :, :], b_mat[:T, :, :], n_mat[:T, :, :], BQ[:T].reshape(T, 1, J), tax_path, cons_params) guesses_b = utils.convex_combo(b_mat, guesses_b, nu) guesses_n = utils.convex_combo(n_mat, guesses_n, nu) if T_H.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() print 'r dist = ', np.array( list(utils.pct_diff_func(rnew[:T], r[:T]))).max() print 'BQ dist = ', np.array( list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten())).max() print 'T_H dist = ', np.array( list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() print 'T_H path = ', T_H[:20] # print 'r old = ', r[:T] # print 'r new = ', rnew[:T] # print 'K old = ', K[:T] # print 'L old = ', L[:T] # print 'income = ', y_path[:, :, -1] # print 'taxes = ', tax_path[:, :, -1] # print 'labor supply = ', n_mat[:, :, -1] # print 'max and min labor = ', n_mat.max(), n_mat.min() # print 'max and min labor = ', np.argmax(n_mat), np.argmin(n_mat) # print 'max and min labor, j = 7 = ', n_mat[:,:,-1].max(), n_mat[:,:,-1].min() # print 'max and min labor, j = 6 = ', n_mat[:,:,-2].max(), n_mat[:,:,-2].min() # print 'max and min labor, j = 5 = ', n_mat[:,:,4].max(), n_mat[:,:,4].min() # print 'max and min labor, j = 4 = ', n_mat[:,:,3].max(), n_mat[:,:,3].min() # print 'max and min labor, j = 3 = ', n_mat[:,:,2].max(), n_mat[:,:,2].min() # print 'max and min labor, j = 2 = ', n_mat[:,:,1].max(), n_mat[:,:,1].min() # print 'max and min labor, j = 1 = ', n_mat[:,:,0].max(), n_mat[:,:,0].min() # print 'max and min labor, S = 80 = ', n_mat[:,-1,-1].max(), n_mat[:,-1,-1].min() # print "number > 1 = ", (n_mat > 1).sum() # print "number < 0, = ", (n_mat < 0).sum() # print "number > 1, j=7 = ", (n_mat[:T,:,-1] > 1).sum() # print "number < 0, j=7 = ", (n_mat[:T,:,-1] < 0).sum() # print "number > 1, s=80, j=7 = ", (n_mat[:T,-1,-1] > 1).sum() # print "number < 0, s=80, j=7 = ", (n_mat[:T,-1,-1] < 0).sum() # print "number > 1, j= 7, age 80= ", (n_mat[:T,-1,-1] > 1).sum() # print "number < 0, j = 7, age 80= ", (n_mat[:T,-1,-1] < 0).sum() # print "number > 1, j= 7, age 80, period 0 to 10= ", (n_mat[:30,-1,-1] > 1).sum() # print "number < 0, j = 7, age 80, period 0 to 10= ", (n_mat[:30,-1,-1] < 0).sum() # print "number > 1, j= 7, age 70-79, period 0 to 10= ", (n_mat[:30,70:80,-1] > 1).sum() # print "number < 0, j = 7, age 70-79, period 0 to 10= ", (n_mat[:30,70:80 ,-1] < 0).sum() # diag_dict = {'n_mat': n_mat, 'b_mat': b_mat, 'y_path': y_path, 'c_path': c_path} # pickle.dump(diag_dict, open('tpi_iter1.pkl', 'wb')) else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(np.abs(T_H_new[:T] - T_H[: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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist Y[:T] = Ynew # Solve HH problem in inner loop guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T - 1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] K[0] = K0 K_params = (omega[:T - 1].reshape(T - 1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T - 1].reshape(T - 1, S, 1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(bmat_splus1[:T - 1], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) wnew = firm.get_w_from_r(rnew, w_params) omega_shift = np.append(omega_S_preTP.reshape(1, S), omega[:T - 1, :], axis=0) BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, S, J)), b_mat[:T - 1, :, :], axis=0) BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) total_tax_params = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): total_tax_params[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) tax_receipt_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', total_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) net_tax_receipts = np.array( list( tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1), ( 1, S, J)), np.tile(wnew[:T].reshape(T, 1, 1), ( 1, S, J)), bmat_s, n_mat[:T, :, :], BQnew[:T].reshape( T, 1, J), factor, tax_receipt_params)) + [T_Hss] * S) if fix_transfers: G[:T] = net_tax_receipts[:T] - T_H[:T] else: T_H[:T] = net_tax_receipts[:T] G[:T] = 0.0 etr_params_path = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:, :, :, i] = np.tile( np.reshape(np.transpose(etr_params[:, :T, i]), (T, S, 1)), (1, 1, J)) tax_path_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1), (1, S, J)), np.tile(w[:T].reshape(T, 1, 1), (1, S, J)), bmat_s, n_mat[:T, :, :], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), bmat_s, bmat_splus1, n_mat[:T, :, :], BQ[:T].reshape(T, 1, J), tax_path, cons_params) C_params = (omega[:T].reshape(T, S, 1), lambdas, 'TPI') C = household.get_C(c_path, C_params) I_params = (delta, g_y, omega[:T].reshape(T, S, 1), lambdas, imm_rates[:T].reshape(T, S, 1), g_n_vector[1:T + 1], 'TPI') I = firm.get_I(bmat_splus1[:T], K[1:T + 1], K[:T], I_params) rc_error = Y[:T] - C[:T] - I[:T] - G[:T] print 'Resource Constraint Difference:', rc_error # compute utility u_params = (sigma, np.tile(chi_n.reshape(1, S, 1), (T, 1, J)), b_ellipse, ltilde, upsilon, np.tile(rho.reshape(1, S, 1), (T, 1, J)), np.tile(chi_b.reshape(1, 1, J), (T, S, 1))) utility_path = household.get_u(c_path[:T, :, :], n_mat[:T, :, :], bmat_splus1[:T, :, :], u_params) # compute before and after-tax income y_path = (np.tile(r[:T].reshape(T, 1, 1), (1, S, J)) * bmat_s[:T, :, :] + np.tile(w[:T].reshape(T, 1, 1), (1, S, J)) * np.tile(e.reshape(1, S, J), (T, 1, 1)) * n_mat[:T, :, :]) inctax_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), etr_params_path) y_aftertax_path = (y_path - tax.tau_income( np.tile(r[:T].reshape(T, 1, 1), (1, S, J)), np.tile(w[:T].reshape(T, 1, 1), (1, S, J)), bmat_s[:T, :, :], n_mat[:T, :, :], factor, inctax_params)) # compute after-tax wealth wtax_params = (h_wealth, p_wealth, m_wealth) b_aftertax_path = bmat_s[:T, :, :] - tax.tau_wealth( bmat_s[:T, :, :], wtax_params) print 'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_path[t], t, ltilde) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, 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, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'G': G, 'T_H': T_H, 'r': r, 'w': w, 'b_mat': b_mat, 'n_mat': n_mat, 'c_path': c_path, 'tax_path': tax_path, 'bmat_s': bmat_s, 'utility_path': utility_path, 'b_aftertax_path': b_aftertax_path, 'y_aftertax_path': y_aftertax_path, 'y_path': y_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure } macro_output = { 'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'G': G, 'T_H': T_H, 'r': r, 'w': w, 'tax_path': tax_path } # if ((TPIiter >= maxiter) or (np.absolute(TPIdist) > mindist_TPI)) and ENFORCE_SOLUTION_CHECKS : # raise RuntimeError("Transition path equlibrium not found") # # if ((np.any(np.absolute(rc_error) >= 1e-6)) # and ENFORCE_SOLUTION_CHECKS): # raise RuntimeError("Transition path equlibrium not found") # # if ((np.any(np.absolute(eul_savings) >= mindist_TPI) or # (np.any(np.absolute(eul_laborleisure) > mindist_TPI))) # and ENFORCE_SOLUTION_CHECKS): # raise RuntimeError("Transition path equlibrium not found") return output, macro_output
def run_steady_state(income_tax_parameters, ss_parameters, iterative_params, get_baseline=False, calibrate_model=False, output_dir="./OUTPUT"): ''' ------------------------------------------------------------------------ Run SS ------------------------------------------------------------------------ ''' J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_parameters # Generate initial guesses for chi^b_j and chi^n_s chi_params = np.zeros(S + J) chi_params[:J] = chi_b_guess chi_params[J:] = chi_n_guess # First run SS simulation with guesses at initial values for b, n, w, r, etc # For inital guesses of b and n, we choose very small b, and medium n b_guess = np.ones((S, J)).flatten() * .05 n_guess = np.ones((S, J)).flatten() * .4 * ltilde # For initial guesses of w, r, T_H, and factor, we use values that are close # to some steady state values. wguess = 1.2 rguess = .06 T_Hguess = 0.12 factorguess = 70000.0 guesses = [wguess, rguess, T_Hguess, factorguess] args_ = (b_guess.reshape(S, J), n_guess.reshape(S, J), chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) [solutions, infodict, ier, message] = opt.fsolve(SS_fsolve, guesses, args=args_, xtol=mindist_SS, full_output=True) [wguess, rguess, T_Hguess, factorguess] = solutions fsolve_flag = True solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e, fsolve_flag) if calibrate_model: global Nfeval, value_all, chi_params_all Nfeval = 1 value_all = np.zeros((10000)) chi_params_all = np.zeros((S + J, 10000)) outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_path = os.path.join(output_dir, "Saved_moments/SS_init_solutions.pkl") pickle.dump(outputs, open(ss_init_path, "wb")) function_to_minimize_X = lambda x: function_to_minimize( x, chi_params, income_tax_parameters, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir) bnds = tuple([(1e-6, None)] * (S + J)) # In order to scale all the parameters to estimate in the minimizer, we have the minimizer fit a vector of ones that # will be multiplied by the chi initial guesses inside the function. Otherwise, if chi^b_j=1e5 for some j, and the # minimizer peturbs that value by 1e-8, the % difference will be extremely small, outside of the tolerance of the # minimizer, and it will not change that parameter. chi_params_scalars = np.ones(S + J) #chi_params_scalars = opt.minimize(function_to_minimize_X, chi_params_scalars, # method='TNC', tol=MINIMIZER_TOL, bounds=bnds, callback=callbackF(chi_params_scalars), options=MINIMIZER_OPTIONS).x # chi_params_scalars = opt.minimize(function_to_minimize, chi_params_scalars, # args=(chi_params, income_tax_parameters, ss_parameters, iterative_params, # omega_SS, rho, lambdas, tau_bq, e, output_dir), # method='TNC', tol=MINIMIZER_TOL, bounds=bnds, # callback=callbackF(chi_params_scalars,chi_params, income_tax_parameters, # ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir), # options=MINIMIZER_OPTIONS).x chi_params_scalars = opt.minimize( function_to_minimize, chi_params_scalars, args=(chi_params, income_tax_parameters, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir), method='TNC', tol=MINIMIZER_TOL, bounds=bnds, options=MINIMIZER_OPTIONS).x chi_params *= chi_params_scalars print 'The final scaling params', chi_params_scalars print 'The final bequest parameter values:', chi_params solutions_dict = pickle.load(open(ss_init_path, "rb")) solutions = solutions_dict['solutions'] b_guess = solutions[:S * J] n_guess = solutions[S * J:2 * S * J] wguess, rguess, factorguess, T_Hguess = solutions[2 * S * J:] guesses = [wguess, rguess, T_Hguess, factorguess] args_ = (b_guess.reshape(S, J), n_guess.reshape(S, J), chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) [solutions, infodict, ier, message] = opt.fsolve(SS_fsolve, guesses, args=args_, xtol=mindist_SS, full_output=True) [wguess, rguess, T_Hguess, factorguess] = solutions fsolve_flag = True solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e, fsolve_flag) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' if get_baseline: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_dir = os.path.join(output_dir, "Saved_moments/SS_baseline_solutions.pkl") pickle.dump(outputs, open(ss_init_dir, "wb")) else: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_exp_dir = os.path.join(output_dir, "Saved_moments/SS_reform_solutions.pkl") pickle.dump(outputs, open(ss_exp_dir, "wb")) bssmat = solutions[0:(S - 1) * J].reshape(S - 1, J) bq = solutions[ (S - 1) * J:S * J] # technically, this is just the intentional bequests - wealth of those with max age bssmat_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat)) bssmat_splus1 = np.array(list(bssmat) + list(bq.reshape(1, J))) nssmat = solutions[S * J:2 * S * J].reshape(S, J) wss, rss, factor_ss, T_Hss = solutions[2 * S * J:] Kss = household.get_K(bssmat_splus1, omega_SS.reshape(S, 1), lambdas, g_n_ss, 'SS') Lss = firm.get_L(e, nssmat, omega_SS.reshape(S, 1), lambdas, 'SS') Yss = firm.get_Y(Kss, Lss, ss_parameters) Iss = firm.get_I(Kss, Kss, delta, g_y, g_n_ss) theta = np.zeros(J) #tax.replacement_rate_vals( #nssmat, wss, factor_ss, e, J, omega_SS.reshape(S, 1), lambdas) BQss = household.get_BQ(rss, bssmat_splus1, omega_SS.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_ss, 'SS') b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) etr_params_3D = np.tile( np.reshape(etr_params, (S, 1, etr_params.shape[1])), (1, J, 1)) mtrx_params_3D = np.tile( np.reshape(mtrx_params, (S, 1, mtrx_params.shape[1])), (1, J, 1)) etr_params_extended = np.append(etr_params, np.reshape(etr_params[-1, :], (1, etr_params.shape[1])), axis=0)[1:, :] etr_params_extended_3D = np.tile( np.reshape(etr_params_extended, (S, 1, etr_params_extended.shape[1])), (1, J, 1)) mtry_params_extended = np.append(mtry_params, np.reshape(mtry_params[-1, :], (1, mtry_params.shape[1])), axis=0)[1:, :] mtry_params_extended_3D = np.tile( np.reshape(mtry_params_extended, (S, 1, mtry_params_extended.shape[1])), (1, J, 1)) e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) mtry_ss = tax.MTR_capital(rss, bssmat_splus1, wss, e_extended[1:, :], nss_extended[1:, :], factor_ss, analytical_mtrs, etr_params_extended_3D, mtry_params_extended_3D) mtrx_ss = tax.MTR_labor(rss, bssmat_s, wss, e, nssmat, factor_ss, analytical_mtrs, etr_params_3D, mtrx_params_3D) np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") taxss_params = (J, S, retire, np.tile( np.reshape(etr_params, (S, 1, etr_params.shape[1])), (1, J, 1)), h_wealth, p_wealth, m_wealth, tau_payroll) taxss = tax.total_taxes(rss, b_s, wss, e, nssmat, BQss, lambdas, factor_ss, T_Hss, None, 'SS', False, taxss_params, theta, tau_bq) cssmat = household.get_cons(rss, b_s, wss, e, nssmat, BQss.reshape(1, J), lambdas.reshape(1, J), bssmat_splus1, ss_parameters, taxss) Css = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') resource_constraint = Yss - (Css + Iss) print 'Resource Constraint Difference:', resource_constraint constraint_params = ltilde household.constraint_checker_SS(bssmat, nssmat, cssmat, constraint_params) b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) b_splus1 = bssmat_splus1 b_splus2 = np.array( list(bssmat_splus1[1:]) + list(np.zeros(J).reshape((1, J)))) chi_b = np.tile(chi_params[:J].reshape(1, J), (S, 1)) chi_n = np.array(chi_params[J:]) euler_savings = np.zeros((S, J)) euler_labor_leisure = np.zeros((S, J)) for j in xrange(J): euler_savings[:, j] = household.euler_savings_func( wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], b_splus2[:, j], BQss[j], factor_ss, T_Hss, chi_b[:, j], income_tax_parameters, ss_parameters, theta[j], tau_bq[j], rho, lambdas[j]) euler_labor_leisure[:, j] = household.euler_labor_leisure_func( wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], BQss[j], factor_ss, T_Hss, chi_n, income_tax_parameters, ss_parameters, theta[j], tau_bq[j], lambdas[j]) ''' ------------------------------------------------------------------------ Save the values in various ways, depending on the stage of the simulation, to be used in TPI or graphing functions ------------------------------------------------------------------------ ''' # Pickle variables output = { 'Kss': Kss, 'bssmat': bssmat, 'Lss': Lss, 'Css': Css, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b } utils.mkdirs(os.path.join(output_dir, "SSinit")) ss_init_dir = os.path.join(output_dir, "SSinit/ss_init_vars.pkl") pickle.dump(output, open(ss_init_dir, "wb")) bssmat_init = bssmat_splus1 nssmat_init = nssmat # Pickle variables for TPI initial values output2 = {'bssmat_init': bssmat_init, 'nssmat_init': nssmat_init} ss_init_tpi = os.path.join(output_dir, "SSinit/ss_init_tpi_vars.pkl") pickle.dump(output2, open(ss_init_tpi, "wb")) return output
def run_steady_state(ss_parameters, iterative_params, get_baseline=False, calibrate_model=False): ''' ------------------------------------------------------------------------ Run SS ------------------------------------------------------------------------ ''' if get_baseline: # Generate initial guesses for chi^b_j and chi^n_s chi_params = np.zeros(S+J) chi_params[:J] = chi_b_guess chi_params[J:] = chi_n_guess # First run SS simulation with guesses at initial values for b, n, w, r, etc # For inital guesses of b and n, we choose very small b, and medium n b_guess = np.ones((S, J)).flatten() * .01 n_guess = np.ones((S, J)).flatten() * .5 * ltilde # For initial guesses of w, r, T_H, and factor, we use values that are close # to some steady state values. wguess = 1.2 rguess = .06 T_Hguess = 0 factorguess = 100000 solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) if calibrate_model: outputs = {'solutions':solutions, 'chi_params':chi_params} pickle.dump(outputs, open("OUTPUT/Saved_moments/SS_init_solutions.pkl", "wb")) function_to_minimize_X = lambda x: function_to_minimize(x, chi_params, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e) bnds = tuple([(1e-6, None)] * (S + J)) # In order to scale all the parameters to estimate in the minimizer, we have the minimizer fit a vector of ones that # will be multiplied by the chi initial guesses inside the function. Otherwise, if chi^b_j=1e5 for some j, and the # minimizer peturbs that value by 1e-8, the % difference will be extremely small, outside of the tolerance of the # minimizer, and it will not change that parameter. chi_params_scalars = np.ones(S+J) chi_params_scalars = opt.minimize(function_to_minimize_X, chi_params_scalars, method='TNC', tol=MINIMIZER_TOL, bounds=bnds, options=MINIMIZER_OPTIONS).x chi_params *= chi_params_scalars print 'The final scaling params', chi_params_scalars print 'The final bequest parameter values:', chi_params solutions_dict = pickle.load(open("OUTPUT/Saved_moments/SS_init_solutions.pkl", "rb")) solutions = solutions_dict['solutions'] b_guess = solutions[:S*J] n_guess = solutions[S*J:2*S*J] wguess, rguess, factorguess, T_Hguess = solutions[2*S*J:] solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) else: variables = pickle.load(open("OUTPUT/Saved_moments/SS_init_solutions.pkl", "rb")) solutions = solutions_dict['solutions'] chi_params = solutions_dict['chi_params'] b_guess = solutions[:S*J] n_guess = solutions[S*J:2*S*J] wguess, rguess, factorguess, T_Hguess = solutions[2*S*J:] solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' if get_baseline: outputs = {'solutions':solutions, 'chi_params':chi_params} pickle.dump(outputs, open("OUTPUT/Saved_moments/SS_init_solutions.pkl", "wb")) else: outputs = {'solutions':solutions, 'chi_params':chi_params} pickle.dump(outputs, open("OUTPUT/Saved_moments/SS_experiment_solutions.pkl", "wb")) bssmat = solutions[0:(S-1) * J].reshape(S-1, J) bq = solutions[(S-1)*J:S*J] bssmat_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat)) bssmat_splus1 = np.array(list(bssmat) + list(bq.reshape(1, J))) nssmat = solutions[S * J:2*S*J].reshape(S, J) wss, rss, factor_ss, T_Hss = solutions[2*S*J:] Kss = household.get_K(bssmat_splus1, omega_SS.reshape(S, 1), lambdas, g_n_ss, 'SS') Lss = firm.get_L(e, nssmat, omega_SS.reshape(S, 1), lambdas, 'SS') Yss = firm.get_Y(Kss, Lss, ss_parameters) Iss = firm.get_I(Kss, Kss, delta, g_y, g_n_ss) theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, e, J, omega_SS.reshape(S, 1), lambdas) BQss = household.get_BQ(rss, bssmat_splus1, omega_SS.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_ss, 'SS') b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) taxss = tax.total_taxes(rss, b_s, wss, e, nssmat, BQss, lambdas, factor_ss, T_Hss, None, 'SS', False, ss_parameters, theta, tau_bq) cssmat = household.get_cons(rss, b_s, wss, e, nssmat, BQss.reshape(1, J), lambdas.reshape(1, J), bssmat_splus1, ss_parameters, taxss) Css = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') resource_constraint = Yss - (Css + Iss) print 'Resource Constraint Difference:', resource_constraint household.constraint_checker_SS(bssmat, nssmat, cssmat, ss_parameters) b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) b_splus1 = bssmat_splus1 b_splus2 = np.array(list(bssmat_splus1[1:]) + list(np.zeros(J).reshape((1, J)))) chi_b = np.tile(chi_params[:J].reshape(1, J), (S, 1)) chi_n = np.array(chi_params[J:]) euler_savings = np.zeros((S, J)) euler_labor_leisure = np.zeros((S, J)) for j in xrange(J): euler_savings[:, j] = household.euler_savings_func(wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], b_splus2[:, j], BQss[j], factor_ss, T_Hss, chi_b[:, j], ss_parameters, theta[j], tau_bq[j], rho, lambdas[j]) euler_labor_leisure[:, j] = household.euler_labor_leisure_func(wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], BQss[j], factor_ss, T_Hss, chi_n, ss_parameters, theta[j], tau_bq[j], lambdas[j]) ''' ------------------------------------------------------------------------ Save the values in various ways, depending on the stage of the simulation, to be used in TPI or graphing functions ------------------------------------------------------------------------ ''' # Pickle variables output = {'Kss':Kss, 'bssmat':bssmat, 'Lss':Lss, 'nssmat':nssmat, 'Yss':Yss, 'wss':wss, 'rss':rss, 'theta':theta, 'BQss':BQss, 'factor_ss':factor_ss, 'bssmat_s':bssmat_s, 'cssmat':cssmat, 'bssmat_splus1':bssmat_splus1, 'T_Hss':T_Hss, 'euler_savings':euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n':chi_n, 'chi_b':chi_b} if get_baseline: pickle.dump(output, open("OUTPUT/SSinit/ss_init_vars.pkl", "wb")) bssmat_init = bssmat_splus1 nssmat_init = nssmat # Pickle variables for TPI initial values output2 = {'bssmat_init':bssmat_init, 'nssmat_init':nssmat_init} pickle.dump(output2, open("OUTPUT/SSinit/ss_init_tpi_vars.pkl", "wb")) else: pickle.dump(output, open("OUTPUT/SS/ss_vars.pkl", "wb")) return output
def run_TPI(income_tax_params, tpi_params, iterative_params, initial_values, SS_values, fix_transfers=False, output_dir="./OUTPUT"): # unpack tuples of parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params maxiter, mindist_SS, mindist_TPI = iterative_params J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_vector, tau_payroll, tau_bq, rho, omega, N_tilde, lambdas, imm_rates, e, retire, mean_income_data,\ factor, T_H_baseline, h_wealth, p_wealth, m_wealth, b_ellipse, upsilon, chi_b, chi_n, theta = tpi_params K0, b_sinit, b_splus1init, factor, initial_b, initial_n, omega_S_preTP = initial_values Kss, Lss, rss, wss, BQss, T_Hss, Gss, bssmat_splus1, nssmat = SS_values TPI_FIG_DIR = output_dir # Initialize guesses at time paths domain = np.linspace(0, T, T) r = np.ones(T + S) * rss BQ = np.zeros((T + S, J)) BQ0_params = (omega_S_preTP.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_vector[0], 'SS') BQ0 = household.get_BQ(r[0], initial_b, BQ0_params) for j in xrange(J): BQ[:, j] = list(np.linspace(BQ0[j], BQss[j], T)) + [BQss[j]] * S BQ = np.array(BQ) # print "BQ values = ", BQ[0, :], BQ[100, :], BQ[-1, :], BQss # print "K0 vs Kss = ", K0-Kss if fix_transfers: T_H = T_H_baseline else: 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(T + S) * T_Hss2 * (r/rss) G = np.ones(T + S) * Gss # # print "T_H values = ", T_H[0], T_H[100], T_H[-1], T_Hss # # print "omega diffs = ", (omega_S_preTP-omega[-1]).max(), (omega[10]-omega[-1]).max() # # Make array of initial guesses for labor supply and savings domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) # print 'diff btwn start and end b: ', (guesses_b[0]-guesses_b[-1]).max() # domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) # b_mat = np.zeros((T + S, S, J)) # n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) # # print 'diff btwn start and end n: ', (guesses_n[0]-guesses_n[-1]).max() # # # find economic aggregates K = np.zeros(T+S) L = np.zeros(T+S) K[0] = K0 K_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1,S,1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(guesses_b[:T-1], K_params) K[T:] = Kss L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(guesses_n[:T], L_params) L[T:] = Lss Y_params = (alpha, Z) Y = firm.get_Y(K, L, Y_params) r_params = (alpha, delta) r[:T] = firm.get_r(Y[:T], K[:T], r_params) # uncomment lines below if want to use starting values from prior run r = TPI_START_VALUES['r'] K = TPI_START_VALUES['K'] L = TPI_START_VALUES['L'] Y = TPI_START_VALUES['Y'] T_H = TPI_START_VALUES['T_H'] BQ = TPI_START_VALUES['BQ'] G = TPI_START_VALUES['G'] guesses_b = TPI_START_VALUES['b_mat'] guesses_n = TPI_START_VALUES['n_mat'] TPIiter = 0 TPIdist = 10 PLOT_TPI = False euler_errors = np.zeros((T, 2 * S, J)) TPIdist_vec = np.zeros(maxiter) # print 'analytical mtrs in tpi = ', analytical_mtrs while (TPIiter < maxiter) and (TPIdist >= mindist_TPI): # Plot TPI for K for each iteration, so we can see if there is a # problem if PLOT_TPI is True: K_plot = list(K) + list(np.ones(10) * Kss) L_plot = list(L) + list(np.ones(10) * Lss) plt.figure() plt.axhline( y=Kss, color='black', linewidth=2, label=r"Steady State $\hat{K}$", ls='--') plt.plot(np.arange( T + 10), Kpath_plot[:T + 10], 'b', linewidth=2, label=r"TPI time path $\hat{K}_t$") plt.savefig(os.path.join(TPI_FIG_DIR, "TPI_K")) guesses = (guesses_b, guesses_n) w_params = (Z, alpha, delta) w = firm.get_w_from_r(r, w_params) # print 'r and rss diff = ', r-rss # print 'w and wss diff = ', w-wss # print 'BQ and BQss diff = ', BQ-BQss # print 'T_H and T_Hss diff = ', T_H - T_Hss # print 'guess b and bss = ', (bssmat_splus1 - guesses_b).max() # print 'guess n and nss = ', (nssmat - guesses_n).max() outer_loop_vars = (r, w, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) # Solve HH problem in inner loop euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) # print 'guess b and bss = ', (b_mat - guesses_b).max() # print 'guess n and nss over time = ', (n_mat - guesses_n).max(axis=2).max(axis=1) # print 'guess n and nss over age = ', (n_mat - guesses_n).max(axis=0).max(axis=1) # print 'guess n and nss over ability = ', (n_mat - guesses_n).max(axis=0).max(axis=0) # quit() print 'Max Euler error: ', (np.abs(euler_errors)).max() bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T-1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] K[0] = K0 K_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1, S, 1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(bmat_splus1[:T-1], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) # print 'K diffs = ', K-K0 # print 'L diffs = ', L-L[0] Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) wnew = firm.get_w_from_r(rnew, w_params) omega_shift = np.append(omega_S_preTP.reshape(1, S), omega[:T-1, :], axis=0) BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') # b_mat_shift = np.append(np.reshape(initial_b, (1, S, J)), # b_mat[:T-1, :, :], axis=0) b_mat_shift = bmat_splus1[:T, :, :] # print 'b diffs = ', (bmat_splus1[100, :, :] - initial_b).max(), (bmat_splus1[0, :, :] - initial_b).max(), (bmat_splus1[1, :, :] - initial_b).max() # print 'r diffs = ', rnew[1]-r[1], rnew[100]-r[100], rnew[-1]-r[-1] BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) BQss2 = np.empty(J) for j in range(J): BQss_params = (omega[1, :], lambdas[j], rho, g_n_vector[1], 'SS') BQss2[j] = household.get_BQ(rnew[1], bmat_splus1[1, :, j], BQss_params) # print 'BQ test = ', BQss2-BQss, BQss-BQnew[1], BQss-BQnew[100], BQss-BQnew[-1] total_tax_params = np.zeros((T, S, J, etr_params.shape[2])) for i in range(etr_params.shape[2]): total_tax_params[:, :, :, i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_receipt_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', total_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) net_tax_receipts = np.array(list(tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1),(1,S,J)), np.tile(wnew[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQnew[:T].reshape(T, 1, J), factor, tax_receipt_params)) + [T_Hss] * S) r[:T] = utils.convex_combo(rnew[:T], r[:T], nu) BQ[:T] = utils.convex_combo(BQnew[:T], BQ[:T], nu) if fix_transfers: T_H_new = T_H G[:T] = net_tax_receipts[:T] - T_H[:T] else: T_H_new = net_tax_receipts T_H[:T] = utils.convex_combo(T_H_new[:T], T_H[:T], nu) G[:T] = 0.0 etr_params_path = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:,:,:,i] = np.tile( np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_path_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) b_to_use = np.zeros((T, S, J)) b_to_use[0, 1:, :] = initial_b[:-1, :] b_to_use[1:, 1:, :] = b_mat[:T-1, :-1, :] tax_path = tax.total_taxes( np.tile(r[:T].reshape(T, 1, 1),(1,S,J)), np.tile(w[:T].reshape(T, 1, 1),(1,S,J)), b_to_use, n_mat[:T,:,:], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) y_path = (np.tile(r[:T].reshape(T, 1, 1), (1, S, J)) * b_to_use[:T, :, :] + np.tile(w[:T].reshape(T, 1, 1), (1, S, J)) * np.tile(e.reshape(1, S, J), (T, 1, 1)) * n_mat[:T, :, :]) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), b_to_use[:T,:,:], b_mat[:T,:,:], n_mat[:T,:,:], BQ[:T].reshape(T, 1, J), tax_path, cons_params) guesses_b = utils.convex_combo(b_mat, guesses_b, nu) guesses_n = utils.convex_combo(n_mat, guesses_n, nu) if T_H.all() != 0: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() print 'r dist = ', np.array(list(utils.pct_diff_func(rnew[:T], r[:T]))).max() print 'BQ dist = ', np.array(list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten())).max() print 'T_H dist = ', np.array(list(utils.pct_diff_func(T_H_new[:T], T_H[:T]))).max() print 'T_H path = ', T_H[:20] # print 'r old = ', r[:T] # print 'r new = ', rnew[:T] # print 'K old = ', K[:T] # print 'L old = ', L[:T] # print 'income = ', y_path[:, :, -1] # print 'taxes = ', tax_path[:, :, -1] # print 'labor supply = ', n_mat[:, :, -1] # print 'max and min labor = ', n_mat.max(), n_mat.min() # print 'max and min labor = ', np.argmax(n_mat), np.argmin(n_mat) # print 'max and min labor, j = 7 = ', n_mat[:,:,-1].max(), n_mat[:,:,-1].min() # print 'max and min labor, j = 6 = ', n_mat[:,:,-2].max(), n_mat[:,:,-2].min() # print 'max and min labor, j = 5 = ', n_mat[:,:,4].max(), n_mat[:,:,4].min() # print 'max and min labor, j = 4 = ', n_mat[:,:,3].max(), n_mat[:,:,3].min() # print 'max and min labor, j = 3 = ', n_mat[:,:,2].max(), n_mat[:,:,2].min() # print 'max and min labor, j = 2 = ', n_mat[:,:,1].max(), n_mat[:,:,1].min() # print 'max and min labor, j = 1 = ', n_mat[:,:,0].max(), n_mat[:,:,0].min() # print 'max and min labor, S = 80 = ', n_mat[:,-1,-1].max(), n_mat[:,-1,-1].min() # print "number > 1 = ", (n_mat > 1).sum() # print "number < 0, = ", (n_mat < 0).sum() # print "number > 1, j=7 = ", (n_mat[:T,:,-1] > 1).sum() # print "number < 0, j=7 = ", (n_mat[:T,:,-1] < 0).sum() # print "number > 1, s=80, j=7 = ", (n_mat[:T,-1,-1] > 1).sum() # print "number < 0, s=80, j=7 = ", (n_mat[:T,-1,-1] < 0).sum() # print "number > 1, j= 7, age 80= ", (n_mat[:T,-1,-1] > 1).sum() # print "number < 0, j = 7, age 80= ", (n_mat[:T,-1,-1] < 0).sum() # print "number > 1, j= 7, age 80, period 0 to 10= ", (n_mat[:30,-1,-1] > 1).sum() # print "number < 0, j = 7, age 80, period 0 to 10= ", (n_mat[:30,-1,-1] < 0).sum() # print "number > 1, j= 7, age 70-79, period 0 to 10= ", (n_mat[:30,70:80,-1] > 1).sum() # print "number < 0, j = 7, age 70-79, period 0 to 10= ", (n_mat[:30,70:80 ,-1] < 0).sum() # diag_dict = {'n_mat': n_mat, 'b_mat': b_mat, 'y_path': y_path, 'c_path': c_path} # pickle.dump(diag_dict, open('tpi_iter1.pkl', 'wb')) else: TPIdist = np.array(list(utils.pct_diff_func(rnew[:T], r[:T])) + list(utils.pct_diff_func(BQnew[:T], BQ[:T]).flatten()) + list(np.abs(T_H_new[:T]-T_H[: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 '\tIteration:', TPIiter print '\t\tDistance:', TPIdist Y[:T] = Ynew # Solve HH problem in inner loop guesses = (guesses_b, guesses_n) outer_loop_vars = (r, w, BQ, T_H) inner_loop_params = (income_tax_params, tpi_params, initial_values, ind) euler_errors, b_mat, n_mat = inner_loop(guesses, outer_loop_vars, inner_loop_params) bmat_s = np.zeros((T, S, J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:T-1, :-1, :] bmat_splus1 = np.zeros((T, S, J)) bmat_splus1[:, :, :] = b_mat[:T, :, :] K[0] = K0 K_params = (omega[:T-1].reshape(T-1, S, 1), lambdas.reshape(1, 1, J), imm_rates[:T-1].reshape(T-1,S,1), g_n_vector[1:T], 'TPI') K[1:T] = household.get_K(bmat_splus1[:T-1], K_params) L_params = (e.reshape(1, S, J), omega[:T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') L[:T] = firm.get_L(n_mat[:T], L_params) Y_params = (alpha, Z) Ynew = firm.get_Y(K[:T], L[:T], Y_params) r_params = (alpha, delta) rnew = firm.get_r(Ynew[:T], K[:T], r_params) wnew = firm.get_w_from_r(rnew, w_params) omega_shift = np.append(omega_S_preTP.reshape(1,S),omega[:T-1,:],axis=0) BQ_params = (omega_shift.reshape(T, S, 1), lambdas.reshape(1, 1, J), rho.reshape(1, S, 1), g_n_vector[:T].reshape(T, 1), 'TPI') b_mat_shift = np.append(np.reshape(initial_b,(1,S,J)),b_mat[:T-1,:,:],axis=0) BQnew = household.get_BQ(rnew[:T].reshape(T, 1), b_mat_shift, BQ_params) total_tax_params = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): total_tax_params[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_receipt_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas.reshape(1, 1, J), omega[:T].reshape(T, S, 1), 'TPI', total_tax_params, theta, tau_bq, tau_payroll, h_wealth, p_wealth, m_wealth, retire, T, S, J) net_tax_receipts = np.array(list(tax.get_lump_sum(np.tile(rnew[:T].reshape(T, 1, 1),(1,S,J)), np.tile(wnew[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQnew[:T].reshape(T, 1, J), factor, tax_receipt_params)) + [T_Hss] * S) if fix_transfers: G[:T] = net_tax_receipts[:T] - T_H[:T] else: T_H[:T] = net_tax_receipts[:T] G[:T] = 0.0 etr_params_path = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_path_params = (np.tile(e.reshape(1, S, J),(T,1,1)), lambdas, 'TPI', retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) tax_path = tax.total_taxes(np.tile(r[:T].reshape(T, 1, 1),(1,S,J)), np.tile(w[:T].reshape(T, 1, 1),(1,S,J)), bmat_s, n_mat[:T,:,:], BQ[:T, :].reshape(T, 1, J), factor, T_H[:T].reshape(T, 1, 1), None, False, tax_path_params) cons_params = (e.reshape(1, S, J), lambdas.reshape(1, 1, J), g_y) c_path = household.get_cons(r[:T].reshape(T, 1, 1), w[:T].reshape(T, 1, 1), bmat_s, bmat_splus1, n_mat[:T,:,:], BQ[:T].reshape(T, 1, J), tax_path, cons_params) C_params = (omega[:T].reshape(T, S, 1), lambdas, 'TPI') C = household.get_C(c_path, C_params) I_params = (delta, g_y, omega[:T].reshape(T, S, 1), lambdas, imm_rates[:T].reshape(T, S, 1), g_n_vector[1:T+1], 'TPI') I = firm.get_I(bmat_splus1[:T], K[1:T+1], K[:T], I_params) rc_error = Y[:T] - C[:T] - I[:T] - G[:T] print 'Resource Constraint Difference:', rc_error # compute utility u_params = (sigma, np.tile(chi_n.reshape(1, S, 1), (T, 1, J)), b_ellipse, ltilde, upsilon, np.tile(rho.reshape(1, S, 1), (T, 1, J)), np.tile(chi_b.reshape(1, 1, J), (T, S, 1))) utility_path = household.get_u(c_path[:T, :, :], n_mat[:T, :, :], bmat_splus1[:T, :, :], u_params) # compute before and after-tax income y_path = (np.tile(r[:T].reshape(T, 1, 1), (1, S, J)) * bmat_s[:T, :, :] + np.tile(w[:T].reshape(T, 1, 1), (1, S, J)) * np.tile(e.reshape(1, S, J), (T, 1, 1)) * n_mat[:T, :, :]) inctax_params = (np.tile(e.reshape(1, S, J), (T, 1, 1)), etr_params_path) y_aftertax_path = (y_path - tax.tau_income(np.tile(r[:T].reshape(T, 1, 1), (1, S, J)), np.tile(w[:T].reshape(T, 1, 1), (1, S, J)), bmat_s[:T,:,:], n_mat[:T,:,:], factor, inctax_params)) # compute after-tax wealth wtax_params = (h_wealth, p_wealth, m_wealth) b_aftertax_path = bmat_s[:T,:,:] - tax.tau_wealth(bmat_s[:T,:,:], wtax_params) print'Checking time path for violations of constaints.' for t in xrange(T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_path[t], t, ltilde) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, 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, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'G': G, 'T_H': T_H, 'r': r, 'w': w, 'b_mat': b_mat, 'n_mat': n_mat, 'c_path': c_path, 'tax_path': tax_path, 'bmat_s': bmat_s, 'utility_path': utility_path, 'b_aftertax_path': b_aftertax_path, 'y_aftertax_path': y_aftertax_path, 'y_path': y_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure} macro_output = {'Y': Y, 'K': K, 'L': L, 'C': C, 'I': I, 'BQ': BQ, 'G': G, 'T_H': T_H, 'r': r, 'w': w, 'tax_path': tax_path} # if ((TPIiter >= maxiter) or (np.absolute(TPIdist) > mindist_TPI)) and ENFORCE_SOLUTION_CHECKS : # raise RuntimeError("Transition path equlibrium not found") # # if ((np.any(np.absolute(rc_error) >= 1e-6)) # and ENFORCE_SOLUTION_CHECKS): # raise RuntimeError("Transition path equlibrium not found") # # if ((np.any(np.absolute(eul_savings) >= mindist_TPI) or # (np.any(np.absolute(eul_laborleisure) > mindist_TPI))) # and ENFORCE_SOLUTION_CHECKS): # raise RuntimeError("Transition path equlibrium not found") return output, macro_output
def run_steady_state(ss_parameters, iterative_params, get_baseline=False, calibrate_model=False, output_dir="./OUTPUT"): ''' ------------------------------------------------------------------------ Run SS ------------------------------------------------------------------------ ''' if get_baseline: # Generate initial guesses for chi^b_j and chi^n_s chi_params = np.zeros(S + J) chi_params[:J] = chi_b_guess chi_params[J:] = chi_n_guess # First run SS simulation with guesses at initial values for b, n, w, r, etc # For inital guesses of b and n, we choose very small b, and medium n b_guess = np.ones((S, J)).flatten() * .01 n_guess = np.ones((S, J)).flatten() * .5 * ltilde # For initial guesses of w, r, T_H, and factor, we use values that are close # to some steady state values. wguess = 1.2 rguess = .06 T_Hguess = 0 factorguess = 100000 solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) if calibrate_model: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_path = os.path.join(output_dir, "Saved_moments/SS_init_solutions.pkl") pickle.dump(outputs, open(ss_init_path, "wb")) function_to_minimize_X = lambda x: function_to_minimize( x, chi_params, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir) bnds = tuple([(1e-6, None)] * (S + J)) # In order to scale all the parameters to estimate in the minimizer, we have the minimizer fit a vector of ones that # will be multiplied by the chi initial guesses inside the function. Otherwise, if chi^b_j=1e5 for some j, and the # minimizer peturbs that value by 1e-8, the % difference will be extremely small, outside of the tolerance of the # minimizer, and it will not change that parameter. chi_params_scalars = np.ones(S + J) chi_params_scalars = opt.minimize(function_to_minimize_X, chi_params_scalars, method='TNC', tol=MINIMIZER_TOL, bounds=bnds, options=MINIMIZER_OPTIONS).x chi_params *= chi_params_scalars print 'The final scaling params', chi_params_scalars print 'The final bequest parameter values:', chi_params solutions_dict = pickle.load(open(ss_init_path, "rb")) solutions = solutions_dict['solutions'] b_guess = solutions[:S * J] n_guess = solutions[S * J:2 * S * J] wguess, rguess, factorguess, T_Hguess = solutions[2 * S * J:] solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) else: variables = pickle.load(open(ss_init_path, "rb")) solutions = solutions_dict['solutions'] chi_params = solutions_dict['chi_params'] b_guess = solutions[:S * J] n_guess = solutions[S * J:2 * S * J] wguess, rguess, factorguess, T_Hguess = solutions[2 * S * J:] solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[J:], chi_params[:J], ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' if get_baseline: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_dir = os.path.join(output_dir, "Saved_moments/SS_init_solutions.pkl") pickle.dump(outputs, open(ss_init_dir, "wb")) else: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_exp_dir = os.path.join(output_dir, "Saved_moments/SS_experiment_solutions.pkl") pickle.dump(outputs, open(ss_exp_dir, "wb")) bssmat = solutions[0:(S - 1) * J].reshape(S - 1, J) bq = solutions[(S - 1) * J:S * J] bssmat_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat)) bssmat_splus1 = np.array(list(bssmat) + list(bq.reshape(1, J))) nssmat = solutions[S * J:2 * S * J].reshape(S, J) wss, rss, factor_ss, T_Hss = solutions[2 * S * J:] Kss = household.get_K(bssmat_splus1, omega_SS.reshape(S, 1), lambdas, g_n_ss, 'SS') Lss = firm.get_L(e, nssmat, omega_SS.reshape(S, 1), lambdas, 'SS') Yss = firm.get_Y(Kss, Lss, ss_parameters) Iss = firm.get_I(Kss, Kss, delta, g_y, g_n_ss) theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, e, J, omega_SS.reshape(S, 1), lambdas) BQss = household.get_BQ(rss, bssmat_splus1, omega_SS.reshape(S, 1), lambdas, rho.reshape(S, 1), g_n_ss, 'SS') b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) taxss = tax.total_taxes(rss, b_s, wss, e, nssmat, BQss, lambdas, factor_ss, T_Hss, None, 'SS', False, ss_parameters, theta, tau_bq) cssmat = household.get_cons(rss, b_s, wss, e, nssmat, BQss.reshape(1, J), lambdas.reshape(1, J), bssmat_splus1, ss_parameters, taxss) Css = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') resource_constraint = Yss - (Css + Iss) print 'Resource Constraint Difference:', resource_constraint household.constraint_checker_SS(bssmat, nssmat, cssmat, ss_parameters) b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) b_splus1 = bssmat_splus1 b_splus2 = np.array( list(bssmat_splus1[1:]) + list(np.zeros(J).reshape((1, J)))) chi_b = np.tile(chi_params[:J].reshape(1, J), (S, 1)) chi_n = np.array(chi_params[J:]) euler_savings = np.zeros((S, J)) euler_labor_leisure = np.zeros((S, J)) for j in xrange(J): euler_savings[:, j] = household.euler_savings_func( wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], b_splus2[:, j], BQss[j], factor_ss, T_Hss, chi_b[:, j], ss_parameters, theta[j], tau_bq[j], rho, lambdas[j]) euler_labor_leisure[:, j] = household.euler_labor_leisure_func( wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], BQss[j], factor_ss, T_Hss, chi_n, ss_parameters, theta[j], tau_bq[j], lambdas[j]) ''' ------------------------------------------------------------------------ Save the values in various ways, depending on the stage of the simulation, to be used in TPI or graphing functions ------------------------------------------------------------------------ ''' # Pickle variables output = { 'Kss': Kss, 'bssmat': bssmat, 'Lss': Lss, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b } if get_baseline: utils.mkdirs(os.path.join(output_dir, "SSinit")) ss_init_dir = os.path.join(output_dir, "SSinit/ss_init_vars.pkl") pickle.dump(output, open(ss_init_dir, "wb")) bssmat_init = bssmat_splus1 nssmat_init = nssmat # Pickle variables for TPI initial values output2 = {'bssmat_init': bssmat_init, 'nssmat_init': nssmat_init} ss_init_tpi = os.path.join(output_dir, "SSinit/ss_init_tpi_vars.pkl") pickle.dump(output2, open(ss_init_tpi, "wb")) else: utils.mkdirs(os.path.join(output_dir, "SS")) ss_vars = os.path.join(output_dir, "SS/ss_vars.pkl") pickle.dump(output, open(ss_vars, "wb")) return output
def SS_solver(b_guess_init, n_guess_init, wss, rss, T_Hss, factor_ss, params, fsolve_flag=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = lenght X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() household.get_K() firm.get_L() firm.get_Y() firm.get_r() firm.get_w() household.get_BQ() tax.replacement_rate_vals() tax.get_lump_sum() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' bssmat, nssmat, chi_params, ss_params, income_tax_params, iterative_params = params J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, tau_bq, rho, omega_SS, lambdas, e, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_params analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params chi_b, chi_n = chi_params maxiter, mindist_SS = iterative_params # Rename the inputs w = wss r = rss T_H = T_Hss factor = factor_ss dist = 10 iteration = 0 dist_vec = np.zeros(maxiter) if fsolve_flag == True: maxiter = 1 while (dist > mindist_SS) and (iteration < maxiter): # Solve for the steady state levels of b and n, given w, r, T_H and # factor outer_loop_vars = (bssmat, nssmat, r, w, T_H, factor) inner_loop_params = (ss_params, income_tax_params, chi_params) euler_errors, bssmat, nssmat, new_r, new_w, \ new_T_H, new_factor, new_BQ, average_income_model = inner_loop(outer_loop_vars, inner_loop_params) r = utils.convex_combo(new_r, r, nu) w = utils.convex_combo(new_w, w, nu) factor = utils.convex_combo(new_factor, factor, nu) T_H = utils.convex_combo(new_T_H, T_H, nu) if T_H != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If T_H is zero (if there are no taxes), a percent difference # will throw NaN's, so we use an absoluate difference dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [abs(new_T_H - T_H)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu /= 2.0 print 'New value of nu:', nu iteration += 1 print "Iteration: %02d" % iteration, " Distance: ", dist ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1,J)),bssmat[:-1,:],axis=0) bssmat_splus1 = bssmat wss = w rss = r factor_ss = factor T_Hss = T_H Kss_params = (omega_SS.reshape(S, 1), lambdas, g_n_ss, 'SS') Kss = household.get_K(bssmat_splus1, Kss_params) Lss_params = (e, omega_SS.reshape(S, 1), lambdas, 'SS') Lss = firm.get_L(nssmat, Lss_params) Yss_params = (alpha, Z) Yss = firm.get_Y(Kss, Lss, Yss_params) Iss_params = (delta, g_y, g_n_ss) Iss = firm.get_I(Kss, Kss, Iss_params) BQss = new_BQ theta = np.zeros(J) # zero out payroll taxes since included in tax functions # # theta_params = (e, J, omega_SS.reshape(S, 1), lambdas) # # tax.replacement_rate_vals(nssmat, wss, factor_ss, theta_params) # solve resource constraint etr_params_3D = np.tile(np.reshape(etr_params,(S,1,etr_params.shape[1])),(1,J,1)) mtrx_params_3D = np.tile(np.reshape(mtrx_params,(S,1,mtrx_params.shape[1])),(1,J,1)) ''' ------------------------------------------------------------------------ The code below is to calulate and save model MTRs - only exists help debug ------------------------------------------------------------------------ ''' # etr_params_extended = np.append(etr_params,np.reshape(etr_params[-1,:],(1,etr_params.shape[1])),axis=0)[1:,:] # etr_params_extended_3D = np.tile(np.reshape(etr_params_extended,(S,1,etr_params_extended.shape[1])),(1,J,1)) # mtry_params_extended = np.append(mtry_params,np.reshape(mtry_params[-1,:],(1,mtry_params.shape[1])),axis=0)[1:,:] # mtry_params_extended_3D = np.tile(np.reshape(mtry_params_extended,(S,1,mtry_params_extended.shape[1])),(1,J,1)) # e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) # nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) # mtry_ss_params = (e_extended[1:,:], etr_params_extended_3D, mtry_params_extended_3D, analytical_mtrs) # mtry_ss = tax.MTR_capital(rss, wss, bssmat_splus1, nss_extended[1:,:], factor_ss, mtry_ss_params) # mtrx_ss_params = (e, etr_params_3D, mtrx_params_3D, analytical_mtrs) # mtrx_ss = tax.MTR_labor(rss, wss, bssmat_s, nssmat, factor_ss, mtrx_ss_params) # np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") # np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") # solve resource constraint taxss_params = (e, lambdas, 'SS', retire, etr_params_3D, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) taxss = tax.total_taxes(rss, wss, bssmat_s, nssmat, BQss, factor_ss, T_Hss, None, False, taxss_params) css_params = (e, lambdas.reshape(1, J), g_y) cssmat = household.get_cons(rss, wss, bssmat_s, bssmat_splus1, nssmat, BQss.reshape( 1, J), taxss, css_params) Css_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css = household.get_C(cssmat, Css_params) resource_constraint = Yss - (Css + Iss) print 'Resource Constraint Difference:', resource_constraint if ENFORCE_SOLUTION_CHECKS and np.absolute(resource_constraint) > 1e-8: err = "Steady state aggregate resource constraint not satisfied" raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat, nssmat, cssmat, ltilde) euler_savings = euler_errors[:S,:] euler_labor_leisure = euler_errors[S:,:] ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = {'Kss': Kss, 'bssmat': bssmat, 'Lss': Lss, 'Css':Css, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b} return output
savings = np.copy(bssmat_splus1) beq_ut = chi_b.reshape(S, J) * (rho.reshape(S, 1)) * \ (savings**(1 - sigma) - 1) / (1 - sigma) utility = ((cssmat_init ** (1 - sigma) - 1) / (1 - sigma)) + chi_n.reshape(S, 1) * \ (b_ellipse * (1 - (nssmat_init / ltilde)**upsilon) ** (1 / upsilon) + k_ellipse) utility += beq_ut utility_init = utility.sum(0) T_Hss_init = T_Hss Kss_init = Kss Lss_init = Lss Css_init = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') iss_init = firm.get_I(bssmat_splus1, bssmat_splus1, delta, g_y, g_n_ss) income_init = cssmat + iss_init # print((income_init*omega_SS).sum()) # print(Css + delta * Kss) # print(Kss) # print(Lss) # print(Css_init) # print()(utility_init * omega_SS).sum()) the_inequalizer(income_init, omega_SS, lambdas, S, J) ''' ------------------------------------------------------------------------ SS baseline graphs ------------------------------------------------------------------------ '''
def run_steady_state(income_tax_parameters, ss_parameters, iterative_params, get_baseline=False, calibrate_model=False, output_dir="./OUTPUT"): ''' ------------------------------------------------------------------------ Run SS ------------------------------------------------------------------------ ''' J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_parameters # Generate initial guesses for chi^b_j and chi^n_s chi_params = np.zeros(S + J) chi_params[:J] = chi_b_guess chi_params[J:] = chi_n_guess # First run SS simulation with guesses at initial values for b, n, w, r, etc # For inital guesses of b and n, we choose very small b, and medium n b_guess = np.ones((S, J)).flatten() * 0.05 n_guess = np.ones((S, J)).flatten() * .4 * ltilde # For initial guesses of w, r, T_H, and factor, we use values that are close # to some steady state values. wguess = 1.2 rguess = .06 T_Hguess = 0.12 factorguess = 70000.0 guesses = [wguess, rguess, T_Hguess, factorguess] args_ = (b_guess.reshape(S, J), n_guess.reshape(S, J), chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) [solutions, infodict, ier, message] = opt.fsolve(SS_fsolve, guesses, args=args_, xtol=mindist_SS, full_output=True) [wguess, rguess, T_Hguess, factorguess] = solutions fsolve_flag = True solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[ J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e, fsolve_flag) if calibrate_model: global Nfeval, value_all, chi_params_all Nfeval = 1 value_all = np.zeros((10000)) chi_params_all = np.zeros((S+J,10000)) outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_path = os.path.join( output_dir, "Saved_moments/SS_init_solutions.pkl") pickle.dump(outputs, open(ss_init_path, "wb")) function_to_minimize_X = lambda x: function_to_minimize( x, chi_params, income_tax_parameters, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir) bnds = tuple([(1e-6, None)] * (S + J)) # In order to scale all the parameters to estimate in the minimizer, we have the minimizer fit a vector of ones that # will be multiplied by the chi initial guesses inside the function. Otherwise, if chi^b_j=1e5 for some j, and the # minimizer peturbs that value by 1e-8, the % difference will be extremely small, outside of the tolerance of the # minimizer, and it will not change that parameter. chi_params_scalars = np.ones(S + J) #chi_params_scalars = opt.minimize(function_to_minimize_X, chi_params_scalars, # method='TNC', tol=MINIMIZER_TOL, bounds=bnds, callback=callbackF(chi_params_scalars), options=MINIMIZER_OPTIONS).x # chi_params_scalars = opt.minimize(function_to_minimize, chi_params_scalars, # args=(chi_params, income_tax_parameters, ss_parameters, iterative_params, # omega_SS, rho, lambdas, tau_bq, e, output_dir), # method='TNC', tol=MINIMIZER_TOL, bounds=bnds, # callback=callbackF(chi_params_scalars,chi_params, income_tax_parameters, # ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir), # options=MINIMIZER_OPTIONS).x chi_params_scalars = opt.minimize(function_to_minimize, chi_params_scalars, args=(chi_params, income_tax_parameters, ss_parameters, iterative_params, omega_SS, rho, lambdas, tau_bq, e, output_dir), method='TNC', tol=MINIMIZER_TOL, bounds=bnds, options=MINIMIZER_OPTIONS).x chi_params *= chi_params_scalars print 'The final scaling params', chi_params_scalars print 'The final bequest parameter values:', chi_params solutions_dict = pickle.load(open(ss_init_path, "rb")) solutions = solutions_dict['solutions'] b_guess = solutions[:S * J] n_guess = solutions[S * J:2 * S * J] wguess, rguess, factorguess, T_Hguess = solutions[2 * S * J:] guesses = [wguess, rguess, T_Hguess, factorguess] args_ = (b_guess.reshape(S, J), n_guess.reshape(S, J), chi_params[J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e) [solutions, infodict, ier, message] = opt.fsolve(SS_fsolve, guesses, args=args_, xtol=mindist_SS, full_output=True) [wguess, rguess, T_Hguess, factorguess] = solutions fsolve_flag = True solutions = SS_solver(b_guess.reshape(S, J), n_guess.reshape(S, J), wguess, rguess, T_Hguess, factorguess, chi_params[ J:], chi_params[:J], income_tax_parameters, ss_parameters, iterative_params, tau_bq, rho, lambdas, omega_SS, e, fsolve_flag) ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' if get_baseline: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_init_dir = os.path.join( output_dir, "Saved_moments/SS_baseline_solutions.pkl") pickle.dump(outputs, open(ss_init_dir, "wb")) else: outputs = {'solutions': solutions, 'chi_params': chi_params} ss_exp_dir = os.path.join( output_dir, "Saved_moments/SS_reform_solutions.pkl") pickle.dump(outputs, open(ss_exp_dir, "wb")) bssmat = solutions[0:(S - 1) * J].reshape(S - 1, J) bq = solutions[(S - 1) * J:S * J] # technically, this is just the intentional bequests - wealth of those with max age bssmat_s = np.array(list(np.zeros(J).reshape(1, J)) + list(bssmat)) bssmat_splus1 = np.array(list(bssmat) + list(bq.reshape(1, J))) nssmat = solutions[S * J:2 * S * J].reshape(S, J) wss, rss, factor_ss, T_Hss = solutions[2 * S * J:] Kss = household.get_K(bssmat_splus1, omega_SS.reshape( S, 1), lambdas, g_n_ss, 'SS') Lss = firm.get_L(e, nssmat, omega_SS.reshape(S, 1), lambdas, 'SS') Yss = firm.get_Y(Kss, Lss, ss_parameters) Iss = firm.get_I(Kss, Kss, delta, g_y, g_n_ss) theta = np.zeros(J) #tax.replacement_rate_vals( #nssmat, wss, factor_ss, e, J, omega_SS.reshape(S, 1), lambdas) BQss = household.get_BQ(rss, bssmat_splus1, omega_SS.reshape( S, 1), lambdas, rho.reshape(S, 1), g_n_ss, 'SS') b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) etr_params_3D = np.tile(np.reshape(etr_params,(S,1,etr_params.shape[1])),(1,J,1)) mtrx_params_3D = np.tile(np.reshape(mtrx_params,(S,1,mtrx_params.shape[1])),(1,J,1)) etr_params_extended = np.append(etr_params,np.reshape(etr_params[-1,:],(1,etr_params.shape[1])),axis=0)[1:,:] etr_params_extended_3D = np.tile(np.reshape(etr_params_extended,(S,1,etr_params_extended.shape[1])),(1,J,1)) mtry_params_extended = np.append(mtry_params,np.reshape(mtry_params[-1,:],(1,mtry_params.shape[1])),axis=0)[1:,:] mtry_params_extended_3D = np.tile(np.reshape(mtry_params_extended,(S,1,mtry_params_extended.shape[1])),(1,J,1)) e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) mtry_ss = tax.MTR_capital(rss, bssmat_splus1, wss, e_extended[1:,:], nss_extended[1:,:], factor_ss, analytical_mtrs, etr_params_extended_3D, mtry_params_extended_3D) mtrx_ss = tax.MTR_labor(rss, bssmat_s, wss, e, nssmat, factor_ss, analytical_mtrs, etr_params_3D, mtrx_params_3D) #np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") #np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") taxss_params = (J,S, retire, np.tile(np.reshape(etr_params,(S,1,etr_params.shape[1])),(1,J,1)), h_wealth, p_wealth, m_wealth, tau_payroll) taxss = tax.total_taxes(rss, b_s, wss, e, nssmat, BQss, lambdas, factor_ss, T_Hss, None, 'SS', False, taxss_params, theta, tau_bq) cssmat = household.get_cons(rss, b_s, wss, e, nssmat, BQss.reshape( 1, J), lambdas.reshape(1, J), bssmat_splus1, ss_parameters, taxss) Css = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') resource_constraint = Yss - (Css + Iss) print 'Resource Constraint Difference:', resource_constraint constraint_params = ltilde household.constraint_checker_SS(bssmat, nssmat, cssmat, constraint_params) b_s = np.array(list(np.zeros(J).reshape((1, J))) + list(bssmat)) b_splus1 = bssmat_splus1 b_splus2 = np.array(list(bssmat_splus1[1:]) + list(np.zeros(J).reshape((1, J)))) chi_b = np.tile(chi_params[:J].reshape(1, J), (S, 1)) chi_n = np.array(chi_params[J:]) euler_savings = np.zeros((S, J)) euler_labor_leisure = np.zeros((S, J)) for j in xrange(J): euler_savings[:, j] = household.euler_savings_func(wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], b_splus2[:, j], BQss[j], factor_ss, T_Hss, chi_b[:, j], income_tax_parameters, ss_parameters, theta[j], tau_bq[j], rho, lambdas[j]) euler_labor_leisure[:, j] = household.euler_labor_leisure_func(wss, rss, e[:, j], nssmat[:, j], b_s[:, j], b_splus1[:, j], BQss[j], factor_ss, T_Hss, chi_n, income_tax_parameters, ss_parameters, theta[j], tau_bq[j], lambdas[j]) ''' ------------------------------------------------------------------------ Save the values in various ways, depending on the stage of the simulation, to be used in TPI or graphing functions ------------------------------------------------------------------------ ''' # Pickle variables output = {'Kss': Kss, 'bssmat': bssmat, 'Lss': Lss, 'Css':Css, 'nssmat': nssmat, 'Yss': Yss, 'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b} utils.mkdirs(os.path.join(output_dir, "SSinit")) ss_init_dir = os.path.join(output_dir, "SSinit/ss_init_vars.pkl") pickle.dump(output, open(ss_init_dir, "wb")) bssmat_init = bssmat_splus1 nssmat_init = nssmat # Pickle variables for TPI initial values output2 = {'bssmat_init': bssmat_init, 'nssmat_init': nssmat_init} ss_init_tpi = os.path.join(output_dir, "SSinit/ss_init_tpi_vars.pkl") pickle.dump(output2, open(ss_init_tpi, "wb")) return output
Y_base = Yinit BQpath_TPIbase = BQpath_TPI eul_savings_init = eul_savings eul_laborleisure_init = eul_laborleisure b_mat_init = b_mat n_mat_init = n_mat T_H_initbase = T_H_init b1 = np.zeros((T, S, J)) b1[:, 1:, :] = b_mat_init[:T, :-1, :] b2 = np.zeros((T, S, J)) b2[:, :, :] = b_mat_init[:T, :, :] c_path_init = c_path inv_mat_init = firm.get_I( b_mat_init[1:T + 1], b_mat_init[:T], delta, g_y, g_n_vector[:T].reshape(T, 1, 1)) y_mat_init = c_path_init + inv_mat_init # Lifetime Utility Graphs: c_ut_init = np.zeros((S, S, J)) for s in range(S - 1): c_ut_init[:, s + 1, :] = c_path_init[s + 1:s + 1 + S, s + 1, :] c_ut_init[:, 0, :] = c_path_init[:S, 0, :] L_ut_init = np.zeros((S, S, J)) for s in range(S - 1): L_ut_init[:, s + 1, :] = n_mat_init[s + 1:s + 1 + S, s + 1, :] L_ut_init[:, 0, :] = n_mat_init[:S, 0, :] B_ut_init = BQpath_TPIbase[S:T] b_ut_init = np.zeros((S, S, J)) for s in range(S): b_ut_init[:, s, :] = b_mat_init[s:s + S, s, :]
def SS_solver(b_guess_init, n_guess_init, wss, rss, T_Hss, BQss, factor_ss, params, baseline, fsolve_flag=False): ''' -------------------------------------------------------------------- Solves for the steady state distribution of capital, labor, as well as w, r, T_H and the scaling factor, using a bisection method similar to TPI. -------------------------------------------------------------------- INPUTS: b_guess_init = [S,J] array, initial guesses for savings n_guess_init = [S,J] array, initial guesses for labor supply wguess = scalar, initial guess for SS real wage rate rguess = scalar, initial guess for SS real interest rate T_Hguess = scalar, initial guess for lump sum transfer factorguess = scalar, initial guess for scaling factor to dollars chi_b = [J,] vector, chi^b_j, the utility weight on bequests chi_n = [S,] vector, chi^n_s utility weight on labor supply params = lenght X tuple, list of parameters iterative_params = length X tuple, list of parameters that determine the convergence of the while loop tau_bq = [J,] vector, bequest tax rate rho = [S,] vector, mortality rates by age lambdas = [J,] vector, fraction of population with each ability type omega = [S,] vector, stationary population weights e = [S,J] array, effective labor units by age and ability type OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_equation_solver() household.get_K() firm.get_L() firm.get_Y() firm.get_r() firm.get_w() household.get_BQ() tax.replacement_rate_vals() tax.get_lump_sum() utils.convex_combo() utils.pct_diff_func() OBJECTS CREATED WITHIN FUNCTION: b_guess = [S,] vector, initial guess at household savings n_guess = [S,] vector, initial guess at household labor supply b_s = [S,] vector, wealth enter period with b_splus1 = [S,] vector, household savings b_splus2 = [S,] vector, household savings one period ahead BQ = scalar, aggregate bequests to lifetime income group theta = scalar, replacement rate for social security benenfits error1 = [S,] vector, errors from FOC for savings error2 = [S,] vector, errors from FOC for labor supply tax1 = [S,] vector, total income taxes paid cons = [S,] vector, household consumption RETURNS: solutions = steady state values of b, n, w, r, factor, T_H ((2*S*J+4)x1 array) OUTPUT: None -------------------------------------------------------------------- ''' bssmat, nssmat, chi_params, ss_params, income_tax_params, iterative_params = params J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y,\ g_n_ss, tau_payroll, tau_bq, rho, omega_SS, lambdas, imm_rates, e, retire, mean_income_data,\ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = ss_params analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params chi_b, chi_n = chi_params maxiter, mindist_SS = iterative_params # Rename the inputs w = wss r = rss T_H = T_Hss BQ = BQss factor = factor_ss dist = 10 iteration = 0 dist_vec = np.zeros(maxiter) if fsolve_flag == True: maxiter = 1 while (dist > mindist_SS) and (iteration < maxiter): # Solve for the steady state levels of b and n, given w, r, T_H and # factor outer_loop_vars = (bssmat, nssmat, r, w, T_H, factor) inner_loop_params = (ss_params, income_tax_params, chi_params) euler_errors, bssmat, nssmat, new_r, new_w, \ new_T_H, new_BQ, new_theta, new_factor, average_income_model = inner_loop(outer_loop_vars, inner_loop_params, baseline) # print 'T_H: ', T_H, new_T_H # print 'factor: ', factor, new_factor # print 'interest rate: ', r, new_r # print 'wage rate: ', w, new_w r = utils.convex_combo(new_r, r, nu) w = utils.convex_combo(new_w, w, nu) factor = utils.convex_combo(new_factor, factor, nu) T_H = utils.convex_combo(new_T_H, T_H, nu) BQ = utils.convex_combo(new_BQ, BQ, nu) theta = utils.convex_combo(new_theta, theta, nu) if T_H != 0: dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [utils.pct_diff_func(new_T_H, T_H)] + [utils.pct_diff_func(new_BQ, BQ)] + [utils.pct_diff_func(new_theta, theta)] + [utils.pct_diff_func(new_factor, factor)]).max() else: # If T_H is zero (if there are no taxes), a percent difference # will throw NaN's, so we use an absoluate difference dist = np.array([utils.pct_diff_func(new_r, r)] + [utils.pct_diff_func(new_w, w)] + [abs(new_T_H - T_H)] + [utils.pct_diff_func(new_BQ, BQ)] + [utils.pct_diff_func(new_theta, theta)] + [utils.pct_diff_func(new_factor, factor)]).max() dist_vec[iteration] = dist # Similar to TPI: if the distance between iterations increases, then # decrease the value of nu to prevent cycling if iteration > 10: if dist_vec[iteration] - dist_vec[iteration - 1] > 0: nu /= 2.0 #print 'New value of nu:', nu iteration += 1 #print "Iteration: %02d" % iteration, " Distance: ", dist ''' ------------------------------------------------------------------------ Generate the SS values of variables, including euler errors ------------------------------------------------------------------------ ''' bssmat_s = np.append(np.zeros((1,J)),bssmat[:-1,:],axis=0) bssmat_splus1 = bssmat wss = w rss = r factor_ss = factor T_Hss = T_H Kss_params = (omega_SS.reshape(S, 1), lambdas, imm_rates, g_n_ss, 'SS') Kss = household.get_K(bssmat_splus1, Kss_params) Lss_params = (e, omega_SS.reshape(S, 1), lambdas, 'SS') Lss = firm.get_L(nssmat, Lss_params) Yss_params = (alpha, Z) Yss = firm.get_Y(Kss, Lss, Yss_params) Iss_params = (delta, g_y, omega_SS, lambdas, imm_rates, g_n_ss, 'SS') Iss = firm.get_I(bssmat_splus1, Kss, Kss, Iss_params) BQss = new_BQ # theta_params = (e, S, J, omega_SS.reshape(S, 1), lambdas,retire) # theta = tax.replacement_rate_vals(nssmat, wss, factor_ss, theta_params) # solve resource constraint etr_params_3D = np.tile(np.reshape(etr_params,(S,1,etr_params.shape[1])),(1,J,1)) mtrx_params_3D = np.tile(np.reshape(mtrx_params,(S,1,mtrx_params.shape[1])),(1,J,1)) taxss_params = (e, lambdas, 'SS', retire, etr_params_3D, h_wealth, p_wealth, m_wealth, tau_payroll, theta, tau_bq, J, S) taxss = tax.total_taxes(rss, wss, bssmat_s, nssmat, BQss, factor_ss, T_Hss, None, False, taxss_params) css_params = (e, lambdas.reshape(1, J), g_y) cssmat = household.get_cons(rss, wss, bssmat_s, bssmat_splus1, nssmat, BQss.reshape( 1, J), taxss, css_params) Css_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css = household.get_C(cssmat, Css_params) resource_constraint = Yss - (Css + Iss) ''' ------------------------------------------------------------------------ The code below is to calulate and save model MTRs - only exists to help debug ------------------------------------------------------------------------ ''' # etr_params_extended = np.append(etr_params,np.reshape(etr_params[-1,:],(1,etr_params.shape[1])),axis=0)[1:,:] # etr_params_extended_3D = np.tile(np.reshape(etr_params_extended,(S,1,etr_params_extended.shape[1])),(1,J,1)) # mtry_params_extended = np.append(mtry_params,np.reshape(mtry_params[-1,:],(1,mtry_params.shape[1])),axis=0)[1:,:] # mtry_params_extended_3D = np.tile(np.reshape(mtry_params_extended,(S,1,mtry_params_extended.shape[1])),(1,J,1)) # e_extended = np.array(list(e) + list(np.zeros(J).reshape(1, J))) # nss_extended = np.array(list(nssmat) + list(np.zeros(J).reshape(1, J))) # mtry_ss_params = (e_extended[1:,:], etr_params_extended_3D, mtry_params_extended_3D, analytical_mtrs) # mtry_ss = tax.MTR_capital(rss, wss, bssmat_splus1, nss_extended[1:,:], factor_ss, mtry_ss_params) # mtrx_ss_params = (e, etr_params_3D, mtrx_params_3D, analytical_mtrs) # mtrx_ss = tax.MTR_labor(rss, wss, bssmat_s, nssmat, factor_ss, mtrx_ss_params) # # etr_ss_params = (e, etr_params_3D) # etr_ss = tax.tau_income(rss, wss, bssmat_s, nssmat, factor_ss, etr_ss_params) # # np.savetxt("etr_ss.csv", etr_ss, delimiter=",") # np.savetxt("mtr_ss_capital.csv", mtry_ss, delimiter=",") # np.savetxt("mtr_ss_labor.csv", mtrx_ss, delimiter=",") print 'interest rate: ', rss print 'wage rate: ', wss print 'factor: ', factor_ss print 'T_H', T_Hss print 'Resource Constraint Difference:', resource_constraint print 'Max Euler Error: ', (np.absolute(euler_errors)).max() if ENFORCE_SOLUTION_CHECKS and np.absolute(resource_constraint) > 1e-8: err = "Steady state aggregate resource constraint not satisfied" raise RuntimeError(err) # check constraints household.constraint_checker_SS(bssmat, nssmat, cssmat, ltilde) if np.absolute(resource_constraint) > 1e-8 or (np.absolute(euler_errors)).max() > 1e-8: ss_flag = 1 else: ss_flag = 0 euler_savings = euler_errors[:S,:] euler_labor_leisure = euler_errors[S:,:] ''' ------------------------------------------------------------------------ Return dictionary of SS results ------------------------------------------------------------------------ ''' output = {'Kss': Kss, 'bssmat': bssmat, 'Lss': Lss, 'Css':Css, 'Iss':Iss, 'nssmat': nssmat, 'Yss': Yss,'wss': wss, 'rss': rss, 'theta': theta, 'BQss': BQss, 'factor_ss': factor_ss, 'bssmat_s': bssmat_s, 'cssmat': cssmat, 'bssmat_splus1': bssmat_splus1, 'T_Hss': T_Hss, 'euler_savings': euler_savings, 'euler_labor_leisure': euler_labor_leisure, 'chi_n': chi_n, 'chi_b': chi_b, 'ss_flag':ss_flag} return output
r_base = rinit Y_base = Yinit BQpath_TPIbase = BQpath_TPI eul_savings_init = eul_savings eul_laborleisure_init = eul_laborleisure b_mat_init = b_mat n_mat_init = n_mat T_H_initbase = T_H_init b1 = np.zeros((T, S, J)) b1[:, 1:, :] = b_mat_init[:T, :-1, :] b2 = np.zeros((T, S, J)) b2[:, :, :] = b_mat_init[:T, :, :] c_path_init = c_path inv_mat_init = firm.get_I(b_mat_init[1:T + 1], b_mat_init[:T], delta, g_y, g_n_vector[:T].reshape(T, 1, 1)) y_mat_init = c_path_init + inv_mat_init # Lifetime Utility Graphs: c_ut_init = np.zeros((S, S, J)) for s in range(S - 1): c_ut_init[:, s + 1, :] = c_path_init[s + 1:s + 1 + S, s + 1, :] c_ut_init[:, 0, :] = c_path_init[:S, 0, :] L_ut_init = np.zeros((S, S, J)) for s in range(S - 1): L_ut_init[:, s + 1, :] = n_mat_init[s + 1:s + 1 + S, s + 1, :] L_ut_init[:, 0, :] = n_mat_init[:S, 0, :] B_ut_init = BQpath_TPIbase[S:T] b_ut_init = np.zeros((S, S, J)) for s in range(S): b_ut_init[:, s, :] = b_mat_init[s:s + S, s, :]
def TP_solutions(winit, rinit, T_H_init, BQinit2, Kss, Lss, Yss, BQss, theta, income_tax_params, wealth_tax_params, ellipse_params, parameters, g_n_vector, omega_stationary, K0, b_sinit, b_splus1init, L0, Y0, r0, BQ0, T_H_0, tax0, c0, initial_b, initial_n, factor_ss, tau_bq, chi_b, chi_n, output_dir="./OUTPUT", **kwargs): ''' This function returns the solutions for all variables along the time path. ''' J, S, T, BW, beta, sigma, alpha, Z, delta, ltilde, nu, g_y, g_n_ss, tau_payroll, retire, mean_income_data, \ h_wealth, p_wealth, m_wealth, b_ellipse, upsilon = parameters analytical_mtrs, etr_params, mtrx_params, mtry_params = income_tax_params print 'Computing final solutions' # Extend time paths past T winit = np.array(list(winit) + list(np.ones(S) * wss)) rinit = np.array(list(rinit) + list(np.ones(S) * rss)) T_H_init = np.array(list(T_H_init) + list(np.ones(S) * T_Hss)) BQinit = np.zeros((T + S, J)) for j in xrange(J): BQinit[:, j] = list(BQinit2[:,j]) + [BQss[j]] * S BQinit = np.array(BQinit) # Make array of initial guesses domain = np.linspace(0, T, T) domain2 = np.tile(domain.reshape(T, 1, 1), (1, S, 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, S, J), (S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T).reshape(T, 1, 1), (1, S, J)) guesses_n = domain3 * (nssmat - initial_n) + initial_n ending_n_tail = np.tile(nssmat.reshape(1, S, J), (S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = np.zeros((T + S, S, J)) n_mat = np.zeros((T + S, S, J)) ind = np.arange(S) # initialize array of Euler errors euler_errors = np.zeros((T, 2 * S, J)) # As in SS, you need the final distributions of b and n to match the final # w, r, BQ, etc. Otherwise the euler errors are large. You need one more # fsolve. for j in xrange(J): b_mat[1, -1, j], n_mat[0, -1, j] = np.array(opt.fsolve(SS_TPI_firstdoughnutring, [guesses_b[1, -1, j], guesses_n[0, -1, j]], args=(winit[1], rinit[1], BQinit[1, j], T_H_init[1], initial_b, factor_ss, j, income_tax_params, parameters, theta, tau_bq), xtol=1e-13)) for s in xrange(S - 2): # Upper triangle ind2 = np.arange(s + 2) b_guesses_to_use = np.diag(guesses_b[1:S + 1, :, j], S - (s + 2)) n_guesses_to_use = np.diag(guesses_n[:S, :, j], S - (s + 2)) # initialize array of diagonal elements length_diag = (np.diag(np.transpose(etr_params[:S,:,0]),S-(s+2))).shape[0] etr_params_to_use = np.zeros((length_diag,etr_params.shape[2])) mtrx_params_to_use = np.zeros((length_diag,mtrx_params.shape[2])) mtry_params_to_use = np.zeros((length_diag,mtry_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_to_use[:,i] = np.diag(np.transpose(etr_params[:S,:,i]),S-(s+2)) mtrx_params_to_use[:,i] = np.diag(np.transpose(mtrx_params[:S,:,i]),S-(s+2)) mtry_params_to_use[:,i] = np.diag(np.transpose(mtry_params[:S,:,i]),S-(s+2)) inc_tax_params_upper = (analytical_mtrs, etr_params_to_use, mtrx_params_to_use, mtry_params_to_use) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, s, 0, inc_tax_params_upper, parameters, theta, tau_bq, rho, lambdas, e, initial_b, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:len(solutions) / 2] b_mat[1 + ind2, S - (s + 2) + ind2, j] = b_vec n_vec = solutions[len(solutions) / 2:] n_mat[ind2, S - (s + 2) + ind2, j] = n_vec for t in xrange(0, T): b_guesses_to_use = .75 * np.diag(guesses_b[t + 1:t + S + 1, :, j]) n_guesses_to_use = np.diag(guesses_n[t:t + S, :, j]) # initialize array of diagonal elements length_diag = (np.diag(np.transpose(etr_params[:,t:t+S,i]))).shape[0] etr_params_to_use = np.zeros((length_diag,etr_params.shape[2])) mtrx_params_to_use = np.zeros((length_diag,mtrx_params.shape[2])) mtry_params_to_use = np.zeros((length_diag,mtry_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_to_use[:,i] = np.diag(np.transpose(etr_params[:,t:t+S,i])) mtrx_params_to_use[:,i] = np.diag(np.transpose(mtrx_params[:,t:t+S,i])) mtry_params_to_use[:,i] = np.diag(np.transpose(mtry_params[:,t:t+S,i])) inc_tax_params_TP = (analytical_mtrs, etr_params_to_use, mtrx_params_to_use, mtry_params_to_use) solutions = opt.fsolve(Steady_state_TPI_solver, list( b_guesses_to_use) + list(n_guesses_to_use), args=( winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, inc_tax_params_TP, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n), xtol=1e-13) b_vec = solutions[:S] b_mat[t + 1 + ind, ind, j] = b_vec n_vec = solutions[S:] n_mat[t + ind, ind, j] = n_vec inputs = list(solutions) euler_errors[t, :, j] = np.abs(Steady_state_TPI_solver( inputs, winit, rinit, BQinit[:, j], T_H_init, factor_ss, j, None, t, inc_tax_params_TP, parameters, theta, tau_bq, rho, lambdas, e, None, chi_b, chi_n)) b_mat[0, :, :] = initial_b ''' ------------------------------------------------------------------------ Generate variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' Kinit = household.get_K(b_mat[:T], omega_stationary[:T].reshape( T, S, 1), lambdas.reshape(1, 1, J), g_n_vector[:T], 'TPI') Linit = firm.get_L(e.reshape(1, S, J), n_mat[:T], omega_stationary[ :T, :].reshape(T, S, 1), lambdas.reshape(1, 1, J), 'TPI') Kpath_TPI = np.array(list(Kinit) + list(np.ones(10) * Kss)) Lpath_TPI = np.array(list(Linit) + list(np.ones(10) * Lss)) BQpath_TPI = np.array(list(BQinit) + list(np.ones((10, J)) * BQss)) b_s = np.zeros((T, S, J)) b_s[:, 1:, :] = b_mat[:T, :-1, :] b_splus1 = np.zeros((T, S, J)) b_splus1[:, :, :] = b_mat[1:T + 1, :, :] # initialize array etr_params_path = np.zeros((T,S,J,etr_params.shape[2])) for i in range(etr_params.shape[2]): etr_params_path[:,:,:,i] = np.tile(np.reshape(np.transpose(etr_params[:,:T,i]),(T,S,1)),(1,1,J)) tax_path_params = J, S, retire, etr_params_path, h_wealth, p_wealth, m_wealth, tau_payroll tax_path = tax.total_taxes(np.tile(rinit[:T].reshape(T, 1, 1),(1,S,J)), b_s, np.tile(winit[:T].reshape(T, 1, 1),(1,S,J)), np.tile(e.reshape(1, S, J),(T,1,1)), n_mat[:T,:,:], BQinit[:T, :].reshape(T, 1, J), lambdas, factor_ss, T_H_init[:T].reshape(T, 1, 1), None, 'TPI', False, tax_path_params, theta, tau_bq) c_path = household.get_cons(rinit[:T].reshape(T, 1, 1), b_s, winit[:T].reshape(T, 1, 1), e.reshape( 1, S, J), n_mat[:T], BQinit[:T].reshape(T, 1, J), lambdas.reshape(1, 1, J), b_splus1, parameters, tax_path) Y_path = firm.get_Y(Kpath_TPI[:T], Lpath_TPI[:T], parameters) C_path = household.get_C(c_path, omega_stationary[ :T].reshape(T, S, 1), lambdas, 'TPI') I_path = firm.get_I(Kpath_TPI[1:T + 1], Kpath_TPI[:T], delta, g_y, g_n_vector[:T]) print 'Resource Constraint Difference:', Y_path - C_path - I_path print'Checking time path for violations of constaints.' hh_constraint_params = ltilde for t in xrange(T): household.constraint_checker_TPI( b_mat[t], n_mat[t], c_path[t], t, hh_constraint_params) eul_savings = euler_errors[:, :S, :].max(1).max(1) eul_laborleisure = euler_errors[:, S:, :].max(1).max(1) print 'Max Euler error, savings: ', eul_savings print 'Max Euler error labor supply: ', eul_laborleisure ''' ------------------------------------------------------------------------ Create the unstationarized versions of the paths of macro aggregates ------------------------------------------------------------------------ ''' # tvec = np.linspace(0, len(C_path), len(C_path)) # growth_path = np.exp(g_y*tvec) # pop_path = np.zeros(len(C_path)) # for i in range(0,len(C_path)): # pop_path[i] = np.exp(g_n_vector[:i].sum()) # note that this normalizes the pop in the initial period to one # growth_pop_path = growth_path*pop_path # C_ns_path = C_path * growth_pop_path # K_ns_path = Kinit * growth_pop_path # BQ_ns_path = growth_pop_path * BQinit[:T] # L_ns_path = Linit * pop_path # T_H_ns_path = T_H_init[:T] * growth_pop_path # w_ns_path = winit*growth_path # I_ns_path = I_path * growth_pop_path # Y_ns_path = Y_path * growth_pop_path ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = {'Kpath_TPI': Kpath_TPI, 'b_mat': b_mat, 'c_path': c_path, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'Lpath_TPI': Lpath_TPI, 'BQpath_TPI': BQpath_TPI, 'n_mat': n_mat, 'rinit': rinit, 'Y_path': Y_path, 'T_H_init': T_H_init, 'tax_path': tax_path, 'winit': winit} macro_output = {'Kpath_TPI': Kpath_TPI, 'C_path': C_path, 'I_path': I_path, 'Lpath_TPI': Lpath_TPI, 'BQpath_TPI': BQpath_TPI, 'rinit': rinit, 'Y_path': Y_path, 'T_H_init': T_H_init, 'winit': winit, 'tax_path': tax_path} # macro_ns_output = {'K_ns_path': K_ns_path, 'C_ns_path': C_ns_path, 'I_ns_path': I_ns_path, # 'L_ns_path': L_ns_path, 'BQ_ns_path': BQ_ns_path, # 'rinit': rinit, 'Y_ns_path': Y_ns_path, 'T_H_ns_path': T_H_ns_path, # 'w_ns_path': w_ns_path} tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) tpi_dir = os.path.join(output_dir, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_macro_vars.pkl") pickle.dump(macro_output, open(tpi_vars, "wb"))
savings = np.copy(bssmat_splus1) beq_ut = chi_b.reshape(S, J) * (rho.reshape(S, 1)) * \ (savings**(1 - sigma) - 1) / (1 - sigma) utility = ((cssmat_init ** (1 - sigma) - 1) / (1 - sigma)) + chi_n.reshape(S, 1) * \ (b_ellipse * (1 - (nssmat_init / ltilde)**upsilon) ** (1 / upsilon) + k_ellipse) utility += beq_ut utility_init = utility.sum(0) T_Hss_init = T_Hss Kss_init = Kss Lss_init = Lss Css_init = household.get_C(cssmat, omega_SS.reshape(S, 1), lambdas, 'SS') iss_init = firm.get_I(bssmat_splus1, bssmat_splus1, delta, g_y, g_n_ss) income_init = cssmat + iss_init # print((income_init*omega_SS).sum()) # print(Css + delta * Kss) # print(Kss) # print(Lss) # print(Css_init) # print()(utility_init * omega_SS).sum()) the_inequalizer(income_init, omega_SS, lambdas, S, J) ''' ------------------------------------------------------------------------ SS baseline graphs ------------------------------------------------------------------------ ''' domain = np.linspace(starting_age, ending_age, S)
beq_ut = chi_b.reshape(1, J) * (rho.reshape(S, 1)) * \ (savings**(1 - sigma) - 1) / (1 - sigma) utility = ((cssmat_init ** (1 - sigma) - 1) / (1 - sigma)) + chi_n.reshape(S, 1) * \ (b_ellipse * (1 - (nssmat_init / ltilde)**upsilon) ** (1 / upsilon) + k_ellipse) utility += beq_ut utility_init = utility.sum(0) T_Hss_init = T_Hss Kss_init = Kss Lss_init = Lss c_params = (omega_SS.reshape(S, 1), lambdas, 'SS') Css_init = household.get_C(cssmat, c_params) i_params = (delta, g_y, omega_SS.reshape(1, S), lambdas, imm_rates, g_n_ss, 'SS') iss_init = firm.get_I(bssmat_splus1, Kss_init, Kss_init, i_params) income_init = cssmat + iss_init # print (income_init*omega_SS).sum() # print Css + delta * Kss # print Kss # print Lss # print Css_init # print (utility_init * omega_SS).sum() the_inequalizer(income_init, omega_SS, lambdas, S, J) ''' ------------------------------------------------------------------------ SS baseline graphs ------------------------------------------------------------------------ ''' domain = np.linspace(starting_age, ending_age, S)