def get_SS(c1_guess, r_old, params): beta, sigma, p, ltilde, b, upsilon, chi_n_vec, A, alpha, delta, ss_max_iter, ss_tol, xi_ss = params abs_ss = 1 ss_iter = 0 while abs_ss > ss_tol and ss_iter < ss_max_iter: ss_iter += 1 r_old = r_old * np.ones(p) w_old = firms.get_w(r_old, (A, alpha, delta)) * np.ones(p) # Calculate household decisions that make last-period savings zero c1_args = (r_old, w_old, beta, sigma, ltilde, b, upsilon, chi_n_vec, p, 0.0) result_c1 = opt.root(hh.get_b_last, c1_guess, args = (c1_args)) if result_c1.success: c1 = result_c1.x else: raise ValueError("failed to find an appropriate initial consumption") # Calculate aggregate supplies for capital and labor cvec = hh.get_c(c1, r_old, beta, sigma, p) nvec = hh.get_n(cvec, sigma, ltilde, b, upsilon, chi_n_vec, w_old, p) bvec = hh.get_b(cvec, nvec, r_old, w_old, p) K = aggr.get_K(bvec)[0] L = aggr.get_L(nvec)[0] C = aggr.get_C(cvec) Y = aggr.get_Y(K, L, (A, alpha)) b_err = abs(hh.get_b_errors(cvec, r_old[0], beta, sigma)).max() n_err = abs(hh.get_n_errors(nvec, cvec, sigma, ltilde, b, upsilon, chi_n_vec, w_old[0])).max() b_last = hh.get_b_last(cvec[0], r_old, w_old, beta, sigma, ltilde, b, upsilon, chi_n_vec, p, 0.0) r_new = firms.get_r(K, L, (A, alpha, delta)) # Check market clearing abs_ss = ((r_new - r_old) ** 2).max() # Update guess r_old = xi_ss * r_new + (1 - xi_ss) * r_old print('iteration:', ss_iter, ' squared distance: ', abs_ss) return r_old[0], w_old[0], cvec, nvec, bvec, K, L, C, Y, b_err, n_err, b_last
def solve_ss(r_init, params): ''' Solves for the steady-state equlibrium of the OG model ''' beta, sigma, n, alpha, A, delta, xi = params ss_dist = 7.0 ss_tol = 1e-8 ss_iter = 0 ss_max_iter = 300 r = r_init while (ss_dist > ss_tol) & (ss_iter < ss_max_iter): # get w w = firm.get_w(r, alpha, A, delta) # solve HH problem foc_args = (beta, sigma, r, w, n, 0.0) b_sp1_guess = [0.05, 0.05] result = opt.root(hh.FOCs, b_sp1_guess, args=foc_args) b_sp1 = result.x euler_errors = result.fun b_s = np.append(0.0, b_sp1) # use market clearing L = agg.get_L(n) K = agg.get_K(b_s) # find implied r r_prime = firm.get_r(L, K, alpha, A, delta) # check distance ss_dist = np.absolute(r - r_prime) print('Iteration = ', ss_iter, ', Distance = ', ss_dist, ', r = ', r) # update r r = xi * r_prime + (1 - xi) * r # update iteration counter ss_iter += 1 return r, b_sp1, euler_errors
def SS_EulErrs(bvec, *args): ''' -------------------------------------------------------------------- -------------------------------------------------------------------- INPUTS: bvec = (S-1,) vector, lifetime savings args = length 7 tuple, (nvec, beta, sigma, A, alpha, delta, EulDiff) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: aggr.get_K() aggr.get_L() firms.get_r() firms.get_w() hh.get_cons() hh.get_b_errors() OBJECTS CREATED WITHIN FUNCTION: nvec = (S,) vector, exogenous lifetime labor supply n_s beta = scalar in (0,1), discount factor for each model per sigma = scalar > 0, coefficient of relative risk aversion A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital EulDiff = boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 K = scalar > 0, aggregate capital stock K_cstr = boolean, =True if K < epsilon L = scalar > 0, exogenous aggregate labor r_params = length 3 tuple, (A, alpha, delta) r = scalar > 0, interest rate w_params = length 2 tuple, (A, alpha) w = scalar > 0, wage c_args = length 3 tuple, (nvec, r, w) cvec = (S,) vector, household consumption c_s b_args = length 4 tuple, (beta, sigma, r, EulDiff) errors = (S-1,) vector, savings Euler errors given bvec FILES CREATED BY THIS FUNCTION: None RETURNS: errors -------------------------------------------------------------------- ''' nvec, beta, sigma, A, alpha, delta, EulDiff = args K, K_cstr = aggr.get_K(bvec) L = aggr.get_L(nvec) r_params = (A, alpha, delta) r = firms.get_r(K, L, r_params) w_params = (A, alpha) w = firms.get_w(K, L, w_params) c_args = (nvec, r, w) cvec = hh.get_cons(bvec, 0.0, c_args) b_args = (beta, sigma, r, EulDiff) errors = hh.get_b_errors(cvec, b_args) return errors
def solve_tp(r_path_init, params): ''' Solves for the time path equlibrium using TPI ''' (beta, sigma, n, alpha, A, delta, T, xi, b_sp1_pre, r_ss, b_sp1_ss) = params tpi_dist = 7.0 tpi_tol = 1e-8 tpi_iter = 0 tpi_max_iter = 300 r_path = np.append(r_path_init, np.ones(2) * r_ss) while (tpi_dist > tpi_tol) & (tpi_iter < tpi_max_iter): w_path = firm.get_w(r_path, alpha, A, delta) # Solve HH problem b_sp1_mat = np.zeros((T + 2, 2)) euler_errors_mat = np.zeros((T + 2, 2)) # solve upper right corner foc_args = (beta, sigma, r_path[:2], w_path[:2], n[-2:], b_sp1_pre[0]) b_sp1_guess = b_sp1_ss[-1] result = opt.root(hh.FOCs, b_sp1_guess, args=foc_args) b_sp1_mat[0, -1] = result.x euler_errors_mat[0, -1] = result.fun # solve all full lifetimes DiagMaskb = np.eye(2, dtype=bool) for t in range(T): foc_args = (beta, sigma, r_path[t:t + 3], w_path[t:t + 3], n, 0.0) b_sp1_guess = b_sp1_ss result = opt.root(hh.FOCs, b_sp1_guess, args=foc_args) b_sp1_mat[t:t + 2, :] = (DiagMaskb * result.x + b_sp1_mat[t:t + 2, :]) euler_errors_mat[t:t + 2, :] = (DiagMaskb * result.fun + euler_errors_mat[t:t + 2, :]) # create a b_s_mat b_s_mat = np.zeros((T, 3)) b_s_mat[0, 1:] = b_sp1_pre b_s_mat[1:, 1:] = b_sp1_mat[:T - 1, :] # use market clearing L_path = np.ones(T) * agg.get_L(n) K_path = agg.get_K(b_s_mat) # find implied r r_path_prime = firm.get_r(L_path, K_path, alpha, A, delta) # check distance tpi_dist = np.absolute(r_path[:T] - r_path_prime[:T]).max() print('Iteration = ', tpi_iter, ', Distance = ', tpi_dist) # update r r_path[:T] = xi * r_path_prime[:T] + (1 - xi) * r_path[:T] # update iteration counter tpi_iter += 1 if tpi_iter < tpi_max_iter: print('The time path solved') else: print('The time path did not solve') return r_path[:T], euler_errors_mat[:T, :]
def solve_ss(r_init, params): ''' Solves for the steady-state equlibrium of the OG model ''' beta, sigma, alpha, A, delta, xi, omega_SS, imm_rates_SS, S = params ss_dist = 7.0 ss_tol = 1e-8 ss_iter = 0 ss_max_iter = 300 r = r_init # w = w_init # Why do we need w as well? Are we not going to get it by providing r_init to firm.get_w()? # I think Jason said this too and I'm going to stick to what we did in class. while (ss_dist > ss_tol) & (ss_iter < ss_max_iter): # get w w = firm.get_w(r, alpha, A, delta) # solve HH problem foc_args = (beta, sigma, r, w, 0.0) n_s_guess = np.ones(S) b_sp1_guess = np.ones(S - 1) * 0.5 HH_guess = np.append(b_sp1_guess, n_s_guess) result = opt.root(hh.FOCs, HH_guess, args=foc_args) b_sp1 = result.x[0:S - 1] n_s = result.x[S - 1:] euler_errors = result.fun b_s = np.append(0.0, b_sp1) # use market clearing L = agg.get_L(n_s, omega_SS) K = agg.get_K(b_s, omega_SS, imm_rates_SS) # find implied r r_prime = firm.get_r(L, K, alpha, A, delta) # find implied w w_prime = firm.get_w(r, alpha, A, delta) # check distance ss_dist_r = np.absolute(r - r_prime) ss_dist_w = np.absolute(w - w_prime) print('Iteration = ', ss_iter, ', Distance r = ', ss_dist_r, ', r = ', r, ', w = ', w) # update r r = xi * r_prime + (1 - xi) * r # update iteration counter ss_iter += 1 return r, w, b_sp1, euler_errors
def solve_ss(r_init, w_init, params): ''' Solves for the steady-state equlibrium of the OG model ''' beta, sigma, n, alpha, A, delta, xi = params ss_dist = 7.0 ss_tol = 1e-8 ss_iter = 0 ss_max_iter = 300 r = r_init w = w_init while (ss_dist > ss_tol) & (ss_iter < ss_max_iter): # solve HH problem foc_args = (beta, sigma, r, w, 0.0) n_s_guess = np.ones(S) b_sp1_guess = np.ones(S-1) * 0.5 HH_guess = np.append(b_sp1_guess, n_s_guess) result = opt.root(hh.FOCs, HH_guess, args=foc_args) b_sp1 = result.x[0: S-1] n_s = result.x[S-1:] euler_errors = result.fun b_s = np.append(0.0, b_sp1) # use market clearing L = agg.get_L(n) K = agg.get_K(b_s) # find implied r r_prime = firm.get_r(L, K, alpha, A, delta) # find implied w w_prime = firm.get_w(L, K, G, alpha, A) # check distance ss_dist_r = np.absolute(r - r_prime) ss_dist_w = np.absolute(w - w_prime) print('Iteration = ', ss_iter, ', Distance r = ', ss_dist_r, ', Disrance w = ' ss_dist_w, ', r = ', r, ', w = ', w) # update r r = xi * r_prime + (1 - xi) * r # update w w = xi * w_prime + (1 - xi) * w # update iteration counter ss_iter += 1 return r, w, b_sp1, euler_errors
def solve_ss(r_init, params): ''' Solves for the steady-state equlibrium of the OG model ''' beta, sigma, alpha, A, delta, xi, l_tilde, chi, theta, omega_SS, imm_rates_SS, rho_s, S = params ss_dist = 7.0 ss_tol = 1e-8 ss_iter = 0 ss_max_iter = 300 r = r_init while (ss_dist > ss_tol) & (ss_iter < ss_max_iter): # get w w = firm.get_w(r, alpha, A, delta) # solve HH problem foc_args = (beta, sigma, r, w, 0.0, l_tilde, chi, theta, omega_SS, rho_s) n_s_guess = np.ones(S) b_sp1_guess = np.ones(S-1) * 0.5 HH_guess = np.append(b_sp1_guess, n_s_guess) result = opt.root(hh.FOCs, HH_guess, args=foc_args) b_sp1 = result.x[0: S-1] n_s = result.x[S-1:] euler_errors = result.fun b_s = np.append(0.0, b_sp1) # use market clearing L = agg.get_L(n_s, omega_SS) K = agg.get_K(b_s, omega_SS, imm_rates_SS) # find implied r r_prime = firm.get_r(L, K, alpha, A, delta) # check distance ss_dist_r = np.absolute(r - r_prime) print('Iteration = ', ss_iter, ', Distance r = ', ss_dist_r, ', r = ', r) # update r r = xi * r_prime + (1 - xi) * r # update iteration counter ss_iter += 1 return ss_iter, r, w, b_sp1, euler_errors
def get_SS(args, graph=False): (init_vals, beta, sigma, chi_n_vec, l_tilde, b_ellip, upsilon, S, alpha, A, delta, etrparam_vec, mtrxparam_vec, mtryparam_vec, avg_inc_data) = args dist = 10 mindist = 1e-08 maxiter = 500 ss_iter = 0 xi = 0.2 r_params = (alpha, A, delta) w_params = (alpha, A) Y_params = (alpha, A) while dist > mindist and ss_iter < maxiter: ss_iter += 1 K, L, X = init_vals Y = aggr.get_Y(K, L, Y_params) factor = (S * avg_inc_data) / (Y - delta * K) r = firms.get_r(K, L, r_params) w = firms.get_w(K, L, w_params) c1_guess = 0.1 c1_args = (r, w, X, factor, beta, sigma, chi_n_vec, l_tilde, b_ellip, upsilon, S, etrparam_vec, mtrxparam_vec, mtryparam_vec) results_c1 = opt.root(hh.get_bSp1, c1_guess, args=(c1_args)) c1 = results_c1.x cvec, nvec, bvec = hh.get_cnbvecs(c1, c1_args) # print('cvec: ', cvec) # print('nvec: ', nvec) # print('bvec: ', bvec) bs_vec = np.append(0, bvec[:-1]) K_new = max(aggr.get_K(bvec[:-1]), 0.001) L_new = max(aggr.get_L(nvec), 0.001) lab_inc = w * nvec cap_inc = r * bs_vec tot_tax_liab_all = tax.get_tot_tax_liab(lab_inc, cap_inc, factor, etrparam_vec) X_new = (1 / S) * (tot_tax_liab_all.sum()) # factor_new = avg_inc_data / ((1 / S) * # (r * bs_vec + w * nvec).sum()) new_vals = np.array([K_new, L_new, X_new]) dist = ((((new_vals - init_vals) / init_vals) * 100)**2).sum() init_vals = xi * new_vals + (1 - xi) * init_vals print('iter:', ss_iter, ' dist: ', dist) print(init_vals) c_ss = cvec n_ss = nvec b_ss = bs_vec K_ss = K_new L_ss = L_new r_ss = r w_ss = w Y_params = (alpha, A) Y_ss = aggr.get_Y(K_ss, L_ss, Y_params) C_ss = aggr.get_C(c_ss) X_ss = X_new factor_ss = factor tot_tax_liab_all_ss = tot_tax_liab_all tot_tax_liab_ss = X_ss * S ss_output = { 'c_ss': c_ss, 'n_ss': n_ss, 'b_ss': b_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'r_ss': r_ss, 'w_ss': w_ss, 'Y_ss': Y_ss, 'C_ss': C_ss, 'X_ss': X_ss, 'factor_ss': factor_ss, 'tot_tax_liab_all_ss': tot_tax_liab_all_ss, 'tot_tax_liab_ss': tot_tax_liab_ss } if graph: # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = 'images' output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot c_ss, n_ss, b_ss # Plot steady-state consumption and savings distributions age_pers = np.arange(1, S + 1) fig, ax = plt.subplots() plt.plot(age_pers, c_ss, marker='D', label='Consumption') plt.plot(age_pers, np.append(0, b_ss[:-1]), marker='D', label='Savings') # for the minor ticks, use no labels; default NullFormatter minorLocator = MultipleLocator(1) ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') # plt.title('Steady-state consumption and savings', fontsize=20) plt.xlabel(r'Age $s$') plt.ylabel(r'Units of consumption') plt.xlim((0, S + 1)) # plt.ylim((-1.0, 1.15 * (b_ss.max()))) plt.legend(loc='upper left') output_path = os.path.join(output_dir, 'SS_bc') plt.savefig(output_path) # plt.show() plt.close() # Plot steady-state labor supply distributions fig, ax = plt.subplots() plt.plot(age_pers, n_ss, marker='D', label='Labor supply') # for the minor ticks, use no labels; default NullFormatter minorLocator = MultipleLocator(1) ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') # plt.title('Steady-state labor supply', fontsize=20) plt.xlabel(r'Age $s$') plt.ylabel(r'Labor supply') plt.xlim((0, S + 1)) # plt.ylim((-0.1, 1.15 * (n_ss.max()))) plt.legend(loc='upper right') output_path = os.path.join(output_dir, 'SS_n') plt.savefig(output_path) # plt.show() plt.close() return ss_output
def solve_tp(g_n_path, omega_S_preTP, rho_s, imm_rates_path, omega_SS, omega_path_S, params): ''' Solves for the time path equilibrium using TPI ''' # Missing some elements of params b_ss, r_ss, n_s, r_11, alpha, A, delta, beta, sigma, T, S = params dist = 8.0 mindist = 1e-08 maxiter = 300 tpi_iter = 0 xi = 0.2 while dist > mindist and tpi_iter < maxiter: # Define paths b_11 = 1.1 * b_ss BQ_params = (g_n_path[0], omega_S_preTP, rho_s) K_params = (g_n_path[0], omega_S_preTP, imm_rates_path[0, :]) BQ_11 = agg.get_BQ(b_11, r_11, BQ_params, method = "TPI") BQ_ss = agg.get_BQ(b_ss, r_ss, BQ_params, method = "SS") K_11 = agg.get_K(b_11, K_params) BQpath_init = np.zeros(T + S - 1) BQpath_init[:T] = np.linspace(BQ_11, BQ_ss, T) BQpath_init[T:] = BQ_ss L_ss = agg.get_L(n_s, omega_SS) r_11 = firm.get_r(L_ss, K_11, alpha, A, delta) # I can't figure out how r_11 and r_path differ ''' Is r_11 an initial guess? Depending on how you're defining r_11, the arguments passed to the function call above and below will vary ''' r_path = firm.get_r(L_ss, K_11, alpha, A, delta) w_path = firm.get_w(r_path, alpha, A, delta) bmat = np.zeros((S - 1, T + S - 1)) # What is b_1 supposed to be? bmat[:, 0] = b_1 # Solve for households for p in range(2, S): b_guess = np.diagonal(bmat[S - p:, :p - 1]) b_init = bmat[S - p - 1, 0] b_params = (b_init, n_s[-p:], r_path[:p], w_path[:p], BQpath_init[:p], rho_s[-p:], beta, sigma) results_bp = opt.root(hh.FOCs, b_guess, args=(b_params)) b_solve_p = results_bp.x DiagMaskbp = np.eye(p - 1, dtype=bool) bmat[S - p:, 1:p] = DiagMaskbp * b_solve_p + bmat[S - p:, 1:p] for t in range(1, T + 1): b_guess = np.diagonal(bmat[:, t - 1:t + S - 2]) b_init = 0.0 b_params = (b_init, n_s, r_path[t - 1:t + S - 1], w_path[t - 1:t + S - 1], BQpath_init[t - 1:t + S - 1], rho_s, beta, sigma) results_bt = opt.root(hh.FOCs, b_guess, args=(b_params)) b_solve_t = results_bt.x DiagMaskbt = np.eye(S - 1, dtype=bool) bmat[:, t:t + S - 1] = (DiagMaskbt * b_solve_t + bmat[:, t:t + S - 1]) new_Kpath = np.zeros(T) new_Kpath[0] = K_11 new_Kpath[1:] = \ (1 / (omega_path_S[:T - 1, :-1]) * bmat[:, 1:T].T + imm_rates_path[:T - 1, 1:] * omega_path_S[:T - 1, 1:] * bmat[:, 1:T].T).sum(axis=1) new_BQpath = np.zeros(T) new_BQpath[0] = BQ_11 new_BQpath[1:] = \ ((1 + r_path[1:T]) / (rho_s[:-1]) * omega_path_S[:T - 1, :-1] * bmat[:, 1:T].T).sum(axis=1) dist = ((BQ_init - new_BQ) ** 2).sum() BQpath_init[:T] = xi * new_BQpath[:T] + (1 - xi) * BQpath_init[:T] # update iteration counter tpi_iter += 1 if tpi_iter < maxiter: print('The time path solved! ->', ' iter:', tpi_iter, ', dist: ', dist) else: print('The time path did not solve.') return [new_Kpath, new_BQpath]
def inner_loop(r, w, args): ''' -------------------------------------------------------------------- Given values for r and w, solve for equilibrium errors from the two first order conditions of the firm -------------------------------------------------------------------- INPUTS: r = scalar > 0, guess at steady-state interest rate w = scalar > 0, guess at steady-state wage args = length 16 tuple, (c1_init, J, S, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, Z, gamma, delta, SS_tol, c1_options) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.c1_bSp1err() hh.get_cnb_mats() aggr.get_K() aggr.get_L() firms.get_r() firms.get_w() OBJECTS CREATED WITHIN FUNCTION: c1_init = (J,) vector, initial guess for c1 J = integer >= 1, number of heterogeneous ability groups S = integer in [3, 80], number of periods an individual lives lambdas = (J,) vector, income percentiles for distribution of ability within each cohort emat = (S, J) matrix, lifetime ability profiles for each lifetime income group j beta = scalar in (0,1), discount factor sigma = scalar >= 1, coefficient of relative risk aversion l_tilde = scalar > 0, per-period time endowment for every agent b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s scales disutility of labor supply Z = scalar > 0, total factor productivity parameter in firms' production function gamma = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital SS_tol = scalar > 0, tolerance level for steady-state fsolve c1_options = length 1 dict, options for c1_bSp1err() rpath = (S,) vector, lifetime path of interest rates wpath = (S,) vector, lifetime path of wages c1_args = length 11 tuple, args to pass into hh.c1_bSp1err() results_c1 = results object, results from opt.root(c1_bSp1err,...) c1vec = (J,) vector, optimal initial period consumption for all J types given r and w cnb_args = length 9 tuple, args to pass into get_cnb_mats() cmat = (S, J) matrix, household lifetime consumption (c_j1, c_j2, ...c_jS) nmat = (S, J) matrix, household lifetime labor supply (n_j1, n_j2, ...n_jS) bmat = (S, J) matrix, household lifetime savings (b_j1, b_j2, ...b_jS) with b1=0 b_Sp1_vec = (J,) vector, final period savings, should be close to 0 n_err_mat = (S, J) vector, labor supply Euler errors b_err_mat = (S, J) vector, savings Euler errors K = scalar > 0, aggregate capital stock K_cstr = boolean, =True if K < epsilon L = scalar > 0, aggregate labor L_cstr = boolean, =True if L < epsilon rw_params = length 3 tuple, (Z, gamma, delta) r_new = scalar > 0, guess at steady-state interest rate w_new = scalar > 0, guess at steady-state wage FILES CREATED BY THIS FUNCTION: None RETURNS: K, L, cmat, nmat, bmat, b_Sp1_vec, r_new, w_new, n_err_mat, b_err_mat -------------------------------------------------------------------- ''' (c1_init, J, S, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, Z, gamma, delta, SS_tol, c1_options) = args rpath = r * np.ones(S) wpath = w * np.ones(S) c1_args = (np.zeros(J), emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, rpath, wpath, SS_tol) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=SS_tol, options=(c1_options)) c1vec = results_c1.x cnb_args = (np.zeros(J), emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, SS_tol) cmat, nmat, bmat, b_Sp1_vec, n_err_mat, b_err_mat = \ hh.get_cnb_mats(c1vec, rpath, wpath, cnb_args) K, K_cstr = aggr.get_K(bmat, lambdas) L, L_cstr = aggr.get_L(nmat, lambdas, emat) rw_params = (Z, gamma, delta) r_new = firms.get_r(K, L, rw_params) w_new = firms.get_w(r_new, rw_params) return (K, L, cmat, nmat, bmat, b_Sp1_vec, r_new, w_new, n_err_mat, b_err_mat)
tpi_paramsfile = os.path.join(tpi_output_dir, 'tpi_args.pkl') r_ss = ss_output['r_ss'] K_ss = ss_output['K_ss'] L_ss = ss_output['L_ss'] C_ss = ss_output['C_ss'] b_ss = ss_output['b_ss'] n_ss = ss_output['n_ss'] # Choose initial period distribution of wealth (bmat1), which # determines initial period aggregate capital stock init_wgts = 0.95 * np.ones((S, J)) bmat1 = init_wgts * b_ss # Make sure init. period distribution is feasible in terms of K K1, K1_cstr = aggr.get_K(bmat1, lambdas) # If initial bvec1 is not feasible end program if K1_cstr: print('Initial savings distribution is not feasible because ' + 'K1<epsilon. Some element(s) of bmat1 must increase.') else: tpi_params = (J, S, T1, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter_TPI, mindist_TPI, TPI_tol, xi_TPI, TPI_EulDiff) tpi_output = tpi.get_TPI(tpi_params, bmat1, TPI_graphs) tpi_args = (J, S, T1, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter_TPI,
def get_TPI(b1vec, ss_params, params): # r_guess: guess of interest rate path from period 1 to T1 beta, sigma, S, ltilde, b, upsilon, chi_n_vec, A, alpha, delta, tpi_max_iter, tpi_tol, xi_tpi, T1, T2 = params r_ss, w_ss, c_ss, n_ss, b_ss, K_ss, L_ss = ss_params abs_tpi = 1 tpi_iter = 0 rpath_old = np.zeros(T2 + S - 1) rpath_old[:T1] = get_path(r_ss, r_ss, T1, 'quadratic') rpath_old[T1:] = r_ss while abs_tpi > tpi_tol and tpi_iter < tpi_max_iter: c1_guess = 1.0 tpi_iter += 1 wpath_old = firms.get_w(rpath_old, (A, alpha, delta)) bmat = np.zeros((S, T2 + S - 1)) bmat[:, 0] = b1vec bmat[:, T2:] = np.matlib.repmat(b_ss, S - 1, 1).T nmat = np.zeros((S, T2 + S - 1)) nmat[:, T2:] = np.matlib.repmat(n_ss, S - 1, 1).T cmat = np.zeros((S, T2 + S - 1)) cmat[:, T2:] = np.matlib.repmat(c_ss, S - 1, 1).T # Solve the incomplete remaining lifetime decisions of agents alive # in period t=1 but not born in period t=1 for p in range(S): # p is remaining periods of life c1_args = (rpath_old[:p + 1], wpath_old[:p + 1], beta, sigma, ltilde, b, upsilon, chi_n_vec[S - p - 1:], p + 1, b1vec[S - p - 1]) result_c1 = opt.root(hh.get_b_last, c1_guess, args = (c1_args)) if result_c1.success: c1 = result_c1.x else: raise ValueError("failed to find an appropriate initial consumption") # Calculate aggregate supplies for capital and labor cvec = hh.get_c(c1, rpath_old[:p + 1], beta, sigma, p + 1) nvec = hh.get_n(cvec, sigma, ltilde, b, upsilon, chi_n_vec[S - p - 1: ], wpath_old[:p + 1], p + 1) bvec = hh.get_b(cvec, nvec, rpath_old[:p + 1], wpath_old[:p + 1], p + 1, bs = b1vec[S - p - 1])[1:] # Insert the vector lifetime solutions diagonally (twist donut) DiagMaskbp = np.eye(p) bp_path = DiagMaskbp * bvec bmat[S - p:, 1:p + 1] += bp_path DiagMasknp = np.eye(p + 1) np_path = DiagMasknp * nvec nmat[S - p - 1:, :p + 1] += np_path DiagMaskcp = np.eye(p + 1) cp_path = DiagMaskcp * cvec cmat[S - p - 1:, :p + 1] += cp_path # Solve for complete lifetime decisions of agents born in periods # 1 to T2 and insert the vector lifetime solutions diagonally (twist # donut) into the cpath, bpath, and EulErrPath matrices for t in range(1, T2): c1_args = (rpath_old[t: S + t], wpath_old[t: S + t], beta, sigma, ltilde, b, upsilon, chi_n_vec, S, 0.0) result_c1 = opt.root(hh.get_b_last, c1_guess, args = (c1_args)) if result_c1.success: c1 = result_c1.x else: raise ValueError("failed to find an appropriate initial consumption") # Calculate aggregate supplies for capital and labor cvec = hh.get_c(c1, rpath_old[t : S + t], beta, sigma, S) nvec = hh.get_n(cvec, sigma, ltilde, b, upsilon, chi_n_vec, wpath_old[t: S + t], S) bvec = hh.get_b(cvec, nvec, rpath_old[t: S + t], wpath_old[t: S + t], S) DiagMaskbt = np.eye(S) bt_path = DiagMaskbt * bvec bmat[:, t: t + S] += bt_path DiagMasknt = np.eye(S) nt_path = DiagMasknt * nvec nmat[:, t: t + S] += nt_path DiagMaskct = np.eye(S) ct_path = DiagMaskct * cvec cmat[:, t: t + S] += ct_path bmat[:, T2:] = np.matlib.repmat(b_ss, S - 1, 1).T nmat[:, T2:] = np.matlib.repmat(n_ss, S - 1, 1).T cmat[:, T2:] = np.matlib.repmat(c_ss, S - 1, 1).T K = aggr.get_K(bmat)[0] L = aggr.get_L(nmat)[0] Y = aggr.get_Y(K, L, (A, alpha)) C = aggr.get_C(cmat) rpath_new = firms.get_r(K, L, (A, alpha, delta)) # Calculate the implied capital stock from conjecture and the error abs_tpi = ((rpath_old[:T2] - rpath_new[:T2]) ** 2).sum() # Update guess rpath_old[:T2] = xi_tpi * rpath_new[:T2] + (1 - xi_tpi) * rpath_old[:T2] b_err = np.zeros(T2 + S - 1) n_err = np.zeros(T2 + S - 1) b_last = bmat[S-1, :] for i in range(T2 + S - 1): b_err[i] = abs(hh.get_b_errors(cmat[:, i], rpath_old[i], beta, sigma)).max() n_err[i] = abs(hh.get_n_errors(nmat[:, i], cmat[:, i], sigma, ltilde, b, upsilon, chi_n_vec, wpath_old[i])).max() Rc_err = Y[:-1] - C[:-1] - K[1:] + (1 - delta) * K[:-1] print('iteration:', tpi_iter, ' squared distance: ', abs_tpi) k_first = [k for k in K if abs(k - K_ss) < 0.00001][0] T1 = np.where(K == k_first)[0][0] return cmat, nmat, bmat, rpath_old, wpath_old, K, L, Y, C, b_err, n_err, b_last, Rc_err, T1
def get_SS(init_vals, args, graphs=False): ''' -------------------------------------------------------------------- Solve for the steady-state solution of the S-period-lived agent OG model with endogenous labor supply using the bisection method in K and L for the outer loop -------------------------------------------------------------------- INPUTS: init_vals = length 3 tuple, (r_init, c1_init, factor_init) args = length 19 tuple, (J, S, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec_hat, Z, gamma, delta, Bsct_Tol, Eul_Tol, xi, maxiter, mean_ydata, init_calc) graphs = boolean, =True if output steady-state graphs OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: firms.get_r() firms.get_w() utils.print_time() inner_loop() creat_graphs() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar > 0, clock time at beginning of program r_init = scalar > -delta, initial guess for steady-state interest rate c1_init = (J,) vector, initial guess for first period consumption by all J ability types factor_init = scalar > 0, initial guess for factor that scales model units to data units J = integer >= 1, number of heterogeneous ability groups S = integer in [3, 80], number of periods an individual lives lambdas = (J,) vector, income percentiles for distribution of ability within each cohort emat = (S, J) matrix, lifetime ability profiles for each lifetime income group j beta = scalar in (0,1), discount factor for each model per sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment of each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec_hat = (S,) vector, values for chi^n_s hat from data Z = scalar > 0, total factor productivity parameter in firms' production function gamma = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital Bsct_Tol = scalar > 0, tolerance level for outer-loop bisection method Eul_Tol = scalar > 0, tolerance level for inner-loop root finder xi = scalar in (0, 1], SS updating parameter in outer- loop bisection method maxiter = integer >= 1, maximum number of iterations in outer- loop bisection method mean_ydata = scalar > 0, average household income from the data init_calc = boolean, =True if initial steady-state calculation with chi_n_vec = 1 for all s iter_SS = integer >= 0, index of iteration number dist = scalar > 0, distance metric for current iteration c1_options = length 1 dict, options to pass into opt.root(c1_bSp1err,...) rw_params = length 3 tuple, (Z, gamma, delta) args to pass into firms.get_w() c1ss_init = (J,) vector, initial guess for css_{j,1}, updates each iteration lambda_mat = (S, J) matrix, lambdas vector copied down S rows w_init = scalar, initial value for wage chi_n_vec = (S,) vector, chi^n_s values that scale the disutility of labor supply inner_args = length 16 tuple, args to pass into inner_loop() K_new = scalar > 0, updated K given r_init and w_init L_new = scalar > 0, updated L given r_init and w_init cmat = (S, J) matrix, lifetime household consumption by age s and ability j nmat = (S, J) matrix, lifetime household labor supply by age s and ability j bmat = (S, J) matrix, lifetime household savings by age s and ability j (b1, b2,...bS) b_Sp1_vec = (J,) vector, household savings in last period for each ability type, should be arbitrarily close to 0 r_new = scalar > 0, updated interest rate given nmat, bmat w_new = scalar > 0, updated wage given nmat and bmat n_err_mat = (S, J) matrix, labor supply Euler errors given r_init and w_init b_err_mat = (S, J) matrix, savings Euler errors given r_init and w_init. First row is identically zeros all_errors = (2JS + J,) vector, (n_errors, b_errors, b_Sp1_vec) avg_inc_model = scalar > 0, average household income in model factor_new = scalar > 0, updated factor value given nmat, bmat, r_new, and w_new c_ss = (S, J) matrix, steady-state lifetime consumption n_ss = (S, J) matrix, steady-state lifetime labor supply b_ss = (S, J) matrix, steady-state wealth (savings) at beginning of each period (b1, b2, ...bS) b_Sp1_ss = (J,) vector, steady-state savings in last period of life for all J ability types, approx. 0 in equilbrm n_err_ss = (S, J) matrix, lifetime labor supply Euler errors b_err_ss = (S, J) matrix, lifetime savings Euler errors r_ss = scalar > 0, steady-state interest rate w_ss = scalar > 0, steady-state wage K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor Y_params = length 2 tuple, (Z, gamma) Y_ss = scalar > 0, steady-state aggregate output (GDP) C_ss = scalar > 0, steady-state aggregate consumption RCerr_ss = scalar, resource constraint error ss_time = scalar, seconds elapsed for steady-state computation ss_output = length 16 dict, steady-state objects {c_ss, n_ss, b_ss, b_Sp1_ss, w_ss, r_ss, K_ss, L_ss, Y_ss, C_ss, n_err_ss, b_err_ss, RCerr_ss, ss_time, chi_n_vec, factor_ss} FILES CREATED BY THIS FUNCTION: None RETURNS: ss_output -------------------------------------------------------------------- ''' start_time = time.clock() r_init, BQ_init, factor_init, bmat_init, nmat_init = init_vals (J, E, S, lambdas, emat, mort_rates, imm_rates, omega_SS, g_n_SS, zeta_mat, chi_n_vec_hat, chi_b_vec, beta, sigma, l_tilde, b_ellip, upsilon, g_y, Z, gamma, delta, SS_tol_outer, SS_tol_inner, xi, maxiter, mean_ydata, init_calc) = args iter_SS = 0 dist = 10 rw_params = (Z, gamma, delta) BQ_args = (lambdas, omega_SS, mort_rates, g_n_SS) lambda_mat = np.tile(lambdas.reshape((1, J)), (S, 1)) omega_mat = np.tile(omega_SS.reshape((S, 1)), (1, J)) while (iter_SS < maxiter) and (dist >= SS_tol_outer): iter_SS += 1 w_init = firms.get_w(r_init, rw_params) if init_calc: print('Factor init is one. No modification performed to ' + 'chi_n_vec. Dist calculated without factor.') chi_n_vec = chi_n_vec_hat else: chi_n_vec = chi_n_vec_hat * (factor_init**(sigma - 1)) rpath = r_init * np.ones(S) wpath = w_init * np.ones(S) BQpath = BQ_init * np.ones(S) cnb_args = (S, lambdas, emat, mort_rates, omega_SS, zeta_mat, chi_n_vec, chi_b_vec, beta, sigma, l_tilde, b_ellip, upsilon, g_y, g_n_SS, SS_tol_inner) cmat, nmat, bmat, n_err_mat, b_err_mat = \ hh.get_cnb_mats(bmat_init, nmat_init, np.zeros(J), rpath, wpath, BQpath, cnb_args) K_args = (lambdas, omega_SS, imm_rates, g_n_SS) K_new, K_cstr = aggr.get_K(bmat, K_args) L_args = (emat, lambdas, omega_SS) L_new, L_cstr = aggr.get_L(nmat, L_args) r_new = firms.get_r(K_new, L_new, rw_params) w_new = firms.get_w(r_new, rw_params) BQ_new = aggr.get_BQ(bmat, r_new, BQ_args) all_errors = \ np.hstack((b_err_mat.flatten(), n_err_mat.flatten())) if init_calc: dist = max(np.absolute((r_new - r_init) / r_init), np.absolute((BQ_new - BQ_init) / BQ_init)) else: avg_inc_model = (omega_mat * lambda_mat * (r_new * bmat + w_new * emat * nmat)).sum() factor_new = mean_ydata / avg_inc_model print('mean_ydata: ', mean_ydata, ', avg_inc_model: ', avg_inc_model) print('r_new: ', r_new, 'BQ_new', BQ_new, 'factor_new: ', factor_new) dist = max(np.absolute((r_new - r_init) / r_init), np.absolute((BQ_new - BQ_init) / BQ_init), np.absolute((factor_new - factor_init) / factor_init)) factor_init = xi * factor_new + (1 - xi) * factor_init r_init = xi * r_new + (1 - xi) * r_init BQ_init = xi * BQ_new + (1 - xi) * BQ_init print('SS Iter=', iter_SS, ', SS Dist=', '%10.4e' % (dist), ', Max Abs Err=', '%10.4e' % (np.absolute(all_errors).max())) bmat_init = bmat nmat_init = nmat chi_n_vec = chi_n_vec_hat * (factor_init**(sigma - 1)) c_ss = cmat.copy() n_ss = nmat.copy() b_ss = bmat.copy() n_err_ss = n_err_mat.copy() b_err_ss = b_err_mat.copy() r_ss = r_new.copy() w_ss = w_new.copy() BQ_ss = BQ_new.copy() K_ss = K_new.copy() L_ss = L_new.copy() factor_ss = factor_init I_args = (lambdas, omega_SS, imm_rates, g_n_SS, g_y, delta) I_ss = aggr.get_I(b_ss, I_args) NX_args = (lambdas, omega_SS, imm_rates, g_y) NX_ss = aggr.get_NX(b_ss, NX_args) Y_params = (Z, gamma) Y_ss = aggr.get_Y(K_ss, L_ss, Y_params) C_args = (lambdas, omega_SS) C_ss = aggr.get_C(c_ss, C_args) RCerr_ss = Y_ss - C_ss - I_ss - NX_ss ss_time = time.clock() - start_time ss_output = { 'c_ss': c_ss, 'n_ss': n_ss, 'b_ss': b_ss, 'BQ_ss': BQ_ss, 'w_ss': w_ss, 'r_ss': r_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'I_ss': I_ss, 'Y_ss': Y_ss, 'C_ss': C_ss, 'NX_ss': NX_ss, 'n_err_ss': n_err_ss, 'b_err_ss': b_err_ss, 'RCerr_ss': RCerr_ss, 'ss_time': ss_time, 'chi_n_vec': chi_n_vec, 'factor_ss': factor_ss } print('n_ss is: ', n_ss) print('b_ss is: ', b_ss) print('c_ss is: ', c_ss) print('K_ss=', K_ss, ', L_ss=', L_ss, 'Y_ss=', Y_ss) print('r_ss=', r_ss, ', w_ss=', w_ss, 'C_ss=', C_ss) print('BQ_ss=', BQ_ss, ', I_ss=', I_ss, ', NX_ss=', NX_ss) print('Maximum abs. labor supply Euler error is: ', np.absolute(n_err_ss).max()) print('Maximum abs. savings Euler error is: ', np.absolute(b_err_ss).max()) print('Resource constraint error is: ', RCerr_ss) print('Final chi_n_vec from SS:', chi_n_vec) print('SS factor is: ', factor_ss) # Print SS computation time utils.print_time(ss_time, 'SS') if graphs: gr_args = (E, S, J, chi_n_vec, lambdas) create_graphs(c_ss, b_ss, n_ss, gr_args) return ss_output
def inner_loop(r, w, args): ''' -------------------------------------------------------------------- Given values for r and w, solve for the households' optimal decisions -------------------------------------------------------------------- INPUTS: r = scalar > 0, guess at steady-state interest rate w = scalar > 0, guess at steady-state wage args = length 14 tuple, (nvec_init, bvec_init, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, EulDiff, SS_tol) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: euler_sys() aggr.get_K() aggr.get_L() firms.get_r() firms.get_w() OBJECTS CREATED WITHIN FUNCTION: nvec_init = (S,) vector, initial guesses at choice of labor supply bvec_init = (S,) vector, initial guesses at choice of savings S = integer >= 3, number of periods in individual lifetime beta = scalar in (0,1), discount factor sigma = scalar >= 1, coefficient of relative risk aversion l_tilde = scalar > 0, per-period time endowment for every agent b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital EulDiff = boolean, =True if simple difference Euler errors, otherwise percent deviation Euler errors SS_tol = scalar > 0, tolerance level for steady-state fsolve cvec = (S,) vector, lifetime consumption (c1, c2, ...cS) nvec = (S,) vector, lifetime labor supply (n1, n2, ...nS) bvec = (S,) vector, lifetime savings (b1, b2, ...bS) with b1=0 b_Sp1 = scalar, final period savings, should be close to zero n_errors = (S,) vector, labor supply Euler errors b_errors = (S-1,) vector, savings Euler errors K = scalar > 0, aggregate capital stock K_cstr = boolean, =True if K < epsilon L = scalar > 0, aggregate labor L_cstr = boolean, =True if L < epsilon r_params = length 3 tuple, (A, alpha, delta) w_params = length 2 tuple, (A, alpha) r_new = scalar > 0, guess at steady-state interest rate w_new = scalar > 0, guess at steady-state wage FILES CREATED BY THIS FUNCTION: None RETURNS: K, L, cvec, nvec, bvec, b_Sp1, r_new, w_new, n_errors, b_errors -------------------------------------------------------------------- ''' (nmat_init, bmat_init, S, J, beta, sigma, emat, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, lambdas, EulDiff, SS_tol) = args nmat = np.zeros((S, J)) bmat = np.zeros((S - 1, J)) n_err_mat = np.zeros((S, J)) b_err_mat = np.zeros((S - 1, J)) for j in range(J): euler_args = (r, w, beta, sigma, emat[:, j], l_tilde, chi_n_vec, b_ellip, upsilon, EulDiff, S, SS_tol) guesses = np.append(nmat_init[:, j], bmat_init[:, j]) results_euler = opt.root(euler_sys, guesses, args=(euler_args), method='lm', tol=SS_tol) nmat[:, j] = results_euler.x[:S] bmat[:, j] = results_euler.x[S:] n_err_mat[:, j] = results_euler.fun[:S] b_err_mat[:, j] = results_euler.fun[S:] b_s_mat = np.append(np.zeros((1, J)), bmat, axis=0) b_sp1_mat = np.append(bmat, np.zeros((1, J)), axis=0) cmat = hh.get_cons(r, w, b_s_mat, b_sp1_mat, nmat, emat) b_Sp1_vec = np.zeros(J) K, K_cnstr = aggr.get_K(bmat, lambdas) L = aggr.get_L(nmat, emat, lambdas) r_params = (A, alpha, delta) r_new = firms.get_r(K, L, r_params) w_params = (A, alpha, delta) w_new = firms.get_w_from_r(r_new, w_params) return (K, L, cmat, nmat, bmat, b_Sp1_vec, r_new, w_new, n_err_mat, b_err_mat)
def get_SS(args, graph=False): (KL_init, beta, sigma, emat, chi_n_vec, l_tilde, b, upsilon, lambdas, S, J, alpha, A, delta) = args dist = 10 mindist = 1e-08 maxiter = 500 ss_iter = 0 xi = 0.2 r_params = (alpha, A, delta) w_params = (alpha, A) while dist > mindist and ss_iter < maxiter: ss_iter += 1 K, L = KL_init r = firms.get_r(K, L, r_params) w = firms.get_w(K, L, w_params) cmat = np.zeros((S, J)) nmat = np.zeros((S, J)) bmat = np.zeros((S, J)) c1 = 1.0 for j in range(J): c1_guess = c1 c1_args = (r, w, beta, sigma, chi_n_vec, l_tilde, b, upsilon, emat[:, j], S) results_c1 = opt.root(hh.get_bSp1, c1_guess, args=(c1_args)) c1 = results_c1.x cmat[:, j] = hh.get_recurs_c(c1, r, beta, sigma, S) nmat[:, j] = hh.get_n_s(cmat[:, j], w, sigma, chi_n_vec, l_tilde, b, upsilon, emat[:, j]) bmat[:, j] = hh.get_recurs_b(cmat[:, j], nmat[:, j], r, w, emat[:, j]) K_new = aggr.get_K(bmat[:-1, :], lambdas, S) L_new = aggr.get_L(nmat, emat, lambdas, S) KL_new = np.array([K_new, L_new]) dist = ((KL_new - KL_init)**2).sum() KL_init = xi * KL_new + (1 - xi) * KL_init print('iter:', ss_iter, ' dist: ', dist) c_ss = cmat n_ss = nmat b_ss = bmat K_ss = K_new L_ss = L_new r_ss = r w_ss = w Y_params = (alpha, A) Y_ss = aggr.get_Y(K_ss, L_ss, Y_params) C_ss = aggr.get_C(c_ss, lambdas, S) ss_output = { 'c_ss': c_ss, 'n_ss': n_ss, 'b_ss': b_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'r_ss': r_ss, 'w_ss': w_ss, 'Y_ss': Y_ss, 'C_ss': C_ss } if graph: ''' ---------------------------------------------------------------- cur_path = string, path name of current directory output_fldr = string, folder in current path to save files output_dir = string, total path of images folder output_path = string, path of file name of figure to be saved sgrid = (S,) vector, ages from 1 to S lamcumsum = (J,) vector, cumulative sum of lambdas vector jmidgrid = (J,) vector, midpoints of ability percentile bins smat = (J, S) matrix, sgrid copied down J rows jmat = (J, S) matrix, jmidgrid copied across S columns ---------------------------------------------------------------- ''' # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = 'images' output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot 3D steady-state consumption distribution sgrid = np.arange(1, S + 1) lamcumsum = lambdas.cumsum() jmidgrid = 0.5 * lamcumsum + 0.5 * (lamcumsum - lambdas) smat, jmat = np.meshgrid(sgrid, jmidgrid) cmap_c = cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'indiv. consumption $c_{j,s}$') ax.plot_surface(smat, jmat, c_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'c_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state consumption distribution minorLocator = MultipleLocator(1) fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, c_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, c_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'indiv. consumption $c_{j,s}$') output_path = os.path.join(output_dir, 'c_ss_2D') plt.savefig(output_path) # plt.show() plt.close() # Plot 3D steady-state labor supply distribution fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'labor supply $n_{j,s}$') ax.plot_surface(smat, jmat, n_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'n_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state labor supply distribution minorLocator = MultipleLocator(1) fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, n_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, n_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'labor supply $n_{j,s}$') output_path = os.path.join(output_dir, 'n_ss_2D') plt.savefig(output_path) # plt.show() plt.close() # Plot 3D steady-state savings/wealth distribution fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'indiv. savings $b_{j,s}$') ax.plot_surface(smat, jmat, b_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'b_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state savings/wealth distribution fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, b_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, b_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'indiv. savings $b_{j,s}$') output_path = os.path.join(output_dir, 'b_ss_2D') plt.savefig(output_path) # plt.show() plt.close() return ss_output
def feasible(bvec, params): ''' -------------------------------------------------------------------- Check whether a vector of steady-state savings is feasible in that it satisfies the nonnegativity constraints on consumption in every period c_s > 0 and that the aggregate capital stock is strictly positive K > 0 -------------------------------------------------------------------- INPUTS: bvec = (S-1,) vector, household savings b_{s+1} params = length 4 tuple, (nvec, A, alpha, delta) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: get_L() get_K() get_w() get_r() get_cvec() OBJECTS CREATED WITHIN FUNCTION: nvec = (S,) vector, exogenous labor supply values n_s A = scalar > 0, total factor productivity alpha = scalar in (0, 1), capital share of income delta = scalar in (0, 1), per-period depreciation rate S = integer >= 3, number of periods in individual life L = scalar > 0, aggregate labor K = scalar, steady-state aggregate capital stock K_cstr = boolean, =True if K <= 0 w_params = length 2 tuple, (A, alpha) w = scalar, steady-state wage r_params = length 3 tuple, (A, alpha, delta) r = scalar, steady-state interest rate bvec2 = (S,) vector, steady-state savings distribution plus initial period wealth of zero cvec = (S,) vector, steady-state consumption by age c_cnstr = (S,) Boolean vector, =True for elements for which c_s<=0 b_cnstr = (S-1,) Boolean, =True for elements for which b_s causes a violation of the nonnegative consumption constraint FILES CREATED BY THIS FUNCTION: None RETURNS: b_cnstr, c_cnstr, K_cnstr -------------------------------------------------------------------- ''' nvec, A, alpha, delta = params S = nvec.shape[0] L = aggr.get_L(nvec) K, K_cstr = aggr.get_K(bvec) if not K_cstr: w_params = (A, alpha) w = firms.get_w(K, L, w_params) r_params = (A, alpha, delta) r = firms.get_r(K, L, r_params) c_params = (nvec, r, w) cvec = hh.get_cons(bvec, 0.0, c_params) c_cstr = cvec <= 0 b_cstr = c_cstr[:-1] + c_cstr[1:] else: c_cstr = np.ones(S, dtype=bool) b_cstr = np.ones(S - 1, dtype=bool) return c_cstr, K_cstr, b_cstr
def get_TPI(bvec1, args, graphs): ''' -------------------------------------------------------------------- Solves for transition path equilibrium using time path iteration (TPI) -------------------------------------------------------------------- INPUTS: bvec1 = (S,) vector, initial period savings distribution args = length 22 tuple, (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter, Out_Tol, In_Tol, EulDiff, xi) graphs = Boolean, =True if want graphs of TPI objects OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: aggr.get_K() get_path() firms.get_r() firms.get_w() inner_loop() solve_bn_path() aggr.get_L() aggr.get_Y() aggr.get_C() utils.print_time() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar, current processor time in seconds (float) S = integer in [3,80], number of periods an individual lives T1 = integer > S, number of time periods until steady state is assumed to be reached T2 = integer > T1, number of time periods after which steady-state is forced in TPI beta = scalar in (0,1), discount factor for model period sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment for each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], per-period capital depreciation rt r_ss = scalar > 0, steady-state aggregate interest rate K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor C_ss = scalar > 0, steady-state aggregate consumption b_ss = (S,) vector, steady-state savings distribution (b1, b2,... bS) n_ss = (S,) vector, steady-state labor supply distribution (n1, n2,... nS) maxiter = integer >= 1, Maximum number of iterations for TPI mindist = scalar > 0, convergence criterion for TPI TPI_tol = scalar > 0, tolerance level for TPI root finders xi = scalar in (0,1], TPI path updating parameter diff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 K1 = scalar > 0, initial aggregate capital stock K1_cnstr = Boolean, =True if K1 <= 0 rpath_init = (T2+S-1,) vector, initial guess for the time path of interest rates iter_TPI = integer >= 0, current iteration of TPI dist = scalar >= 0, distance measure between initial and new paths rw_params = length 3 tuple, (A, alpha, delta) Y_params = length 2 tuple, (A, alpha) cnb_params = length 11 tuple, args to pass into inner_loop() rpath = (T2+S-1,) vector, time path of the interest rates wpath = (T2+S-1,) vector, time path of the wages ind = (S,) vector, integers from 0 to S bn_args = length 14 tuple, arguments to be passed to solve_bn_path() cpath = (S, T2+S-1) matrix, time path of distribution of individual consumption c_{s,t} npath = (S, T2+S-1) matrix, time path of distribution of individual labor supply n_{s,t} bpath = (S, T2+S-1) matrix, time path of distribution of individual savings b_{s,t} n_err_path = (S, T2+S-1) matrix, time path of distribution of individual labor supply Euler errors b_err_path = (S, T2+S-1) matrix, time path of distribution of individual savings Euler errors. First column and first row are identically zero bSp1_err_path = (S, T2) matrix, residual last period savings, which should be close to zero in equilibrium. Nonzero elements of matrix should only be in first column and first row Kpath_new = (T2+S-1,) vector, new path of the aggregate capital stock implied by household and firm optimization Kpath_cnstr = (T2+S-1,) Boolean vector, =True if K_t<=0 Lpath_new = (T2+S-1,) vector, new path of the aggregate labor rpath_new = (T2+S-1,) vector, updated time path of interest rate wpath_new = (T2+S-1,) vector, updated time path of the wages Ypath = (T2+S-1,) vector, equilibrium time path of aggregate output (GDP) Y_t Cpath = (T2+S-1,) vector, equilibrium time path of aggregate consumption C_t RCerrPath = (T2+S-2,) vector, equilibrium time path of the resource constraint error: Y_t - C_t - K_{t+1} + (1-delta)*K_t Kpath = (T2+S-1,) vector, equilibrium time path of aggregate capital stock K_t Lpath = (T2+S-1,) vector, equilibrium time path of aggregate labor L_t tpi_time = scalar, time to compute TPI solution (seconds) tpi_output = length 14 dictionary, {cpath, npath, bpath, wpath, rpath, Kpath, Lpath, Ypath, Cpath, bSp1_err_path, n_err_path, b_err_path, RCerrPath, tpi_time} FILES CREATED BY THIS FUNCTION: Kpath.png Lpath.png Ypath.png C_aggr_path.png wpath.png rpath.png cpath.png npath.png bpath.png RETURNS: tpi_output -------------------------------------------------------------------- ''' start_time = time.clock() (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter, Out_Tol, In_Tol, EulDiff, xi) = args K1, K1_cnstr = aggr.get_K(bvec1) # Create time path for r rpath_init = np.zeros(T2 + S - 1) rpath_init[:T1] = get_path(r_ss, r_ss, T1, 'quadratic') rpath_init[T1:] = r_ss iter_TPI = int(0) dist = 10.0 rw_params = (A, alpha, delta) Y_params = (A, alpha) cnb_args = (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, n_ss, In_Tol, EulDiff) while (iter_TPI < maxiter) and (dist >= Out_Tol): iter_TPI += 1 rpath = rpath_init wpath = firms.get_w(rpath_init, rw_params) cpath, npath, bpath, n_err_path, b_err_path = \ inner_loop(rpath, wpath, cnb_args) Kpath_new = np.zeros(T2 + S - 1) Kpath_new[:T2], Kpath_cstr = aggr.get_K(bpath[:, :T2]) Kpath_new[T2:] = K_ss Kpath_cstr = np.append(Kpath_cstr, np.zeros(S - 1, dtype=bool)) Lpath_new = np.zeros(T2 + S - 1) Lpath_new[:T2], Lpath_cstr = aggr.get_L(npath[:, :T2]) Lpath_new[T2:] = L_ss Lpath_cstr = np.append(Lpath_cstr, np.zeros(S - 1, dtype=bool)) rpath_new = firms.get_r(Kpath_new, Lpath_new, rw_params) wpath = firms.get_w(rpath_new, rw_params) Ypath = aggr.get_Y(Kpath_new, Lpath_new, Y_params) Cpath = np.zeros(T2 + S - 1) Cpath[:T2] = aggr.get_C(cpath[:, :T2]) Cpath[T2:] = C_ss RCerrPath = (Ypath[:-1] - Cpath[:-1] - Kpath_new[1:] + (1 - delta) * Kpath_new[:-1]) # Check the distance of rpath_new dist = (np.absolute(rpath_new[:T2] - rpath_init[:T2])).sum() print( 'TPI iter: ', iter_TPI, ', dist: ', "%10.4e" % (dist), ', max abs all errs: ', "%10.4e" % (np.absolute( np.hstack( (b_err_path.max(axis=0), n_err_path.max(axis=0)))).max())) # The resource constraint does not bind across the transition # path until the equilibrium is solved rpath_init[:T2] = (xi * rpath_new[:T2] + (1 - xi) * rpath_init[:T2]) if (iter_TPI == maxiter) and (dist > Out_Tol): print('TPI reached maxiter and did not converge.') elif (iter_TPI == maxiter) and (dist <= Out_Tol): print('TPI converged in the last iteration. ' + 'Should probably increase maxiter_TPI.') Kpath = Kpath_new Lpath = Lpath_new tpi_time = time.clock() - start_time tpi_output = { 'cpath': cpath, 'npath': npath, 'bpath': bpath, 'wpath': wpath, 'rpath': rpath, 'Kpath': Kpath, 'Lpath': Lpath, 'Ypath': Ypath, 'Cpath': Cpath, 'n_err_path': n_err_path, 'b_err_path': b_err_path, 'RCerrPath': RCerrPath, 'tpi_time': tpi_time } # Print maximum resource constraint error. Only look at resource # constraint up to period T2 - 1 because period T2 includes K_{t+1}, # which was forced to be the steady-state print('Max abs. RC error: ', "%10.4e" % (np.absolute(RCerrPath[:T2 - 1]).max())) # Print TPI computation time utils.print_time(tpi_time, 'TPI') if graphs: graph_args = (S, T2) create_graphs(tpi_output, graph_args) return tpi_output
def get_SS_bsct(init_vals, args, graphs=False): ''' -------------------------------------------------------------------- Solve for the steady-state solution of the S-period-lived agent OG model with endogenous labor supply using the bisection method for the outer loop -------------------------------------------------------------------- INPUTS: init_vals = length 3 tuple, (Kss_init, Lss_init, c1_init) args = length 15 tuple, (J, S, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, SS_tol, EulDiff) graphs = boolean, =True if output steady-state graphs OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: firms.get_r() firms.get_w() hh.bn_solve() hh.c1_bSp1err() hh.get_cnb_vecs() aggr.get_K() aggr.get_L() aggr.get_Y() aggr.get_C() hh.get_cons() hh.get_n_errors() hh.get_b_errors() utils.print_time() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar > 0, clock time at beginning of program Kss_init = scalar > 0, initial guess for steady-state aggregate capital stock Lss_init = scalar > 0, initial guess for steady-state aggregate labor rss_init = scalar > 0, initial guess for steady-state interest rate wss_init = scalar > 0, initial guess for steady-state wage c1_init = scalar > 0, initial guess for first period consumpt'n S = integer in [3, 80], number of periods an individual lives beta = scalar in (0,1), discount factor for each model per sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment for each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital SS_tol = scalar > 0, tolerance level for steady-state fsolve EulDiff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 hh_fsolve = boolean, =True if solve inner-loop household problem by choosing c_1 to set final period savings b_{S+1}=0 KL_outer = boolean, =True if guess K and L in outer loop Otherwise, guess r and w in outer loop maxiter_SS = integer >= 1, maximum number of iterations in outer loop bisection method iter_SS = integer >= 0, index of iteration number mindist_SS = scalar > 0, minimum distance tolerance for convergence dist_SS = scalar > 0, distance metric for current iteration xi_SS = scalar in (0,1], updating parameter KL_init = (2,) vector, (K_init, L_init) c1_options = length 1 dict, options to pass into opt.root(c1_bSp1err,...) cnb_args = length 8 tuple, args to pass into get_cnb_vecs() r_params = length 3 tuple, args to pass into get_r() w_params = length 2 tuple, args to pass into get_w() K_init = scalar, initial value of aggregate capital stock L_init = scalar, initial value of aggregate labor r_init = scalar, initial value for interest rate w_init = scalar, initial value for wage rpath = (S,) vector, lifetime path of interest rates wpath = (S,) vector, lifetime path of wages c1_args = length 10 tuple, args to pass into c1_bSp1err() results_c1 = results object, root finder results from opt.root(c1_bSp1err,...) c1_new = scalar, updated value of optimal c1 given r_init and w_init cvec_new = (S,) vector, updated values for lifetime consumption nvec_new = (S,) vector, updated values for lifetime labor supply bvec_new = (S,) vector, updated values for lifetime savings (b1, b2,...bS) b_Sp1_new = scalar, updated value for savings in last period, should be arbitrarily close to zero K_new = scalar, updated K given bvec_new K_cnstr = boolean, =True if K_new <= 0 L_new = scalar, updated L given nvec_new KL_new = (2,) vector, updated K and L given bvec_new, nvec_new K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor r_ss = scalar > 0, steady-state interest rate w_ss = scalar > 0, steady-state wage c1_ss = scalar > 0, steady-state consumption in first period c_ss = (S,) vector, steady-state lifetime consumption n_ss = (S,) vector, steady-state lifetime labor supply b_ss = (S,) vector, steady-state lifetime savings (b1_ss, b2_ss, ...bS_ss) where b1_ss=0 b_Sp1_ss = scalar, steady-state savings for period after last period of life. b_Sp1_ss approx. 0 in equilibrium Y_params = length 2 tuple, (A, alpha) Y_ss = scalar > 0, steady-state aggregate output (GDP) C_ss = scalar > 0, steady-state aggregate consumption n_err_params = length 5 tuple, args to pass into get_n_errors() n_err_ss = (S,) vector, lifetime labor supply Euler errors b_err_params = length 2 tuple, args to pass into get_b_errors() b_err_ss = (S-1) vector, lifetime savings Euler errors RCerr_ss = scalar, resource constraint error ss_time = scalar, seconds elapsed to run steady-state comput'n ss_output = length 14 dict, steady-state objects {n_ss, b_ss, c_ss, b_Sp1_ss, w_ss, r_ss, K_ss, L_ss, Y_ss, C_ss, n_err_ss, b_err_ss, RCerr_ss, ss_time} FILES CREATED BY THIS FUNCTION: SS_bc.png SS_n.png RETURNS: ss_output -------------------------------------------------------------------- ''' start_time = time.clock() Kss_init, Lss_init, c1_init = init_vals (J, S, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, SS_tol, EulDiff) = args maxiter_SS = 200 iter_SS = 0 mindist_SS = 1e-12 dist_SS = 10 xi_SS = 0.2 KL_init = np.array([Kss_init, Lss_init]) c1_options = {'maxiter': 500} r_params = (A, alpha, delta) w_params = (A, alpha) while (iter_SS < maxiter_SS) and (dist_SS >= mindist_SS): iter_SS += 1 K_init, L_init = KL_init r_init = firms.get_r(r_params, K_init, L_init) w_init = firms.get_w(w_params, K_init, L_init) rpath = r_init * np.ones(S) wpath = w_init * np.ones(S) cmat = np.zeros((S, J)) nmat = np.zeros((S, J)) bmat = np.zeros((S, J)) b_Sp1_vec = np.zeros(J) for j in range(J): c1_args = (0.0, emat[:, j], beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, rpath, wpath, EulDiff) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=SS_tol, options=(c1_options)) c1 = results_c1.x cnb_args = (0.0, emat[:, j], beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, EulDiff) cmat[:, j], nmat[:, j], bmat[:, j], b_Sp1_vec[j] = \ hh.get_cnb_vecs(c1, rpath, wpath, cnb_args) K_new, K_cnstr = aggr.get_K(bmat, lambdas) L_new = aggr.get_L(nmat, emat, lambdas) KL_new = np.array([K_new, L_new]) dist_SS = ((KL_new - KL_init) ** 2).sum() KL_init = xi_SS * KL_new + (1 - xi_SS) * KL_init print('SS Iteration=', iter_SS, ', SS Distance=', '%10.4e' % (dist_SS), ',K:', '%10.4e' % (K_new), 'L:', '%10.4e' % (L_new)) K_ss, L_ss = KL_init r_ss = firms.get_r(r_params, K_ss, L_ss) w_ss = firms.get_w(w_params, K_ss, L_ss) c_ss = cmat n_ss = nmat b_ss = bmat b_Sp1_ss = b_Sp1_vec Y_params = (A, alpha) Y_ss = aggr.get_Y(Y_params, K_ss, L_ss) C_ss = aggr.get_C(c_ss, lambdas) n_err_ss = np.zeros((S, J)) b_err_ss = np.zeros((S - 1, J)) for j in range(J): n_err_params = (emat[:, j], sigma, l_tilde, chi_n_vec, b_ellip, upsilon) n_err_ss[:, j] = hh.get_n_errors(n_err_params, w_ss, c_ss[:, j], n_ss[:, j], EulDiff) b_err_params = (beta, sigma) b_err_ss[:, j] = hh.get_b_errors(b_err_params, r_ss, c_ss[:, j], EulDiff) RCerr_ss = Y_ss - C_ss - delta * K_ss ss_time = time.clock() - start_time ss_output = { 'n_ss': n_ss, 'b_ss': b_ss, 'c_ss': c_ss, 'b_Sp1_ss': b_Sp1_ss, 'w_ss': w_ss, 'r_ss': r_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'Y_ss': Y_ss, 'C_ss': C_ss, 'n_err_ss': n_err_ss, 'b_err_ss': b_err_ss, 'RCerr_ss': RCerr_ss, 'ss_time': ss_time} print('K_ss=', K_ss, ', L_ss=', L_ss) print('r_ss=', r_ss, ', w_ss=', w_ss) print('Maximum abs. labor supply Euler error is: ', np.absolute(n_err_ss).max()) print('Maximum abs. savings Euler error is: ', np.absolute(b_err_ss).max()) print('Resource constraint error is: ', RCerr_ss) print('Max. absolute SS residual savings b_Sp1_j is: ', np.absolute(b_Sp1_ss).max()) # Print SS computation time utils.print_time(ss_time, 'SS') if graphs: ''' ---------------------------------------------------------------- cur_path = string, path name of current directory output_fldr = string, folder in current path to save files output_dir = string, total path of images folder output_path = string, path of file name of figure to be saved sgrid = (S,) vector, ages from 1 to S lamcumsum = (J,) vector, cumulative sum of lambdas vector jmidgrid = (J,) vector, midpoints of ability percentile bins smat = (J, S) matrix, sgrid copied down J rows jmat = (J, S) matrix, jmidgrid copied across S columns ---------------------------------------------------------------- ''' # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = 'images' output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot 3D steady-state consumption distribution sgrid = np.arange(1, S + 1) lamcumsum = lambdas.cumsum() jmidgrid = 0.5 * lamcumsum + 0.5 * (lamcumsum - lambdas) smat, jmat = np.meshgrid(sgrid, jmidgrid) cmap_c = cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'indiv. consumption $c_{j,s}$') ax.plot_surface(smat, jmat, c_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'c_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state consumption distribution minorLocator = MultipleLocator(1) fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, c_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, c_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'indiv. consumption $c_{j,s}$') output_path = os.path.join(output_dir, 'c_ss_2D') plt.savefig(output_path) # plt.show() plt.close() # Plot 3D steady-state labor supply distribution fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'labor supply $n_{j,s}$') ax.plot_surface(smat, jmat, n_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'n_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state labor supply distribution minorLocator = MultipleLocator(1) fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, n_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, n_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'labor supply $n_{j,s}$') output_path = os.path.join(output_dir, 'n_ss_2D') plt.savefig(output_path) # plt.show() plt.close() # Plot 3D steady-state savings/wealth distribution fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'ability-$j$') ax.set_zlabel(r'indiv. savings $b_{j,s}$') ax.plot_surface(smat, jmat, b_ss.T, rstride=1, cstride=6, cmap=cmap_c) output_path = os.path.join(output_dir, 'b_ss_3D') plt.savefig(output_path) # plt.show() plt.close() # Plot 2D steady-state savings/wealth distribution fig, ax = plt.subplots() linestyles = np.array(["-", "--", "-.", ":"]) markers = np.array(["x", "v", "o", "d", ">", "|"]) pct_lb = 0 for j in range(J): this_label = (str(int(np.rint(pct_lb))) + " - " + str(int(np.rint(pct_lb + 100 * lambdas[j]))) + "%") pct_lb += 100 * lambdas[j] if j <= 3: ax.plot(sgrid, b_ss[:, j], label=this_label, linestyle=linestyles[j], color='black') elif j > 3: ax.plot(sgrid, b_ss[:, j], label=this_label, marker=markers[j - 4], color='black') ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax.set_xlabel(r'age-$s$') ax.set_ylabel(r'indiv. savings $b_{j,s}$') output_path = os.path.join(output_dir, 'b_ss_2D') plt.savefig(output_path) # plt.show() plt.close() return ss_output
b_ss = ss_output['b_ss'] n_ss = ss_output['n_ss'] chi_n_vec = ss_output['chi_n_vec'] # Choose initial period distribution of wealth (bvec1), which # determines initial period aggregate capital stock ub_factor = 1.04 lb_factor = 0.98 init_wgts_vec = ((ub_factor - lb_factor) / (S - 1) * (np.linspace(1, S, S) - 1) + lb_factor) init_wgts = np.tile(init_wgts_vec.reshape((S, 1)), (1, J)) bmat1 = init_wgts * b_ss # Make sure init. period distribution is feasible in terms of K K_args = (lambdas, omega_preTP, imm_rates, g_n_path[0]) K1, K1_cstr = aggr.get_K(bmat1, K_args) # If initial bvec1 is not feasible end program if K1_cstr: print('Initial savings distribution is not feasible because ' + 'K1<=0. Some element(s) of bmat1 must increase.') else: tpi_params = (J, E, S, T1, T2, lambdas, emat, mort_rates, imm_rates_mat, omega_path, omega_preTP, g_n_path, zeta_mat, chi_n_vec, chi_b_vec, beta, sigma, l_tilde, b_ellip, upsilon, g_y, Z, gamma, delta, r_ss, BQ_ss, K_ss, K1, L_ss, C_ss, NX_ss, b_ss, n_ss, TPI_maxiter, TPI_OutTol, TPI_InTol, xi_TPI) tpi_output = tpi.get_TPI(bmat1, tpi_params, TPI_graphs) tpi_args = (J, E, S, T1, T2, lambdas, emat, mort_rates, imm_rates_mat,
def get_SS(bss_guess, args, graphs=False): ''' -------------------------------------------------------------------- Solve for the steady-state solution of the S-period-lived agent OG model with exogenous labor supply using one root finder in bvec -------------------------------------------------------------------- INPUTS: bss_guess = (S-1,) vector, initial guess for b_ss args = length 8 tuple, (nvec, beta, sigma, A, alpha, delta, SS_tol, SS_EulDiff) graphs = boolean, =True if output steady-state graphs OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: SS_EulErrs() aggr.get_K() aggr.get_L() aggr.get_Y() aggr.get_C() firms.get_r() firms.get_w() hh.get_cons() utils.print_time() get_ss_graphs() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar > 0, clock time at beginning of program nvec = (S,) vector, exogenous lifetime labor supply n_s beta = scalar in (0,1), discount factor for each model per sigma = scalar > 0, coefficient of relative risk aversion A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital SS_tol = scalar > 0, tolerance level for steady-state fsolve SS_EulDiff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 b_args = length 7 tuple, args passed to opt.root(SS_EulErrs,...) results_b = results object, output from opt.root(SS_EulErrs,...) b_ss = (S-1,) vector, steady-state savings b_{s+1} K_ss = scalar > 0, steady-state aggregate capital stock Kss_cstr = boolean, =True if K_ss < epsilon L = scalar > 0, exogenous aggregate labor r_params = length 3 tuple, (A, alpha, delta) r_ss = scalar > 0, steady-state interest rate w_params = length 2 tuple, (A, alpha) w_ss = scalar > 0, steady-state wage c_args = length 3 tuple, (nvec, r_ss, w_ss) c_ss = (S,) vector, steady-state individual consumption c_s Y_params = length 2 tuple, (A, alpha) Y_ss = scalar > 0, steady-state aggregate output (GDP) C_ss = scalar > 0, steady-state aggregate consumption b_err_ss = (S-1,) vector, Euler errors associated with b_ss RCerr_ss = scalar, steady-state resource constraint error ss_time = scalar > 0, time elapsed during SS computation (in seconds) ss_output = length 10 dict, steady-state objects {b_ss, c_ss, w_ss, r_ss, K_ss, Y_ss, C_ss, b_err_ss, RCerr_ss, ss_time} FILES CREATED BY THIS FUNCTION: None RETURNS: ss_output -------------------------------------------------------------------- ''' start_time = time.clock() nvec, beta, sigma, A, alpha, delta, SS_tol, SS_EulDiff = args b_args = (nvec, beta, sigma, A, alpha, delta, SS_EulDiff) results_b = opt.root(SS_EulErrs, bss_guess, args=(b_args)) b_ss = results_b.x K_ss, Kss_cstr = aggr.get_K(b_ss) L = aggr.get_L(nvec) r_params = (A, alpha, delta) r_ss = firms.get_r(K_ss, L, r_params) w_params = (A, alpha) w_ss = firms.get_w(K_ss, L, w_params) c_args = (nvec, r_ss, w_ss) c_ss = hh.get_cons(b_ss, 0.0, c_args) Y_params = (A, alpha) Y_ss = aggr.get_Y(K_ss, L, Y_params) C_ss = aggr.get_C(c_ss) b_err_ss = results_b.fun RCerr_ss = Y_ss - C_ss - delta * K_ss ss_time = time.clock() - start_time ss_output = { 'b_ss': b_ss, 'c_ss': c_ss, 'w_ss': w_ss, 'r_ss': r_ss, 'K_ss': K_ss, 'Y_ss': Y_ss, 'C_ss': C_ss, 'b_err_ss': b_err_ss, 'RCerr_ss': RCerr_ss, 'ss_time': ss_time } print('b_ss is: ', b_ss) print('K_ss=', K_ss, ', r_ss=', r_ss, ', w_ss=', w_ss) print('Max. abs. savings Euler error is: ', np.absolute(b_err_ss).max()) print('Max. abs. resource constraint error is: ', np.absolute(RCerr_ss).max()) # Print SS computation time utils.print_time(ss_time, 'SS') if graphs: get_ss_graphs(c_ss, b_ss) return ss_output
def inner_loop(r, w, Y, x, params): ''' -------------------------------------------------------------------- Given values for r and w, solve for equilibrium errors from the two first order conditions of the firm -------------------------------------------------------------------- INPUTS: r = scalar > 0, guess at steady-state interest rate w = scalar > 0, guess at steady-state wage Y = scalar > 0, guess steady-state output x = scalar > 0, guess as steady-state transfers per household params = length 16 tuple, (c1_init, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, tax_params, fiscal_params, diff, hh_fsolve, SS_tol) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.bn_solve() hh.c1_bSp1err() hh.get_cnb_vecs() aggr.get_K() aggr.get_L() firms.get_r() firms.get_w() OBJECTS CREATED WITHIN FUNCTION: c1_init = scalar > 0, initial guess for c1 S = integer >= 3, number of periods in individual lifetime beta = scalar in (0,1), discount factor sigma = scalar >= 1, coefficient of relative risk aversion l_tilde = scalar > 0, per-period time endowment for every agent b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital tax_params = length 3 tuple, (tau_l, tau_k, tau_c) fiscal_params = length 7 tuple, (tG1, tG2, alpha_X, alpha_G, rho_G, alpha_D, alpha_D0) diff = boolean, =True if simple difference Euler errors, otherwise percent deviation Euler errors hh_fsolve = boolean, =True if solve inner-loop household problem by choosing c_1 to set final period savings b_{S+1}=0. Otherwise, solve the household problem as multivariate root finder with 2S-1 unknowns and equations SS_tol = scalar > 0, tolerance level for steady-state fsolve tau_l = scalar, marginal tax rate on labor income tau_k = scalar, marginal tax rate on capital income tau_c = scalar, marginal tax rate on corporate income tG1 = integer, model period when budget closure rule begins tG2 = integer, model period when budget is closed alpha_X = scalar, ratio of lump sum transfers to GDP alpha_G = scalar, ratio of government spending to GDP prior to budget closure rule beginning rho_G = scalar in (0,1), rate of convergence to SS budget alpha_D = scalar, steady-state debt to GDP ratio alpha_D0 = scalar, debt to GDP ratio in the initial period r_params = length 3 tuple, args to pass into get_r() w_params = length 2 tuple, args to pass into get_w() Y_params = length 2 tuple, args to pass into get_Y() b_init = (S-1,) vector, initial guess at distribution of savings n_init = (S,) vector, initial guess at distribution of labor supply guesses = (2S-1,) vector, initial guesses at b and n bn_params = length 12 tuple, parameters to pass to solve_bn_path() (r, w, x, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, tax_params, diff) euler_errors = (2S-1,) vector, Euler errors for FOCs for b and n b_splus1_vec = (S,) vector, optimal savings choice nvec = (S,) vector, optimal labor supply choice b_Sp1 = scalar, last period savings b_s_vec = (S,) vector, wealth enter period with cvec = (S,) vector, optimal consumption rpath = (S,) vector, lifetime path of interest rates wpath = (S,) vector, lifetime path of wages c1_args = length 10 tuple, args to pass into c1_bSp1err() c1_options = length 1 dict, options for c1_bSp1err() results_c1 = results object, results from c1_bSp1err() c1 = scalar > 0, optimal initial period consumption given r and w cnb_args = length 8 tuple, args to pass into get_cnb_vecs() cvec = (S,) vector, lifetime consumption (c1, c2, ...cS) nvec = (S,) vector, lifetime labor supply (n1, n2, ...nS) bvec = (S,) vector, lifetime savings (b1, b2, ...bS) with b1=0 b_Sp1 = scalar, final period savings, should be close to zero B = scalar > 0, aggregate savings B_cnstr = boolean, =True if B < 0 L = scalar > 0, aggregate labor debt = scalar, total government debt K = scalar > 0, aggregate capital stock K_cnstr = boolean, =True if K < 0 r_new = scalar > 0, implied steady-state interest rate w_new = scalar > 0, implied steady-state wage Y_new = scalar >0, implied steady-state output x_new = scalar >=0, implied transfers per household FILES CREATED BY THIS FUNCTION: None RETURNS: B, K, L, Y_new, debt, cvec, nvec, b_s_vec, b_splus1_vec, b_Sp1, x_new, r_new, w_new -------------------------------------------------------------------- ''' c1_init, S, beta, sigma, l_tilde, b_ellip, upsilon,\ chi_n_vec, A, alpha, delta, tax_params, fiscal_params,\ diff, hh_fsolve, SS_tol = params tau_l, tau_k, tau_c = tax_params tG1, tG2, alpha_X, alpha_G, rho_G, alpha_D, alpha_D0 = fiscal_params r_params = (A, alpha, delta, tau_c) w_params = (A, alpha) Y_params = (A, alpha) if hh_fsolve: b_init = np.ones((S - 1, 1)) * 0.05 n_init = np.ones((S, 1)) * 0.4 guesses = np.append(b_init, n_init) bn_params = (r, w, x, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, tax_params, diff) [solutions, infodict, ier, message] = \ opt.fsolve(hh.bn_solve, guesses, args=bn_params, xtol=SS_tol, full_output=True) euler_errors = infodict['fvec'] print('Max Euler errors: ', np.absolute(euler_errors).max()) b_splus1_vec = np.append(solutions[:S - 1], 0.0) nvec = solutions[S - 1:] b_Sp1 = 0.0 b_s_vec = np.append(0.0, b_splus1_vec[:-1]) cvec = hh.get_cons(r, w, b_s_vec, b_splus1_vec, nvec, x, tax_params) else: rpath = r * np.ones(S) wpath = w * np.ones(S) xpath = x * np.ones(S) c1_options = {'maxiter': 500} c1_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, tax_params, xpath, rpath, wpath, diff) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=SS_tol, options=(c1_options)) c1_new = results_c1.x cnb_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, tax_params, diff) cvec, nvec, b_s_vec, b_Sp1 = \ hh.get_cnb_vecs(c1_new, rpath, wpath, xpath, cnb_args) b_splus1_vec = np.append(b_s_vec[1:], b_Sp1) B, B_cnstr = aggr.get_K(b_s_vec) L = aggr.get_L(nvec) L = np.maximum(0.0001, L) debt = alpha_D * Y K = B - debt K_cnstr = K < 0 if K_cnstr: print('Aggregate capital constraint is violated K<=0 for ' + 'in the steady state.') r_new = firms.get_r(r_params, K, L) w_new = firms.get_w(w_params, K, L) Y_new = aggr.get_Y(Y_params, K, L) x_new = (alpha_X * Y_new) / S return B, K, L, Y_new, debt, cvec, nvec, b_s_vec, b_splus1_vec, \ b_Sp1, x_new, r_new, w_new
def solve_tp(g_n_path, omega_S_preTP, rho_s, imm_rates_path, params): ''' Solves for the time path equilibrium using TPI ''' # Missing some elements of params b_ss, r_11, T, S = params dist = 8.0 mindist = 1e-08 maxiter = 300 tpi_iter = 0 xi = 0.2 while dist > mindist and tpi_iter < maxiter: # Define paths b_11 = 1.1 * b_ss BQ_params = (g_n_path[0], omega_S_preTP, rho_s) K_params = (g_n_path[0], omega_S_preTP, imm_rates_path[0, :]) BQ_11 = agg.get_BQ(b_11, r_11, BQ_params) K_11 = agg.get_K(b_11, K_params) BQpath_init = np.zeros(T + S - 1) BQpath_init[:T] = np.linspace(BQ_11, BQ_ss, T) BQpath_init[T:] = BQ_ss r_11 = firm.get_r(K_11, L_ss, r_params) r_path = firm.get_r(L_ss, r_params) w_path = firm.get_w(L_ss, w_params) bmat = np.zeros((S - 1, T + S - 1)) bmat[:, 0] = b_1 # Solve for households for p in range(2, S): b_guess = np.diagonal(bmat[S - p:, :p - 1]) b_init = bmat[S - p - 1, 0] b_params = (b_init, n[-p:], r_path[:p], w_path[:p], BQpath_init[:p], rho_s[-p:], beta, sigma) results_bp = opt.root(hh.FOCs, b_guess, args=(b_params)) b_solve_p = results_bp.x DiagMaskbp = np.eye(p - 1, dtype=bool) bmat[S - p:, 1:p] = DiagMaskbp * b_solve_p + bmat[S - p:, 1:p] for t in range(1, T + 1): b_guess = np.diagonal(bmat[:, t - 1:t + S - 2]) b_init = 0.0 b_params = (b_init, n, r_path[t - 1:t + S - 1], w_path[t - 1:t + S - 1], BQpath_init[t - 1:t + S - 1], rho_s, beta, sigma) results_bt = opt.root(hh.FOCs, b_guess, args=(b_params)) b_solve_t = results_bt.x DiagMaskbt = np.eye(S - 1, dtype=bool) bmat[:, t:t + S - 1] = (DiagMaskbt * b_solve_t + bmat[:, t:t + S - 1]) new_Kpath = np.zeros(T) new_Kpath[0] = K_1 new_Kpath[1:] = \ (1 / (omega_path_S[:T - 1, :-1]) * bmat[:, 1:T].T + imm_rates_path[:T - 1, 1:] * omega_path_S[:T - 1, 1:] * bmat[:, 1:T].T).sum(axis=1) new_BQpath = np.zeros(T) new_BQpath[0] = BQ_1 new_BQpath[1:] = \ ((1 + r_path[1:T]) / (rho_s[:-1]) * omega_path_S[:T - 1, :-1] * bmat[:, 1:T].T).sum(axis=1) dist = ((BQ_init - new_BQ)**2).sum() BQpath_init[:T] = xi * new_BQpath[:T] + (1 - xi) * BQpath_init[:T] # update iteration counter tpi_iter += 1 if tpi_iter < maxiter: print('The time path solved! ->', ' iter:', tpi_iter, ', dist: ', dist) else: print('The time path did not solve.') return [new_Kpath, new_BQpath]
def get_TPI(bvec1, params, graphs): ''' -------------------------------------------------------------------- Generates steady-state time path for all endogenous objects from initial state (K1, Gamma1) to the steady state. -------------------------------------------------------------------- INPUTS: params = length 16 tuple, (S, T, beta, sigma, nvec, A, alpha, delta, b_ss, K_ss, C_ss, maxiter_TPI, mindist_TPI, TPI_tol, xi, EulDiff) bvec1 = (S-1,) vector, initial period distribution of savings graphs = Boolean, =True if want graphs of TPI objects OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: c5ssf.get_K() get_path() c5ssf.get_r() c5ssf.get_w() get_cbepath() c5ssf.get_Y() c5ssf.get_C() c5ssf.print_time() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar, current processor time in seconds (float) (S, T, beta, sigma, nvec, A, alpha, delta, b_ss, K_ss, C_ss, maxiter_TPI, mindist_TPI, TPI_tol, xi_TPI, TPI_EulDiff) S = integer in [3,80], number of periods an individual lives T = integer > S, number of time periods until steady state beta = scalar in (0,1), discount factor for model period sigma = scalar > 0, coefficient of relative risk aversion nvec = (S,) vector, exogenous labor supply n_{s,t} A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital b_ss = (S-1,) vector, steady-state distribution of savings K_ss = scalar > 0, steady-state aggregate capital stock C_ss = scalar > 0, steady-state aggregate consumption maxiter_TPI = integer >= 1, Maximum number of iterations for TPI mindist_TPI = scalar > 0, Convergence criterion for TPI TPI_tol = scalar > 0, tolerance level for fsolve's in TPI xi = scalar in (0,1], TPI path updating parameter EulDiff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 L = scalar > 0, exogenous aggregate labor K1 = scalar > 0, initial aggregate capital stock K1_cstr = boolean, =True if K1 <= 0 Kpath_init = (T+S-2,) vector, initial guess for the time path of the aggregate capital stock iter_TPI = integer >= 0, current iteration of TPI dist_TPI = scalar >= 0, distance measure for fixed point Kpath_new = (T+S-2,) vector, new path of the aggregate capital stock implied by household and firm optimization r_params = length 3 tuple, (A, alpha, delta) w_params = length 2 tuple, (A, alpha) cbe_params = length 9 tuple, (S, T, beta, sigma, nvec, bvec1, b_ss, TPI_tol, EulDiff) rpath = (T+S-2,) vector, time path of the interest rate wpath = (T+S-2,) vector, time path of the wage cpath = (S, T+S-2) matrix, time path values of distribution of consumption c_{s,t} bpath = (S-1, T+S-2) matrix, time path of distribution of individual savings b_{s,t} EulErrPath = (S-1, T+S-2) matrix, time path of individual Euler errors corresponding to individual savings b_{s,t} (first column is zeros) Kpath_cnstr = (T+S-2,) Boolean vector, =True if K_t<=0 Kpath = (T+S-2,) vector, equilibrium time path of aggregate capital stock K_t Y_params = length 2 tuple, (A, alpha) Ypath = (T+S-2,) vector, equilibrium time path of aggregate output (GDP) Y_t Cpath = (T+S-2,) vector, equilibrium time path of aggregate consumption C_t RCerrPath = (T+S-1,) vector, equilibrium time path of the resource constraint error: Y_t - C_t - K_{t+1} + (1-delta)*K_t tpi_time = scalar, time to compute TPI solution (seconds) tpi_output = length 10 dictionary, {bpath, cpath, wpath, rpath, Kpath, Ypath, Cpath, EulErrPath, RCerrPath, tpi_time} FILES CREATED BY THIS FUNCTION: Kpath.png Ypath.png Cpath.png wpath.png rpath.png bpath.png cpath.png RETURNS: tpi_output -------------------------------------------------------------------- ''' start_time = time.clock() (S, T, beta, sigma, nvec, A, alpha, delta, b_ss, K_ss, C_ss, maxiter_TPI, mindist_TPI, TPI_tol, xi, EulDiff) = params L = aggr.get_L(nvec) K1, K1_cstr = aggr.get_K(bvec1) # Create time paths for K and L Kpath_init = np.zeros(T + S - 2) Kpath_init[:T] = get_path(K1, K_ss, T, "quadratic") Kpath_init[T:] = K_ss iter_TPI = int(0) dist_TPI = 10. Kpath_new = Kpath_init.copy() r_params = (A, alpha, delta) w_params = (A, alpha) cbe_params = (S, T, beta, sigma, nvec, bvec1, b_ss, TPI_tol, EulDiff) while (iter_TPI < maxiter_TPI) and (dist_TPI >= mindist_TPI): iter_TPI += 1 Kpath_init = xi * Kpath_new + (1 - xi) * Kpath_init rpath = firms.get_r(Kpath_init, L, r_params) wpath = firms.get_w(Kpath_init, L, w_params) cpath, bpath, EulErrPath = get_cbepath(cbe_params, rpath, wpath) Kpath_new = np.zeros(T + S - 2) Kpath_new[:T], Kpath_cstr = aggr.get_K(bpath[:, :T]) Kpath_new[T:] = K_ss * np.ones(S - 2) Kpath_cstr = np.append(Kpath_cstr, np.zeros(S - 2, dtype=bool)) Kpath_new[Kpath_cstr] = 0.1 # Check the distance of Kpath_new1 dist_TPI = ((Kpath_new[1:T] - Kpath_init[1:T]) ** 2).sum() # dist_TPI = np.absolute((Kpath_new[1:T] - Kpath_init[1:T]) / # Kpath_init[1:T]).max() print( 'TPI iter: ', iter_TPI, ', dist: ', "%10.4e" % (dist_TPI), ', max. abs. Euler errs: ', "%10.4e" % (np.absolute(EulErrPath).max())) if iter_TPI == maxiter_TPI and dist_TPI > mindist_TPI: print('TPI reached maxiter and did not converge.') elif iter_TPI == maxiter_TPI and dist_TPI <= mindist_TPI: print('TPI converged in the last iteration. ' + 'Should probably increase maxiter_TPI.') Kpath = Kpath_new Y_params = (A, alpha) Ypath = aggr.get_Y(Kpath, L, Y_params) Cpath = np.zeros(T + S - 2) Cpath[:T - 1] = aggr.get_C(cpath[:, :T - 1]) Cpath[T - 1:] = C_ss * np.ones(S - 1) RCerrPath = (Ypath[:-1] - Cpath[:-1] - Kpath[1:] + (1 - delta) * Kpath[:-1]) tpi_time = time.clock() - start_time tpi_output = { 'bpath': bpath, 'cpath': cpath, 'wpath': wpath, 'rpath': rpath, 'Kpath': Kpath, 'Ypath': Ypath, 'Cpath': Cpath, 'EulErrPath': EulErrPath, 'RCerrPath': RCerrPath, 'tpi_time': tpi_time} # Print TPI computation time util.print_time(tpi_time, 'TPI') if graphs: ''' ---------------------------------------------------------------- cur_path = string, path name of current directory output_fldr = string, folder in current path to save files output_dir = string, total path of images folder output_path = string, path of file name of figure to be saved tvec = (T+S-2,) vector, time period vector tgridTm1 = (T-1,) vector, time period vector to T-1 tgridT = (T,) vector, time period vector to T-1 sgrid = (S,) vector, all ages from 1 to S sgrid2 = (S-1,) vector, all ages from 2 to S tmatb = (S-1, T) matrix, time periods for all savings decisions ages (S-1) and time periods (T) smatb = (S-1, T) matrix, ages for all savings decision ages (S-1) and time periods (T) tmatc = (3, T-1) matrix, time periods for all consumption decisions ages (S) and time periods (T-1) smatc = (3, T-1) matrix, ages for all consumption decisions ages (S) and time periods (T-1) ---------------------------------------------------------------- ''' # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = "images" output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot time path of aggregate capital stock tvec = np.linspace(1, T + S - 2, T + S - 2) minorLocator = MultipleLocator(1) fig, ax = plt.subplots() plt.plot(tvec, Kpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate capital stock K') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate capital $K_{t}$') output_path = os.path.join(output_dir, "Kpath") plt.savefig(output_path) # plt.show() # Plot time path of aggregate output (GDP) fig, ax = plt.subplots() plt.plot(tvec, Ypath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate output (GDP) Y') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate output $Y_{t}$') output_path = os.path.join(output_dir, "Ypath") plt.savefig(output_path) # plt.show() # Plot time path of aggregate consumption fig, ax = plt.subplots() plt.plot(tvec, Cpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate consumption C') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate consumption $C_{t}$') output_path = os.path.join(output_dir, "C_aggr_path") plt.savefig(output_path) # plt.show() # Plot time path of real wage fig, ax = plt.subplots() plt.plot(tvec, wpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real wage w') plt.xlabel(r'Period $t$') plt.ylabel(r'Real wage $w_{t}$') output_path = os.path.join(output_dir, "wpath") plt.savefig(output_path) # plt.show() # Plot time path of real interest rate fig, ax = plt.subplots() plt.plot(tvec, rpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real interest rate r') plt.xlabel(r'Period $t$') plt.ylabel(r'Real interest rate $r_{t}$') output_path = os.path.join(output_dir, "rpath") plt.savefig(output_path) # plt.show() # Plot time path of individual savings distribution tgridT = np.linspace(1, T, T) sgrid2 = np.linspace(2, S, S - 1) tmatb, smatb = np.meshgrid(tgridT, sgrid2) cmap_bp = matplotlib.cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'period-$t$') ax.set_ylabel(r'age-$s$') ax.set_zlabel(r'individual savings $b_{s,t}$') strideval = max(int(1), int(round(S / 10))) ax.plot_surface(tmatb, smatb, bpath[:, :T], rstride=strideval, cstride=strideval, cmap=cmap_bp) output_path = os.path.join(output_dir, "bpath") plt.savefig(output_path) # plt.show() # Plot time path of individual consumption distribution tgridTm1 = np.linspace(1, T - 1, T - 1) sgrid = np.linspace(1, S, S) tmatc, smatc = np.meshgrid(tgridTm1, sgrid) cmap_cp = matplotlib.cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'period-$t$') ax.set_ylabel(r'age-$s$') ax.set_zlabel(r'individual consumption $c_{s,t}$') strideval = max(int(1), int(round(S / 10))) ax.plot_surface(tmatc, smatc, cpath[:, :T - 1], rstride=strideval, cstride=strideval, cmap=cmap_cp) output_path = os.path.join(output_dir, "cpath") plt.savefig(output_path) # plt.show() return tpi_output
def get_TPI(bmat1, args, graphs): ''' -------------------------------------------------------------------- Solves for transition path equilibrium using time path iteration (TPI) -------------------------------------------------------------------- INPUTS: bmat1 = (S, J) matrix, initial period wealth (savings) distribution args = length 25 tuple, (J, S, T1, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, Z, gamma, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter, Out_Tol, In_Tol, xi) graphs = Boolean, =True if want graphs of TPI objects OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: get_path() firms.get_r() firms.get_w() get_cnbpath() aggr.get_K() aggr.get_L() aggr.get_Y() aggr.get_C() utils.print_time() create_graphs() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar, current processor time in seconds (float) J = integer >= 1, number of heterogeneous ability groups S = integer in [3,80], number of periods an individual lives T1 = integer > S, number of time periods until steady state is assumed to be reached T2 = integer > T1, number of time periods after which steady-state is forced in TPI lambdas = (J,) vector, income percentiles for distribution of ability within each cohort emat = (S, J) matrix, lifetime ability profiles for each lifetime income group j beta = scalar in (0,1), discount factor for model period sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment for each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s Z = scalar > 0, total factor productivity parameter in firms' production function gamma = scalar in (0,1), capital share of income delta = scalar in [0,1], per-period capital depreciation rt r_ss = scalar > 0, steady-state aggregate interest rate K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor C_ss = scalar > 0, steady-state aggregate consumption b_ss = (S,) vector, steady-state savings distribution (b1, b2,... bS) n_ss = (S,) vector, steady-state labor supply distribution (n1, n2,... nS) maxiter = integer >= 1, Maximum number of iterations for TPI Out_Tol = scalar > 0, convergence criterion for TPI outer loop In_Tol = scalar > 0, tolerance level for TPI inner-loop root finders xi = scalar in (0,1], TPI path updating parameter K1 = scalar > 0, initial aggregate capital stock K1_cnstr = Boolean, =True if K1 <= 0 rpath_init = (T2+S-1,) vector, initial guess for the time path of interest rates iter_TPI = integer >= 0, current iteration of TPI dist = scalar >= 0, distance measure between initial and new paths rw_params = length 3 tuple, (Z, gamma, delta) Y_params = length 2 tuple, (Z, gamma) cnb_args = length 13 tuple, args to pass into get_cnbpath() rpath = (T2+S-1,) vector, time path of the interest rates wpath = (T2+S-1,) vector, time path of the wages cpath = (S, J, T2+S-1) array, time path of distribution of household consumption c_{j,s,t} npath = (S, J, T2+S-1) matrix, time path of distribution of household labor supply n_{j,s,t} bpath = (S, J, T2+S-1) matrix, time path of distribution of household savings b_{j,s,t} n_err_path = (S, J, T2+S-1) matrix, time path of distribution of household labor supply Euler errors b_err_path = (S, J, T2+S-1) matrix, time path of distribution of household savings Euler errors. b_{j,1,t} = 0 for all j and t Kpath_new = (T2+S-1,) vector, new path of aggregate capital stock implied by household and firm optimization Kpath_cnstr = (T2+S-1,) Boolean vector, =True if K_t<=epsilon Lpath_new = (T2+S-1,) vector, new path of aggregate labor implied by household and firm optimization Lpath_cstr = (T2+S-1,) Boolean vector, =True if L_t<=epsilon rpath_new = (T2+S-1,) vector, updated time path of interest rate Ypath = (T2+S-1,) vector, equilibrium time path of aggregate output (GDP) Y_t Cpath = (T2+S-1,) vector, equilibrium time path of aggregate consumption C_t RCerrPath = (T2+S-2,) vector, equilibrium time path of the resource constraint error. Should be 0 in eqlb'm Y_t - C_t - K_{t+1} + (1-delta)*K_t MaxAbsEulErr = scalar > 0, maximum absolute Euler error. Includes both labor supply and savings Euler errors Kpath = (T2+S-1,) vector, equilibrium time path of aggregate capital stock K_t Lpath = (T2+S-1,) vector, equilibrium time path of aggregate labor L_t tpi_time = scalar, time to compute TPI solution (seconds) tpi_output = length 13 dictionary, {cpath, npath, bpath, wpath, rpath, Kpath, Lpath, Ypath, Cpath, n_err_path, b_err_path, RCerrPath, tpi_time} graph_args = length 4 tuple, (J, S, T2, lambdas) FILES CREATED BY THIS FUNCTION: Kpath.png Lpath.png rpath.png wpath.png Ypath.png C_aggr_path.png cpath_avg_s.png cpath_avg_j.png npath_avg_s.png npath_avg_j.png bpath_avg_s.png bpath_avg_j.png RETURNS: tpi_output -------------------------------------------------------------------- ''' start_time = time.clock() (J, E, S, T1, T2, lambdas, emat, mort_rates, imm_rates_mat, omega_path, g_n_path, zeta_mat, chi_n_vec, chi_b_vec, beta, sigma, l_tilde, b_ellip, upsilon, g_y, Z, gamma, delta, r_ss, BQ_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter, Out_Tol, In_Tol, xi) = args K1, K1_cnstr = aggr.get_K(bmat1, lambdas) # Create time paths for r and BQ rpath_init = np.zeros(T2 + S - 1) BQpath_init = np.zeros(T2 + S - 1) rpath_init[:T1] = get_path(r_ss, r_ss, T1, 'quadratic') rpath_init[T1:] = r_ss BQ_args = (lambdas, omega_path[0, :], mort_rates, g_n_path[0]) BQ_1 = aggr.get_BQ(bmat1, r_ss, BQ_args) BQpath_init[:T1] = get_path(BQ_1, BQ_ss, T1, 'quadratic') BQpath_init[T1:] = BQ_ss iter_TPI = int(0) dist = 10.0 rw_params = (Z, gamma, delta) Y_params = (Z, gamma) cnb_args = (J, S, T2, lambdas, emat, omega_path, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bmat1, n_ss, In_Tol) while (iter_TPI < maxiter) and (dist >= Out_Tol): iter_TPI += 1 rpath = rpath_init BQpath = BQpath_init wpath = firms.get_w(rpath_init, rw_params) cpath, npath, bpath, n_err_path, b_err_path = \ get_cnbpath(rpath, wpath, cnb_args) Kpath_new = np.zeros(T2 + S - 1) Kpath_new[:T2], Kpath_cstr = aggr.get_K(bpath[:, :, :T2], lambdas) Kpath_new[T2:] = K_ss Kpath_cstr = np.append(Kpath_cstr, np.zeros(S - 1, dtype=bool)) Lpath_new = np.zeros(T2 + S - 1) Lpath_new[:T2], Lpath_cstr = aggr.get_L(npath[:, :, :T2], lambdas, emat) Lpath_new[T2:] = L_ss Lpath_cstr = np.append(Lpath_cstr, np.zeros(S - 1, dtype=bool)) rpath_new = firms.get_r(Kpath_new, Lpath_new, rw_params) BQpath_new = aggr.get_BQ() Ypath = aggr.get_Y(Kpath_new, Lpath_new, Y_params) Cpath = np.zeros(T2 + S - 1) Cpath[:T2] = aggr.get_C(cpath[:, :, :T2], lambdas) Cpath[T2:] = C_ss RCerrPath = np.zeros(T2 + S - 1) RCerrPath[:-1] = (Ypath[:-1] - Cpath[:-1] - Kpath_new[1:] + (1 - delta) * Kpath_new[:-1]) RCerrPath[-1] = RCerrPath[-2] # Check the distance of rpath_new dist = (np.absolute(rpath_new[:T2] - rpath_init[:T2])).max() MaxAbsEulErr = np.absolute(np.hstack((n_err_path, b_err_path))).max() print('TPI iter: ', iter_TPI, ', dist: ', "%10.4e" % (dist), ', max abs all errs: ', "%10.4e" % MaxAbsEulErr) # The resource constraint does not bind across the transition # path until the equilibrium is solved rpath_init[:T2] = (xi * rpath_new[:T2] + (1 - xi) * rpath_init[:T2]) if (iter_TPI == maxiter) and (dist > Out_Tol): print('TPI reached maxiter and did not converge.') elif (iter_TPI == maxiter) and (dist <= Out_Tol): print('TPI converged in the last iteration. ' + 'Should probably increase maxiter_TPI.') Kpath = Kpath_new Lpath = Lpath_new tpi_time = time.clock() - start_time tpi_output = { 'cpath': cpath, 'npath': npath, 'bpath': bpath, 'wpath': wpath, 'rpath': rpath, 'Kpath': Kpath, 'Lpath': Lpath, 'Ypath': Ypath, 'Cpath': Cpath, 'n_err_path': n_err_path, 'b_err_path': b_err_path, 'RCerrPath': RCerrPath, 'tpi_time': tpi_time } # Print maximum resource constraint error. Only look at resource # constraint up to period T2 - 1 because period T2 includes K_{t+1}, # which was forced to be the steady-state print('Max abs. RC error: ', "%10.4e" % (np.absolute(RCerrPath[:T2 - 1]).max())) # Print TPI computation time utils.print_time(tpi_time, 'TPI') if graphs: graph_args = (J, S, T2, lambdas) create_graphs(tpi_output, graph_args) return tpi_output
def inner_loop(r, w, args): ''' -------------------------------------------------------------------- Given values for r and w, solve for equilibrium errors from the two first order conditions of the firm -------------------------------------------------------------------- INPUTS: r = scalar > 0, guess at steady-state interest rate w = scalar > 0, guess at steady-state wage args = length 14 tuple, (c1_init, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, EulDiff, Eul_Tol, c1_options) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.c1_bSp1err() hh.get_cnb_vecs() aggr.get_K() aggr.get_L() firms.get_r() firms.get_w() OBJECTS CREATED WITHIN FUNCTION: c1_init = scalar > 0, initial guess for c1 S = integer >= 3, number of periods in individual lifetime beta = scalar in (0,1), discount factor sigma = scalar >= 1, coefficient of relative risk aversion l_tilde = scalar > 0, per-period time endowment for every agent b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], model-period depreciation rate of capital EulDiff = boolean, =True if simple difference Euler errors, otherwise percent deviation Euler errors SS_tol = scalar > 0, tolerance level for steady-state fsolve c1_options = length 1 dict, options for c1_bSp1err() rpath = (S,) vector, lifetime path of interest rates wpath = (S,) vector, lifetime path of wages c1_args = length 10 tuple, args to pass into hh.c1_bSp1err() results_c1 = results object, results from c1_bSp1err() c1 = scalar > 0, optimal initial period consumption given r and w cnb_args = length 8 tuple, args to pass into get_cnb_vecs() cvec = (S,) vector, lifetime consumption (c1, c2, ...cS) nvec = (S,) vector, lifetime labor supply (n1, n2, ...nS) bvec = (S,) vector, lifetime savings (b1, b2, ...bS) with b1=0 b_Sp1 = scalar, final period savings, should be close to zero n_errors = (S,) vector, labor supply Euler errors b_errors = (S-1,) vector, savings Euler errors K = scalar > 0, aggregate capital stock K_cstr = boolean, =True if K < epsilon L = scalar > 0, aggregate labor L_cstr = boolean, =True if L < epsilon r_params = length 3 tuple, (A, alpha, delta) w_params = length 2 tuple, (A, alpha) r_new = scalar > 0, guess at steady-state interest rate w_new = scalar > 0, guess at steady-state wage FILES CREATED BY THIS FUNCTION: None RETURNS: K, L, cvec, nvec, bvec, b_Sp1, r_new, w_new, n_errors, b_errors -------------------------------------------------------------------- ''' (c1_init, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, EulDiff, SS_tol, c1_options) = args rpath = r * np.ones(S) wpath = w * np.ones(S) c1_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, rpath, wpath, EulDiff) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=SS_tol, options=(c1_options)) c1 = results_c1.x cnb_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, EulDiff) cvec, nvec, bvec, b_Sp1, n_errors, b_errors = \ hh.get_cnb_vecs(c1, rpath, wpath, cnb_args) K, K_cstr = aggr.get_K(bvec) L, L_cstr = aggr.get_L(nvec) r_params = (A, alpha, delta) r_new = firms.get_r(K, L, r_params) w_params = (A, alpha, delta) w_new = firms.get_w(r_new, w_params) return (K, L, cvec, nvec, bvec, b_Sp1, r_new, w_new, n_errors, b_errors)
def get_TPI(params, bmat1, graphs): ''' -------------------------------------------------------------------- Solves for transition path equilibrium using time path iteration (TPI) -------------------------------------------------------------------- INPUTS: params = length 23 tuple, (J, S, T1, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, K_ss, L_ss, C_ss, maxiter, mindist, TPI_tol, xi, diff) bmat1 = (S, J) matrix, initial period savings distribution graphs = Boolean, =True if want graphs of TPI objects OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: aggr.get_K() get_path() firms.get_r() firms.get_w() get_cnbpath() aggr.get_L() aggr.get_Y() aggr.get_C() utils.print_time() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar, current processor time in seconds (float) J = integer >= 1, number of heterogeneous ability groups S = integer in [3,80], number of periods an individual lives T1 = integer > S, number of time periods until steady state is assumed to be reached T2 = integer > T1, number of time periods after which steady-state is forced in TPI lambdas = (J,) vector, income percentiles for distribution of ability within each cohort emat = (S, J) matrix, e_{j,s} ability by age and income group beta = scalar in (0,1), discount factor for model period sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment for each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], per-period capital depreciation rt K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor supply C_ss = scalar > 0, steady-state aggregate consumption maxiter = integer >= 1, Maximum number of iterations for TPI mindist = scalar > 0, convergence criterion for TPI TPI_tol = scalar > 0, tolerance level for TPI root finders xi = scalar in (0,1], TPI path updating parameter diff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 K1 = scalar > 0, initial aggregate capital stock K1_cstr = Boolean, =True if K1 <= 0 Kpath_init = (T2+S-1,) vector, initial guess for the time path of the aggregate capital stock Lpath_init = (T2+S-1,) vector, initial guess for the time path of aggregate labor iter_TPI = integer >= 0, current iteration of TPI dist = scalar >= 0, distance measure between initial and new paths r_params = length 3 tuple, (A, alpha, delta) w_params = length 2 tuple, (A, alpha) Y_params = length 2 tuple, (A, alpha) cnb_params = length 14 tuple, args to pass into get_cnbpath() rpath = (T2+S-1,) vector, time path of the interest rates wpath = (T2+S-1,) vector, time path of the wages cpath = (S, J, T2+S-1) array, time path of distribution of individual consumption c_{j,s,t} npath = (S, J, T2+S-1) array, time path of distribution of individual labor supply n_{j,s,t} bpath = (S, J, T2+S-1) array, time path of distribution of individual savings b_{j,s,t} n_err_path = (S, J, T2+S-1) array, time path of distribution of individual labor supply Euler errors b_err_path = (S, J, T2+S-1) array, time path of distribution of individual savings Euler errors. First column and first row are identically zero bSp1_err_path = (S, J, T2) array, residual last period savings, should be close to zero in equilibrium. Nonzero elements of matrix should only be in first matrix [:, :, 0] and top plane [0, :, :] Kpath_new = (T2+S-1,) vector, new path of the aggregate capital stock implied by household and firm optimization Kpath_cstr = (T2+S-1,) Boolean vector, =True if K_t<epsilon Lpath_new = (T2+S-1,) vector, new path of the aggregate labor rpath_new = (T2+S-1,) vector, updated time path of interest rate wpath_new = (T2+S-1,) vector, updated time path of the wages Ypath = (T2+S-1,) vector, equilibrium time path of aggregate output (GDP) Y_t Cpath = (T2+S-1,) vector, equilibrium time path of aggregate consumption C_t RCerrPath = (T2+S-2,) vector, equilibrium time path of the resource constraint error: Y_t - C_t - K_{t+1} + (1-delta)*K_t KL_path_new = (2*T2,) vector, appended K_path_new and L_path_new from observation 1 to T2 KL_path_init = (2*T2,) vector, appended K_path_init and L_path_init from observation 1 to T2 Kpath = (T2+S-1,) vector, equilibrium time path of aggregate capital stock K_t Lpath = (T2+S-1,) vector, equilibrium time path of aggregate labor L_t tpi_time = scalar, time to compute TPI solution (seconds) tpi_output = length 14 dictionary, {cpath, npath, bpath, wpath, rpath, Kpath, Lpath, Ypath, Cpath, bSp1_err_path, n_err_path, b_err_path, RCerrPath, tpi_time} FILES CREATED BY THIS FUNCTION: Kpath.png Lpath.png Ypath.png C_aggr_path.png wpath.png rpath.png cpath.png npath.png bpath.png RETURNS: tpi_output -------------------------------------------------------------------- ''' start_time = time.clock() (J, S, T1, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, K_ss, L_ss, C_ss, maxiter, mindist, TPI_tol, xi, diff) = params K1, K1_cstr = aggr.get_K(bmat1, lambdas) # Create time paths for K and L Kpath_init = np.zeros(T2 + S - 1) Kpath_init[:T1] = get_path(K1, K_ss, T1, 'quadratic') Kpath_init[T1:] = K_ss Lpath_init = L_ss * np.ones(T2 + S - 1) iter_TPI = int(0) dist = 10.0 r_params = (A, alpha, delta) w_params = (A, alpha) Y_params = (A, alpha) cnb_params = (J, S, T2, lambdas, emat, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bmat1, TPI_tol, diff) while (iter_TPI < maxiter) and (dist >= mindist): iter_TPI += 1 rpath = firms.get_r(r_params, Kpath_init, Lpath_init) wpath = firms.get_w(w_params, Kpath_init, Lpath_init) cpath, npath, bpath, n_err_path, b_err_path, bSp1_err_path = \ get_cnbpath(cnb_params, rpath, wpath) Kpath_new = np.zeros(T2 + S - 1) Kpath_new[:T2], Kpath_cstr = aggr.get_K(bpath[:, :, :T2], lambdas) Kpath_new[T2:] = K_ss Kpath_cstr = np.append(Kpath_cstr, np.zeros(S - 1, dtype=bool)) Kpath_new[Kpath_cstr] = 0.01 Lpath_new = np.zeros(T2 + S - 1) Lpath_new[:T2] = aggr.get_L(npath[:, :, :T2], emat, lambdas) Lpath_new[T2:] = L_ss rpath_new = firms.get_r(r_params, Kpath_new, Lpath_new) wpath_new = firms.get_w(w_params, Kpath_new, Lpath_new) Ypath = aggr.get_Y(Y_params, Kpath_new, Lpath_new) Cpath = np.zeros(T2 + S - 1) Cpath[:T2] = aggr.get_C(cpath[:, :, :T2], lambdas) Cpath[T2:] = C_ss RCerrPath = (Ypath[:-1] - Cpath[:-1] - Kpath_new[1:] + (1 - delta) * Kpath_new[:-1]) # Check the distance of Kpath_new1 KL_path_new = np.append(Kpath_new[:T2], Lpath_new[:T2]) KL_path_init = np.append(Kpath_init[:T2], Lpath_init[:T2]) dist = ((KL_path_new - KL_path_init) ** 2).sum() # dist = np.absolute(KL_path_new - KL_path_init).max() print( 'TPI iter: ', iter_TPI, ', dist: ', "%10.4e" % (dist), ', max abs all errs: ', "%10.4e" % (np.hstack(np.absolute(b_err_path).max(), np.absolute(n_err_path).max(), np.absolute(bSp1_err_path).max())).max()) # The resource constraint does not bind across the transition # path until the equilibrium is solved Kpath_init = xi * Kpath_new + (1 - xi) * Kpath_init Lpath_init = xi * Lpath_new + (1 - xi) * Lpath_init if (iter_TPI == maxiter) and (dist > mindist): print('TPI reached maxiter and did not converge.') elif (iter_TPI == maxiter) and (dist <= mindist): print('TPI converged in the last iteration. ' + 'Should probably increase maxiter_TPI.') Kpath = Kpath_new Lpath = Lpath_new rpath = rpath_new wpath = wpath_new tpi_time = time.clock() - start_time tpi_output = { 'cpath': cpath, 'npath': npath, 'bpath': bpath, 'wpath': wpath, 'rpath': rpath, 'Kpath': Kpath, 'Lpath': Lpath, 'Ypath': Ypath, 'Cpath': Cpath, 'bSp1_err_path': bSp1_err_path, 'n_err_path': n_err_path, 'b_err_path': b_err_path, 'RCerrPath': RCerrPath, 'tpi_time': tpi_time} # Print maximum resource constraint error. Only look at resource # constraint up to period T2 - 1 because period T2 includes K_{t+1}, # which was forced to be the steady-state print('Max abs. labor supply Euler error: ', '%10.4e' % np.absolute(n_err_path[:T2 - 1]).max()) print('Max abs. savings Euler error: ', '%10.4e' % np.absolute(b_err_path[:T2 - 1]).max()) print('Max abs. final per savings: ', '%10.4e' % np.absolute(bSp1_err_path[:T2 - 1]).max()) print('Max abs. RC error: ', '%10.4e' % (np.absolute(RCerrPath[:T2 - 1]).max())) # Print TPI computation time utils.print_time(tpi_time, 'TPI') if graphs: ''' ---------------------------------------------------------------- cur_path = string, path name of current directory output_fldr = string, folder in current path to save files output_dir = string, total path of images folder output_path = string, path of file name of figure to be saved tvec = (T2+S-1,) vector, time period vector tgridT = (T2,) vector, time period vector from 1 to T2 sgrid = (S,) vector, all ages from 1 to S tmat = (S, T2) matrix, time periods for decisions ages (S) and time periods (T2) smat = (S, T2) matrix, ages for all decisions ages (S) and time periods (T2) ---------------------------------------------------------------- ''' # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = "images" output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot time path of aggregate capital stock tvec = np.linspace(1, T2 + S - 1, T2 + S - 1) minorLocator = MultipleLocator(1) fig, ax = plt.subplots() plt.plot(tvec, Kpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate capital stock K') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate capital $K_{t}$') output_path = os.path.join(output_dir, 'Kpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate labor fig, ax = plt.subplots() plt.plot(tvec, Lpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate labor L') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate labor $L_{t}$') output_path = os.path.join(output_dir, 'Lpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate output (GDP) fig, ax = plt.subplots() plt.plot(tvec, Ypath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate output (GDP) Y') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate output $Y_{t}$') output_path = os.path.join(output_dir, 'Ypath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate consumption fig, ax = plt.subplots() plt.plot(tvec, Cpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate consumption C') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate consumption $C_{t}$') output_path = os.path.join(output_dir, 'C_aggr_path') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of real wage fig, ax = plt.subplots() plt.plot(tvec, wpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real wage w') plt.xlabel(r'Period $t$') plt.ylabel(r'Real wage $w_{t}$') output_path = os.path.join(output_dir, 'wpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of real interest rate fig, ax = plt.subplots() plt.plot(tvec, rpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real interest rate r') plt.xlabel(r'Period $t$') plt.ylabel(r'Real interest rate $r_{t}$') output_path = os.path.join(output_dir, 'rpath') plt.savefig(output_path) # plt.show() plt.close() # Come up with nice visualization for time paths of individual # decisions return tpi_output
r_ss = ss_output['r_ss'] K_ss = ss_output['K_ss'] L_ss = ss_output['L_ss'] C_ss = ss_output['C_ss'] b_ss = ss_output['b_ss'] n_ss = ss_output['n_ss'] # Choose initial period distribution of wealth (bvec1), which # determines initial period aggregate capital stock init_wgts = ((1.5 - 0.87) / (S - 1) * (np.linspace(1, S, S) - 1) + 0.87) bvec1 = init_wgts * b_ss # Make sure init. period distribution is feasible in terms of K K1, K1_cstr = aggr.get_K(bvec1) # If initial bvec1 is not feasible end program if K1_cstr: print('Initial savings distribution is not feasible because ' + 'K1<=0. Some element(s) of bvec1 must increase.') else: tpi_params = (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter_TPI, TPI_OutTol, TPI_InTol, TPI_EulDiff, xi_TPI) tpi_output = tpi.get_TPI(bvec1, tpi_params, TPI_graphs) tpi_args = (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_ss, K_ss, L_ss, C_ss, b_ss, n_ss, maxiter_TPI, TPI_OutTol, TPI_InTol,
def get_SS(args, graph=False): (KL_init, beta, sigma, chi_n_vec, l_tilde, b, upsilon, S, alpha, A, delta) = args dist = 10 mindist = 1e-08 maxiter = 500 ss_iter = 0 xi = 0.2 r_params = (alpha, A, delta) w_params = (alpha, A) while dist > mindist and ss_iter < maxiter: ss_iter += 1 K, L = KL_init r = firms.get_r(K, L, r_params) w = firms.get_w(K, L, w_params) c1_guess = 1.0 c1_args = (r, w, beta, sigma, chi_n_vec, l_tilde, b, upsilon, S) results_c1 = opt.root(hh.get_bSp1, c1_guess, args=(c1_args)) c1 = results_c1.x cvec = hh.get_recurs_c(c1, r, beta, sigma, S) nvec = hh.get_n_s(cvec, w, sigma, chi_n_vec, l_tilde, b, upsilon) bvec = hh.get_recurs_b(cvec, nvec, r, w) K_new = aggr.get_K(bvec[:-1]) L_new = aggr.get_L(nvec) KL_new = np.array([K_new, L_new]) dist = ((KL_new - KL_init)**2).sum() KL_init = xi * KL_new + (1 - xi) * KL_init print('iter:', ss_iter, ' dist: ', dist) c_ss = cvec n_ss = nvec b_ss = bvec K_ss = K_new L_ss = L_new r_ss = r w_ss = w Y_params = (alpha, A) Y_ss = aggr.get_Y(K_ss, L_ss, Y_params) C_ss = aggr.get_C(c_ss) ss_output = { 'c_ss': c_ss, 'n_ss': n_ss, 'b_ss': b_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'r_ss': r_ss, 'w_ss': w_ss, 'Y_ss': Y_ss, 'C_ss': C_ss } if graph: # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = 'images' output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot c_ss, n_ss, b_ss # Plot steady-state consumption and savings distributions age_pers = np.arange(1, S + 1) fig, ax = plt.subplots() plt.plot(age_pers, c_ss, marker='D', label='Consumption') plt.plot(age_pers, np.append(0, b_ss[:-1]), marker='D', label='Savings') # for the minor ticks, use no labels; default NullFormatter minorLocator = MultipleLocator(1) ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') # plt.title('Steady-state consumption and savings', fontsize=20) plt.xlabel(r'Age $s$') plt.ylabel(r'Units of consumption') plt.xlim((0, S + 1)) # plt.ylim((-1.0, 1.15 * (b_ss.max()))) plt.legend(loc='upper left') output_path = os.path.join(output_dir, 'SS_bc') plt.savefig(output_path) # plt.show() plt.close() # Plot steady-state labor supply distributions fig, ax = plt.subplots() plt.plot(age_pers, n_ss, marker='D', label='Labor supply') # for the minor ticks, use no labels; default NullFormatter minorLocator = MultipleLocator(1) ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') # plt.title('Steady-state labor supply', fontsize=20) plt.xlabel(r'Age $s$') plt.ylabel(r'Labor supply') plt.xlim((0, S + 1)) # plt.ylim((-0.1, 1.15 * (n_ss.max()))) plt.legend(loc='upper right') output_path = os.path.join(output_dir, 'SS_n') plt.savefig(output_path) # plt.show() plt.close() return ss_output
def get_TPI(params, bvec1, graphs): ''' -------------------------------------------------------------------- Solves for transition path equilibrium using time path iteration (TPI) -------------------------------------------------------------------- INPUTS: params = length 21 tuple, (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, K_ss, L_ss, C_ss, maxiter, mindist, TPI_tol, xi, diff, hh_fsolve) bvec1 = (S,) vector, initial period savings distribution graphs = Boolean, =True if want graphs of TPI objects OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: aggr.get_K() get_path() firms.get_r() firms.get_w() get_cnbpath() solve_bn_path() aggr.get_L() aggr.get_Y() aggr.get_C() utils.print_time() OBJECTS CREATED WITHIN FUNCTION: start_time = scalar, current processor time in seconds (float) S = integer in [3,80], number of periods an individual lives T1 = integer > S, number of time periods until steady state is assumed to be reached T2 = integer > T1, number of time periods after which steady-state is forced in TPI beta = scalar in (0,1), discount factor for model period sigma = scalar > 0, coefficient of relative risk aversion l_tilde = scalar > 0, time endowment for each agent each period b_ellip = scalar > 0, fitted value of b for elliptical disutility of labor upsilon = scalar > 1, fitted value of upsilon for elliptical disutility of labor chi_n_vec = (S,) vector, values for chi^n_s A = scalar > 0, total factor productivity parameter in firms' production function alpha = scalar in (0,1), capital share of income delta = scalar in [0,1], per-period capital depreciation rt K_ss = scalar > 0, steady-state aggregate capital stock L_ss = scalar > 0, steady-state aggregate labor supply C_ss = scalar > 0, steady-state aggregate consumption maxiter = integer >= 1, Maximum number of iterations for TPI mindist = scalar > 0, convergence criterion for TPI TPI_tol = scalar > 0, tolerance level for TPI root finders xi = scalar in (0,1], TPI path updating parameter diff = Boolean, =True if want difference version of Euler errors beta*(1+r)*u'(c2) - u'(c1), =False if want ratio version [beta*(1+r)*u'(c2)]/[u'(c1)] - 1 hh_fsolve = boolean, =True if solve inner-loop household problem by choosing c_1 to set final period savings b_{S+1}=0. Otherwise, solve the household problem as multivariate root finder with 2S-1 unknowns and equations K1 = scalar > 0, initial aggregate capital stock K1_cnstr = Boolean, =True if K1 <= 0 Kpath_init = (T2+S-1,) vector, initial guess for the time path of the aggregate capital stock Lpath_init = (T2+S-1,) vector, initial guess for the time path of aggregate labor domain = (T2,) vector, integers from 0 to T2-1 domain2 = (T2,S) array, integers from 0 to T2-1 repeated S times ending_b = (S,) vector, distribution of savings at end of time path initial_b = (S,) vector, distribution of savings in initial period guesses_b = (T2,S) array, initial guess at distribution of savings over the time path ending_b_tail = (S,S) array, distribution of savings for S periods after end of time path guesses_b = (T2+S,S) array, guess at distribution of savings for T2+S periods domain3 = (T2,S) array, integers from 0 to T2-1 repeated S times initial_n = (S,) vector, distribution of labor supply in initial period guesses_n = (T2,S) array, initial guess at distribution of labor supply over the time path ending_n_tail = (S,S) array, distribution of labor supply for S periods after end of time path guesses_n = (T2+S,S) array, guess at distribution of labor supply for T2+S periods guesses = length 2 tuple, initial guesses at distributions of savings and labor supply over the time path iter_TPI = integer >= 0, current iteration of TPI dist = scalar >= 0, distance measure between initial and new paths r_params = length 3 tuple, (A, alpha, delta) w_params = length 2 tuple, (A, alpha) Y_params = length 2 tuple, (A, alpha) cnb_params = length 11 tuple, args to pass into get_cnbpath() rpath = (T2+S-1,) vector, time path of the interest rates wpath = (T2+S-1,) vector, time path of the wages ind = (S,) vector, integers from 0 to S bn_args = length 14 tuple, arguments to be passed to solve_bn_path() cpath = (S, T2+S-1) matrix, time path of distribution of individual consumption c_{s,t} npath = (S, T2+S-1) matrix, time path of distribution of individual labor supply n_{s,t} bpath = (S, T2+S-1) matrix, time path of distribution of individual savings b_{s,t} n_err_path = (S, T2+S-1) matrix, time path of distribution of individual labor supply Euler errors b_err_path = (S, T2+S-1) matrix, time path of distribution of individual savings Euler errors. First column and first row are identically zero bSp1_err_path = (S, T2) matrix, residual last period savings, which should be close to zero in equilibrium. Nonzero elements of matrix should only be in first column and first row Kpath_new = (T2+S-1,) vector, new path of the aggregate capital stock implied by household and firm optimization Kpath_cnstr = (T2+S-1,) Boolean vector, =True if K_t<=0 Lpath_new = (T2+S-1,) vector, new path of the aggregate labor rpath_new = (T2+S-1,) vector, updated time path of interest rate wpath_new = (T2+S-1,) vector, updated time path of the wages Ypath = (T2+S-1,) vector, equilibrium time path of aggregate output (GDP) Y_t Cpath = (T2+S-1,) vector, equilibrium time path of aggregate consumption C_t RCerrPath = (T2+S-2,) vector, equilibrium time path of the resource constraint error: Y_t - C_t - K_{t+1} + (1-delta)*K_t KL_path_new = (2*T2,) vector, appended K_path_new and L_path_new from observation 1 to T2 KL_path_init = (2*T2,) vector, appended K_path_init and L_path_init from observation 1 to T2 Kpath = (T2+S-1,) vector, equilibrium time path of aggregate capital stock K_t Lpath = (T2+S-1,) vector, equilibrium time path of aggregate labor L_t tpi_time = scalar, time to compute TPI solution (seconds) tpi_output = length 14 dictionary, {cpath, npath, bpath, wpath, rpath, Kpath, Lpath, Ypath, Cpath, bSp1_err_path, n_err_path, b_err_path, RCerrPath, tpi_time} FILES CREATED BY THIS FUNCTION: Kpath.png Lpath.png Ypath.png C_aggr_path.png wpath.png rpath.png cpath.png npath.png bpath.png RETURNS: tpi_output -------------------------------------------------------------------- ''' start_time = time.clock() (S, T1, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, K_ss, L_ss, C_ss, b_splus1_ss, n_ss, maxiter, mindist, TPI_tol, xi, diff, hh_fsolve) = params K1, K1_cnstr = aggr.get_K(bvec1) # Create time paths for K and L Kpath_init = np.zeros(T2 + S - 1) Kpath_init[:T1] = get_path(K1, K_ss, T1, 'quadratic') Kpath_init[T1:] = K_ss Lpath_init = L_ss * np.ones(T2 + S - 1) # Make arrays of initial guesses for labor supply and savings domain = np.linspace(0, T2, T2) domain2 = np.tile(domain.reshape(T2, 1), (1, S)) ending_b = b_splus1_ss initial_b = bvec1 guesses_b = (-1 / (domain2 + 1)) * (ending_b - initial_b) + ending_b ending_b_tail = np.tile(ending_b.reshape(1, S), (S, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, T2).reshape( T2, 1, ), (1, S)) initial_n = n_ss guesses_n = domain3 * (n_ss - initial_n) + initial_n ending_n_tail = np.tile(n_ss.reshape(1, S), (S, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) guesses = (guesses_b, guesses_n) iter_TPI = int(0) dist = 10.0 r_params = (A, alpha, delta) w_params = (A, alpha) Y_params = (A, alpha) cnb_params = (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, TPI_tol, diff) while (iter_TPI < maxiter) and (dist >= mindist): iter_TPI += 1 rpath = firms.get_r(r_params, Kpath_init, Lpath_init) wpath = firms.get_w(w_params, Kpath_init, Lpath_init) if hh_fsolve: ind = np.arange(S) bn_args = (rpath, wpath, ind, S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, TPI_tol, diff) npath, b_splus1_path, n_err_path, b_err_path = solve_bn_path( guesses, bn_args) bSp1_err_path = np.zeros((S, T2 + S - 1)) b_s_path = np.zeros((S, T2 + S - 1)) b_s_path[:, 0] = bvec1 b_s_path[1:, 1:] = b_splus1_path[:-1, :-1] cpath = hh.get_cons(rpath, wpath, b_s_path, b_splus1_path, npath) # update guesses for next iteration guesses = (np.transpose(b_splus1_path), np.transpose(npath)) else: cpath, npath, b_s_path, n_err_path, b_err_path, bSp1_err_path = \ get_cnbpath(cnb_params, rpath, wpath) b_splus1_path = np.append(b_s_path[1:, :T2], np.reshape(bSp1_err_path[-1, :], (1, T2)), axis=0) Kpath_new = np.zeros(T2 + S - 1) Kpath_new[:T2], Kpath_cnstr = aggr.get_K(b_s_path[:, :T2]) Kpath_new[T2:] = K_ss Kpath_cnstr = np.append(Kpath_cnstr, np.zeros(S - 1, dtype=bool)) Kpath_new[Kpath_cnstr] = 0.01 Lpath_new = np.zeros(T2 + S - 1) Lpath_new[:T2] = aggr.get_L(npath[:, :T2]) Lpath_new[T2:] = L_ss rpath_new = firms.get_r(r_params, Kpath_new, Lpath_new) wpath_new = firms.get_w(w_params, Kpath_new, Lpath_new) Ypath = aggr.get_Y(Y_params, Kpath_new, Lpath_new) Cpath = np.zeros(T2 + S - 1) Cpath[:T2] = aggr.get_C(cpath[:, :T2]) Cpath[T2:] = C_ss RCerrPath = (Ypath[:-1] - Cpath[:-1] - Kpath_new[1:] + (1 - delta) * Kpath_new[:-1]) # Check the distance of Kpath_new1 KL_path_new = np.append(Kpath_new[:T2], Lpath_new[:T2]) KL_path_init = np.append(Kpath_init[:T2], Lpath_init[:T2]) dist = ((KL_path_new - KL_path_init)**2).sum() # dist = np.absolute(KL_path_new - KL_path_init).max() print( 'TPI iter: ', iter_TPI, ', dist: ', "%10.4e" % (dist), ', max abs all errs: ', "%10.4e" % (np.absolute( np.hstack((b_err_path.max(axis=0), n_err_path.max(axis=0), bSp1_err_path.max(axis=0)))).max())) # The resource constraint does not bind across the transition # path until the equilibrium is solved Kpath_init = xi * Kpath_new + (1 - xi) * Kpath_init Lpath_init = xi * Lpath_new + (1 - xi) * Lpath_init if (iter_TPI == maxiter) and (dist > mindist): print('TPI reached maxiter and did not converge.') elif (iter_TPI == maxiter) and (dist <= mindist): print('TPI converged in the last iteration. ' + 'Should probably increase maxiter_TPI.') Kpath = Kpath_new Lpath = Lpath_new rpath = rpath_new wpath = wpath_new tpi_time = time.clock() - start_time tpi_output = { 'cpath': cpath, 'npath': npath, 'b_s_path': b_s_path, 'b_splus1_path': b_splus1_path, 'wpath': wpath, 'rpath': rpath, 'Kpath': Kpath, 'Lpath': Lpath, 'Ypath': Ypath, 'Cpath': Cpath, 'bSp1_err_path': bSp1_err_path, 'n_err_path': n_err_path, 'b_err_path': b_err_path, 'RCerrPath': RCerrPath, 'tpi_time': tpi_time } # Print maximum resource constraint error. Only look at resource # constraint up to period T2 - 1 because period T2 includes K_{t+1}, # which was forced to be the steady-state print('Max abs. RC error: ', "%10.4e" % (np.absolute(RCerrPath[:T2 - 1]).max())) # Print TPI computation time utils.print_time(tpi_time, 'TPI') if graphs: ''' ---------------------------------------------------------------- cur_path = string, path name of current directory output_fldr = string, folder in current path to save files output_dir = string, total path of images folder output_path = string, path of file name of figure to be saved tvec = (T2+S-1,) vector, time period vector tgridT = (T2,) vector, time period vector from 1 to T2 sgrid = (S,) vector, all ages from 1 to S tmat = (S, T2) matrix, time periods for decisions ages (S) and time periods (T2) smat = (S, T2) matrix, ages for all decisions ages (S) and time periods (T2) ---------------------------------------------------------------- ''' # Create directory if images directory does not already exist cur_path = os.path.split(os.path.abspath(__file__))[0] output_fldr = "images" output_dir = os.path.join(cur_path, output_fldr) if not os.access(output_dir, os.F_OK): os.makedirs(output_dir) # Plot time path of aggregate capital stock tvec = np.linspace(1, T2 + S - 1, T2 + S - 1) minorLocator = MultipleLocator(1) fig, ax = plt.subplots() plt.plot(tvec, Kpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate capital stock K') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate capital $K_{t}$') output_path = os.path.join(output_dir, 'Kpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate capital stock fig, ax = plt.subplots() plt.plot(tvec, Lpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate labor L') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate labor $L_{t}$') output_path = os.path.join(output_dir, 'Lpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate output (GDP) fig, ax = plt.subplots() plt.plot(tvec, Ypath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate output (GDP) Y') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate output $Y_{t}$') output_path = os.path.join(output_dir, 'Ypath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of aggregate consumption fig, ax = plt.subplots() plt.plot(tvec, Cpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for aggregate consumption C') plt.xlabel(r'Period $t$') plt.ylabel(r'Aggregate consumption $C_{t}$') output_path = os.path.join(output_dir, 'C_aggr_path') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of real wage fig, ax = plt.subplots() plt.plot(tvec, wpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real wage w') plt.xlabel(r'Period $t$') plt.ylabel(r'Real wage $w_{t}$') output_path = os.path.join(output_dir, 'wpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of real interest rate fig, ax = plt.subplots() plt.plot(tvec, rpath, marker='D') # for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) plt.grid(b=True, which='major', color='0.65', linestyle='-') plt.title('Time path for real interest rate r') plt.xlabel(r'Period $t$') plt.ylabel(r'Real interest rate $r_{t}$') output_path = os.path.join(output_dir, 'rpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of individual consumption distribution tgridT = np.linspace(1, T2, T2) sgrid = np.linspace(1, S, S) tmat, smat = np.meshgrid(tgridT, sgrid) cmap_c = cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'period-$t$') ax.set_ylabel(r'age-$s$') ax.set_zlabel(r'individual consumption $c_{s,t}$') strideval = max(int(1), int(round(S / 10))) ax.plot_surface(tmat, smat, cpath[:, :T2], rstride=strideval, cstride=strideval, cmap=cmap_c) output_path = os.path.join(output_dir, 'cpath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of individual labor supply distribution cmap_n = cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'period-$t$') ax.set_ylabel(r'age-$s$') ax.set_zlabel(r'individual labor supply $n_{s,t}$') strideval = max(int(1), int(round(S / 10))) ax.plot_surface(tmat, smat, npath[:, :T2], rstride=strideval, cstride=strideval, cmap=cmap_n) output_path = os.path.join(output_dir, 'npath') plt.savefig(output_path) # plt.show() plt.close() # Plot time path of individual savings distribution cmap_b = cm.get_cmap('summer') fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel(r'period-$t$') ax.set_ylabel(r'age-$s$') ax.set_zlabel(r'individual savings $b_{s,t}$') strideval = max(int(1), int(round(S / 10))) ax.plot_surface(tmat, smat, b_splus1_path[:, :T2], rstride=strideval, cstride=strideval, cmap=cmap_b) output_path = os.path.join(output_dir, 'bpath') plt.savefig(output_path) # plt.show() plt.close() return tpi_output
def create_tpi_params(**sim_params): ''' ------------------------------------------------------------------------ Set factor and initial capital stock to SS from baseline ------------------------------------------------------------------------ ''' baseline_ss = os.path.join(sim_params['baseline_dir'], "SS/SS_vars.pkl") ss_baseline_vars = pickle.load(open(baseline_ss, "rb")) factor = ss_baseline_vars['factor_ss'] initial_b = ss_baseline_vars['bssmat_splus1'] initial_n = ss_baseline_vars['nssmat'] if sim_params['baseline_spending']==True: baseline_tpi = os.path.join(sim_params['baseline_dir'], "TPI/TPI_vars.pkl") tpi_baseline_vars = pickle.load(open(baseline_tpi, "rb")) T_Hbaseline = tpi_baseline_vars['T_H'] Gbaseline = tpi_baseline_vars['G'] theta_params = (sim_params['e'], sim_params['S'], sim_params['retire']) if sim_params['baseline']==True: SS_values = (ss_baseline_vars['Kss'], ss_baseline_vars['Bss'], ss_baseline_vars['Lss'], ss_baseline_vars['rss'], ss_baseline_vars['wss'], ss_baseline_vars['BQss'], ss_baseline_vars['T_Hss'], ss_baseline_vars['revenue_ss'], ss_baseline_vars['bssmat_splus1'], ss_baseline_vars['nssmat'], ss_baseline_vars['Yss'], ss_baseline_vars['Gss']) theta = tax.replacement_rate_vals(ss_baseline_vars['nssmat'], ss_baseline_vars['wss'], factor, theta_params) elif sim_params['baseline']==False: reform_ss = os.path.join(sim_params['input_dir'], "SS/SS_vars.pkl") ss_reform_vars = pickle.load(open(reform_ss, "rb")) SS_values = (ss_reform_vars['Kss'],ss_reform_vars['Bss'], ss_reform_vars['Lss'], ss_reform_vars['rss'], ss_reform_vars['wss'], ss_reform_vars['BQss'], ss_reform_vars['T_Hss'], ss_reform_vars['revenue_ss'], ss_reform_vars['bssmat_splus1'], ss_reform_vars['nssmat'], ss_reform_vars['Yss'], ss_reform_vars['Gss']) theta = tax.replacement_rate_vals(ss_reform_vars['nssmat'], ss_reform_vars['wss'], factor, theta_params) # Make a vector of all one dimensional parameters, to be used in the # following functions wealth_tax_params = [sim_params['h_wealth'], sim_params['p_wealth'], sim_params['m_wealth']] ellipse_params = [sim_params['b_ellipse'], sim_params['upsilon']] chi_params = [sim_params['chi_b_guess'], sim_params['chi_n_guess']] N_tilde = sim_params['omega'].sum(1) #this should just be one in each year given how we've constructed omega sim_params['omega'] = sim_params['omega'] / N_tilde.reshape(sim_params['T'] + sim_params['S'], 1) tpi_params = [sim_params['J'], sim_params['S'], sim_params['T'], sim_params['BW'], sim_params['beta'], sim_params['sigma'], sim_params['alpha'], sim_params['gamma'], sim_params['epsilon'], sim_params['Z'], sim_params['delta'], sim_params['ltilde'], sim_params['nu'], sim_params['g_y'], sim_params['g_n_vector'], sim_params['tau_payroll'], sim_params['tau_bq'], sim_params['rho'], sim_params['omega'], N_tilde, sim_params['lambdas'], sim_params['imm_rates'], sim_params['e'], sim_params['retire'], sim_params['mean_income_data'], factor] + \ wealth_tax_params + ellipse_params + chi_params + [theta] iterative_params = [sim_params['maxiter'], sim_params['mindist_SS'], sim_params['mindist_TPI']] small_open_params = [sim_params['small_open'], sim_params['tpi_firm_r'], sim_params['tpi_hh_r']] 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 ## Assumption for tax functions is that policy in last year of BW is # extended permanently etr_params_TP = np.zeros((S,T+S,sim_params['etr_params'].shape[2])) etr_params_TP[:,:BW,:] = sim_params['etr_params'] etr_params_TP[:,BW:,:] = np.reshape(sim_params['etr_params'][:,BW-1,:],(S,1,sim_params['etr_params'].shape[2])) mtrx_params_TP = np.zeros((S,T+S,sim_params['mtrx_params'].shape[2])) mtrx_params_TP[:,:BW,:] = sim_params['mtrx_params'] mtrx_params_TP[:,BW:,:] = np.reshape(sim_params['mtrx_params'][:,BW-1,:],(S,1,sim_params['mtrx_params'].shape[2])) mtry_params_TP = np.zeros((S,T+S,sim_params['mtry_params'].shape[2])) mtry_params_TP[:,:BW,:] = sim_params['mtry_params'] mtry_params_TP[:,BW:,:] = np.reshape(sim_params['mtry_params'][:,BW-1,:],(S,1,sim_params['mtry_params'].shape[2])) income_tax_params = (sim_params['analytical_mtrs'], etr_params_TP, mtrx_params_TP, mtry_params_TP) ''' ------------------------------------------------------------------------ Set government finance parameters ------------------------------------------------------------------------ ''' budget_balance = sim_params['budget_balance'] ALPHA_T = sim_params['ALPHA_T'] ALPHA_G = sim_params['ALPHA_G'] tG1 = sim_params['tG1'] tG2 = sim_params['tG2'] rho_G = sim_params['rho_G'] debt_ratio_ss = sim_params['debt_ratio_ss'] if sim_params['baseline_spending']==False: fiscal_params = (budget_balance, ALPHA_T, ALPHA_G, tG1, tG2, rho_G, debt_ratio_ss) else: fiscal_params = (budget_balance, ALPHA_T, ALPHA_G, tG1, tG2, rho_G, debt_ratio_ss, T_Hbaseline, Gbaseline) initial_debt = sim_params['initial_debt'] ''' ------------------------------------------------------------------------ Set business tax parameters ------------------------------------------------------------------------ ''' tau_b = sim_params['tau_b'] delta_tau = sim_params['delta_tau'] biz_tax_params = (tau_b, delta_tau) initial_debt = sim_params['initial_debt'] ''' ------------------------------------------------------------------------ Set other parameters and initial values ------------------------------------------------------------------------ ''' # Get an initial distribution of wealth with the initial population # distribution. When small_open=True, the value of K0 is used as a placeholder for first-period wealth (B0) omega_S_preTP = sim_params['omega_S_preTP'] B0_params = (omega_S_preTP.reshape(S, 1), lambdas, imm_rates[0].reshape(S,1), g_n_vector[0], 'SS') B0 = aggr.get_K(initial_b, B0_params) b_sinit = np.array(list(np.zeros(J).reshape(1, J)) + list(initial_b[:-1])) b_splus1init = initial_b initial_values = (B0, b_sinit, b_splus1init, factor, initial_b, initial_n, omega_S_preTP, initial_debt) return (income_tax_params, tpi_params, iterative_params, small_open_params, initial_values, SS_values, fiscal_params, biz_tax_params)