def euler_sys(guesses, *args): ''' -------------------------------------------------------------------- Specify the system of Euler Equations characterizing the household problem. -------------------------------------------------------------------- INPUTS: guesses = (2S-1,) vector, guess at labor supply and savings decisions args = length 14 tuple, (r, w, beta, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff, S, SS_tol) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.get_n_errors() hh.get_n_errors() hh.get_cons() OBJECTS CREATED WITHIN FUNCTION: r = scalar > 0, guess at steady-state interest rate w = scalar > 0, guess at steady-state wage 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 chi_n_vec = (S,) vector, values for chi^n_s 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 A = scalar > 0, total factor productivity parameter in firms' production function diff = boolean, =True if simple difference Euler errors, otherwise percent deviation Euler errors S = integer >= 3, number of periods in individual lifetime SS_tol = scalar > 0, tolerance level for steady-state fsolve nvec = (S,) vector, lifetime labor supply (n1, n2, ...nS) bvec = (S,) vector, lifetime savings (b1, b2, ...bS) with b1=0 cvec = (S,) vector, lifetime consumption (c1, c2, ...cS) b_sp1 = = (S,) vector, lifetime savings (b1, b2, ...bS) with bS=0 n_errors = (S,) vector, labor supply Euler errors b_errors = (S-1,) vector, savings Euler errors FILES CREATED BY THIS FUNCTION: None RETURNS: array of n_errors and b_errors -------------------------------------------------------------------- ''' (r, w, beta, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff, S) = args nvec = guesses[:S] bvec1 = guesses[S:] b_s = np.append(0.0, bvec1) b_sp1 = np.append(bvec1, 0.0) cvec = hh.get_cons(r, w, b_s, b_sp1, nvec) n_args = (w, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff, cvec) n_errors = hh.get_n_errors(nvec, *n_args) b_args = (r, beta, sigma, diff) b_errors = hh.get_b_errors(cvec, *b_args) errors = np.append(n_errors, b_errors) return errors
def firstdoughnutring(guesses, args): ''' Solves the first entries of the upper triangle of the twist doughnut. This is separate from the main TPI function because the the values of b and n are scalars, so it is easier to just have a separate function for these cases. Inputs: guesses = guess for b and n (2x1 list) winit = initial wage rate (scalar) rinit = initial rental rate (scalar) BQinit = initial aggregate bequest (scalar) T_H_init = initial lump sum tax (scalar) initial_b = initial distribution of capital (SxJ array) factor = steady state scaling factor (scalar) j = which ability type is being solved for (scalar) parameters = list of parameters (list) theta = replacement rates (Jx1 array) tau_bq = bequest tax rates (Jx1 array) Output: euler errors (2x1 list) ''' # unpack tuples of parameters r, w, S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec,\ initial_b, diff = args b_splus1 = 0.0 # leave zero savings in last period of life n = float(guesses[1]) b_s = float(initial_b[-1]) # Euler equations cons = hh.get_cons(r, w, b_s, b_splus1, n) b_params = (beta, sigma) error1 = 0.0 #hh.get_b_errors(b_params, r, cons, diff) n_args = (w, cons, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff) error2 = hh.get_n_errors(n, n_args) if n <= 0 or n >= 1: error2 += 1e14 if cons <= 0: error1 += 1e14 return [error1] + [error2]
def get_cnbpath(params, rpath, wpath): ''' -------------------------------------------------------------------- Given time paths for interest rates and wages, this function generates matrices for the time path of the distribution of individual consumption, labor supply, savings, the corresponding Euler errors for the labor supply decision and the savings decision, and the residual error of end-of-life savings associated with solving each lifetime decision. -------------------------------------------------------------------- INPUTS: params = length 11 tuple, (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, TPI_tol, diff) rpath = (T2+S-1,) vector, equilibrium time path of interest rate wpath = (T2+S-1,) vector, equilibrium time path of the real wage OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.c1_bSp1err() hh.get_cnb_vecs() hh.get_n_errors() hh.get_b_errors() OBJECTS CREATED WITHIN FUNCTION: S = integer in [3,80], number of periods an individual lives T2 = integer > S, number of periods until steady state beta = scalar in (0,1), discount factor 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 bvec1 = (S,) vector, initial period savings distribution TPI_tol = scalar > 0, tolerance level for fsolve's in TPI 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 cpath = (S, T2+S-1) matrix, time path of the distribution of consumption npath = (S, T2+S-1) matrix, time path of the distribution of labor supply bpath = (S, T2+S-1) matrix, time path of the distribution of savings n_err_path = (S, T2+S-1) matrix, time path of distribution of labor supply Euler errors b_err_path = (S, T2+S-1) matrix, time path of distribution of savings Euler errors 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 c1_options = length 1 dict, options for opt.root(hh.c1_bSp1err,...) b_err_params = length 2 tuple, args to pass into hh.get_b_errors() p = integer in [1, S-1], index representing number of periods remaining in a lifetime, used to solve incomplete lifetimes c1_init = scalar > 0, guess for initial period consumption c1_args = length 10 tuple, args to pass into opt.root(hh.c1_bSp1err,...) results_c1 = results object, solution from opt.root(hh.c1_bSp1err,...) c1 = scalar > 0, optimal initial consumption cnb_args = length 8 tuple, args to pass into hh.get_cnb_vecs() cvec = (p,) vector, individual lifetime consumption decisions nvec = (p,) vector, individual lifetime labor supply decisions bvec = (p,) vector, individual lifetime savings decisions b_Sp1 = scalar, savings in last period for next period. Should be zero in equilibrium DiagMaskc = (p, p) boolean identity matrix DiagMaskb = (p-1, p-1) boolean identity matrix n_err_params = length 5 tuple, args to pass into hh.get_n_errors() n_err_vec = (p,) vector, individual lifetime labor supply Euler errors b_err_vec = (p-1,) vector, individual lifetime savings Euler errors t = integer in [0,T2-1], index of time period (minus 1) FILES CREATED BY THIS FUNCTION: None RETURNS: cpath, npath, bpath, n_err_path, b_err_path, bSp1_err_path -------------------------------------------------------------------- ''' (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, TPI_tol, diff) = params cpath = np.zeros((S, T2 + S - 1)) npath = np.zeros((S, T2 + S - 1)) bpath = np.append(bvec1.reshape((S, 1)), np.zeros((S, T2 + S - 2)), axis=1) n_err_path = np.zeros((S, T2 + S - 1)) b_err_path = np.zeros((S, T2 + S - 1)) bSp1_err_path = np.zeros((S, T2)) # Solve the incomplete remaining lifetime decisions of agents alive # in period t=1 but not born in period t=1 c1_options = {'maxiter': 500} b_err_params = (beta, sigma) for p in range(1, S): c1_init = 0.1 c1_args = (bvec1[-p], beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec[-p:], rpath[:p], wpath[:p], diff) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=TPI_tol, options=(c1_options)) c_1 = results_c1.x cnb_args = (bvec1[-p], beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec[-p:], diff) cvec, nvec, bvec, b_Sp1 = \ hh.get_cnb_vecs(c_1, rpath[:p], wpath[:p], cnb_args) DiagMaskc = np.eye(p, dtype=bool) DiagMaskb = np.eye(p - 1, dtype=bool) cpath[-p:, :p] = DiagMaskc * cvec + cpath[-p:, :p] npath[-p:, :p] = DiagMaskc * nvec + npath[-p:, :p] n_err_args = (wpath[:p], cvec, sigma, l_tilde, chi_n_vec[-p:], b_ellip, upsilon, diff) n_err_vec = hh.get_n_errors(nvec, n_err_args) n_err_path[-p:, :p] = (DiagMaskc * n_err_vec + n_err_path[-p:, :p]) bSp1_err_path[-p, 0] = b_Sp1 if p > 1: bpath[S - p + 1:, 1:p] = (DiagMaskb * bvec[1:] + bpath[S - p + 1:, 1:p]) b_err_vec = hh.get_b_errors(b_err_params, rpath[1:p], cvec, diff) b_err_path[S - p + 1:, 1:p] = (DiagMaskb * b_err_vec + b_err_path[S - p + 1:, 1:p]) # print('p=', p, ', max. abs. all errs: ', # np.hstack((n_err_vec, b_err_vec, b_Sp1)).max()) # Solve the remaining lifetime decisions of agents born between # period t=1 and t=T (complete lifetimes) DiagMaskc = np.eye(S, dtype=bool) DiagMaskb = np.eye(S - 1, dtype=bool) for t in range(T2): # Go from periods 1 to T (columns 0 to T-1) if t == 0: c1_init = 0.1 else: c1_init = cpath[0, t - 1] c1_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, rpath[t:t + S], wpath[t:t + S], diff) results_c1 = \ opt.root(hh.c1_bSp1err, c1_init, args=(c1_args), method='lm', tol=TPI_tol, options=(c1_options)) c_1 = results_c1.x cnb_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, diff) cvec, nvec, bvec, b_Sp1 = \ hh.get_cnb_vecs(c_1, rpath[t:t + S], wpath[t:t + S], cnb_args) cpath[:, t:t + S] = DiagMaskc * cvec + cpath[:, t:t + S] npath[:, t:t + S] = DiagMaskc * nvec + npath[:, t:t + S] n_err_args = (wpath[t:t + S], cvec, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff) n_err_vec = hh.get_n_errors(nvec, n_err_args) n_err_path[:, t:t + S] = (DiagMaskc * n_err_vec + n_err_path[:, t:t + S]) bpath[:, t:t + S] = DiagMaskc * bvec + bpath[:, t:t + S] b_err_vec = hh.get_b_errors(b_err_params, rpath[t + 1:t + S], cvec, diff) b_err_path[1:, t + 1:t + S] = (DiagMaskb * b_err_vec + b_err_path[1:, t + 1:t + S]) bSp1_err_path[0, t] = b_Sp1 # print('t=', t, ', max. abs. all errs: ', # np.absolute(np.hstack((n_err_vec, b_err_vec, # b_Sp1))).max()) return cpath, npath, bpath, n_err_path, b_err_path, bSp1_err_path
def twist_doughnut(guesses, td_args): ''' Parameters: guesses = distribution of capital and labor (various length list) w = wage rate ((T+S)x1 array) r = rental rate ((T+S)x1 array) BQ = aggregate bequests ((T+S)x1 array) T_H = lump sum tax over time ((T+S)x1 array) factor = scaling factor (scalar) j = which ability type is being solved for (scalar) s = which upper triangle loop is being solved for (scalar) t = which diagonal is being solved for (scalar) params = list of parameters (list) theta = replacement rates (Jx1 array) tau_bq = bequest tax rate (Jx1 array) rho = mortalit rate (Sx1 array) lambdas = ability weights (Jx1 array) e = ability type (SxJ array) initial_b = capital stock distribution in period 0 (SxJ array) chi_b = chi^b_j (Jx1 array) chi_n = chi^n_s (Sx1 array) Output: Value of Euler error (various length list) ''' rpath, wpath, s, t, S, T2, beta, sigma, l_tilde, b_ellip, upsilon, \ chi_n_vec, initial_b, diff = td_args length = len(guesses) // 2 b_guess = np.array(guesses[:length]) n_guess = np.array(guesses[length:]) b_guess[-1] = 0.0 # save nothing in last period if length == S: b_s = np.array([0] + list(b_guess[:-1])) else: # b_s = np.array([(initial_b[-(s + 3)])] + list(b_guess[:-1])) b_s = np.array([(initial_b[-(s + 2)])] + list(b_guess[:-1])) w = wpath[t:t + length] r = rpath[t:t + length] # Euler equations cons = hh.get_cons(r, w, b_s, b_guess, n_guess) b_params = (beta, sigma) euler_errors = hh.get_b_errors(b_params, r[1:], cons, diff) error1 = np.append(euler_errors, 0.0) n_args = (w, cons, sigma, l_tilde, chi_n_vec[-length:], b_ellip, upsilon, diff) error2 = hh.get_n_errors(n_guess, n_args) # Check and punish constraint violations mask1 = n_guess < 0 error2[mask1] += 1e14 mask2 = n_guess > l_tilde error2[mask2] += 1e14 mask3 = cons < 0 error2[mask3] += 1e14 return list(error1.flatten()) + list(error2.flatten())
def inner_loop(rpath, wpath, args): ''' -------------------------------------------------------------------- Given time paths for interest rates and wages, this function generates matrices for the time path of the distribution of individual consumption, labor supply, savings, the corresponding Euler errors for the labor supply decision and the savings decision, and the residual error of end-of-life savings associated with solving each lifetime decision. -------------------------------------------------------------------- INPUTS: rpath = (T2+S-1,) vector, equilibrium time path of interest rate wpath = (T2+S-1,) vector, equilibrium time path of the real wage args = length 12 tuple, (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, n_ss, In_Tol, diff) OTHER FUNCTIONS AND FILES CALLED BY THIS FUNCTION: hh.get_n_errors() hh.get_b_errors() OBJECTS CREATED WITHIN FUNCTION: S = integer in [3,80], number of periods an individual lives T2 = integer > S, number of periods until steady state beta = scalar in (0,1), discount factor 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 bvec1 = (S,) vector, initial period savings distribution In _tol = scalar > 0, tolerance level for fsolve's in TPI 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 cpath = (S, T2+S-1) matrix, time path of the distribution of consumption npath = (S, T2+S-1) matrix, time path of the distribution of labor supply bpath = (S, T2+S-1) matrix, time path of the distribution of savings n_err_path = (S, T2+S-1) matrix, time path of distribution of labor supply Euler errors b_err_path = (S, T2+S-1) matrix, time path of distribution of savings Euler errors 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 b_err_params = length 2 tuple, args to pass into hh.get_b_errors() p = integer in [1, S-1], index representing number of periods remaining in a lifetime, used to solve incomplete lifetimes cvec = (p,) vector, individual lifetime consumption decisions nvec = (p,) vector, individual lifetime labor supply decisions bvec = (p,) vector, individual lifetime savings decisions b_Sp1 = scalar, savings in last period for next period. Should be zero in equilibrium DiagMaskc = (p, p) boolean identity matrix DiagMaskb = (p-1, p-1) boolean identity matrix n_err_params = length 5 tuple, args to pass into hh.get_n_errors() n_err_vec = (p,) vector, individual lifetime labor supply Euler errors b_err_vec = (p-1,) vector, individual lifetime savings Euler errors t = integer in [0,T2-1], index of time period (minus 1) FILES CREATED BY THIS FUNCTION: None RETURNS: cpath, npath, bpath, n_err_path, b_err_path, bSp1_err_path -------------------------------------------------------------------- ''' (S, T2, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, bvec1, n_ss, In_Tol, diff) = args cpath = np.zeros((S, T2 + S - 1)) npath = np.zeros((S, T2 + S - 1)) bpath = np.append(bvec1.reshape((S, 1)), np.zeros((S, T2 + S - 2)), axis=1) n_err_path = np.zeros((S, T2 + S - 1)) b_err_path = np.zeros((S, T2 + S - 1)) b_err_args = (beta, sigma, diff) # Solve the incomplete remaining lifetime decisions of agents alive # in period t=1 but not born in period t=1 for p in range(1, S): if p == 1: # p=1 individual only has an s=S labor supply decision n_S n_S1_init = n_ss[-1] nS1_args = (wpath[0], sigma, l_tilde, chi_n_vec[-1], b_ellip, upsilon, diff, rpath[0], bvec1[-1], 0.0) results_nS1 = opt.root(hh.get_n_errors, n_S1_init, args=(nS1_args), method='lm', tol=In_Tol) n_S1 = results_nS1.x npath[-1, 0] = n_S1 n_err_path[-1, 0] = results_nS1.fun cpath[-1, 0] = hh.get_cons(rpath[0], wpath[0], bvec1[-1], 0.0, n_S1) else: # 1<p<S chooses b_{s+1} and n_s and has incomplete lives DiagMaskb = np.eye(p - 1, dtype=bool) DiagMaskn = np.eye(p, dtype=bool) b_sp1_init = np.diag(bpath[S - p + 1:, :p - 1]) n_s_init = np.hstack( (n_ss[S - p], np.diag(npath[S - p + 1:, :p - 1]))) bn_init = np.hstack((b_sp1_init, n_s_init)) bn_args = (rpath[:p], wpath[:p], bvec1[-p], p, beta, sigma, l_tilde, chi_n_vec[-p:], b_ellip, upsilon, diff) results_bn = opt.root(hh.bn_errors, bn_init, args=(bn_args), tol=In_Tol) bvec = results_bn.x[:p - 1] nvec = results_bn.x[p - 1:] b_s_vec = np.append(bvec1[-p], bvec) b_sp1_vec = np.append(bvec, 0.0) cvec = hh.get_cons(rpath[:p], wpath[:p], b_s_vec, b_sp1_vec, nvec) npath[S - p:, :p] = DiagMaskn * nvec + npath[S - p:, :p] bpath[S - p + 1:, 1:p] = (DiagMaskb * bvec + bpath[S - p + 1:, 1:p]) cpath[S - p:, :p] = DiagMaskn * cvec + cpath[S - p:, :p] n_args = (wpath[:p], sigma, l_tilde, chi_n_vec[-p:], b_ellip, upsilon, diff, cvec) n_errors = hh.get_n_errors(nvec, *n_args) n_err_path[S - p:, :p] = (DiagMaskn * n_errors + n_err_path[S - p:, :p]) b_errors = hh.get_b_errors(cvec, rpath[1:p], *b_err_args) b_err_path[S - p + 1:, 1:p] = (DiagMaskb * b_errors + b_err_path[S - p + 1:, 1:p]) # Solve the complete remaining lifetime decisions of agents born # between period t=1 and t=T2 for t in range(T2): DiagMaskb = np.eye(S - 1, dtype=bool) DiagMaskn = np.eye(S, dtype=bool) b_sp1_init = np.diag(bpath[1:, t:t + S - 1]) if t == 0: n_s_init = np.hstack((n_ss[0], np.diag(npath[1:, t:t + S - 1]))) else: n_s_init = np.diag(npath[:, t - 1:t + S - 1]) bn_init = np.hstack((b_sp1_init, n_s_init)) bn_args = (rpath[t:t + S], wpath[t:t + S], 0.0, S, beta, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff) results_bn = opt.root(hh.bn_errors, bn_init, args=(bn_args), tol=In_Tol) bvec = results_bn.x[:S - 1] nvec = results_bn.x[S - 1:] b_s_vec = np.append(0.0, bvec) b_sp1_vec = np.append(bvec, 0.0) cvec = hh.get_cons(rpath[t:t + S], wpath[t:t + S], b_s_vec, b_sp1_vec, nvec) npath[:, t:t + S] = DiagMaskn * nvec + npath[:, t:t + S] bpath[1:, t + 1:t + S] = (DiagMaskb * bvec + bpath[1:, t + 1:t + S]) cpath[:, t:t + S] = DiagMaskn * cvec + cpath[:, t:t + S] n_args = (wpath[t:t + S], sigma, l_tilde, chi_n_vec, b_ellip, upsilon, diff, cvec) n_errors = hh.get_n_errors(nvec, *n_args) n_err_path[:, t:t + S] = (DiagMaskn * n_errors + n_err_path[:, t:t + S]) b_errors = hh.get_b_errors(cvec, rpath[t + 1:t + S], *b_err_args) b_err_path[1:, t + 1:t + S] = (DiagMaskb * b_errors + b_err_path[1:, t + 1:t + S]) return cpath, npath, bpath, n_err_path, b_err_path
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 5 tuple, (Kss_init, Lss_init, rss_init, wss_init,c1_init) args = length 16 tuple, (S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, tax_params, fiscal_params, SS_tol, EulDiff, hh_fsolve, KL_outer) 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 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) 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 want to solve HH problem with one large root finder call 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 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 9 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() Y_params = length 2 tuple, args to pass into get_Y() 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 Y_init = scalar, initial value for output x_init = scalar, initial value for per household lump sum transfers rpath = (S,) vector, lifetime path of interest rates wpath = (S,) vector, lifetime path of wages xpath = (S,) vector, lifetime path of lump sum transfers 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 b_splus1_vec_new = (S,) vector, updated values for lifetime savings (b1, b2,...bS) b_s_vec_new = (S,) vector, updated values for lifetime savings enter period with (b0, b1,...bS) b_Sp1_new = scalar, updated value for savings in last period, should be arbitrarily close to zero B_new = scalar, aggregate household savings given bvec_new B_cnstr = boolean, =True if K_new <= 0 L_new = scalar, updated L given nvec_new debt_ss = scalar, government debt in the SS K_new = scalar, updated K given bvec_new and SS debt K_cnstr = boolean, =True if K_new <= 0 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 B_ss = scalar > 0, steady-state aggregate savings r_ss = scalar > 0, steady-state interest rate w_ss = scalar > 0, steady-state wage x_ss = scalar > 0, steady-state per household lump sum transfers 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_splus1_ss = (S,) vector, steady-state lifetime savings (b1_ss, b2_ss, ...bS+1_ss) b_s_ss = (S,) vector, steady-state lifetime savings enter period with (b0_ss, b2_ss, ...bS_ss) where b0_ss=0 b_Sp1_ss = scalar, steady-state savings for period after last period of life. b_Sp1_ss approx. 0 in equilibrium 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 rev_params = length 4 tuple, (A, alpha, delta, tax_params) R_ss = scalar, steady-state tax revenue X_ss = scalar, total steady-state government transfers debt_service_ss = scalar, steady-state debt service cost G_ss = steady-state government spending RCerr_ss = scalar, resource constraint error ss_time = scalar, seconds elapsed to run steady-state comput'n ss_output = length 17 dict, steady-state objects {n_ss, b_s_ss, b_splus1_ss, c_ss, b_Sp1_ss, w_ss, r_ss, B_ss, K_ss, L_ss, Y_ss, C_ss, G_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, rss_init, wss_init, c1_init = init_vals (S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, tax_params, fiscal_params, SS_tol, EulDiff, hh_fsolve) = args tau_l, tau_k, tau_c = tax_params tG1, tG2, alpha_X, alpha_G, rho_G, alpha_D, alpha_D0 = fiscal_params maxiter_SS = 200 iter_SS = 0 mindist_SS = 1e-10 dist_SS = 10 xi_SS = 0.15 KL_init = np.array([Kss_init, Lss_init]) r_params = (A, alpha, delta, tau_c) w_params = (A, alpha) Y_params = (A, alpha) inner_loop_params = (c1_init, S, beta, sigma, l_tilde, \ b_ellip, upsilon, chi_n_vec, A, alpha, delta,\ tax_params, fiscal_params,\ EulDiff, hh_fsolve, SS_tol) 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) Y_init = aggr.get_Y(Y_params, K_init, L_init) x_init = (alpha_X * Y_init) / S B_new, K_new, L_new, Y_new, debt, cvec, nvec, b_s_vec, b_splus1_vec,\ b_Sp1, x_new, r_new, w_new\ = inner_loop(r_init, w_init, Y_init, x_init, inner_loop_params) 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 rev_params = (A, alpha, delta, tax_params) R_new = tax.revenue(r_new, w_new, b_s_vec, nvec, K_new, L_new, rev_params) X_new = x_new * S G_new = R_new - (X_new + debt * r_new) print('tax rev to GDP: ', R_new / Y_new) print('SS outlays to GDP: ', ((debt * r_new) + X_new + G_new) / Y_new) print('SS G spending to GDP: ', G_new / Y_new) print('factor prices: ', r_new, w_new) print('SS Iteration=', iter_SS, ', SS Distance=', dist_SS) B_ss, K_ss, L_ss, Y_ss, debt_ss, c_ss, n_ss, b_s_ss, b_splus1_ss,\ b_Sp1_ss, x_ss, r_ss, w_ss\ = inner_loop(r_new, w_new, Y_new, x_new, inner_loop_params) C_ss = aggr.get_C(c_ss) n_err_args = (w_ss, c_ss, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, tau_l, EulDiff) n_err_ss = hh.get_n_errors(n_ss, n_err_args) b_err_params = (beta, sigma, tau_k) b_err_ss = hh.get_b_errors(b_err_params, r_ss, c_ss, EulDiff) rev_params = (A, alpha, delta, tax_params) R_ss = tax.revenue(r_ss, w_ss, b_s_ss, n_ss, K_ss, L_ss, rev_params) X_ss = x_ss * S debt_service_ss = r_ss * alpha_D * Y_ss G_ss = R_ss - (X_ss + debt_service_ss) RCerr_ss = Y_ss - C_ss - delta * K_ss - G_ss print('SS tax rev to GDP: ', R_ss / Y_ss) print('SS outlays to GDP: ', (debt_service_ss + X_ss + G_ss) / Y_ss) print('SS G spending to GDP: ', G_ss / Y_ss) ss_time = time.clock() - start_time ss_output = { 'n_ss': n_ss, 'b_s_ss': b_s_ss, 'b_splus1_ss': b_splus1_ss, 'c_ss': c_ss, 'b_Sp1_ss': b_Sp1_ss, 'w_ss': w_ss, 'r_ss': r_ss, 'B_ss': B_ss, 'K_ss': K_ss, 'L_ss': L_ss, 'Y_ss': Y_ss, 'C_ss': C_ss, 'G_ss': G_ss, 'X_ss': X_ss, 'n_err_ss': n_err_ss, 'b_err_ss': b_err_ss, 'RCerr_ss': RCerr_ss, 'ss_time': ss_time } print('n_ss is: ', n_ss) print('b_s_ss is: ', b_s_ss) 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('Steay-state government spending is: ', G_ss) if G_ss < 0: print('WARNING: SS debt to GDP ratio and tax policy are generating ' + 'negative government spending.') print('Steay-state tax revenue, transfers, and debt service are: ', R_ss, X_ss, debt_service_ss) print('Steady-state residual savings b_Sp1 is: ', b_Sp1_ss) # 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 age_pers = (S,) vector, ages from 1 to S ---------------------------------------------------------------- ''' # 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 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, b_splus1_ss, 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_SS(init_vals, args, graphs=False): ''' -------------------------------------------------------------------- Solve for the steady-state solution of the S-period-lived agent OG model with endogenous labor supply and a small open economy. -------------------------------------------------------------------- INPUTS: init_vals = length 5 tuple, (Kss_init, Lss_init, rss_init, wss_init,c1_init) args = length 14 tuple, (S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, SS_tol, EulDiff, hh_fsolve, KL_outer) 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 supplied 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 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 supplied L_init = scalar, initial value of aggregate labor r_init = scalar, initial value for interest rate w_init = scalar, initial value for wage K_d = scalar, capital demand 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 b_s_new = (S,) vector, updated values for lifetime wealth b_splus1_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 supplied K_d_ss = scalar > 0, steady-state aggregate capital stock demanded 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_s_ss = (S,) vector, steady-state wealth enter period with b_splus1_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() c1_init = init_vals (S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, A, alpha, delta, r_star, SS_tol, EulDiff, hh_fsolve) = args c1_options = {'maxiter': 500} cnb_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, EulDiff) w_params = (A, alpha, delta) K_params = (A, alpha, delta) r_ss = r_star w_ss = firms.get_w(r_ss, w_params) 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_ss, w_ss, S, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, EulDiff) [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_ss = np.append(solutions[:S - 1], 0.0) n_ss = solutions[S - 1:] b_Sp1_ss = 0.0 b_s_ss = np.append(0.0, b_splus1_ss[:-1]) c_ss = hh.get_cons(r_ss, w_ss, b_s_ss, b_splus1_ss, n_ss) else: rpath = r_ss * np.ones(S) wpath = w_ss * np.ones(S) c1_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, rpath, wpath, EulDiff) c1_options = {'maxiter': 500} results_c1 = \ opt.root(hh.c1_bSp1err, c1_new, args=(c1_args), method='lm', tol=SS_tol, options=(c1_options)) c1_ss = results_c1.x cnb_args = (0.0, beta, sigma, l_tilde, b_ellip, upsilon, chi_n_vec, EulDiff) c_ss, n_ss, b_s_ss, b_Sp1_ss = hh.get_cnb_vecs(c1_ss, rpath, wpath, cnb_args) b_splus1_ss = np.append(b_s_ss[1:], b_Sp1_ss) L_ss = aggr.get_L_s(n_ss) K_s_ss, K_cnstr = aggr.get_K_s(b_s_ss) K_d_ss = firms.get_K_d(r_ss, L_ss, K_params) Y_params = (A, alpha) Y_ss = aggr.get_Y(Y_params, K_d_ss, L_ss) C_ss = aggr.get_C(c_ss) n_err_args = (w_ss, c_ss, sigma, l_tilde, chi_n_vec, b_ellip, upsilon, EulDiff) n_err_ss = hh.get_n_errors(n_ss, n_err_args) b_err_params = (beta, sigma) b_err_ss = hh.get_b_errors(b_err_params, r_ss, c_ss, EulDiff) NX_ss = Y_ss - C_ss - delta * K_s_ss RCerr_ss = Y_ss - C_ss - delta * K_s_ss - NX_ss ss_time = time.clock() - start_time ss_output = { 'n_ss': n_ss, 'b_s_ss': b_s_ss, 'b_splus1_ss': b_splus1_ss, 'c_ss': c_ss, 'b_Sp1_ss': b_Sp1_ss, 'w_ss': w_ss, 'r_ss': r_ss, 'K_s_ss': K_s_ss, 'K_d_ss': K_d_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('n_ss is: ', n_ss) print('b_splus1_ss is: ', b_splus1_ss) print('K_s_ss=', K_s_ss, 'K_d_ss=', K_d_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('Net Exports = ', NX_ss) print('Output and consumption: ', Y_ss, C_ss) print('Steady-state residual savings b_Sp1 is: ', b_Sp1_ss) # 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 age_pers = (S,) vector, ages from 1 to S ---------------------------------------------------------------- ''' # 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 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, b_splus1_ss, 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_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