def test_euler_equation_solver(): # Test SS.inner_loop function. Provide inputs to function and # ensure that output returned matches what it has been before. input_tuple = utils.safe_read_pickle( os.path.join(CUR_PATH, 'test_io_data', 'euler_eqn_solver_inputs.pkl')) (guesses, params) = input_tuple p = Specifications() (r, w, TR, factor, j, p.J, p.S, p.beta, p.sigma, p.ltilde, p.g_y, p.g_n_ss, tau_payroll, retire, p.mean_income_data, h_wealth, p_wealth, m_wealth, p.b_ellipse, p.upsilon, j, p.chi_b, p.chi_n, tau_bq, p.rho, lambdas, p.omega_SS, p.e, p.analytical_mtrs, etr_params, mtrx_params, mtry_params) = params p.eta = (p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).reshape(1, p.S, p.J) p.tau_bq = np.ones(p.T + p.S) * 0.0 p.tau_payroll = np.ones(p.T + p.S) * tau_payroll p.h_wealth = np.ones(p.T + p.S) * h_wealth p.p_wealth = np.ones(p.T + p.S) * p_wealth p.m_wealth = np.ones(p.T + p.S) * m_wealth p.retire = (np.ones(p.T + p.S) * retire).astype(int) p.etr_params = np.transpose(etr_params.reshape( p.S, 1, etr_params.shape[-1]), (1, 0, 2)) p.mtrx_params = np.transpose(mtrx_params.reshape( p.S, 1, mtrx_params.shape[-1]), (1, 0, 2)) p.mtry_params = np.transpose(mtry_params.reshape( p.S, 1, mtry_params.shape[-1]), (1, 0, 2)) p.tax_func_type = 'DEP' p.lambdas = lambdas.reshape(p.J, 1) b_splus1 = np.array(guesses[:p.S]).reshape(p.S, 1) + 0.005 BQ = aggregates.get_BQ(r, b_splus1, j, p, 'SS', False) bq = household.get_bq(BQ, j, p, 'SS') tr = household.get_tr(TR, j, p, 'SS') args = (r, w, bq, tr, factor, j, p) test_list = SS.euler_equation_solver(guesses, *args) expected_list = np.array([ -3.62741663e+00, -6.30068841e+00, -6.76592886e+00, -6.97731223e+00, -7.05777777e+00, -6.57305440e+00, -7.11553046e+00, -7.30569622e+00, -7.45808107e+00, -7.89984062e+00, -8.11466111e+00, -8.28230086e+00, -8.79253862e+00, -8.86994311e+00, -9.31299476e+00, -9.80834199e+00, -9.97333771e+00, -1.08349979e+01, -1.13199826e+01, -1.22890930e+01, -1.31550471e+01, -1.42753713e+01, -1.55721098e+01, -1.73811490e+01, -1.88856303e+01, -2.09570569e+01, -2.30559500e+01, -2.52127149e+01, -2.76119605e+01, -3.03141128e+01, -3.30900203e+01, -3.62799730e+01, -3.91169706e+01, -4.24246421e+01, -4.55740527e+01, -4.92914871e+01, -5.30682805e+01, -5.70043846e+01, -6.06075991e+01, -6.45251018e+01, -6.86128365e+01, -7.35896515e+01, -7.92634608e+01, -8.34733231e+01, -9.29802390e+01, -1.01179788e+02, -1.10437881e+02, -1.20569527e+02, -1.31569973e+02, -1.43633399e+02, -1.57534056e+02, -1.73244610e+02, -1.90066728e+02, -2.07980863e+02, -2.27589046e+02, -2.50241670e+02, -2.76314755e+02, -3.04930986e+02, -3.36196973e+02, -3.70907934e+02, -4.10966644e+02, -4.56684022e+02, -5.06945218e+02, -5.61838645e+02, -6.22617808e+02, -6.90840503e+02, -7.67825713e+02, -8.54436805e+02, -9.51106365e+02, -1.05780305e+03, -1.17435473e+03, -1.30045062e+03, -1.43571221e+03, -1.57971603e+03, -1.73204264e+03, -1.88430524e+03, -2.03403679e+03, -2.17861987e+03, -2.31532884e+03, -8.00654731e+03, -5.21487172e-02, -2.80234170e-01, 4.93894552e-01, 3.11884938e-01, 6.55799607e-01, 5.62182419e-01, 3.86074983e-01, 3.43741491e-01, 4.22461089e-01, 3.63707951e-01, 4.93150010e-01, 4.72813688e-01, 4.07390308e-01, 4.94974186e-01, 4.69900128e-01, 4.37562389e-01, 5.67370182e-01, 4.88965362e-01, 6.40728461e-01, 6.14619979e-01, 4.97173823e-01, 6.19549666e-01, 6.51193557e-01, 4.48906118e-01, 7.93091492e-01, 6.51249363e-01, 6.56307713e-01, 1.12948552e+00, 9.50018058e-01, 6.79613030e-01, 9.51359123e-01, 6.31059147e-01, 7.97896887e-01, 8.44620817e-01, 7.43683837e-01, 1.56693187e+00, 2.75630011e-01, 5.32956891e-01, 1.57110727e+00, 1.22674610e+00, 4.63932928e-01, 1.47225464e+00, 1.16948107e+00, 1.07965795e+00, -3.20557791e-01, -1.17064127e+00, -7.84880649e-01, -7.60851182e-01, -1.61415945e+00, -8.30363975e-01, -1.68459409e+00, -1.49260581e+00, -1.84257084e+00, -1.72143079e+00, -1.43131579e+00, -1.63719219e+00, -1.43874851e+00, -1.57207905e+00, -1.72909159e+00, -1.98778122e+00, -1.80843826e+00, -2.12828312e+00, -2.24768762e+00, -2.36961877e+00, -2.49117258e+00, -2.59914065e+00, -2.82309085e+00, -2.93613362e+00, -3.34446991e+00, -3.45445086e+00, -3.74962140e+00, -3.78113417e+00, -4.55643800e+00, -4.86929016e+00, -5.08657898e+00, -5.22054177e+00, -5.54606515e+00, -5.78478304e+00, -5.93652041e+00, -6.11519786e+00]) assert(np.allclose(np.array(test_list), np.array(expected_list)))
def run_TPI(p, client=None): ''' Solve for transition path equilibrium of OG-India. Args: p (OG-India Specifcations object): model parameters client (Dask client object): client Returns: output (dictionary): dictionary with transition path solution results ''' # unpack tuples of parameters initial_values, ss_vars, theta, baseline_values = get_initial_SS_values(p) (B0, b_sinit, b_splus1init, factor, initial_b, initial_n, D0) = initial_values (TRbaseline, Gbaseline) = baseline_values print('Government spending breakpoints are tG1: ', p.tG1, '; and tG2:', p.tG2) # Initialize guesses at time paths # Make array of initial guesses for labor supply and savings domain = np.linspace(0, p.T, p.T) domain2 = np.tile(domain.reshape(p.T, 1, 1), (1, p.S, p.J)) ending_b = ss_vars['bssmat_splus1'] guesses_b = (-1 / (domain2 + 1)) * (ending_b - initial_b) + ending_b ending_b_tail = np.tile(ending_b.reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_b = np.append(guesses_b, ending_b_tail, axis=0) domain3 = np.tile(np.linspace(0, 1, p.T).reshape(p.T, 1, 1), (1, p.S, p.J)) guesses_n = domain3 * (ss_vars['nssmat'] - initial_n) + initial_n ending_n_tail = np.tile(ss_vars['nssmat'].reshape(1, p.S, p.J), (p.S, 1, 1)) guesses_n = np.append(guesses_n, ending_n_tail, axis=0) b_mat = guesses_b n_mat = guesses_n ind = np.arange(p.S) L_init = np.ones((p.T + p.S, )) * ss_vars['Lss'] B_init = np.ones((p.T + p.S, )) * ss_vars['Bss'] L_init[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B_init[1:p.T] = aggr.get_B(b_mat[:p.T], p, 'TPI', False)[:p.T - 1] B_init[0] = B0 if not p.small_open: if p.budget_balance: K_init = B_init else: K_init = B_init * ss_vars['Kss'] / ss_vars['Bss'] else: K_init = firm.get_B(L_init, p.firm_r, p, 'TPI') K = K_init K_d = K_init * ss_vars['K_d_ss'] / ss_vars['Kss'] K_f = K_init * ss_vars['K_f_ss'] / ss_vars['Kss'] L = L_init B = B_init Y = np.zeros_like(K) Y[:p.T] = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') Y[p.T:] = ss_vars['Yss'] r = np.zeros_like(Y) if not p.small_open: r[:p.T] = firm.get_r(Y[:p.T], K[:p.T], p, 'TPI') r[p.T:] = ss_vars['rss'] else: r = p.firm_r # compute w w = np.zeros_like(r) w[:p.T] = firm.get_w_from_r(r[:p.T], p, 'TPI') w[p.T:] = ss_vars['wss'] r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r else: r_hh = aggr.get_r_hh(r, r_gov, K, ss_vars['Dss']) if p.small_open: r_hh = p.hh_r BQ0 = aggr.get_BQ(r[0], initial_b, None, p, 'SS', True) if not p.use_zeta: BQ = np.zeros((p.T + p.S, p.J)) for j in range(p.J): BQ[:, j] = (list(np.linspace(BQ0[j], ss_vars['BQss'][j], p.T)) + [ss_vars['BQss'][j]] * p.S) BQ = np.array(BQ) else: BQ = (list(np.linspace(BQ0, ss_vars['BQss'], p.T)) + [ss_vars['BQss']] * p.S) BQ = np.array(BQ) if p.budget_balance: if np.abs(ss_vars['TR_ss']) < 1e-13: TR_ss2 = 0.0 # sometimes SS is very small but not zero, # even if taxes are zero, this get's rid of the approximation # error, which affects the perc changes below else: TR_ss2 = ss_vars['TR_ss'] TR = np.ones(p.T + p.S) * TR_ss2 total_revenue = TR G = np.zeros(p.T + p.S) elif not p.baseline_spending: TR = p.alpha_T * Y G = np.ones(p.T + p.S) * ss_vars['Gss'] elif p.baseline_spending: TR = TRbaseline TR_new = p.TR # Need to set TR_new for later reference G = Gbaseline G_0 = Gbaseline[0] # Initialize some starting values if p.budget_balance: D = np.zeros(p.T + p.S) else: D = np.ones(p.T + p.S) * ss_vars['Dss'] if ss_vars['Dss'] == 0: D_d = np.zeros(p.T + p.S) D_f = np.zeros(p.T + p.S) else: D_d = D * ss_vars['D_d_ss'] / ss_vars['Dss'] D_f = D * ss_vars['D_f_ss'] / ss_vars['Dss'] total_revenue = np.ones(p.T + p.S) * ss_vars['total_revenue_ss'] TPIiter = 0 TPIdist = 10 euler_errors = np.zeros((p.T, 2 * p.S, p.J)) TPIdist_vec = np.zeros(p.maxiter) # TPI loop while (TPIiter < p.maxiter) and (TPIdist >= p.mindist_TPI): r_gov[:p.T] = fiscal.get_r_gov(r[:p.T], p) if p.budget_balance: r_hh[:p.T] = r[:p.T] else: K[:p.T] = firm.get_K_from_Y(Y[:p.T], r[:p.T], p, 'TPI') r_hh[:p.T] = aggr.get_r_hh(r[:p.T], r_gov[:p.T], K[:p.T], D[:p.T]) if p.small_open: r_hh[:p.T] = p.hh_r[:p.T] outer_loop_vars = (r, w, r_hh, BQ, TR, theta) euler_errors = np.zeros((p.T, 2 * p.S, p.J)) lazy_values = [] for j in range(p.J): guesses = (guesses_b[:, :, j], guesses_n[:, :, j]) lazy_values.append( delayed(inner_loop)(guesses, outer_loop_vars, initial_values, j, ind, p)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) for j, result in enumerate(results): euler_errors[:, :, j], b_mat[:, :, j], n_mat[:, :, j] = result bmat_s = np.zeros((p.T, p.S, p.J)) bmat_s[0, 1:, :] = initial_b[:-1, :] bmat_s[1:, 1:, :] = b_mat[:p.T - 1, :-1, :] bmat_splus1 = np.zeros((p.T, p.S, p.J)) bmat_splus1[:, :, :] = b_mat[:p.T, :, :] etr_params_4D = np.tile( p.etr_params.reshape(p.T, p.S, 1, p.etr_params.shape[2]), (1, 1, p.J, 1)) bqmat = household.get_bq(BQ, None, p, 'TPI') trmat = household.get_tr(TR, None, p, 'TPI') tax_mat = tax.total_taxes(r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], factor, trmat[:p.T, :, :], theta, 0, None, False, 'TPI', p.e, etr_params_4D, p) r_hh_path = utils.to_timepath_shape(r_hh, p) wpath = utils.to_timepath_shape(w, p) c_mat = household.get_cons(r_hh_path[:p.T, :, :], wpath[:p.T, :, :], bmat_s, bmat_splus1, n_mat[:p.T, :, :], bqmat[:p.T, :, :], tax_mat, p.e, p.tau_c[:p.T, :, :], p) y_before_tax_mat = (r_hh_path[:p.T, :, :] * bmat_s[:p.T, :, :] + wpath[:p.T, :, :] * p.e * n_mat[:p.T, :, :]) if not p.baseline_spending and not p.budget_balance: Y[:p.T] = TR[:p.T] / p.alpha_T[:p.T] # maybe unecessary (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh[:p.T], w[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat[:p.T, :, :], c_mat[:p.T, :, :], Y[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue[:p.T] = total_rev # set intial debt value if p.baseline: D0 = p.initial_debt_ratio * Y[0] if not p.baseline_spending: G_0 = p.alpha_G[0] * Y[0] dg_fixed_values = (Y, total_revenue, TR, D0, G_0) Dnew, G[:p.T] = fiscal.D_G_path(r_gov, dg_fixed_values, Gbaseline, p) # Fix initial amount of foreign debt holding D_f[0] = p.initial_foreign_debt_ratio * Dnew[0] for t in range(1, p.T): D_f[t + 1] = (D_f[t] / (np.exp(p.g_y) * (1 + p.g_n[t + 1])) + p.zeta_D[t] * (Dnew[t + 1] - (Dnew[t] / (np.exp(p.g_y) * (1 + p.g_n[t + 1]))))) D_d[:p.T] = Dnew[:p.T] - D_f[:p.T] else: # if budget balance Dnew = np.zeros(p.T + 1) G[:p.T] = np.zeros(p.T) D_f[:p.T] = np.zeros(p.T) D_d[:p.T] = np.zeros(p.T) L[:p.T] = aggr.get_L(n_mat[:p.T], p, 'TPI') B[1:p.T] = aggr.get_B(bmat_splus1[:p.T], p, 'TPI', False)[:p.T - 1] K_demand_open = firm.get_K(L[:p.T], p.firm_r[:p.T], p, 'TPI') K_d[:p.T] = B[:p.T] - D_d[:p.T] if np.any(K_d < 0): print('K_d has negative elements. Setting them ' + 'positive to prevent NAN.') K_d[:p.T] = np.fmax(K_d[:p.T], 0.05 * B[:p.T]) K_f[:p.T] = p.zeta_K[:p.T] * (K_demand_open - B[:p.T] + D_d[:p.T]) K = K_f + K_d if np.any(B) < 0: print('B has negative elements. B[0:9]:', B[0:9]) print('B[T-2:T]:', B[p.T - 2, p.T]) if p.small_open: K[:p.T] = K_demand_open Ynew = firm.get_Y(K[:p.T], L[:p.T], p, 'TPI') rnew = r.copy() if not p.small_open: rnew[:p.T] = firm.get_r(Ynew[:p.T], K[:p.T], p, 'TPI') else: rnew[:p.T] = r[:p.T].copy() r_gov_new = fiscal.get_r_gov(rnew, p) if p.budget_balance: r_hh_new = rnew[:p.T] else: r_hh_new = aggr.get_r_hh(rnew[:p.T], r_gov_new[:p.T], K[:p.T], Dnew[:p.T]) if p.small_open: r_hh_new = p.hh_r[:p.T] # compute w wnew = firm.get_w_from_r(rnew[:p.T], p, 'TPI') b_mat_shift = np.append(np.reshape(initial_b, (1, p.S, p.J)), b_mat[:p.T - 1, :, :], axis=0) BQnew = aggr.get_BQ(r_hh_new[:p.T], b_mat_shift, None, p, 'TPI', False) bqmat_new = household.get_bq(BQnew, None, p, 'TPI') (total_rev, T_Ipath, T_Ppath, T_BQpath, T_Wpath, T_Cpath, business_revenue) = aggr.revenue( r_hh_new[:p.T], wnew[:p.T], bmat_s, n_mat[:p.T, :, :], bqmat_new[:p.T, :, :], c_mat[:p.T, :, :], Ynew[:p.T], L[:p.T], K[:p.T], factor, theta, etr_params_4D, p, 'TPI') total_revenue[:p.T] = total_rev if p.budget_balance: TR_new = total_revenue elif not p.baseline_spending: TR_new = p.alpha_T[:p.T] * Ynew[:p.T] # If baseline_spending==True, no need to update TR, it's fixed # update vars for next iteration w[:p.T] = wnew[:p.T] r[:p.T] = utils.convex_combo(rnew[:p.T], r[:p.T], p.nu) BQ[:p.T] = utils.convex_combo(BQnew[:p.T], BQ[:p.T], p.nu) D[:p.T] = Dnew[:p.T] Y[:p.T] = utils.convex_combo(Ynew[:p.T], Y[:p.T], p.nu) if not p.baseline_spending: TR[:p.T] = utils.convex_combo(TR_new[:p.T], TR[:p.T], p.nu) guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu) guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu) print('r diff: ', (rnew[:p.T] - r[:p.T]).max(), (rnew[:p.T] - r[:p.T]).min()) print('BQ diff: ', (BQnew[:p.T] - BQ[:p.T]).max(), (BQnew[:p.T] - BQ[:p.T]).min()) print('TR diff: ', (TR_new[:p.T] - TR[:p.T]).max(), (TR_new[:p.T] - TR[:p.T]).min()) print('Y diff: ', (Ynew[:p.T] - Y[:p.T]).max(), (Ynew[:p.T] - Y[:p.T]).min()) if not p.baseline_spending: if TR.all() != 0: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(TR_new[:p.T], TR[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list( utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(np.abs(TR[:p.T]))).max() else: TPIdist = np.array( list(utils.pct_diff_func(rnew[:p.T], r[:p.T])) + list(utils.pct_diff_func(BQnew[:p.T], BQ[:p.T]).flatten()) + list(utils.pct_diff_func(Ynew[:p.T], Y[:p.T]))).max() TPIdist_vec[TPIiter] = TPIdist # After T=10, if cycling occurs, drop the value of nu # wait til after T=10 or so, because sometimes there is a jump up # in the first couple iterations # if TPIiter > 10: # if TPIdist_vec[TPIiter] - TPIdist_vec[TPIiter - 1] > 0: # nu /= 2 # print 'New Value of nu:', nu TPIiter += 1 print('Iteration:', TPIiter) print('\tDistance:', TPIdist) # Compute effective and marginal tax rates for all agents mtrx_params_4D = np.tile( p.mtrx_params.reshape(p.T, p.S, 1, p.mtrx_params.shape[2]), (1, 1, p.J, 1)) mtry_params_4D = np.tile( p.mtry_params.reshape(p.T, p.S, 1, p.mtry_params.shape[2]), (1, 1, p.J, 1)) e_3D = np.tile(p.e.reshape(1, p.S, p.J), (p.T, 1, 1)) mtry_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, True, e_3D, etr_params_4D, mtry_params_4D, p) mtrx_path = tax.MTR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, False, e_3D, etr_params_4D, mtrx_params_4D, p) etr_path = tax.ETR_income(r_hh_path[:p.T], wpath[:p.T], bmat_s[:p.T, :, :], n_mat[:p.T, :, :], factor, e_3D, etr_params_4D, p) C = aggr.get_C(c_mat, p, 'TPI') # Note that implicity in this computation is that immigrants' # wealth is all in the form of private capital I_d = aggr.get_I(bmat_splus1[:p.T], K_d[1:p.T + 1], K_d[:p.T], p, 'TPI') I = aggr.get_I(bmat_splus1[:p.T], K[1:p.T + 1], K[:p.T], p, 'TPI') # solve resource constraint # net foreign borrowing new_borrowing_f = (D_f[1:p.T + 1] * np.exp(p.g_y) * (1 + p.g_n[1:p.T + 1]) - D_f[:p.T]) debt_service_f = D_f * r_hh RC_error = aggr.resource_constraint(Y[:p.T - 1], C[:p.T - 1], G[:p.T - 1], I_d[:p.T - 1], K_f[:p.T - 1], new_borrowing_f[:p.T - 1], debt_service_f[:p.T - 1], r_hh[:p.T - 1], p) # Compute total investment (not just domestic) I_total = ((1 + p.g_n[:p.T]) * np.exp(p.g_y) * K[1:p.T + 1] - (1.0 - p.delta) * K[:p.T]) rce_max = np.amax(np.abs(RC_error)) print('Max absolute value resource constraint error:', rce_max) print('Checking time path for violations of constraints.') for t in range(p.T): household.constraint_checker_TPI(b_mat[t], n_mat[t], c_mat[t], t, p.ltilde) eul_savings = euler_errors[:, :p.S, :].max(1).max(1) eul_laborleisure = euler_errors[:, p.S:, :].max(1).max(1) print('Max Euler error, savings: ', eul_savings) print('Max Euler error labor supply: ', eul_laborleisure) ''' ------------------------------------------------------------------------ Save variables/values so they can be used in other modules ------------------------------------------------------------------------ ''' output = { 'Y': Y[:p.T], 'B': B, 'K': K, 'K_f': K_f, 'K_d': K_d, 'L': L, 'C': C, 'I': I, 'I_total': I_total, 'I_d': I_d, 'BQ': BQ, 'total_revenue': total_revenue, 'business_revenue': business_revenue, 'IITpayroll_revenue': T_Ipath, 'TR': TR, 'T_P': T_Ppath, 'T_BQ': T_BQpath, 'T_W': T_Wpath, 'T_C': T_Cpath, 'G': G, 'D': D, 'D_f': D_f, 'D_d': D_d, 'r': r, 'r_gov': r_gov, 'r_hh': r_hh, 'w': w, 'bmat_splus1': bmat_splus1, 'bmat_s': bmat_s[:p.T, :, :], 'n_mat': n_mat[:p.T, :, :], 'c_path': c_mat, 'bq_path': bqmat, 'tr_path': trmat, 'y_before_tax_mat': y_before_tax_mat, 'tax_path': tax_mat, 'eul_savings': eul_savings, 'eul_laborleisure': eul_laborleisure, 'resource_constraint_error': RC_error, 'new_borrowing_f': new_borrowing_f, 'debt_service_f': debt_service_f, 'etr_path': etr_path, 'mtrx_path': mtrx_path, 'mtry_path': mtry_path } tpi_dir = os.path.join(p.output_base, "TPI") utils.mkdirs(tpi_dir) tpi_vars = os.path.join(tpi_dir, "TPI_vars.pkl") pickle.dump(output, open(tpi_vars, "wb")) if np.any(G) < 0: print('Government spending is negative along transition path' + ' to satisfy budget') if (((TPIiter >= p.maxiter) or (np.absolute(TPIdist) > p.mindist_TPI)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found' + ' (TPIdist)') if ((np.any(np.absolute(RC_error) >= p.mindist_TPI * 10)) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(RC_error)') if ((np.any(np.absolute(eul_savings) >= p.mindist_TPI) or (np.any(np.absolute(eul_laborleisure) > p.mindist_TPI))) and ENFORCE_SOLUTION_CHECKS): raise RuntimeError('Transition path equlibrium not found ' + '(eulers)') return output
def run_SS(p, client=None): ''' Solve for steady-state equilibrium of OG-India. Args: p (OG-India Specifcations object): model parameters client (Dask client object): client Returns: output (dictionary): dictionary with steady-state solution results ''' # For initial guesses of w, r, TR, and factor, we use values that # are close to some steady state values. if p.baseline: b_guess = np.ones((p.S, p.J)) * 0.07 n_guess = np.ones((p.S, p.J)) * .4 * p.ltilde if p.small_open: rguess = p.firm_r[-1] else: rguess = 0.09 TRguess = 0.12 factorguess = 70000 BQguess = aggr.get_BQ(rguess, b_guess, None, p, 'SS', False) ss_params_baseline = (b_guess, n_guess, None, None, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [TRguess, factorguess] else: guesses = [rguess] + list(BQguess) + [TRguess, factorguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_baseline, xtol=p.mindist_SS, full_output=True) if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-2] TR_ss = solutions_fsolve[-2] factor_ss = solutions_fsolve[-1] Yss = TR_ss / p.alpha_T[-1] # may not be right - if budget_balance # = True, but that's ok - will be fixed in SS_solver fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, TR_ss, factor_ss, Yss, p, client, fsolve_flag) else: # Use the baseline solution to get starting values for the reform baseline_ss_dir = os.path.join(p.baseline_dir, 'SS/SS_vars.pkl') ss_solutions = pickle.load(open(baseline_ss_dir, 'rb'), encoding='latin1') (b_guess, n_guess, rguess, BQguess, TRguess, Yguess, factor) =\ (ss_solutions['bssmat_splus1'], ss_solutions['nssmat'], ss_solutions['rss'], ss_solutions['BQss'], ss_solutions['TR_ss'], ss_solutions['Yss'], ss_solutions['factor_ss']) if p.baseline_spending: TR_ss = TRguess ss_params_reform = (b_guess, n_guess, TR_ss, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [Yguess] else: guesses = [rguess] + list(BQguess) + [Yguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] Yss = solutions_fsolve[-1] else: ss_params_reform = (b_guess, n_guess, None, factor, p, client) if p.use_zeta: guesses = [rguess] + list([BQguess]) + [TRguess] else: guesses = [rguess] + list(BQguess) + [TRguess] [solutions_fsolve, infodict, ier, message] =\ opt.fsolve(SS_fsolve, guesses, args=ss_params_reform, xtol=p.mindist_SS, full_output=True) rss = solutions_fsolve[0] BQss = solutions_fsolve[1:-1] TR_ss = solutions_fsolve[-1] Yss = TR_ss / p.alpha_T[-1] # may not be right - if # budget_balance = True, but that's ok - will be fixed in # SS_solver if ENFORCE_SOLUTION_CHECKS and not ier == 1: raise RuntimeError('Steady state equilibrium not found') # Return SS values of variables fsolve_flag = True # Return SS values of variables output = SS_solver(b_guess, n_guess, rss, BQss, TR_ss, factor, Yss, p, client, fsolve_flag) if output['Gss'] < 0.: warnings.warn('Warning: The combination of the tax policy ' + 'you specified and your target debt-to-GDP ' + 'ratio results in an infeasible amount of ' + 'government spending in order to close the ' + 'budget (i.e., G < 0)') return output
def inner_loop(outer_loop_vars, p, client): ''' This function solves for the inner loop of the SS. That is, given the guesses of the outer loop variables (r, w, TR, factor) this function solves the households' problems in the SS. Args: outer_loop_vars (tuple): tuple of outer loop variables, (bssmat, nssmat, r, BQ, TR, factor) or (bssmat, nssmat, r, BQ, Y, TR, factor) bssmat (Numpy array): initial guess at savings, size = SxJ nssmat (Numpy array): initial guess at labor supply, size = SxJ BQ (array_like): aggregate bequest amount(s) Y (scalar): real GDP TR (scalar): lump sum transfer amount factor (scalar): scaling factor converting model units to dollars w (scalar): real wage rate p (OG-India Specifcations object): model parameters client (Dask client object): client Returns: euler_errors (Numpy array): errors terms from FOCs, size = 2SxJ bssmat (Numpy array): savings, size = SxJ nssmat (Numpy array): labor supply, size = SxJ new_r (scalar): real interest rate on firm capital new_r_gov (scalar): real interest rate on government debt new_r_hh (scalar): real interest rate on household portfolio new_w (scalar): real wage rate new_TR (scalar): lump sum transfer amount new_Y (scalar): real GDP new_factor (scalar): scaling factor converting model units to dollars new_BQ (array_like): aggregate bequest amount(s) average_income_model (scalar): average income in model units ''' # unpack variables to pass to function if p.budget_balance: bssmat, nssmat, r, BQ, TR, factor = outer_loop_vars else: bssmat, nssmat, r, BQ, Y, TR, factor = outer_loop_vars euler_errors = np.zeros((2 * p.S, p.J)) w = firm.get_w_from_r(r, p, 'SS') r_gov = fiscal.get_r_gov(r, p) if p.budget_balance: r_hh = r D = 0 else: D = p.debt_ratio_ss * Y K = firm.get_K_from_Y(Y, r, p, 'SS') r_hh = aggr.get_r_hh(r, r_gov, K, D) if p.small_open: r_hh = p.hh_r[-1] bq = household.get_bq(BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') lazy_values = [] for j in range(p.J): guesses = np.append(bssmat[:, j], nssmat[:, j]) euler_params = (r_hh, w, bq[:, j], tr[:, j], factor, j, p) lazy_values.append( delayed(opt.fsolve)(euler_equation_solver, guesses * .9, args=euler_params, xtol=MINIMIZER_TOL, full_output=True)) results = compute(*lazy_values, scheduler=dask.multiprocessing.get, num_workers=p.num_workers) # for j, result in results.items(): for j, result in enumerate(results): [solutions, infodict, ier, message] = result euler_errors[:, j] = infodict['fvec'] bssmat[:, j] = solutions[:p.S] nssmat[:, j] = solutions[p.S:] L = aggr.get_L(nssmat, p, 'SS') B = aggr.get_B(bssmat, p, 'SS', False) K_demand_open = firm.get_K(L, p.firm_r[-1], p, 'SS') D_f = p.zeta_D[-1] * D D_d = D - D_f if not p.small_open: K_d = B - D_d K_f = p.zeta_K[-1] * (K_demand_open - B + D_d) K = K_f + K_d else: # can remove this else statement by making small open the case # where zeta_K = 1 K_d = B - D_d K_f = K_demand_open - B + D_d K = K_f + K_d new_Y = firm.get_Y(K, L, p, 'SS') if p.budget_balance: Y = new_Y if not p.small_open: new_r = firm.get_r(Y, K, p, 'SS') else: new_r = p.firm_r[-1] new_w = firm.get_w_from_r(new_r, p, 'SS') b_s = np.array(list(np.zeros(p.J).reshape(1, p.J)) + list(bssmat[:-1, :])) new_r_gov = fiscal.get_r_gov(new_r, p) new_r_hh = aggr.get_r_hh(new_r, new_r_gov, K, D) average_income_model = ((new_r_hh * b_s + new_w * p.e * nssmat) * p.omega_SS.reshape(p.S, 1) * p.lambdas.reshape(1, p.J)).sum() if p.baseline: new_factor = p.mean_income_data / average_income_model else: new_factor = factor new_BQ = aggr.get_BQ(new_r_hh, bssmat, None, p, 'SS', False) new_bq = household.get_bq(new_BQ, None, p, 'SS') tr = household.get_tr(TR, None, p, 'SS') theta = tax.replacement_rate_vals(nssmat, new_w, new_factor, None, p) if p.budget_balance: etr_params_3D = np.tile( np.reshape(p.etr_params[-1, :, :], (p.S, 1, p.etr_params.shape[2])), (1, p.J, 1)) taxss = tax.total_taxes(new_r_hh, new_w, b_s, nssmat, new_bq, factor, tr, theta, None, None, False, 'SS', p.e, etr_params_3D, p) cssmat = household.get_cons(new_r_hh, new_w, b_s, bssmat, nssmat, new_bq, taxss, p.e, p.tau_c[-1, :, :], p) new_TR, _, _, _, _, _, _ = aggr.revenue(new_r_hh, new_w, b_s, nssmat, new_bq, cssmat, new_Y, L, K, factor, theta, etr_params_3D, p, 'SS') elif p.baseline_spending: new_TR = TR else: new_TR = p.alpha_T[-1] * new_Y return euler_errors, bssmat, nssmat, new_r, new_r_gov, new_r_hh, \ new_w, new_TR, new_Y, new_factor, new_BQ, average_income_model
def test_get_BQ(r, b_splus1, j, p, method, expected): """ Test of aggregate bequest function. """ BQ = aggr.get_BQ(r, b_splus1, j, p, method, False) assert np.allclose(BQ, expected)