def test_FOC_savings(model_vars, params, expected): # Test FOC condition for household's choice of savings (r, w, b, b_splus1, n, BQ, factor, tr, ubi, theta, tau_c, etr_params, mtry_params, t, j, method) = model_vars if j is not None: test_value = household.FOC_savings( r, w, b, b_splus1, n, BQ, factor, tr, ubi, theta, params.e[:, j], params.rho, tau_c, etr_params, mtry_params, t, j, params, method) else: test_value = household.FOC_savings( r, w, b, b_splus1, n, BQ, factor, tr, ubi, theta, np.squeeze(params.e), params.rho, tau_c, etr_params, mtry_params, t, j, params, method) assert np.allclose(test_value, expected)
def firstdoughnutring(guesses, r, w, bq, tr, theta, factor, ubi, j, initial_b, p): ''' Solves the first entries of the upper triangle of the twist doughnut. This is separate from the main TPI function because the values of b and n are scalars, so it is easier to just have a separate function for these cases. Args: guesses (Numpy array): initial guesses for b and n, length 2 r (scalar): real interest rate w (scalar): real wage rate bq (scalar): bequest amounts by age tr (scalar): government transfer amount theta (Numpy array): retirement replacement rates, length J factor (scalar): scaling factor converting model units to dollars ubi (scalar): individual UBI credit to household s=E+S of type j in period 0 j (int): index of ability type initial_b (Numpy array): SxJ matrix, savings of agents alive at T=0 p (OG-Core Specifications object): model parameters Returns: euler errors (Numpy array): errors from first order conditions, length 2 ''' b_splus1 = float(guesses[0]) n = float(guesses[1]) b_s = float(initial_b[-2, j]) # Find errors from FOC for savings and FOC for labor supply error1 = household.FOC_savings(np.array([r]), np.array([w]), b_s, np.array([b_splus1]), np.array([n]), np.array([bq]), factor, np.array([tr]), np.array([ubi]), theta[j], p.e[-1, j], p.rho[-1], np.array([p.tau_c[0, -1, j]]), p.etr_params[0, -1, :], p.mtry_params[0, -1, :], None, j, p, 'TPI_scalar') error2 = household.FOC_labor(np.array([r]), np.array([w]), b_s, b_splus1, np.array([n]), np.array([bq]), factor, np.array([tr]), np.array([ubi]), theta[j], p.chi_n[-1], p.e[-1, j], np.array([p.tau_c[0, -1, j]]), p.etr_params[0, -1, :], p.mtrx_params[0, -1, :], None, j, p, 'TPI_scalar') if n <= 0 or n >= 1: error2 += 1e12 if b_splus1 <= 0: error1 += 1e12 return [np.squeeze(error1)] + [np.squeeze(error2)]
def euler_equation_solver(guesses, *args): ''' Finds the euler errors for certain b and n, one ability type at a time. Args: guesses (Numpy array): initial guesses for b and n, lenth 2S args (tuple): tuple of arguments (r, w, bq, TR, factor, j, p) w (scalar): real wage rate bq (Numpy array): bequest amounts by age, length S tr (scalar): government transfer amount by age, length S ubi (vector): universal basic income (UBI) payment, length S factor (scalar): scaling factor converting model units to dollars p (OG-Core Specifications object): model parameters Returns: errros (Numpy array): errors from FOCs, length 2S ''' (r, w, bq, tr, ubi, factor, j, p) = args b_guess = np.array(guesses[:p.S]) n_guess = np.array(guesses[p.S:]) b_s = np.array([0] + list(b_guess[:-1])) b_splus1 = b_guess theta = tax.replacement_rate_vals(n_guess, w, factor, j, p) error1 = household.FOC_savings(r, w, b_s, b_splus1, n_guess, bq, factor, tr, ubi, theta, p.e[:, j], p.rho, p.tau_c[-1, :, j], p.etr_params[-1, :, :], p.mtry_params[-1, :, :], None, j, p, 'SS') error2 = household.FOC_labor(r, w, b_s, b_splus1, n_guess, bq, factor, tr, ubi, theta, p.chi_n, p.e[:, j], p.tau_c[-1, :, j], p.etr_params[-1, :, :], p.mtrx_params[-1, :, :], None, j, p, 'SS') # Put in constraints for consumption and savings. # According to the euler equations, they can be negative. When # Chi_b is large, they will be. This prevents that from happening. # I'm not sure if the constraints are needed for labor. # But we might as well put them in for now. mask1 = n_guess < 0 mask2 = n_guess > p.ltilde mask3 = b_guess <= 0 mask4 = np.isnan(n_guess) mask5 = np.isnan(b_guess) error2[mask1] = 1e14 error2[mask2] = 1e14 error1[mask3] = 1e14 error1[mask5] = 1e14 error2[mask4] = 1e14 taxes = tax.net_taxes(r, w, b_s, n_guess, bq, factor, tr, ubi, theta, None, j, False, 'SS', p.e[:, j], p.etr_params[-1, :, :], p) cons = household.get_cons(r, w, b_s, b_splus1, n_guess, bq, taxes, p.e[:, j], p.tau_c[-1, :, j], p) mask6 = cons < 0 error1[mask6] = 1e14 errors = np.hstack((error1, error2)) return errors
def twist_doughnut(guesses, r, w, bq, tr, theta, factor, ubi, j, s, t, tau_c, etr_params, mtrx_params, mtry_params, initial_b, p): ''' Solves the upper triangle of time path iterations. These are the agents who are alive at time T=0 so that we do not solve for their full lifetime (so of their life was before the model begins). Args: guesses (Numpy array): initial guesses for b and n, length 2s r (scalar): real interest rate w (scalar): real wage rate bq (Numpy array): bequest amounts by age, length s tr (scalar): government transfer amount theta (Numpy array): retirement replacement rates, length J factor (scalar): scaling factor converting model units to dollars ubi (array): length remaining periods of life UBI payout to household j (int): index of ability type s (int): years of life remaining t (int): model period tau_c (Numpy array): consumption tax rates, size = sxJ etr_params (Numpy array): ETR function parameters, size = sxsxnum_params mtrx_params (Numpy array): labor income MTR function parameters, size = sxsxnum_params mtry_params (Numpy array): capital income MTR function parameters, size = sxsxnum_params initial_b (Numpy array): savings of agents alive at T=0, size = SxJ p (OG-Core Specifications object): model parameters Returns: euler errors (Numpy array): errors from first order conditions, length 2s ''' length = int(len(guesses) / 2) b_guess = np.array(guesses[:length]) n_guess = np.array(guesses[length:]) if length == p.S: b_s = np.array([0] + list(b_guess[:-1])) else: b_s = np.array([(initial_b[-(s + 3), j])] + list(b_guess[:-1])) b_splus1 = b_guess w_s = w[t:t + length] r_s = r[t:t + length] n_s = n_guess chi_n_s = p.chi_n[-length:] e_s = p.e[-length:, j] rho_s = p.rho[-length:] error1 = household.FOC_savings(r_s, w_s, b_s, b_splus1, n_s, bq, factor, tr, ubi, theta, e_s, rho_s, tau_c, etr_params, mtry_params, t, j, p, 'TPI') error2 = household.FOC_labor(r_s, w_s, b_s, b_splus1, n_s, bq, factor, tr, ubi, theta, chi_n_s, e_s, tau_c, etr_params, mtrx_params, t, j, p, 'TPI') # Check and punish constraint violations mask1 = n_guess < 0 error2[mask1] += 1e12 mask2 = n_guess > p.ltilde error2[mask2] += 1e12 mask4 = b_guess <= 0 error2[mask4] += 1e12 mask5 = b_splus1 < 0 error2[mask5] += 1e12 return list(error1.flatten()) + list(error2.flatten())