From 43aaa379fd83749ab4cde369d7b90f664e189808 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 1 Nov 2024 21:56:14 +1100 Subject: [PATCH 01/17] update cass_fiscal --- lectures/_config.yml | 2 +- lectures/_toc.yml | 1 + lectures/cass_fiscal.md | 1060 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1062 insertions(+), 1 deletion(-) create mode 100644 lectures/cass_fiscal.md diff --git a/lectures/_config.yml b/lectures/_config.yml index ecae8d8ac..784b87d15 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -32,7 +32,7 @@ latex: targetname: quantecon-python.tex sphinx: - extra_extensions: [sphinx_multitoc_numbering, sphinxext.rediraffe, sphinx_tojupyter, sphinxcontrib.youtube, sphinx.ext.todo, sphinx_exercise, sphinx_togglebutton, sphinx.ext.intersphinx, sphinx_reredirects] + extra_extensions: [sphinx_multitoc_numbering, sphinxext.rediraffe, sphinx_tojupyter, sphinxcontrib.youtube, sphinx.ext.todo, sphinx_exercise, sphinx_proof, sphinx_togglebutton, sphinx.ext.intersphinx, sphinx_reredirects] config: bibtex_reference_style: author_year nb_mime_priority_overrides: [ diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 992dcd230..c64a7f344 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -54,6 +54,7 @@ parts: chapters: - file: cass_koopmans_1 - file: cass_koopmans_2 + - file: cass_fiscal - file: ak2 - file: cake_eating_problem - file: cake_eating_numerical diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md new file mode 100644 index 000000000..d3cee5741 --- /dev/null +++ b/lectures/cass_fiscal.md @@ -0,0 +1,1060 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Fiscal Policy Experiments in a Non-stochastic Model + +We will use the following imports + +```{code-cell} ipython3 +import numpy as np +from scipy.optimize import root +import matplotlib.pyplot as plt +from collections import namedtuple +from mpmath import mp +import warnings + +class ConvergenceWarning(UserWarning): + """Warning raised when the bisection method fails to converge.""" + pass + +# Set the precision +mp.dps = 60 +mp.pretty = True +``` + +Note that we will use the `mpmath` library to perform high-precision arithmetic in the shooting algorithm in cases where the solution diverges due to numerical instability. + +We will use the following parameters + +```{code-cell} ipython3 +# Create a named tuple to store the model parameters +Model = namedtuple("Model", + ["β", "γ", "δ", "α", "A"]) + +def create_model(β=0.95, # discount factor + γ=2.0, # relative risk aversion coefficient + δ=0.2, # depreciation rate + α=0.33, # capital share + A=1.0 # TFP + ): + """Create a model instance.""" + return Model(β=β, γ=γ, δ=δ, α=α, A=A) + +model = create_model() + +# Total number of periods +S = 100 +``` + +## The Economy + +### Households +The representative household has preferences over nonnegative streams of a single consumption good $c_t$: + +$$ +\sum_{t=0}^{\infty} \beta^t U(c_t), \quad \beta \in (0, 1) +$$ (eq:utility) +where +- $U(c_t)$ is twice continuously differentiable, and strictly concave with $c_t \geq 0$. + +under the budget constraint + +$$ +\begin{aligned} + \sum_{t=0}^\infty& q_t \left\{ (1 + \tau_{ct})c_t + \underbrace{[k_{t+1} - (1 - \delta)k_t]}_{\text{no tax when investing}} \right\} \\ + &\leq \sum_{t=0}^\infty q_t \left\{ \tau_{kt} - \underbrace{\tau_{kt}(\eta_t - \delta)k_t}_{\text{tax on rental return}} + (1 - \tau_{nt})w_t n_t - \tau_{ht} \right\}. +\end{aligned} +$$ (eq:house_budget) + + +In our model, the representative household has the following CRRA preferences over consumption: + +$$ +U(c) = \frac{c^{1 - \gamma}}{1 - \gamma} +$$ + +where $c$ is consumption and $\gamma$ is the coefficient of relative risk aversion. + + +### Technology + +The economy's production technology is defined by: + +$$ +g_t + c_t + x_t \leq F(k_t, n_t), +$$ (eq:tech_capital) + +- $g_t$ is government expenditure +- $x_t$ is gross investment, and +- $F(k_t, n_t)$ a linearly homogeneous production function with positive and decreasing marginal products of capital $k_t$ and labor $n_t$. + +The law of motion for capital is given by: +$$ + k_{t+1} = (1 - \delta)k_t + x_t, +$$ + +where + +- $\delta \in (0, 1)$ is depreciation rate, $k_t$ is the stock of physical capital, and $x_t$ is gross investment. + + +### Price System + +A price system is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, where + +- $q_t$ is the time 0 pretax price of one unit of investment or consumption at time $t$ ($x_t$ or $c_t$), +- $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, +- $w_t$ is the pretax price at time $t$ that the household receives for renting labor to the firm at time $t$. + +The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0. + +### Government + +Government plans $\{ g_t \}_{t=0}^\infty$ for government purchases and taxes $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to the budget constraint + +$$ +\sum_{t=0}^\infty q_t g_t \leq \sum_{t=0}^\infty q_t \left\{ \tau_{ct}c_t + \tau_{kt}(\eta_t - \delta)k_t + \tau_{nt}w_t n_t + \tau_{ht} \right\}. +$$ (eq:gov_budget) + +### Firm + +Firms maximize their present value of profit: + +$$ +\sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right], +$$ +Euler's theorem for linearly homogeneous functions states that if a function $F(k, n)$ is linearly homogeneous (degree 1), then: + +$$ +F(k, n) = F_k k + F_n n, +$$ + +where $F_k = \frac{\partial F(k, n)}{\partial k}$ and $F_n = \frac{\partial F(k, n)}{\partial n}$. + + +### Equilibrium + +In the equilibrium, given a budget-feasible government policy $\{g_t\}_{t=0}^\infty$ and $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to {eq}`eq:gov_budget`, + +- *Household* chooses $\{c_t\}_{t=0}^\infty$, $\{n_t\}_{t=0}^\infty$, and $\{k_{t+1}\}_{t=0}^\infty$ to maximize utility{eq}`eq:utility` subject to budget constraint{eq}`eq:house_budget`, and +- *Frim* chooses sequences of capital $\{k_t\}_{t=0}^\infty$ and $\{n_t\}_{t=0}^\infty$ to maximize profits + $$ + \sum_{t=0}^\infty q_t [F(k_t, n_t) - \eta_t k_t - w_t n_t] + $$ (eq:firm_profit) +- A **feasible allocation** is a sequence $\{c_t, x_t, n_t, k_t\}_{t=0}^\infty$ that satisfies feasibility condition {eq}`eq:tech_capital`. + + +```{prf:definition} +:label: com_eq_tax + +A **competitive equilibrium with distorting taxes** is a **budget-feasible government policy**, **a feasible allocation**, and **a price system** for which, given the price system and the government policy, the allocation solves the household’s problem and the firm’s problem. +``` + +## Non-arbitrage Condition + +By rearranging {eq}`eq:house_budget` and group $k_t$ at the same $t$, we can get + +$$ + \begin{aligned} + \sum_{t=0}^\infty q_t \left[(1 + \tau_{ct})c_t \right] &\leq \sum_{t=0}^\infty q_t(1 - \tau_{nt})w_t n_t - \sum_{t=0}^\infty q_t \tau_{ht} \\ + &+ \sum_{t=1}^\infty\left\{ \left[(1 - \tau_{kt})(\eta_t - \delta) + 1\right]q_t - q_{t-1}\right\}k_t \\ + &+ \left[(1 - \tau_{k0})(\eta_0 - \delta) + 1\right]q_0k_0 - \lim_{T \to \infty} q_T r k_{T+1} + \end{aligned} +$$ (eq:constrant_house) + +By setting the terms multiplying $k_t$ to $0$ we have the non-arbitrage condition: + +$$ +\frac{q_t}{q_{t+1}} = \left[(1 - \tau_{kt})(\eta_t - \delta) + 1\right] +$$ (eq:no_arb) + +Moreover, we have terminal condition + +$$ +-\lim_{T \to \infty} q_T r k_{T+1} = 0. +$$ (eq:terminal) + +Moreover, applying Euler's theorem on firm's present value gives + +$$ +\sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right] = \sum_{t=0}^\infty q_t \left[ (F_{kt} - \eta_t) k_t + (F_{nt} - w_t) n_t \right] +$$ + +and no-arbitrage analogous to the household case are + +$$ +\eta_t = F_{kt} \quad \text{and} \quad w_t = F_{nt}. +$$ (eq:no_arb_firms) + +## Household's First Order Condition + +Household maximize {eq}`eq:utility` under {eq}`eq:house_budget`. Let $U_1 = \frac{\partial U}{\partial c}, U_2 = \frac{\partial U}{\partial (1-n)} = -\frac{\partial U}{\partial n} = -U_n.$, we can derive FOC from the Lagrangian + +$$ +\mathcal{L} = \sum_{t=0}^\infty \beta^t U(c_t, 1 - n_t) + \mu \left( \sum_{t=0}^\infty q_t \left[(1 + \tau_{ct})c_t - (1 - \tau_{nt})w_t n_t + \ldots \right] \right), +$$ + +Hence we have FOC: + +$$ +\frac{\partial \mathcal{L}}{\partial c_t} = \beta^t U_1(c_t, 1 - n_t) - \mu q_t (1 + \tau_{ct}) = 0 +$$ (eq:foc_c_1) + +and + +$$ +\frac{\partial \mathcal{L}}{\partial n_t} = \beta^t \left(-U_2(c_t, 1 - n_t)\right) - \mu q_t (1 - \tau_{nt}) w_t = 0 +$$ (eq:foc_n_1) + +Rearranguing {eq}`eq:foc_c_1` and {eq}`eq:foc_n_1`, we have + +$$ +\begin{aligned} +\beta^t U_1(c_t, 1 - n_t) = \beta^t U_{1t} = \mu q_t (1 + \tau_{ct}), +\end{aligned} +$$ (eq:foc_c) + +$$ +\begin{aligned} +\beta^t U_2(c_t, 1 - n_t) = \beta^t U_{2t} = \mu q_t (1 - \tau_{nt}) w_t. +\end{aligned} +$$ (eq:foc_n) + + +Plugging {eq}`eq:foc_c` into {eq}`eq:terminal` by replacing $q_t$, we get terminal condition + +$$ +-\lim_{T \to \infty} \frac{U_{1t}}{(1 + \tau_{ct})} r k_{T+1} = 0. +$$ (eq:terminal_final) + +$F(k_t, n_t) = A k_t^\alpha n_t^{1 - \alpha}$ + +$f'(k_t) = \alpha A k_t^{\alpha - 1}$ + +## Computing Equilibria + +To compute an equilibrium we solve a price system $\{q_t, \eta_t, w_t\}$, a budget feasible government policy $\{g_t, \tau_t\} \equiv \{g_t, \tau_{ct}, \tau_{nt}, \tau_{kt}, \tau_{ht}\}$, and an allocation $\{c_t, n_t, k_{t+1}\}$ that solve the system of nonlinear difference equations consisting of + +- feasibility condition {eq}`eq:tech_capital`, no-arbitrage condition for household {eq}`eq:no_arb` and firms {eq}`eq:no_arb_firms`, household's first order conditions {eq}`eq:foc_c` and {eq}`eq:foc_n`. +- initial condition $k_0$, and terminal condition {eq}`eq:terminal_final`. + +### Inelastic Labor Supply + +First, we consider the special case where $U(c, 1-n) = u(c)$. + +First we rewrite {eq}`eq:tech_capital` with $f(k) := F(k, 1)$, + +$$ +k_{t+1} = f(k_t) + (1 - \delta) k_t - g_t - c_t. +$$ (eq:feasi_capital) + +By the properties of linearly homogeneous production function, we have $F_k(k, n) = f'(k)$, and $F_n(k, 1) = f(k, 1) - f'(k)k$. + +Substitute {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we have + +$$ +\begin{aligned} +&\frac{u'(f(k_t) + (1 - \delta) k_t - g_t - k_{t+1})}{(1 + \tau_{ct})} \\ +&- \beta \frac{u'(f(k_{t+1}) + (1 - \delta) k_{t+1} - g_{t+1} - k_{t+2})}{(1 + \tau_{ct+1})} \\ +&\times [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1] = 0. +\end{aligned} +$$ + +which can be written as + +$$ +\begin{aligned} +u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1]. +\end{aligned} +$$ (eq:diff_second) + +which is the Euler equation for the household. + +This equation can be used to solve for the equilibrium sequence of consumption and capital as we will see in the second method. + +### Steady state + +Tax rates and government expenditures serve as forcing functions for the difference equations {eq}`eq:feasi_capital` and {eq}`eq:diff_second`. + +Let $z_t = [g_t, \tau_{kt}, \tau_{ct}]'$. We can write the second-order difference equation into + +$$ +H(k_t, k_{t+1}, k_{t+2}; z_t, z_{t+1}) = 0. +$$ (eq:second_ord_diff) + +We assume that the government policy is in the steady state satisfying $\lim_{t \to \infty} z_t = \bar z$. We assume the steady state is reached for $t > T$. A terminal steady-state capital stock $\bar k$ solves + +$$H(\bar{k}, \bar{k}, \bar{k}, \bar{z}, \bar{z}) = 0$$ + +Hencer we can derive the steady-state from the difference equation {eq}`eq:diff_second` + +$$ +\begin{aligned} +u'(\bar c) &= \beta u'(\bar c) \frac{(1 + \bar \tau_{c})}{(1 + \bar \tau_{c})} [(1 - \bar \tau_{k})(f'(\bar k) - \delta) + 1]. \\ +&\implies 1 = \beta[(1 - \bar \tau_{k})(f'(\bar k) - \delta) + 1] +\end{aligned} +$$ (eq:diff_second_steady) + + +### Other equilibrium quantities + +**Consumption** +$$ +c_t = f(k_t) + (1 - \delta)k_t - k_{t+1} - g_t +$$ (eq:equil_c) + +**Price of the good:** +$$ +q_t = \beta^t \frac{u'(c_t)}{1 + \tau_{ct}} +$$ (eq:equil_q) + +**Marginal product of capital** +$$ +\eta_t = f'(k_t) +$$ + +**Wage:** +$$ +w_t = f(k_t) - k_t f'(k_t) +$$ + +**Gross one-period return on capital:** +$$ +\bar{R}_{t+1} = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1\right] = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} R_{t, t+1} +$$ (eq:gross_rate) + +**One-period discount factor:** +$$ +R^{-1}_{t, t+1} = \frac{q_t}{q_{t-1}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} +$$ (eq:equil_R) + +**Net one-period rate of interest:** +$$ +r_{t, t+1} \equiv R_{t, t+1} - 1 = (1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) +$$ (eq:equil_r) + +### Shooting Algorithm + +In the following sections, we will experiment apply two methods to solve the model: shooting algorithm and minimization of Euler residual and law of motion capital. + +### Experiments + ++++ + +We will do a number of experiments and analyze the transition path for the equilibrium in each case: + +1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. +2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. +3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. +3. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever + ++++ + +Below we write the formulas for the shooting algorithm: + +$u(c) = \frac{c^{1 - \gamma}}{1 - \gamma}$ + +$u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[ (1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right]$ + +$R_{t,t+1} = \left[ (1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})}$ + +$k_{t+1} = f(k_t) + (1 - \delta)k_t - g_t - c_t$ + +$u'(c_t) = \beta R_{t,t+1} u'(c_{t+1}) \iff c_t^{-\gamma} = \beta R_{t,t+1} c_{t+1}^{-\gamma} \iff c_{t+1} = c_t \left( \beta R_{t,t+1} \right)^{1/\gamma}$ + +```{code-cell} ipython3 +def u_prime(c, γ): + """ + Marginal utility: u'(c) = c^{-γ} + """ + return c ** (-γ) + +def f(A, k, α): + """ + Production function: f(k) = A * k^{α} + """ + return A * k ** α + +def f_prime(A, k, α): + """ + Marginal product of capital: f'(k) = α * A * k^{α - 1} + """ + return α * A * k ** (α - 1) + +def compute_R_bar(A, τ_ct, τ_ctp1, τ_ktp1, k_tp1, α, δ): + """ + Gross one-period return on capital: + R̄ = [(1 + τ_c_t) / (1 + τ_c_{t+1})] * { [1 - τ_k_{t+1}] * [f'(k_{t+1}) - δ] + 1 } + """ + return ((1 + τ_ct) / (1 + τ_ctp1)) * ( + (1 - τ_ktp1) * (f_prime(A, k_tp1, α) - δ) + 1) + +def next_k(A, k_t, g_t, c_t, α, δ): + """ + Capital next period: k_{t+1} = f(k_t) + (1 - δ) * k_t - c_t - g_t + """ + return f(A, k_t, α) + (1 - δ) * k_t - g_t - c_t + +def next_c(c_t, R_bar, γ, β): + """ + Consumption next period: c_{t+1} = c_t * (β * R̄)^{1/γ} + """ + return c_t * (β * R_bar) ** (1 / γ) + +# Compute other equilibrium quantities +def compute_R_bar_path(shocks, k_path, model, S): + """ + Compute R̄ path over time. + """ + A, α, δ = model.A, model.α, model.δ + R_bar_path = np.zeros(S + 1) + for t in range(S): + R_bar_path[t] = compute_R_bar( + A, + shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], + k_path[t + 1], + α, δ + ) + R_bar_path[S] = R_bar_path[S - 1] + return R_bar_path + +def compute_η_path(k_path, α, A, S=100): + """ + Compute η path: η_t = f'(k_t) = α * A * k_t^{α - 1} + """ + η_path = np.zeros_like(k_path) + for t in range(S): + η_path[t] = α * A * k_path[t] ** (α - 1) + return η_path + +def compute_w_path(k_path, η_path, α, A, S=100): + """ + Compute w path: w_t = f(k_t) - k_t * f'(k_t) + """ + w_path = np.zeros_like(k_path) + for t in range(S): + w_path[t] = A * k_path[t] ** α - k_path[t] * η_path[t] + return w_path + +def compute_q_path(c_path, β, γ, S=100): + """ + Compute q path: q_t = (β^t * u'(c_t)) / u'(c_0) + """ + q_path = np.zeros_like(c_path) + for t in range(S): + q_path[t] = (β ** t * u_prime(c_path[t], γ)) / u_prime(c_path[0], γ) + return q_path + +def compute_rts_path(q_path, T, t): + """ + Compute r path: + r_t(s) = - (1/s) * ln(q_{t+s} / q_t) + """ + s = np.arange(T) + q_path = np.array([float(q) for q in q_path]) + + with np.errstate(divide='ignore', invalid='ignore'): + rts_path = - np.log(q_path[t + s] / q_path[t]) / s + return rts_path + +# Steady-state calculation +def steady_states(model, g_ss, τ_k_ss=0.0): + """ + Steady-state values: + - Capital: (1 - τ_k_ss) * [α * A * k_ss^{α - 1} - δ] = (1 / β) - 1 + - Consumption: c_ss = A * k_ss^{α} - δ * k_ss - g_ss + """ + β, δ, α, A = model.β, model.δ, model.α, model.A + numerator = δ + (1 / β - 1) / (1 - τ_k_ss) + denominator = α * A + k_ss = (numerator / denominator) ** (1 / (α - 1)) + c_ss = A * k_ss ** α - δ * k_ss - g_ss + return k_ss, c_ss +``` + +Next we prepare the sequence of variables that will be used to initialize the simulation. + +We will start from the steady state and then apply the shocks at the appropriate time. + +```{code-cell} ipython3 +def plot_results(solution, k_ss, c_ss, shocks, shock_param, + axes, model, label='', linestyle='-', T=40): + + k_path = solution[:, 0] + c_path = solution[:, 1] + + axes[0].plot(k_path[:T], linestyle=linestyle, label=label) + axes[0].axhline(k_ss, linestyle='--', color='black') + axes[0].set_title('k') + + # Plot for c + axes[1].plot(c_path[:T], linestyle=linestyle, label=label) + axes[1].axhline(c_ss, linestyle='--', color='black') + axes[1].set_title('c') + + # Plot for g + R_bar_path = compute_R_bar_path(shocks, k_path, model, S) + + axes[2].plot(R_bar_path[:T], linestyle=linestyle, label=label) + axes[2].set_title('$\overline{R}$') + axes[2].axhline(1 / model.β, linestyle='--', color='black') + + η_path = compute_η_path(k_path, model.α, model.A, S=T) + η_ss = model.α * model.A * k_ss ** (model.α - 1) + + axes[3].plot(η_path[:T], linestyle=linestyle, label=label) + axes[3].axhline(η_ss, linestyle='--', color='black') + axes[3].set_title(r'$\eta$') + + axes[4].plot(shocks[shock_param][:T], linestyle=linestyle, label=label) + axes[4].axhline(shocks[shock_param][0], linestyle='--', color='black') + axes[4].set_title(rf'${shock_param}$') +``` + +```{code-cell} ipython3 +def shooting_algorithm(c0, k0, shocks, S, model): + """ + Shooting algorithm for given initial c0 and k0. + """ + # High-precision parameters + β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, model.δ, model.α, model.A]] + g_path = [mp.mpf(g) for g in shocks['g']] + τ_c_path = [mp.mpf(tau_c) for tau_c in shocks['τ_c']] + τ_k_path = [mp.mpf(tau_k) for tau_k in shocks['τ_k']] + + # Initialize paths for consumption and capital + c_path = [mp.mpf('0')] * (S + 1) + k_path = [mp.mpf('0')] * (S + 1) + c_path[0] = mp.mpf(c0) + k_path[0] = mp.mpf(k0) + + # Generate paths for k_t and c_t + for t in range(S): + k_t, c_t = k_path[t], c_path[t] + g_t = g_path[t] + + # Calculate next period's capital + k_tp1 = next_k(A, k_t, g_t, c_t, α, δ) + if k_tp1 < mp.mpf('0'): + raise ValueError(f"Capital stock became negative at time {t + 1}.") + k_path[t + 1] = k_tp1 + + # Calculate next period's consumption + R_bar = compute_R_bar(A, τ_c_path[t], τ_c_path[t + 1], τ_k_path[t + 1], k_tp1, α, δ) + c_tp1 = next_c(c_t, R_bar, γ, β) + if c_tp1 < mp.mpf('0'): + raise ValueError(f"Consumption became negative at time {t + 1}.") + c_path[t + 1] = c_tp1 + + return k_path, c_path + +def bisection_c0(k0, c0, shocks, S, model, tol=mp.mpf('1e-6'), max_iter=1000, verbose=False): + """ + Bisection method to find optimal initial consumption c0. + """ + # High-precision model parameters + β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, model.δ, model.α, model.A]] + + # Compute the steady-state capital with high precision + k_ss_final, _ = steady_states(model, mp.mpf(shocks['g'][-1]), mp.mpf(shocks['τ_k'][-1])) + + # Initial bounds for c0 + c0_lower, c0_upper = mp.mpf(0), A * k_ss_final ** α + + for iter_count in range(max_iter): + try: + # Run the shooting algorithm and calculate the error + k_path, _ = shooting_algorithm(c0, k0, shocks, S, model) + error = k_path[-1] - k_ss_final + + if verbose and iter_count % 100 == 0: + print(f"Iteration {iter_count + 1}: c0 = {c0}, error = {error}") + + # Check for convergence + if abs(error) < tol: + if verbose: + print(f"Converged successfully on iteration {iter_count + 1}") + return c0 + + # Update bounds + if error > mp.mpf('0'): + c0_lower = c0 + else: + c0_upper = c0 + + except (ValueError, FloatingPointError) as e: + # Adjust bounds if an error occurs + if verbose: + print(f"Iteration {iter_count + 1}: shooting failed with c0 = {c0}") + c0_upper = c0 + + # Calculate the new midpoint for bisection + c0 = (c0_lower + c0_upper) / mp.mpf('2') + + # Warn if convergence failed + warnings.warn( + f"Convergence failed after {max_iter} iterations. Returning last value: c0 = {c0}", + ConvergenceWarning + ) + return c0 + +def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_function=shooting_algorithm): + """ + Runs the shooting algorithm to find the optimal c0 and simulate the model. + """ + # Compute initial steady states + k0, c0 = steady_states(model, mp.mpf(shocks['g'][0]), mp.mpf(shocks['τ_k'][0])) + + # Find the optimal initial consumption + optimal_c0 = c0_function(k0, c0, shocks, S, model) + print(f"Parameters: {model}") + print(f"Optimal initial consumption c0: {mp.nstr(optimal_c0, 7)} \n") + + # Simulate the model + k_path, c_path = shooting_function(optimal_c0, k0, shocks, S, model) + + # Combine and return the results + solution = np.column_stack([k_path, c_path]) + return solution +``` + +```{code-cell} ipython3 +# Steady-state calculations +k_ss, c_ss = steady_states(model, g_ss=0.2) + +print(f"Steady-state capital: {k_ss:.4f}") +print(f"Steady-state consumption: {c_ss:.4f}") +``` + +## Experiments with Shooting Algorithm + +### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. + +The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. + +```{code-cell} ipython3 +shocks = { + 'g': np.concatenate((np.repeat(0.2, 10), np.repeat(0.4, S - 9))), + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.repeat(0.0, S + 1) +} + +k_ss_initial, c_ss_initial = steady_states(model, g_ss=0.2) + +# Initial capital +k0 = k_ss_initial + +solution = run_shooting(shocks, S, model) + +fig, axes = plt.subplots(2, 3, figsize=(10, 8)) +axes = axes.flatten() + +plot_results(solution, k_ss_initial, c_ss_initial, shocks, 'g', axes, model, T=40) + +for ax in axes[5:]: + fig.delaxes(ax) + +plt.tight_layout() +plt.show() +``` + +Let's write the procedures above into a function that runs the solver and draw the plots for a given model + +```{code-cell} ipython3 +def experiment_model(shocks, S, model, solver, plot_func, k_ss, c_ss, policy_shock): + """ + Plots the results of running the shooting algorithm given a model + """ + + fig, axes = plt.subplots(2, 3, figsize=(10, 8)) + axes = axes.flatten() + + solution = solver(shocks, S, model) + plot_func(solution, k_ss_initial, c_ss_initial, shocks, policy_shock, axes, model, T=40) + + for ax in axes[5:]: + fig.delaxes(ax) + + plt.tight_layout() + plt.show() +``` + +The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. + +```{code-cell} ipython3 +solution = run_shooting(shocks, S, model) + +fig, axes = plt.subplots(2, 3, figsize=(10, 8)) +axes = axes.flatten() + +label = fr"$\gamma = {model.γ}$" +plot_results(solution, k_ss, c_ss, shocks, 'g', axes, model, label=label, + T=40) + +model_γ2 = create_model(γ=0.2) +solution = run_shooting(shocks, S, model_γ2) + +plot_results(solution, k_ss, c_ss, shocks, 'g', axes, model_γ2, + label=fr"$\gamma = {model_γ2.γ}$", + linestyle='-.', T=40) + +handles, labels = axes[0].get_legend_handles_labels() +fig.legend(handles, labels, loc='lower right', ncol=3, fontsize=14, bbox_to_anchor=(1, 0.1)) + +for ax in axes[5:]: + fig.delaxes(ax) + +plt.tight_layout() +plt.show() +``` + +Let's write another function that runs the solver and draw the plots for two models as we did above + +```{code-cell} ipython3 +def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, k_ss, c_ss, + policy_shock, legend_label_fun=lambda model: fr"$\gamma = {model.γ}$"): + """ + Plots the results of running the shooting algorithm for two different models. + """ + + # Set up the figure and axes for plotting + fig, axes = plt.subplots(2, 3, figsize=(10, 8)) + axes = axes.flatten() + + # Run the shooting algorithm for the first model + solution = solver(shocks, S, model_1) + plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model_1, + label=legend_label_fun(model_1), T=40) + + # Run the shooting algorithm for the second model + solution = solver(shocks, S, model_2) + plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model_2, + label=legend_label_fun(model_2), linestyle='-.', T=40) + + # Create a legend using the labels from the first axis + handles, labels = axes[0].get_legend_handles_labels() + fig.legend(handles, labels, loc='lower right', ncol=3, + fontsize=14, bbox_to_anchor=(1, 0.1)) + + # Remove any extra axes to tidy up the plot layout + for ax in axes[5:]: + fig.delaxes(ax) + + # Adjust the layout and display the plot + plt.tight_layout() + plt.show() +``` + +Now we plot other equilibrium quantities: + +```{code-cell} ipython3 +def plot_prices(solution, c_ss, shock_param, axes, + model, label='', linestyle='-', T=40): + + α, β, δ, γ, A = model.α, model.β, model.δ, model.γ, model.A + + k_path = solution[:, 0] + c_path = solution[:, 1] + + # Plot for c + axes[0].plot(c_path[:T], linestyle=linestyle, label=label) + axes[0].axhline(c_ss, linestyle='--', color='black') + axes[0].set_title('c') + + q_path = compute_q_path(c_path, + β, γ, S=S) + axes[1].plot(q_path[:T], linestyle=linestyle, label=label) + axes[1].plot(β**np.arange(T), linestyle='--', color='black') + axes[1].set_title('q') + + R_bar_path = compute_R_bar_path(shocks, k_path, model, S) + + axes[2].plot(R_bar_path[:T] - 1, linestyle=linestyle, label=label) + axes[2].axhline(1 / β - 1, linestyle='--', color='black') + axes[2].set_title('$r_{t,t+1}$') + + + for style, s in zip(['-', '-.', '--'], [0, 10, 60]): + rts_path = compute_rts_path(q_path, T, s) + axes[3].plot(rts_path, linestyle=style, + color='black' if style == '--' else None, + label=f'$t={s}$') + axes[3].set_xlabel('s') + axes[3].set_title('$r_{t,t+s}$') + + # Plot for g + axes[4].plot(shocks[shock_param][:T], linestyle=linestyle, label=label) + axes[4].axhline(shocks[shock_param][0], linestyle='--', color='black') + axes[4].set_title(shock_param) +``` + +```{code-cell} ipython3 +solution = run_shooting(shocks, S, model) + +fig, axes = plt.subplots(2, 3, figsize=(10, 8)) +axes = axes.flatten() + +plot_prices(solution, c_ss, 'g', axes, model, T=40) + +for ax in axes[5:]: + fig.delaxes(ax) + +handles, labels = axes[3].get_legend_handles_labels() +fig.legend(handles, labels, title=r"$r_{t,t+s}$ with ", loc='lower right', ncol=3, fontsize=10, bbox_to_anchor=(1, 0.1)) +plt.tight_layout() +plt.show() +``` + +### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. + +The experiment replicates the Figure 12.9.4. + +```{code-cell} ipython3 +shocks = { + 'g': np.repeat(0.2, S + 1), + 'τ_c': np.concatenate((np.repeat(0.0, 10), np.repeat(0.2, S - 9))), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_shooting, plot_results, k_ss, c_ss, 'τ_c') +``` + +### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. + +The experiment replicates the Figure 12.9.5. + +```{code-cell} ipython3 +shocks = { + 'g': np.repeat(0.2, S + 1), + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.concatenate((np.repeat(0.0, 10), np.repeat(0.2, S - 9))) +} + +experiment_two_models(shocks, S, model, model_γ2, + run_shooting, plot_results, k_ss, c_ss, 'τ_k') +``` + +### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever + +The experiment replicates the Figure 12.9.6. + +```{code-cell} ipython3 +g_path = np.repeat(0.2, S + 1) +g_path[10] = 0.4 + +shocks = { + 'g': g_path, + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_shooting, plot_results, k_ss, c_ss, 'g') +``` + +## Method 2: Minimization of Euler Residual and Law of Motion Capital + + +$$1 = \beta \left(\frac{c_{t+1}}{c_t}\right)^{-\gamma} \frac{(1+\tau_{ct})}{(1+\tau_{ct+1})} \left[(1 - \tau_{kt+1})(\alpha A k_{t+1}^{\alpha-1} - \delta) + 1 \right]$$ + +and a law of motion for capital + +$$k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t.$$ + ++++ + +### Algorithm for minimization approach (Method 2) + +1. **Calculate initial state $k_0$**: + - Based on the given initial government plan $z_0$. + +2. **Initialize a sequence of initial guesses** $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ + +3. **Compute the residuals** $R_a$, $R_k$ for $t = 0, \dots, S$, and $R_{tk_0}$ for $t=0$: + - **Arbitrage condition** residual for $t = 0, \dots, S$: + $$ + R_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - u'(c_t) + $$ + - **Feasibility condition** residual for $t = 1, \dots, S-1$: + $$ + R_{tk} = k_{t+1} - f(k_t) + (1 - \delta)k_t - g_t - c_t + $$ + - **Initial condition for $k_0$**: + $$ + R_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] + $$ + +4. **Root-finding**: + - Adjust the guesses for $k_t$ and $c_t$ to minimize the residuals $R_{k_0}$, $R_{ta}$, and $R_{tk}$ for $t = 0, \dots, S$. + +5. **Output**: + - The solution $\{c_t, k_t\}_{t=0}^{S}$. + +```{code-cell} ipython3 +# Arbitrage and Transition Equations for method 2 +def arbitrage(c_t, c_tp1, τ_c_t, τ_c_tp1, τ_k_tp1, k_tp1, model): + """ + Computes the arbitrage condition. + """ + β, γ, δ, α, A = model.β, model.γ, model.δ, model.α, model.A + η_tp1 = α * A * k_tp1 ** (α - 1) + return β * (c_tp1 / c_t) ** (-γ) * (1 + τ_c_t) / (1 + τ_c_tp1) * ( + (1 - τ_k_tp1) * (η_tp1 - δ) + 1) - 1 + +def transition(k_t, k_tm1, c_tm1, g_t, model): + """ + Computes the capital transition. + """ + α, A, δ = model.α, model.A, model.δ + return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) + +# Residuals for method 2 +def compute_residuals(vars_flat, k_init, S, shocks, model): + """ + Compute residuals for arbitrage and transition equations. + """ + k, c = vars_flat.reshape((S + 1, 2)).T + residuals = np.zeros(2 * S + 2) + + # Initial condition for capital + residuals[0] = k[0] - k_init + + # Compute residuals for each time step + for t in range(S): + residuals[2 * t + 1] = arbitrage( + c[t], c[t + 1], + shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], + k[t + 1], model + ) + residuals[2 * t + 2] = transition( + k[t + 1], k[t], c[t], + shocks['g'][t], model + ) + + # Terminal condition for arbitrage + residuals[-1] = arbitrage( + c[S], c[S], + shocks['τ_c'][S], shocks['τ_c'][S], shocks['τ_k'][S], + k[S], model + ) + + return residuals + +# Root-finding Algorithm to minimize the residual +def run_min(shocks, S, model): + """ + Root-finding algorithm to minimize the residuals. + """ + k_ss, c_ss = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) + + # Initial guess for the solution path + initial_guess = np.column_stack( + (np.full(S + 1, k_ss), np.full(S + 1, c_ss))).flatten() + + # Solve the system using root-finding + sol = root(compute_residuals, initial_guess, args=(k_ss, S, shocks, model), tol=1e-8) + + # Reshape solution to get time paths for k and c + return sol.x.reshape((S + 1, 2)) +``` + +Below are the results for the same experiments using the method of minimization of Euler residual and law of motion capital. + +This method does not have numerical stability issues so `mp.mpf` is not necessary. + +### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. + +The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. + +```{code-cell} ipython3 +# Define the shocks for the simulation +S = 100 +shocks = { + 'g': np.concatenate((np.repeat(0.2, 10), np.repeat(0.4, S - 9))), + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'g') +``` + +The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. + +```{code-cell} ipython3 +experiment_two_models(shocks, S, model, model_γ2, + run_min, plot_results, k_ss, c_ss, 'g') +``` + +Below replicates the graph 12.9.3: + +```{code-cell} ipython3 +solution = run_min(shocks, S, model) + +fig, axes = plt.subplots(2, 3, figsize=(10, 8)) +axes = axes.flatten() + +plot_prices(solution, c_ss, 'g', axes, model, T=40) + +for ax in axes[5:]: + fig.delaxes(ax) + +handles, labels = axes[3].get_legend_handles_labels() +fig.legend(handles, labels, title=r"$r_{t,t+s}$ with ", loc='lower right', ncol=3, fontsize=10, bbox_to_anchor=(1, 0.1)) +plt.tight_layout() +plt.show() +``` + +### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. + +The experiment replicates the Figure 12.9.4. + +```{code-cell} ipython3 +shocks = { + 'g': np.repeat(0.2, S + 1), + 'τ_c': np.concatenate((np.repeat(0.0, 10), np.repeat(0.2, S - 9))), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'τ_c') +``` + +### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. + +The experiment replicates the Figure 12.9.5. + +```{code-cell} ipython3 +shocks = { + 'g': np.repeat(0.2, S + 1), + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.concatenate((np.repeat(0.0, 10), np.repeat(0.2, S - 9))) +} + +experiment_two_models(shocks, S, model, model_γ2, + run_min, plot_results, k_ss, c_ss, 'τ_k') +``` + +### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever + +The experiment replicates the Figure 12.9.6. + +```{code-cell} ipython3 +g_path = np.repeat(0.2, S + 1) +g_path[10] = 0.4 + +shocks = { + 'g': g_path, + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'g') +``` From 65c204da50bf384e720f0d895c59b3393ac4ac34 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 1 Nov 2024 22:04:55 +1100 Subject: [PATCH 02/17] simplify plotting function --- lectures/cass_fiscal.md | 69 ++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index d3cee5741..30821be3b 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -527,10 +527,10 @@ def shooting_algorithm(c0, k0, shocks, S, model): Shooting algorithm for given initial c0 and k0. """ # High-precision parameters - β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, model.δ, model.α, model.A]] - g_path = [mp.mpf(g) for g in shocks['g']] - τ_c_path = [mp.mpf(tau_c) for tau_c in shocks['τ_c']] - τ_k_path = [mp.mpf(tau_k) for tau_k in shocks['τ_k']] + β, γ, δ, α, A = map(mp.mpf, + [model.β, model.γ, model.δ, model.α, model.A]) + g_path, τ_c_path, τ_k_path = [ + list(map(mp.mpf, shocks[key])) for key in ['g', 'τ_c', 'τ_k']] # Initialize paths for consumption and capital c_path = [mp.mpf('0')] * (S + 1) @@ -550,7 +550,8 @@ def shooting_algorithm(c0, k0, shocks, S, model): k_path[t + 1] = k_tp1 # Calculate next period's consumption - R_bar = compute_R_bar(A, τ_c_path[t], τ_c_path[t + 1], τ_k_path[t + 1], k_tp1, α, δ) + R_bar = compute_R_bar(A, τ_c_path[t], τ_c_path[t + 1], + τ_k_path[t + 1], k_tp1, α, δ) c_tp1 = next_c(c_t, R_bar, γ, β) if c_tp1 < mp.mpf('0'): raise ValueError(f"Consumption became negative at time {t + 1}.") @@ -558,15 +559,18 @@ def shooting_algorithm(c0, k0, shocks, S, model): return k_path, c_path -def bisection_c0(k0, c0, shocks, S, model, tol=mp.mpf('1e-6'), max_iter=1000, verbose=False): +def bisection_c0(k0, c0, shocks, S, model, + tol=mp.mpf('1e-6'), max_iter=1000, verbose=False): """ Bisection method to find optimal initial consumption c0. """ # High-precision model parameters - β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, model.δ, model.α, model.A]] + β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, + model.δ, model.α, model.A]] # Compute the steady-state capital with high precision - k_ss_final, _ = steady_states(model, mp.mpf(shocks['g'][-1]), mp.mpf(shocks['τ_k'][-1])) + k_ss_final, _ = steady_states(model, mp.mpf(shocks['g'][-1]), + mp.mpf(shocks['τ_k'][-1])) # Initial bounds for c0 c0_lower, c0_upper = mp.mpf(0), A * k_ss_final ** α @@ -608,7 +612,9 @@ def bisection_c0(k0, c0, shocks, S, model, tol=mp.mpf('1e-6'), max_iter=1000, ve ) return c0 -def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_function=shooting_algorithm): +def run_shooting(shocks, S, model, + c0_function=bisection_c0, + shooting_func=shooting_algorithm): """ Runs the shooting algorithm to find the optimal c0 and simulate the model. """ @@ -621,7 +627,7 @@ def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_function=s print(f"Optimal initial consumption c0: {mp.nstr(optimal_c0, 7)} \n") # Simulate the model - k_path, c_path = shooting_function(optimal_c0, k0, shocks, S, model) + k_path, c_path = shooting_func(optimal_c0, k0, shocks, S, model) # Combine and return the results solution = np.column_stack([k_path, c_path]) @@ -659,7 +665,8 @@ solution = run_shooting(shocks, S, model) fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() -plot_results(solution, k_ss_initial, c_ss_initial, shocks, 'g', axes, model, T=40) +plot_results(solution, k_ss_initial, + c_ss_initial, shocks, 'g', axes, model, T=40) for ax in axes[5:]: fig.delaxes(ax) @@ -680,7 +687,8 @@ def experiment_model(shocks, S, model, solver, plot_func, k_ss, c_ss, policy_sho axes = axes.flatten() solution = solver(shocks, S, model) - plot_func(solution, k_ss_initial, c_ss_initial, shocks, policy_shock, axes, model, T=40) + plot_func(solution, k_ss_initial, c_ss_initial, + shocks, policy_shock, axes, model, T=40) for ax in axes[5:]: fig.delaxes(ax) @@ -709,7 +717,8 @@ plot_results(solution, k_ss, c_ss, shocks, 'g', axes, model_γ2, linestyle='-.', T=40) handles, labels = axes[0].get_legend_handles_labels() -fig.legend(handles, labels, loc='lower right', ncol=3, fontsize=14, bbox_to_anchor=(1, 0.1)) +fig.legend(handles, labels, loc='lower right', + ncol=3, fontsize=14, bbox_to_anchor=(1, 0.1)) for ax in axes[5:]: fig.delaxes(ax) @@ -721,36 +730,38 @@ plt.show() Let's write another function that runs the solver and draw the plots for two models as we did above ```{code-cell} ipython3 -def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, k_ss, c_ss, - policy_shock, legend_label_fun=lambda model: fr"$\gamma = {model.γ}$"): +def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, + k_ss, c_ss, policy_shock, legend_label_fun=None): """ - Plots the results of running the shooting algorithm for two different models. + Compares and plots results of the shooting algorithm for two models. """ + # Use a default labeling function if none is provided + if legend_label_fun is None: + legend_label_fun = lambda model: fr"$\gamma = {model.γ}$" - # Set up the figure and axes for plotting + # Set up the figure and axes fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() - # Run the shooting algorithm for the first model - solution = solver(shocks, S, model_1) - plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model_1, - label=legend_label_fun(model_1), T=40) + # Function to run and plot for each model + def run_and_plot(model, linestyle='-'): + solution = solver(shocks, S, model) + plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model, + label=legend_label_fun(model), linestyle=linestyle, T=40) - # Run the shooting algorithm for the second model - solution = solver(shocks, S, model_2) - plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model_2, - label=legend_label_fun(model_2), linestyle='-.', T=40) + # Plot for both models + run_and_plot(model_1) + run_and_plot(model_2, linestyle='-.') - # Create a legend using the labels from the first axis + # Set legend using labels from the first axis handles, labels = axes[0].get_legend_handles_labels() fig.legend(handles, labels, loc='lower right', ncol=3, fontsize=14, bbox_to_anchor=(1, 0.1)) - # Remove any extra axes to tidy up the plot layout + # Remove extra axes and tidy up the layout for ax in axes[5:]: fig.delaxes(ax) - - # Adjust the layout and display the plot + plt.tight_layout() plt.show() ``` From 59c5de306ebf1d103d0e446ad75f0973bd37506e Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sat, 2 Nov 2024 12:20:23 +1100 Subject: [PATCH 03/17] simplify code --- lectures/cass_fiscal.md | 185 +++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 95 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 30821be3b..8f7bf797d 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -20,15 +20,11 @@ import numpy as np from scipy.optimize import root import matplotlib.pyplot as plt from collections import namedtuple -from mpmath import mp -import warnings - -class ConvergenceWarning(UserWarning): - """Warning raised when the bisection method fails to converge.""" - pass +from mpmath import mp, mpf +from warnings import warn # Set the precision -mp.dps = 60 +mp.dps = 40 mp.pretty = True ``` @@ -527,119 +523,99 @@ def shooting_algorithm(c0, k0, shocks, S, model): Shooting algorithm for given initial c0 and k0. """ # High-precision parameters - β, γ, δ, α, A = map(mp.mpf, - [model.β, model.γ, model.δ, model.α, model.A]) - g_path, τ_c_path, τ_k_path = [ - list(map(mp.mpf, shocks[key])) for key in ['g', 'τ_c', 'τ_k']] - - # Initialize paths for consumption and capital - c_path = [mp.mpf('0')] * (S + 1) - k_path = [mp.mpf('0')] * (S + 1) - c_path[0] = mp.mpf(c0) - k_path[0] = mp.mpf(k0) + β, γ, δ, α, A = map(mpf, (model.β, model.γ, model.δ, model.α, model.A)) + # Convert shocks to high-precision + g_path, τ_c_path, τ_k_path = ( + list(map(mpf, shocks[key])) for key in ['g', 'τ_c', 'τ_k'] + ) + + # Initialize paths with initial values + c_path = [mpf(c0)] + [mpf(0)] * S + k_path = [mpf(k0)] + [mpf(0)] * S # Generate paths for k_t and c_t for t in range(S): - k_t, c_t = k_path[t], c_path[t] - g_t = g_path[t] - + k_t, c_t, g_t = k_path[t], c_path[t], g_path[t] + # Calculate next period's capital k_tp1 = next_k(A, k_t, g_t, c_t, α, δ) - if k_tp1 < mp.mpf('0'): - raise ValueError(f"Capital stock became negative at time {t + 1}.") + # Failure due to negative capital + if k_tp1 < mpf(0): + return None, None k_path[t + 1] = k_tp1 # Calculate next period's consumption R_bar = compute_R_bar(A, τ_c_path[t], τ_c_path[t + 1], τ_k_path[t + 1], k_tp1, α, δ) c_tp1 = next_c(c_t, R_bar, γ, β) - if c_tp1 < mp.mpf('0'): - raise ValueError(f"Consumption became negative at time {t + 1}.") + # Failure due to negative consumption + if c_tp1 < mpf(0): + return None, None c_path[t + 1] = c_tp1 return k_path, c_path -def bisection_c0(k0, c0, shocks, S, model, - tol=mp.mpf('1e-6'), max_iter=1000, verbose=False): + +def bisection_c0(k0, c0_guess, shocks, S, model, + tol=mpf('1e-6'), max_iter=1000, verbose=False): """ Bisection method to find optimal initial consumption c0. """ - # High-precision model parameters - β, γ, δ, α, A = [mp.mpf(x) for x in [model.β, model.γ, - model.δ, model.α, model.A]] - - # Compute the steady-state capital with high precision - k_ss_final, _ = steady_states(model, mp.mpf(shocks['g'][-1]), - mp.mpf(shocks['τ_k'][-1])) - - # Initial bounds for c0 - c0_lower, c0_upper = mp.mpf(0), A * k_ss_final ** α + β, γ, δ, α, A = map(mpf, (model.β, model.γ, model.δ, model.α, model.A)) + k_ss_final, _ = steady_states(model, + mpf(shocks['g'][-1]), mpf(shocks['τ_k'][-1])) + c0_lower, c0_upper = mpf(0), A * k_ss_final ** α + c0 = c0_guess for iter_count in range(max_iter): - try: - # Run the shooting algorithm and calculate the error - k_path, _ = shooting_algorithm(c0, k0, shocks, S, model) + k_path, _ = shooting_algorithm(c0, k0, shocks, S, model) + if k_path is None: + if verbose: + print(f"Iteration {iter_count + 1}: shooting failed with c0 = {c0}") + # Adjust upper bound when shooting fails + c0_upper = c0 + else: error = k_path[-1] - k_ss_final - if verbose and iter_count % 100 == 0: print(f"Iteration {iter_count + 1}: c0 = {c0}, error = {error}") # Check for convergence if abs(error) < tol: - if verbose: - print(f"Converged successfully on iteration {iter_count + 1}") - return c0 + # Converged successfully + print(f"Converged successfully on iteration {iter_count + 1}") + return c0 - # Update bounds - if error > mp.mpf('0'): + # Update bounds based on the error + if error > mpf(0): c0_lower = c0 else: c0_upper = c0 - except (ValueError, FloatingPointError) as e: - # Adjust bounds if an error occurs - if verbose: - print(f"Iteration {iter_count + 1}: shooting failed with c0 = {c0}") - c0_upper = c0 - # Calculate the new midpoint for bisection - c0 = (c0_lower + c0_upper) / mp.mpf('2') + c0 = (c0_lower + c0_upper) / mpf('2') - # Warn if convergence failed - warnings.warn( - f"Convergence failed after {max_iter} iterations. Returning last value: c0 = {c0}", - ConvergenceWarning - ) + # Return the last computed c0 if convergence was not achieved + # Send a Warning message when this happens + warn(f"Converged failed. Returning the last c0 = {c0}", stacklevel=2) return c0 -def run_shooting(shocks, S, model, - c0_function=bisection_c0, - shooting_func=shooting_algorithm): +def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_func=shooting_algorithm): """ - Runs the shooting algorithm to find the optimal c0 and simulate the model. + Runs the shooting algorithm. """ # Compute initial steady states - k0, c0 = steady_states(model, mp.mpf(shocks['g'][0]), mp.mpf(shocks['τ_k'][0])) + k0, c0 = steady_states(model, mpf(shocks['g'][0]), mpf(shocks['τ_k'][0])) # Find the optimal initial consumption optimal_c0 = c0_function(k0, c0, shocks, S, model) print(f"Parameters: {model}") print(f"Optimal initial consumption c0: {mp.nstr(optimal_c0, 7)} \n") - + # Simulate the model k_path, c_path = shooting_func(optimal_c0, k0, shocks, S, model) # Combine and return the results - solution = np.column_stack([k_path, c_path]) - return solution -``` - -```{code-cell} ipython3 -# Steady-state calculations -k_ss, c_ss = steady_states(model, g_ss=0.2) - -print(f"Steady-state capital: {k_ss:.4f}") -print(f"Steady-state consumption: {c_ss:.4f}") + return np.column_stack([k_path, c_path]) ``` ## Experiments with Shooting Algorithm @@ -649,16 +625,19 @@ print(f"Steady-state consumption: {c_ss:.4f}") The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. ```{code-cell} ipython3 +# Define shocks as a dictionary shocks = { 'g': np.concatenate((np.repeat(0.2, 10), np.repeat(0.4, S - 9))), 'τ_c': np.repeat(0.0, S + 1), 'τ_k': np.repeat(0.0, S + 1) } -k_ss_initial, c_ss_initial = steady_states(model, g_ss=0.2) +k_ss_initial, c_ss_initial = steady_states(model, + shocks['g'][0], + shocks['τ_k'][0]) -# Initial capital -k0 = k_ss_initial +print(f"Steady-state capital: {k_ss_initial:.4f}") +print(f"Steady-state consumption: {c_ss_initial:.4f}") solution = run_shooting(shocks, S, model) @@ -678,17 +657,23 @@ plt.show() Let's write the procedures above into a function that runs the solver and draw the plots for a given model ```{code-cell} ipython3 -def experiment_model(shocks, S, model, solver, plot_func, k_ss, c_ss, policy_shock): +def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): """ Plots the results of running the shooting algorithm given a model """ + k0, c0 = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) + + print(f"Steady-state capital: {k0:.4f}") + print(f"Steady-state consumption: {c0:.4f}") + print('-'*64) + fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() solution = solver(shocks, S, model) - plot_func(solution, k_ss_initial, c_ss_initial, - shocks, policy_shock, axes, model, T=40) + plot_func(solution, k0, c0, + shocks, policy_shock, axes, model, T=T) for ax in axes[5:]: fig.delaxes(ax) @@ -701,18 +686,22 @@ The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gam ```{code-cell} ipython3 solution = run_shooting(shocks, S, model) - +k_ss_initial, c_ss_initial = steady_states(model, + shocks['g'][0], + shocks['τ_k'][0]) fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() label = fr"$\gamma = {model.γ}$" -plot_results(solution, k_ss, c_ss, shocks, 'g', axes, model, label=label, +plot_results(solution, k_ss_initial, c_ss_initial, + shocks, 'g', axes, model, label=label, T=40) model_γ2 = create_model(γ=0.2) solution = run_shooting(shocks, S, model_γ2) -plot_results(solution, k_ss, c_ss, shocks, 'g', axes, model_γ2, +plot_results(solution, k_ss_initial, c_ss_initial, + shocks, 'g', axes, model_γ2, label=fr"$\gamma = {model_γ2.γ}$", linestyle='-.', T=40) @@ -731,10 +720,16 @@ Let's write another function that runs the solver and draw the plots for two mod ```{code-cell} ipython3 def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, - k_ss, c_ss, policy_shock, legend_label_fun=None): + policy_shock, legend_label_fun=None, T=40): """ Compares and plots results of the shooting algorithm for two models. """ + + k0, c0 = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) + print(f"Steady-state capital: {k0:.4f}") + print(f"Steady-state consumption: {c0:.4f}") + print('-'*64) + # Use a default labeling function if none is provided if legend_label_fun is None: legend_label_fun = lambda model: fr"$\gamma = {model.γ}$" @@ -746,8 +741,8 @@ def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, # Function to run and plot for each model def run_and_plot(model, linestyle='-'): solution = solver(shocks, S, model) - plot_func(solution, k_ss, c_ss, shocks, policy_shock, axes, model, - label=legend_label_fun(model), linestyle=linestyle, T=40) + plot_func(solution, k0, c0, shocks, policy_shock, axes, model, + label=legend_label_fun(model), linestyle=linestyle, T=T) # Plot for both models run_and_plot(model_1) @@ -815,7 +810,7 @@ solution = run_shooting(shocks, S, model) fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() -plot_prices(solution, c_ss, 'g', axes, model, T=40) +plot_prices(solution, c_ss_initial, 'g', axes, model, T=40) for ax in axes[5:]: fig.delaxes(ax) @@ -837,7 +832,7 @@ shocks = { 'τ_k': np.repeat(0.0, S + 1) } -experiment_model(shocks, S, model, run_shooting, plot_results, k_ss, c_ss, 'τ_c') +experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` ### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. @@ -852,7 +847,7 @@ shocks = { } experiment_two_models(shocks, S, model, model_γ2, - run_shooting, plot_results, k_ss, c_ss, 'τ_k') + run_shooting, plot_results, 'τ_k') ``` ### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever @@ -869,7 +864,7 @@ shocks = { 'τ_k': np.repeat(0.0, S + 1) } -experiment_model(shocks, S, model, run_shooting, plot_results, k_ss, c_ss, 'g') +experiment_model(shocks, S, model, run_shooting, plot_results, 'g') ``` ## Method 2: Minimization of Euler Residual and Law of Motion Capital @@ -995,14 +990,14 @@ shocks = { 'τ_k': np.repeat(0.0, S + 1) } -experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'g') +experiment_model(shocks, S, model, run_min, plot_results, 'g') ``` The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. ```{code-cell} ipython3 experiment_two_models(shocks, S, model, model_γ2, - run_min, plot_results, k_ss, c_ss, 'g') + run_min, plot_results, 'g') ``` Below replicates the graph 12.9.3: @@ -1013,7 +1008,7 @@ solution = run_min(shocks, S, model) fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() -plot_prices(solution, c_ss, 'g', axes, model, T=40) +plot_prices(solution, c_ss_initial, 'g', axes, model, T=40) for ax in axes[5:]: fig.delaxes(ax) @@ -1035,7 +1030,7 @@ shocks = { 'τ_k': np.repeat(0.0, S + 1) } -experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'τ_c') +experiment_model(shocks, S, model, run_min, plot_results, 'τ_c') ``` ### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. @@ -1050,7 +1045,7 @@ shocks = { } experiment_two_models(shocks, S, model, model_γ2, - run_min, plot_results, k_ss, c_ss, 'τ_k') + run_min, plot_results, 'τ_k') ``` ### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever @@ -1067,5 +1062,5 @@ shocks = { 'τ_k': np.repeat(0.0, S + 1) } -experiment_model(shocks, S, model, run_min, plot_results, k_ss, c_ss, 'g') +experiment_model(shocks, S, model, run_min, plot_results, 'g') ``` From 2ef3df39507d216eb8ad5806e1522703f1c234cc Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sun, 3 Nov 2024 00:45:09 +1100 Subject: [PATCH 04/17] move code up to the equation --- lectures/cass_fiscal.md | 267 ++++++++++++++++++++++++---------------- 1 file changed, 159 insertions(+), 108 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 8f7bf797d..069149e86 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -72,16 +72,6 @@ $$ \end{aligned} $$ (eq:house_budget) - -In our model, the representative household has the following CRRA preferences over consumption: - -$$ -U(c) = \frac{c^{1 - \gamma}}{1 - \gamma} -$$ - -where $c$ is consumption and $\gamma$ is the coefficient of relative risk aversion. - - ### Technology The economy's production technology is defined by: @@ -233,10 +223,6 @@ $$ -\lim_{T \to \infty} \frac{U_{1t}}{(1 + \tau_{ct})} r k_{T+1} = 0. $$ (eq:terminal_final) -$F(k_t, n_t) = A k_t^\alpha n_t^{1 - \alpha}$ - -$f'(k_t) = \alpha A k_t^{\alpha - 1}$ - ## Computing Equilibria To compute an equilibrium we solve a price system $\{q_t, \eta_t, w_t\}$, a budget feasible government policy $\{g_t, \tau_t\} \equiv \{g_t, \tau_{ct}, \tau_{nt}, \tau_{kt}, \tau_{ht}\}$, and an allocation $\{c_t, n_t, k_{t+1}\}$ that solve the system of nonlinear difference equations consisting of @@ -254,6 +240,14 @@ $$ k_{t+1} = f(k_t) + (1 - \delta) k_t - g_t - c_t. $$ (eq:feasi_capital) +```{code-cell} ipython3 +def next_k(A, k_t, g_t, c_t, α, δ): + """ + Capital next period: k_{t+1} = f(k_t) + (1 - δ) * k_t - c_t - g_t + """ + return f(A, k_t, α) + (1 - δ) * k_t - g_t - c_t +``` + By the properties of linearly homogeneous production function, we have $F_k(k, n) = f'(k)$, and $F_n(k, 1) = f(k, 1) - f'(k)k$. Substitute {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we have @@ -304,69 +298,142 @@ $$ (eq:diff_second_steady) ### Other equilibrium quantities -**Consumption** -$$ -c_t = f(k_t) + (1 - \delta)k_t - k_{t+1} - g_t -$$ (eq:equil_c) - **Price of the good:** + $$ q_t = \beta^t \frac{u'(c_t)}{1 + \tau_{ct}} $$ (eq:equil_q) +```{code-cell} ipython3 +def compute_q_path(c_path, β, γ, S=100): + """ + Compute q path: q_t = (β^t * u'(c_t)) / u'(c_0) + """ + q_path = np.zeros_like(c_path) + for t in range(S): + q_path[t] = (β ** t * u_prime(c_path[t], γ)) / u_prime(c_path[0], γ) + return q_path +``` + **Marginal product of capital** + $$ \eta_t = f'(k_t) $$ +```{code-cell} ipython3 +def compute_η_path(k_path, α, A, S=100): + """ + Compute η path: η_t = f'(k_t) = α * A * k_t^{α - 1} + """ + η_path = np.zeros_like(k_path) + for t in range(S): + η_path[t] = α * A * k_path[t] ** (α - 1) + return η_path +``` + **Wage:** + $$ w_t = f(k_t) - k_t f'(k_t) $$ +```{code-cell} ipython3 +def compute_w_path(k_path, η_path, α, A, S=100): + """ + Compute w path: w_t = f(k_t) - k_t * f'(k_t) + """ + w_path = np.zeros_like(k_path) + for t in range(S): + w_path[t] = A * k_path[t] ** α - k_path[t] * η_path[t] + return w_path +``` + **Gross one-period return on capital:** + $$ \bar{R}_{t+1} = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1\right] = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} R_{t, t+1} $$ (eq:gross_rate) +```{code-cell} ipython3 +def compute_R_bar(A, τ_ct, τ_ctp1, τ_ktp1, k_tp1, α, δ): + """ + Gross one-period return on capital: + R̄ = [(1 + τ_c_t) / (1 + τ_c_{t+1})] + * { [1 - τ_k_{t+1}] * [f'(k_{t+1}) - δ] + 1 } + """ + return ((1 - τ_ktp1) * (f_prime(A, k_tp1, α) - δ) + 1) * ( + (1 + τ_ct) / (1 + τ_ctp1)) + +def compute_R_bar_path(shocks, k_path, model, S): + """ + Compute R̄ path over time. + """ + A, α, δ = model.A, model.α, model.δ + R_bar_path = np.zeros(S + 1) + for t in range(S): + R_bar_path[t] = compute_R_bar( + A, + shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], + k_path[t + 1], + α, δ + ) + R_bar_path[S] = R_bar_path[S - 1] + return R_bar_path +``` + **One-period discount factor:** + $$ R^{-1}_{t, t+1} = \frac{q_t}{q_{t-1}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} $$ (eq:equil_R) + **Net one-period rate of interest:** + $$ r_{t, t+1} \equiv R_{t, t+1} - 1 = (1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) $$ (eq:equil_r) -### Shooting Algorithm - -In the following sections, we will experiment apply two methods to solve the model: shooting algorithm and minimization of Euler residual and law of motion capital. +By {eq}`eq:equil_R`, we have -### Experiments - -+++ - -We will do a number of experiments and analyze the transition path for the equilibrium in each case: +$$ +R_{t, t+s} = e^{s \cdot r_{t, t+s}}. +$$ -1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. -2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. -3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. -3. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever +Then by {eq}`eq:equil_r`, we have -+++ +$$ +\frac{q_{t+s}}{q_t} = e^{-s \cdot r_{t, t+s}}. +$$ -Below we write the formulas for the shooting algorithm: +Rearranging the above equation, we have -$u(c) = \frac{c^{1 - \gamma}}{1 - \gamma}$ +$$ +r_{t, t+s} = -\frac{1}{s} \ln\left(\frac{q_{t+s}}{q_t}\right). +$$ -$u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[ (1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right]$ +```{code-cell} ipython3 +def compute_rts_path(q_path, T, t): + """ + Compute r path: + r_t,t+s = - (1/s) * ln(q_{t+s} / q_t) + """ + s = np.arange(1, T + 1) + q_path = np.array([float(q) for q in q_path]) + + with np.errstate(divide='ignore', invalid='ignore'): + rts_path = - np.log(q_path[t + s] / q_path[t]) / s + return rts_path +``` -$R_{t,t+1} = \left[ (1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})}$ +## Specifications of the Model -$k_{t+1} = f(k_t) + (1 - \delta)k_t - g_t - c_t$ +In our model, the representative household has the following CRRA preferences over consumption: -$u'(c_t) = \beta R_{t,t+1} u'(c_{t+1}) \iff c_t^{-\gamma} = \beta R_{t,t+1} c_{t+1}^{-\gamma} \iff c_{t+1} = c_t \left( \beta R_{t,t+1} \right)^{1/\gamma}$ +$$ +U(c) = \frac{c^{1 - \gamma}}{1 - \gamma} +$$ ```{code-cell} ipython3 def u_prime(c, γ): @@ -374,95 +441,75 @@ def u_prime(c, γ): Marginal utility: u'(c) = c^{-γ} """ return c ** (-γ) +``` + +Observe that by substituting {eq}`eq:gross_rate` into {eq}`eq:diff_second`, we have + +$$ +c_{t+1} = c_t \left[ \beta \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) + 1 \right] \right]^{\frac{1}{\gamma}} = c_t \left[ \beta \overline{R}_{t+1} \right]^{\frac{1}{\gamma}} +$$ (eq:consume_R) + +```{code-cell} ipython3 +def next_c(c_t, R_bar, γ, β): + """ + Consumption next period: c_{t+1} = c_t * (β * R̄)^{1/γ} + """ + return c_t * (β * R_bar) ** (1 / γ) +``` + +The production function is given by the Cobb-Douglas form: + +$$ +F(k, 1) = A k^\alpha +$$ +```{code-cell} ipython3 def f(A, k, α): """ Production function: f(k) = A * k^{α} """ + + A, α = model.A, model.α return A * k ** α def f_prime(A, k, α): """ Marginal product of capital: f'(k) = α * A * k^{α - 1} """ + A, α = model.A, model.α return α * A * k ** (α - 1) +``` -def compute_R_bar(A, τ_ct, τ_ctp1, τ_ktp1, k_tp1, α, δ): - """ - Gross one-period return on capital: - R̄ = [(1 + τ_c_t) / (1 + τ_c_{t+1})] * { [1 - τ_k_{t+1}] * [f'(k_{t+1}) - δ] + 1 } - """ - return ((1 + τ_ct) / (1 + τ_ctp1)) * ( - (1 - τ_ktp1) * (f_prime(A, k_tp1, α) - δ) + 1) +## Computation -def next_k(A, k_t, g_t, c_t, α, δ): - """ - Capital next period: k_{t+1} = f(k_t) + (1 - δ) * k_t - c_t - g_t - """ - return f(A, k_t, α) + (1 - δ) * k_t - g_t - c_t +In the following sections, we will experiment apply two methods to solve the model: shooting algorithm and minimization of Euler residual and law of motion capital. -def next_c(c_t, R_bar, γ, β): - """ - Consumption next period: c_{t+1} = c_t * (β * R̄)^{1/γ} - """ - return c_t * (β * R_bar) ** (1 / γ) +### Shooting Algorithm -# Compute other equilibrium quantities -def compute_R_bar_path(shocks, k_path, model, S): - """ - Compute R̄ path over time. - """ - A, α, δ = model.A, model.α, model.δ - R_bar_path = np.zeros(S + 1) - for t in range(S): - R_bar_path[t] = compute_R_bar( - A, - shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], - k_path[t + 1], - α, δ - ) - R_bar_path[S] = R_bar_path[S - 1] - return R_bar_path +1. Solve equation {eq}`eq:diff_second_steady` for the terminal steady-state capital $\bar{k}$ that is associated with the permanent policy vector $\bar{z}$. -def compute_η_path(k_path, α, A, S=100): - """ - Compute η path: η_t = f'(k_t) = α * A * k_t^{α - 1} - """ - η_path = np.zeros_like(k_path) - for t in range(S): - η_path[t] = α * A * k_path[t] ** (α - 1) - return η_path +2. Select a large time index $S \gg T$ and guess an initial consumption rate $c_0$, and use equation {eq}`eq:feasi_capital` to solve for $k_1$. -def compute_w_path(k_path, η_path, α, A, S=100): - """ - Compute w path: w_t = f(k_t) - k_t * f'(k_t) - """ - w_path = np.zeros_like(k_path) - for t in range(S): - w_path[t] = A * k_path[t] ** α - k_path[t] * η_path[t] - return w_path +3. Use equation {eq}`eq:consume_R` to determine $c_{t+1}$. Then, use equation {eq}`eq:feasi_capital` to compute $k_{t+2}$. -def compute_q_path(c_path, β, γ, S=100): - """ - Compute q path: q_t = (β^t * u'(c_t)) / u'(c_0) - """ - q_path = np.zeros_like(c_path) - for t in range(S): - q_path[t] = (β ** t * u_prime(c_path[t], γ)) / u_prime(c_path[0], γ) - return q_path +4. Iterate on step 3 to compute candidate values $\hat{k}_t$ for $t = 1, \dots, S$. -def compute_rts_path(q_path, T, t): - """ - Compute r path: - r_t(s) = - (1/s) * ln(q_{t+s} / q_t) - """ - s = np.arange(T) - q_path = np.array([float(q) for q in q_path]) +5. Compute the difference $\hat{k}_S - \bar{k}$. If $\left| \hat{k}_S - \bar{k} \right| > \epsilon$ for some small $\epsilon$, adjust $c_0$ and repeat steps 2-5. - with np.errstate(divide='ignore', invalid='ignore'): - rts_path = - np.log(q_path[t + s] / q_path[t]) / s - return rts_path +6. Adjust $c_0$ iteratively using bisection method to find a value that makes $\left| \hat{k}_S - \bar{k} \right| < \epsilon$. + +### Experiments + ++++ +We will do a number of experiments and analyze the transition path for the equilibrium in each case: + +1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. +2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. +3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. +3. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever + +```{code-cell} ipython3 # Steady-state calculation def steady_states(model, g_ss, τ_k_ss=0.0): """ @@ -888,7 +935,7 @@ $$k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t.$$ 3. **Compute the residuals** $R_a$, $R_k$ for $t = 0, \dots, S$, and $R_{tk_0}$ for $t=0$: - **Arbitrage condition** residual for $t = 0, \dots, S$: $$ - R_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - u'(c_t) + R_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 $$ - **Feasibility condition** residual for $t = 1, \dots, S-1$: $$ @@ -898,9 +945,13 @@ $$k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t.$$ $$ R_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] $$ + - **Terminal condition for $t = S$**: + $$ + R_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 + $$ -4. **Root-finding**: - - Adjust the guesses for $k_t$ and $c_t$ to minimize the residuals $R_{k_0}$, $R_{ta}$, and $R_{tk}$ for $t = 0, \dots, S$. +4. **Loss Minimization**: + - Adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $R_{k_0}$, $R_{ta}$, $R_{tk}$, and $R_{k_S}$ for $t = 0, \dots, S$. 5. **Output**: - The solution $\{c_t, k_t\}_{t=0}^{S}$. From becf49a7916b50f9d3af938cad52d7848f7d26a7 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sun, 3 Nov 2024 12:08:39 +1100 Subject: [PATCH 05/17] improve clarity of the code and algorithm --- lectures/cass_fiscal.md | 353 ++++++++++++++++++++-------------------- 1 file changed, 180 insertions(+), 173 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 069149e86..ff4a3541e 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -119,6 +119,7 @@ Firms maximize their present value of profit: $$ \sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right], $$ + Euler's theorem for linearly homogeneous functions states that if a function $F(k, n)$ is linearly homogeneous (degree 1), then: $$ @@ -232,140 +233,144 @@ To compute an equilibrium we solve a price system $\{q_t, \eta_t, w_t\}$, a budg ### Inelastic Labor Supply -First, we consider the special case where $U(c, 1-n) = u(c)$. +In this lecture, we consider the special case where $U(c, 1-n) = u(c)$ and $f(k) := F(k, 1)$. -First we rewrite {eq}`eq:tech_capital` with $f(k) := F(k, 1)$, +We rewrite {eq}`eq:tech_capital` with $f(k) := F(k, 1)$, $$ k_{t+1} = f(k_t) + (1 - \delta) k_t - g_t - c_t. $$ (eq:feasi_capital) ```{code-cell} ipython3 -def next_k(A, k_t, g_t, c_t, α, δ): +def next_k(k_t, g_t, c_t, model): """ Capital next period: k_{t+1} = f(k_t) + (1 - δ) * k_t - c_t - g_t """ - return f(A, k_t, α) + (1 - δ) * k_t - g_t - c_t + return f(k_t, model) + (1 - model.δ) * k_t - g_t - c_t ``` -By the properties of linearly homogeneous production function, we have $F_k(k, n) = f'(k)$, and $F_n(k, 1) = f(k, 1) - f'(k)k$. +By the properties of a linearly homogeneous production function, we have $F_k(k, n) = f'(k)$ and $F_n(k, 1) = f(k, 1) - f'(k)k$. -Substitute {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we have +Substituting {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we obtain: $$ \begin{aligned} &\frac{u'(f(k_t) + (1 - \delta) k_t - g_t - k_{t+1})}{(1 + \tau_{ct})} \\ &- \beta \frac{u'(f(k_{t+1}) + (1 - \delta) k_{t+1} - g_{t+1} - k_{t+2})}{(1 + \tau_{ct+1})} \\ -&\times [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1] = 0. +&\times [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1] = 0. \end{aligned} $$ -which can be written as +This can be simplified to: $$ \begin{aligned} -u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1]. +u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1]. \end{aligned} $$ (eq:diff_second) -which is the Euler equation for the household. +which represents the Euler equation for the household. -This equation can be used to solve for the equilibrium sequence of consumption and capital as we will see in the second method. +This equation is instrumental in solving for the equilibrium sequence of consumption and capital, as demonstrated in the second method. ### Steady state -Tax rates and government expenditures serve as forcing functions for the difference equations {eq}`eq:feasi_capital` and {eq}`eq:diff_second`. +Tax rates and government expenditures act as forcing functions for the difference equations {eq}`eq:feasi_capital` and {eq}`eq:diff_second`. -Let $z_t = [g_t, \tau_{kt}, \tau_{ct}]'$. We can write the second-order difference equation into +Define $z_t = [g_t, \tau_{kt}, \tau_{ct}]'$. We can express the second-order difference equation as: $$ H(k_t, k_{t+1}, k_{t+2}; z_t, z_{t+1}) = 0. $$ (eq:second_ord_diff) -We assume that the government policy is in the steady state satisfying $\lim_{t \to \infty} z_t = \bar z$. We assume the steady state is reached for $t > T$. A terminal steady-state capital stock $\bar k$ solves +We assume that the government policy reaches a steady state such that $\lim_{t \to \infty} z_t = \bar z$ and that the steady state holds for $t > T$. The terminal steady-state capital stock $\bar{k}$ satisfies: -$$H(\bar{k}, \bar{k}, \bar{k}, \bar{z}, \bar{z}) = 0$$ +$$ +H(\bar{k}, \bar{k}, \bar{k}, \bar{z}, \bar{z}) = 0. +$$ -Hencer we can derive the steady-state from the difference equation {eq}`eq:diff_second` +From the difference equation {eq}`eq:diff_second`, we can derive the steady-state condition: $$ \begin{aligned} -u'(\bar c) &= \beta u'(\bar c) \frac{(1 + \bar \tau_{c})}{(1 + \bar \tau_{c})} [(1 - \bar \tau_{k})(f'(\bar k) - \delta) + 1]. \\ -&\implies 1 = \beta[(1 - \bar \tau_{k})(f'(\bar k) - \delta) + 1] +u'(\bar{c}) &= \beta u'(\bar{c}) \frac{(1 + \bar{\tau}_{c})}{(1 + \bar{\tau}_{c})} [(1 - \bar{\tau}_{k})(f'(\bar{k}) - \delta) + 1]. \\ +&\implies 1 = \beta[(1 - \bar{\tau}_{k})(f'(\bar{k}) - \delta) + 1]. \end{aligned} $$ (eq:diff_second_steady) +### Other equilibrium quantities and prices -### Other equilibrium quantities - -**Price of the good:** +*Price:* $$ q_t = \beta^t \frac{u'(c_t)}{1 + \tau_{ct}} $$ (eq:equil_q) ```{code-cell} ipython3 -def compute_q_path(c_path, β, γ, S=100): +def compute_q_path(c_path, model, S=100): """ Compute q path: q_t = (β^t * u'(c_t)) / u'(c_0) """ q_path = np.zeros_like(c_path) for t in range(S): - q_path[t] = (β ** t * u_prime(c_path[t], γ)) / u_prime(c_path[0], γ) + q_path[t] = (model.β ** t * + u_prime(c_path[t], model)) / u_prime(c_path[0], model) return q_path ``` -**Marginal product of capital** +*Marginal product of capital* $$ \eta_t = f'(k_t) $$ ```{code-cell} ipython3 -def compute_η_path(k_path, α, A, S=100): +def compute_η_path(k_path, model, S=100): """ Compute η path: η_t = f'(k_t) = α * A * k_t^{α - 1} """ η_path = np.zeros_like(k_path) for t in range(S): - η_path[t] = α * A * k_path[t] ** (α - 1) + η_path[t] = f_prime(k_path[t], model) return η_path ``` -**Wage:** +*Wage:* $$ w_t = f(k_t) - k_t f'(k_t) $$ ```{code-cell} ipython3 -def compute_w_path(k_path, η_path, α, A, S=100): +def compute_w_path(k_path, η_path, model, S=100): """ Compute w path: w_t = f(k_t) - k_t * f'(k_t) """ + A, α = model.A, model.α, model.δ w_path = np.zeros_like(k_path) for t in range(S): - w_path[t] = A * k_path[t] ** α - k_path[t] * η_path[t] + w_path[t] = f(k_path[t], model) - k_path[t] * η_path[t] return w_path ``` -**Gross one-period return on capital:** +*Gross one-period return on capital:* $$ \bar{R}_{t+1} = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1\right] = \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} R_{t, t+1} $$ (eq:gross_rate) ```{code-cell} ipython3 -def compute_R_bar(A, τ_ct, τ_ctp1, τ_ktp1, k_tp1, α, δ): +def compute_R_bar(τ_ct, τ_ctp1, τ_ktp1, k_tp1, model): """ Gross one-period return on capital: R̄ = [(1 + τ_c_t) / (1 + τ_c_{t+1})] * { [1 - τ_k_{t+1}] * [f'(k_{t+1}) - δ] + 1 } """ - return ((1 - τ_ktp1) * (f_prime(A, k_tp1, α) - δ) + 1) * ( - (1 + τ_ct) / (1 + τ_ctp1)) + A, α, δ = model.A, model.α, model.δ + return ((1 + τ_ct) / (1 + τ_ctp1)) * ( + (1 - τ_ktp1) * (f_prime(k_tp1, model) - δ) + 1) -def compute_R_bar_path(shocks, k_path, model, S): +def compute_R_bar_path(shocks, k_path, model, S=100): """ Compute R̄ path over time. """ @@ -373,23 +378,20 @@ def compute_R_bar_path(shocks, k_path, model, S): R_bar_path = np.zeros(S + 1) for t in range(S): R_bar_path[t] = compute_R_bar( - A, shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], - k_path[t + 1], - α, δ - ) + k_path[t + 1], model) R_bar_path[S] = R_bar_path[S - 1] return R_bar_path ``` -**One-period discount factor:** +*One-period discount factor:* $$ R^{-1}_{t, t+1} = \frac{q_t}{q_{t-1}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} $$ (eq:equil_R) -**Net one-period rate of interest:** +*Net one-period rate of interest:* $$ r_{t, t+1} \equiv R_{t, t+1} - 1 = (1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) @@ -414,12 +416,12 @@ r_{t, t+s} = -\frac{1}{s} \ln\left(\frac{q_{t+s}}{q_t}\right). $$ ```{code-cell} ipython3 -def compute_rts_path(q_path, T, t): +def compute_rts_path(q_path, S, t): """ Compute r path: r_t,t+s = - (1/s) * ln(q_{t+s} / q_t) """ - s = np.arange(1, T + 1) + s = np.arange(1, S + 1) q_path = np.array([float(q) for q in q_path]) with np.errstate(divide='ignore', invalid='ignore'): @@ -427,7 +429,7 @@ def compute_rts_path(q_path, T, t): return rts_path ``` -## Specifications of the Model +## Specifications of the model In our model, the representative household has the following CRRA preferences over consumption: @@ -436,35 +438,36 @@ U(c) = \frac{c^{1 - \gamma}}{1 - \gamma} $$ ```{code-cell} ipython3 -def u_prime(c, γ): +def u_prime(c, model): """ Marginal utility: u'(c) = c^{-γ} """ - return c ** (-γ) + return c ** (-model.γ) ``` -Observe that by substituting {eq}`eq:gross_rate` into {eq}`eq:diff_second`, we have +By substituting {eq}`eq:gross_rate` into {eq}`eq:diff_second`, we have $$ c_{t+1} = c_t \left[ \beta \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) + 1 \right] \right]^{\frac{1}{\gamma}} = c_t \left[ \beta \overline{R}_{t+1} \right]^{\frac{1}{\gamma}} $$ (eq:consume_R) ```{code-cell} ipython3 -def next_c(c_t, R_bar, γ, β): +def next_c(c_t, R_bar, model): """ Consumption next period: c_{t+1} = c_t * (β * R̄)^{1/γ} """ + β, γ = model.β, model.γ return c_t * (β * R_bar) ** (1 / γ) ``` -The production function is given by the Cobb-Douglas form: +The production function is given by the Cobb-Douglas form with inelastic labor supply: $$ F(k, 1) = A k^\alpha $$ ```{code-cell} ipython3 -def f(A, k, α): +def f(k, model): """ Production function: f(k) = A * k^{α} """ @@ -472,7 +475,7 @@ def f(A, k, α): A, α = model.A, model.α return A * k ** α -def f_prime(A, k, α): +def f_prime(k, model): """ Marginal product of capital: f'(k) = α * A * k^{α - 1} """ @@ -480,34 +483,23 @@ def f_prime(A, k, α): return α * A * k ** (α - 1) ``` -## Computation +## Computation -In the following sections, we will experiment apply two methods to solve the model: shooting algorithm and minimization of Euler residual and law of motion capital. +In the following sections, we will apply two methods to solve the model: the shooting algorithm and residual minimization using the Euler equation ({eq}`eq:diff_second`) and feasibility condition ({eq}`eq:feasi_capital`). -### Shooting Algorithm +### Method 1: Shooting Algorithm -1. Solve equation {eq}`eq:diff_second_steady` for the terminal steady-state capital $\bar{k}$ that is associated with the permanent policy vector $\bar{z}$. +1. Solve the equation {eq}`eq:diff_second_steady` for the terminal steady-state capital $\bar{k}$ that corresponds to the permanent policy vector $\bar{z}$. -2. Select a large time index $S \gg T$ and guess an initial consumption rate $c_0$, and use equation {eq}`eq:feasi_capital` to solve for $k_1$. +2. Select a large time index $S \gg T$, guess an initial consumption rate $c_0$, and use the equation {eq}`eq:feasi_capital` to solve for $k_1$. -3. Use equation {eq}`eq:consume_R` to determine $c_{t+1}$. Then, use equation {eq}`eq:feasi_capital` to compute $k_{t+2}$. +3. Use the equation {eq}`eq:consume_R` to determine $c_{t+1}$. Then, apply the equation {eq}`eq:feasi_capital` to compute $k_{t+2}$. -4. Iterate on step 3 to compute candidate values $\hat{k}_t$ for $t = 1, \dots, S$. +4. Iterate step 3 to compute candidate values $\hat{k}_t$ for $t = 1, \dots, S$. 5. Compute the difference $\hat{k}_S - \bar{k}$. If $\left| \hat{k}_S - \bar{k} \right| > \epsilon$ for some small $\epsilon$, adjust $c_0$ and repeat steps 2-5. -6. Adjust $c_0$ iteratively using bisection method to find a value that makes $\left| \hat{k}_S - \bar{k} \right| < \epsilon$. - -### Experiments - -+++ - -We will do a number of experiments and analyze the transition path for the equilibrium in each case: - -1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. -2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. -3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. -3. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever +6. Adjust $c_0$ iteratively using the bisection method to find a value that ensures $\left| \hat{k}_S - \bar{k} \right| < \epsilon$. ```{code-cell} ipython3 # Steady-state calculation @@ -523,54 +515,11 @@ def steady_states(model, g_ss, τ_k_ss=0.0): k_ss = (numerator / denominator) ** (1 / (α - 1)) c_ss = A * k_ss ** α - δ * k_ss - g_ss return k_ss, c_ss -``` - -Next we prepare the sequence of variables that will be used to initialize the simulation. - -We will start from the steady state and then apply the shocks at the appropriate time. - -```{code-cell} ipython3 -def plot_results(solution, k_ss, c_ss, shocks, shock_param, - axes, model, label='', linestyle='-', T=40): - - k_path = solution[:, 0] - c_path = solution[:, 1] - - axes[0].plot(k_path[:T], linestyle=linestyle, label=label) - axes[0].axhline(k_ss, linestyle='--', color='black') - axes[0].set_title('k') - - # Plot for c - axes[1].plot(c_path[:T], linestyle=linestyle, label=label) - axes[1].axhline(c_ss, linestyle='--', color='black') - axes[1].set_title('c') - - # Plot for g - R_bar_path = compute_R_bar_path(shocks, k_path, model, S) - - axes[2].plot(R_bar_path[:T], linestyle=linestyle, label=label) - axes[2].set_title('$\overline{R}$') - axes[2].axhline(1 / model.β, linestyle='--', color='black') - - η_path = compute_η_path(k_path, model.α, model.A, S=T) - η_ss = model.α * model.A * k_ss ** (model.α - 1) - - axes[3].plot(η_path[:T], linestyle=linestyle, label=label) - axes[3].axhline(η_ss, linestyle='--', color='black') - axes[3].set_title(r'$\eta$') - - axes[4].plot(shocks[shock_param][:T], linestyle=linestyle, label=label) - axes[4].axhline(shocks[shock_param][0], linestyle='--', color='black') - axes[4].set_title(rf'${shock_param}$') -``` -```{code-cell} ipython3 def shooting_algorithm(c0, k0, shocks, S, model): """ Shooting algorithm for given initial c0 and k0. """ - # High-precision parameters - β, γ, δ, α, A = map(mpf, (model.β, model.γ, model.δ, model.α, model.A)) # Convert shocks to high-precision g_path, τ_c_path, τ_k_path = ( list(map(mpf, shocks[key])) for key in ['g', 'τ_c', 'τ_k'] @@ -585,16 +534,16 @@ def shooting_algorithm(c0, k0, shocks, S, model): k_t, c_t, g_t = k_path[t], c_path[t], g_path[t] # Calculate next period's capital - k_tp1 = next_k(A, k_t, g_t, c_t, α, δ) + k_tp1 = next_k(k_t, g_t, c_t, model) # Failure due to negative capital if k_tp1 < mpf(0): return None, None k_path[t + 1] = k_tp1 # Calculate next period's consumption - R_bar = compute_R_bar(A, τ_c_path[t], τ_c_path[t + 1], - τ_k_path[t + 1], k_tp1, α, δ) - c_tp1 = next_c(c_t, R_bar, γ, β) + R_bar = compute_R_bar(τ_c_path[t], τ_c_path[t + 1], + τ_k_path[t + 1], k_tp1, model) + c_tp1 = next_c(c_t, R_bar, model) # Failure due to negative consumption if c_tp1 < mpf(0): return None, None @@ -603,15 +552,15 @@ def shooting_algorithm(c0, k0, shocks, S, model): return k_path, c_path -def bisection_c0(k0, c0_guess, shocks, S, model, +def bisection_c0(c0_guess, k0, shocks, S, model, tol=mpf('1e-6'), max_iter=1000, verbose=False): """ Bisection method to find optimal initial consumption c0. """ - β, γ, δ, α, A = map(mpf, (model.β, model.γ, model.δ, model.α, model.A)) k_ss_final, _ = steady_states(model, - mpf(shocks['g'][-1]), mpf(shocks['τ_k'][-1])) - c0_lower, c0_upper = mpf(0), A * k_ss_final ** α + mpf(shocks['g'][-1]), + mpf(shocks['τ_k'][-1])) + c0_lower, c0_upper = mpf(0), f(k_ss_final, model) c0 = c0_guess for iter_count in range(max_iter): @@ -646,7 +595,7 @@ def bisection_c0(k0, c0_guess, shocks, S, model, warn(f"Converged failed. Returning the last c0 = {c0}", stacklevel=2) return c0 -def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_func=shooting_algorithm): +def run_shooting(shocks, S, model, c0_func=bisection_c0, shooting_func=shooting_algorithm): """ Runs the shooting algorithm. """ @@ -654,7 +603,7 @@ def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_func=shoot k0, c0 = steady_states(model, mpf(shocks['g'][0]), mpf(shocks['τ_k'][0])) # Find the optimal initial consumption - optimal_c0 = c0_function(k0, c0, shocks, S, model) + optimal_c0 = c0_func(c0, k0, shocks, S, model) print(f"Parameters: {model}") print(f"Optimal initial consumption c0: {mp.nstr(optimal_c0, 7)} \n") @@ -665,9 +614,57 @@ def run_shooting(shocks, S, model, c0_function=bisection_c0, shooting_func=shoot return np.column_stack([k_path, c_path]) ``` -## Experiments with Shooting Algorithm +### Experiments + +We will run a series of experiments and analyze the transition path for the equilibrium in each scenario: + +1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10. +2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10. +3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10. +4. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ reverts to 0.2 permanently. + ++++ + +Next we prepare the sequence of variables that will be used to initialize the simulation. + +We will start from the steady state and then apply the shocks at the appropriate time. + +```{code-cell} ipython3 +def plot_results(solution, k_ss, c_ss, shocks, shock_param, + axes, model, label='', linestyle='-', T=40): + + k_path = solution[:, 0] + c_path = solution[:, 1] + + axes[0].plot(k_path[:T], linestyle=linestyle, label=label) + axes[0].axhline(k_ss, linestyle='--', color='black') + axes[0].set_title('k') + + # Plot for c + axes[1].plot(c_path[:T], linestyle=linestyle, label=label) + axes[1].axhline(c_ss, linestyle='--', color='black') + axes[1].set_title('c') + + # Plot for g + R_bar_path = compute_R_bar_path(shocks, k_path, model, S) + + axes[2].plot(R_bar_path[:T], linestyle=linestyle, label=label) + axes[2].set_title('$\overline{R}$') + axes[2].axhline(1 / model.β, linestyle='--', color='black') + + η_path = compute_η_path(k_path, model, S=T) + η_ss = model.α * model.A * k_ss ** (model.α - 1) + + axes[3].plot(η_path[:T], linestyle=linestyle, label=label) + axes[3].axhline(η_ss, linestyle='--', color='black') + axes[3].set_title(r'$\eta$') + + axes[4].plot(shocks[shock_param][:T], linestyle=linestyle, label=label) + axes[4].axhline(shocks[shock_param][0], linestyle='--', color='black') + axes[4].set_title(rf'${shock_param}$') +``` -### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. +#### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. @@ -706,7 +703,7 @@ Let's write the procedures above into a function that runs the solver and draw t ```{code-cell} ipython3 def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): """ - Plots the results of running the shooting algorithm given a model + Run the shooting algorithm given a model and plot the results. """ k0, c0 = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) @@ -732,10 +729,15 @@ def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. ```{code-cell} ipython3 +# Solve the model using shooting solution = run_shooting(shocks, S, model) + +# Compute the initial steady states k_ss_initial, c_ss_initial = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) + +# Plot the solution for γ=2 fig, axes = plt.subplots(2, 3, figsize=(10, 8)) axes = axes.flatten() @@ -744,6 +746,7 @@ plot_results(solution, k_ss_initial, c_ss_initial, shocks, 'g', axes, model, label=label, T=40) +# Solve and plot the result for γ=0.2 model_γ2 = create_model(γ=0.2) solution = run_shooting(shocks, S, model_γ2) @@ -777,7 +780,7 @@ def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, print(f"Steady-state consumption: {c0:.4f}") print('-'*64) - # Use a default labeling function if none is provided + # Use a default legend labeling function if none is provided if legend_label_fun is None: legend_label_fun = lambda model: fr"$\gamma = {model.γ}$" @@ -824,19 +827,19 @@ def plot_prices(solution, c_ss, shock_param, axes, axes[0].axhline(c_ss, linestyle='--', color='black') axes[0].set_title('c') - q_path = compute_q_path(c_path, - β, γ, S=S) + # Plot for q + q_path = compute_q_path(c_path, model, S=S) axes[1].plot(q_path[:T], linestyle=linestyle, label=label) axes[1].plot(β**np.arange(T), linestyle='--', color='black') axes[1].set_title('q') + # Plot for r_{t,t+1} R_bar_path = compute_R_bar_path(shocks, k_path, model, S) - axes[2].plot(R_bar_path[:T] - 1, linestyle=linestyle, label=label) axes[2].axhline(1 / β - 1, linestyle='--', color='black') axes[2].set_title('$r_{t,t+1}$') - + # Plot for r_{t,t+s} for style, s in zip(['-', '-.', '--'], [0, 10, 60]): rts_path = compute_rts_path(q_path, T, s) axes[3].plot(rts_path, linestyle=style, @@ -868,7 +871,7 @@ plt.tight_layout() plt.show() ``` -### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. +#### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. The experiment replicates the Figure 12.9.4. @@ -882,7 +885,7 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` -### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. +#### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. The experiment replicates the Figure 12.9.5. @@ -897,7 +900,7 @@ experiment_two_models(shocks, S, model, model_γ2, run_shooting, plot_results, 'τ_k') ``` -### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever +#### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever The experiment replicates the Figure 12.9.6. @@ -914,70 +917,73 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'g') ``` -## Method 2: Minimization of Euler Residual and Law of Motion Capital +### Method 2: Residual Minimization Using the Euler Equation and Feasibility Condition +The second method involves minimizing the residuals of the following equations: -$$1 = \beta \left(\frac{c_{t+1}}{c_t}\right)^{-\gamma} \frac{(1+\tau_{ct})}{(1+\tau_{ct+1})} \left[(1 - \tau_{kt+1})(\alpha A k_{t+1}^{\alpha-1} - \delta) + 1 \right]$$ +- *The Euler equation* {eq}`eq:diff_second`: + $$ + 1 = \beta \left(\frac{c_{t+1}}{c_t}\right)^{-\gamma} \frac{(1+\tau_{ct})}{(1+\tau_{ct+1})} \left[(1 - \tau_{kt+1})(\alpha A k_{t+1}^{\alpha-1} - \delta) + 1 \right] + $$ -and a law of motion for capital - -$$k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t.$$ +- *The feasibility condition* {eq}`eq:feasi_capital`: + $$ + k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t. + $$ +++ -### Algorithm for minimization approach (Method 2) +The algorithm is described as follows: -1. **Calculate initial state $k_0$**: - - Based on the given initial government plan $z_0$. +1. *Calculate the initial state $k_0$*: + - Derive $k_0$ based on the given initial government plan $z_0$. -2. **Initialize a sequence of initial guesses** $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ +2. *Initialize a sequence of initial guesses* $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$. -3. **Compute the residuals** $R_a$, $R_k$ for $t = 0, \dots, S$, and $R_{tk_0}$ for $t=0$: - - **Arbitrage condition** residual for $t = 0, \dots, S$: +3. *Compute the residuals* $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: + - Compute the *Euler's equation* residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: $$ - R_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 + l_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 $$ - - **Feasibility condition** residual for $t = 1, \dots, S-1$: + - Compute the *feasibility condition* residual for $t = 1, \dots, S-1$ using {eq}`eq:feasi_capital`: $$ - R_{tk} = k_{t+1} - f(k_t) + (1 - \delta)k_t - g_t - c_t + l_{tk} = k_{t+1} - f(k_t) + (1 - \delta)k_t - g_t - c_t $$ - - **Initial condition for $k_0$**: + - Compute the residual for the *initial condition for $k_0$* using {eq}`eq:diff_second_steady` and the initial capital $k_0$: $$ - R_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] + l_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] $$ - - **Terminal condition for $t = S$**: + - Compute the residual for the *terminal condition for $t = S* using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: $$ - R_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 + l_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 $$ -4. **Loss Minimization**: - - Adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $R_{k_0}$, $R_{ta}$, $R_{tk}$, and $R_{k_S}$ for $t = 0, \dots, S$. - -5. **Output**: - - The solution $\{c_t, k_t\}_{t=0}^{S}$. +4. *Residual Minimization*: + - Adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. ```{code-cell} ipython3 -# Arbitrage and Transition Equations for method 2 -def arbitrage(c_t, c_tp1, τ_c_t, τ_c_tp1, τ_k_tp1, k_tp1, model): +# Euler's equation and feasibility condition +def euler_residual(c_t, c_tp1, τ_c_t, τ_c_tp1, τ_k_tp1, k_tp1, model): """ - Computes the arbitrage condition. + Computes the residuals for Euler's equation. """ β, γ, δ, α, A = model.β, model.γ, model.δ, model.α, model.A η_tp1 = α * A * k_tp1 ** (α - 1) return β * (c_tp1 / c_t) ** (-γ) * (1 + τ_c_t) / (1 + τ_c_tp1) * ( (1 - τ_k_tp1) * (η_tp1 - δ) + 1) - 1 -def transition(k_t, k_tm1, c_tm1, g_t, model): +def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): """ - Computes the capital transition. + Computes the residuals for feasibility condition. """ α, A, δ = model.α, model.A, model.δ return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) -# Residuals for method 2 +# Computing Residuals def compute_residuals(vars_flat, k_init, S, shocks, model): """ - Compute residuals for arbitrage and transition equations. + Compute a vector of residuals under Euler's equation, feasibility condition, + and boundary conditions. """ k, c = vars_flat.reshape((S + 1, 2)).T residuals = np.zeros(2 * S + 2) @@ -987,18 +993,18 @@ def compute_residuals(vars_flat, k_init, S, shocks, model): # Compute residuals for each time step for t in range(S): - residuals[2 * t + 1] = arbitrage( + residuals[2 * t + 1] = euler_residual( c[t], c[t + 1], shocks['τ_c'][t], shocks['τ_c'][t + 1], shocks['τ_k'][t + 1], k[t + 1], model ) - residuals[2 * t + 2] = transition( + residuals[2 * t + 2] = feasi_residual( k[t + 1], k[t], c[t], shocks['g'][t], model ) - # Terminal condition for arbitrage - residuals[-1] = arbitrage( + # Terminal condition + residuals[-1] = euler_residual( c[S], c[S], shocks['τ_c'][S], shocks['τ_c'][S], shocks['τ_k'][S], k[S], model @@ -1009,7 +1015,7 @@ def compute_residuals(vars_flat, k_init, S, shocks, model): # Root-finding Algorithm to minimize the residual def run_min(shocks, S, model): """ - Root-finding algorithm to minimize the residuals. + Root-finding algorithm to minimize the vector of residuals. """ k_ss, c_ss = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) @@ -1018,19 +1024,20 @@ def run_min(shocks, S, model): (np.full(S + 1, k_ss), np.full(S + 1, c_ss))).flatten() # Solve the system using root-finding - sol = root(compute_residuals, initial_guess, args=(k_ss, S, shocks, model), tol=1e-8) + sol = root(compute_residuals, initial_guess, + args=(k_ss, S, shocks, model), tol=1e-8) # Reshape solution to get time paths for k and c return sol.x.reshape((S + 1, 2)) ``` -Below are the results for the same experiments using the method of minimization of Euler residual and law of motion capital. +Below are the results for the same experiments using the second method. -This method does not have numerical stability issues so `mp.mpf` is not necessary. +This method does not have numerical stability issues, so `mp.mpf` is not necessary. -### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. +### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10 -The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. +The experiment replicates Figure 12.9.1 in RMT5 under the parameter $\gamma = 2$. ```{code-cell} ipython3 # Define the shocks for the simulation From 27db15580e5e517357ef0ca87c319e825175913b Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sun, 3 Nov 2024 14:03:25 +1100 Subject: [PATCH 06/17] small updates to the formula --- lectures/cass_fiscal.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index ff4a3541e..5cdca3ce5 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -303,7 +303,7 @@ $$ (eq:diff_second_steady) *Price:* $$ -q_t = \beta^t \frac{u'(c_t)}{1 + \tau_{ct}} +q_t = \frac{\beta^t u'(c_t)}{u'(c_0)} $$ (eq:equil_q) ```{code-cell} ipython3 @@ -434,7 +434,7 @@ def compute_rts_path(q_path, S, t): In our model, the representative household has the following CRRA preferences over consumption: $$ -U(c) = \frac{c^{1 - \gamma}}{1 - \gamma} +u(c) = \frac{c^{1 - \gamma}}{1 - \gamma} $$ ```{code-cell} ipython3 @@ -701,6 +701,7 @@ plt.show() Let's write the procedures above into a function that runs the solver and draw the plots for a given model ```{code-cell} ipython3 +:tags: [hide-input] def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): """ Run the shooting algorithm given a model and plot the results. @@ -769,6 +770,8 @@ plt.show() Let's write another function that runs the solver and draw the plots for two models as we did above ```{code-cell} ipython3 +:tags: [hide-input] + def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, policy_shock, legend_label_fun=None, T=40): """ @@ -953,7 +956,7 @@ The algorithm is described as follows: $$ l_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] $$ - - Compute the residual for the *terminal condition for $t = S* using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: + - Compute the residual for the *terminal condition* for $t = S$ using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: $$ l_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 $$ @@ -979,7 +982,7 @@ def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): α, A, δ = model.α, model.A, model.δ return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) -# Computing Residuals +# Computing residuals as objective function to minimize def compute_residuals(vars_flat, k_init, S, shocks, model): """ Compute a vector of residuals under Euler's equation, feasibility condition, From 912db6ccb38ec91ba9f0f2d289c4a2917bc1fee8 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sun, 3 Nov 2024 15:55:15 +1100 Subject: [PATCH 07/17] update terminology --- lectures/cass_fiscal.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 5cdca3ce5..4edf54fd2 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -318,7 +318,7 @@ def compute_q_path(c_path, model, S=100): return q_path ``` -*Marginal product of capital* +*Capital rental rate* $$ \eta_t = f'(k_t) @@ -335,7 +335,7 @@ def compute_η_path(k_path, model, S=100): return η_path ``` -*Wage:* +*Labor rental rate:* $$ w_t = f(k_t) - k_t f'(k_t) From 4064d9ad7283d4c8e64143907fd4e440db536508 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Wed, 27 Nov 2024 20:09:36 +1100 Subject: [PATCH 08/17] update cass fiscal --- lectures/cass_fiscal.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 4edf54fd2..1a1270c17 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -68,7 +68,7 @@ under the budget constraint $$ \begin{aligned} \sum_{t=0}^\infty& q_t \left\{ (1 + \tau_{ct})c_t + \underbrace{[k_{t+1} - (1 - \delta)k_t]}_{\text{no tax when investing}} \right\} \\ - &\leq \sum_{t=0}^\infty q_t \left\{ \tau_{kt} - \underbrace{\tau_{kt}(\eta_t - \delta)k_t}_{\text{tax on rental return}} + (1 - \tau_{nt})w_t n_t - \tau_{ht} \right\}. + &\leq \sum_{t=0}^\infty q_t \left\{ \eta_t k_t - \underbrace{\tau_{kt}(\eta_t - \delta)k_t}_{\text{tax on rental return}} + (1 - \tau_{nt})w_t n_t - \tau_{ht} \right\}. \end{aligned} $$ (eq:house_budget) @@ -664,7 +664,7 @@ def plot_results(solution, k_ss, c_ss, shocks, shock_param, axes[4].set_title(rf'${shock_param}$') ``` -#### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10. +**Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. @@ -874,7 +874,7 @@ plt.tight_layout() plt.show() ``` -#### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. +**Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10** The experiment replicates the Figure 12.9.4. @@ -888,7 +888,7 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` -#### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. +**Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10** The experiment replicates the Figure 12.9.5. @@ -903,7 +903,7 @@ experiment_two_models(shocks, S, model, model_γ2, run_shooting, plot_results, 'τ_k') ``` -#### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever +**Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever** The experiment replicates the Figure 12.9.6. @@ -945,18 +945,25 @@ The algorithm is described as follows: 3. *Compute the residuals* $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: - Compute the *Euler's equation* residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: + $$ l_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 $$ + - Compute the *feasibility condition* residual for $t = 1, \dots, S-1$ using {eq}`eq:feasi_capital`: + $$ - l_{tk} = k_{t+1} - f(k_t) + (1 - \delta)k_t - g_t - c_t + l_{tk} = k_{t+1} - f(k_t) - (1 - \delta)k_t + g_t + c_t $$ + - Compute the residual for the *initial condition for $k_0$* using {eq}`eq:diff_second_steady` and the initial capital $k_0$: + $$ l_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] $$ + - Compute the residual for the *terminal condition* for $t = S$ using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: + $$ l_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 $$ @@ -1038,7 +1045,7 @@ Below are the results for the same experiments using the second method. This method does not have numerical stability issues, so `mp.mpf` is not necessary. -### Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10 +**Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** The experiment replicates Figure 12.9.1 in RMT5 under the parameter $\gamma = 2$. @@ -1080,7 +1087,7 @@ plt.tight_layout() plt.show() ``` -### Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10. +**Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10.** The experiment replicates the Figure 12.9.4. @@ -1094,7 +1101,7 @@ shocks = { experiment_model(shocks, S, model, run_min, plot_results, 'τ_c') ``` -### Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10. +**Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10.** The experiment replicates the Figure 12.9.5. @@ -1109,7 +1116,7 @@ experiment_two_models(shocks, S, model, model_γ2, run_min, plot_results, 'τ_k') ``` -### Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever +**Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever** The experiment replicates the Figure 12.9.6. From b9baa9caa897ba0492a0ba848bcd23ab7a7922d9 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Sat, 21 Dec 2024 16:57:13 +0800 Subject: [PATCH 09/17] updates --- lectures/cass_fiscal.md | 61 ++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 1a1270c17..acc46d92d 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 + jupytext_version: 1.16.6 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -13,6 +13,24 @@ kernelspec: # Fiscal Policy Experiments in a Non-stochastic Model +## Introduction + +This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model. + +We use the model as a laboratory to exhibit numerical techniques for approximating equilibria and to display the structure of dynamic models in which decision makers have perfect foresight about future government decisions. + +Following {cite}`hall1971dynamic`, we augment a nonstochastic version of the standard growth model with a government that purchases a stream of goods and that finances itself with an array of distorting flat-rate taxes. + +Distorting taxes prevent a competitive equilibrium allocation from solving a planning problem. + +Therefore, to compute an equilibrium allocation and price system, we solve a system of nonlinear difference equations consisting of the first-order conditions for decision makers and the other equilibrium conditions. + +We present two ways to solve the model: + +- The first method is called shooting algorithm; + +- The second method is applying a root-finding algorithm to minimize the residuals derived from the first-order conditions. + We will use the following imports ```{code-cell} ipython3 @@ -33,7 +51,7 @@ Note that we will use the `mpmath` library to perform high-precision arithmetic We will use the following parameters ```{code-cell} ipython3 -# Create a named tuple to store the model parameters +# Create a namedtuple to store the model parameters Model = namedtuple("Model", ["β", "γ", "δ", "α", "A"]) @@ -55,13 +73,16 @@ S = 100 ## The Economy ### Households -The representative household has preferences over nonnegative streams of a single consumption good $c_t$: + +The representative household has preferences over nonnegative streams of a single consumption good $c_t$ and leisure $1-n_t$ that are ordered by: $$ -\sum_{t=0}^{\infty} \beta^t U(c_t), \quad \beta \in (0, 1) +\sum_{t=0}^{\infty} \beta^t U(c_t, 1-n_t), \quad \beta \in (0, 1) $$ (eq:utility) -where -- $U(c_t)$ is twice continuously differentiable, and strictly concave with $c_t \geq 0$. + +where + +- $U$ is twice continuously differentiable, and strictly concave with $c_t \geq 0$. In this lecture, we focus on the special case. under the budget constraint @@ -80,25 +101,28 @@ $$ g_t + c_t + x_t \leq F(k_t, n_t), $$ (eq:tech_capital) +where + - $g_t$ is government expenditure - $x_t$ is gross investment, and -- $F(k_t, n_t)$ a linearly homogeneous production function with positive and decreasing marginal products of capital $k_t$ and labor $n_t$. +- $F(k_t, n_t)$ is a linearly homogeneous production function with positive and decreasing marginal products of capital $k_t$ and labor $n_t$. The law of motion for capital is given by: + $$ - k_{t+1} = (1 - \delta)k_t + x_t, +k_{t+1} = (1 - \delta)k_t + x_t, $$ where -- $\delta \in (0, 1)$ is depreciation rate, $k_t$ is the stock of physical capital, and $x_t$ is gross investment. +- $\delta \in (0, 1)$ is depreciation rate. ### Price System A price system is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, where -- $q_t$ is the time 0 pretax price of one unit of investment or consumption at time $t$ ($x_t$ or $c_t$), +- $q_t$ is the time $0$ pretax price of one unit of investment or consumption at time $t$ ($x_t$ or $c_t$), - $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, - $w_t$ is the pretax price at time $t$ that the household receives for renting labor to the firm at time $t$. @@ -114,13 +138,13 @@ $$ (eq:gov_budget) ### Firm -Firms maximize their present value of profit: +A representative firm chooses $\{k_t, n_t\}_{t=0}^\infty$ to maximize their present value of profit: $$ \sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right], $$ -Euler's theorem for linearly homogeneous functions states that if a function $F(k, n)$ is linearly homogeneous (degree 1), then: +Euler's theorem for linearly homogeneous functions states that if a function $F(k, n)$ is linearly homogeneous of degree 1, then: $$ F(k, n) = F_k k + F_n n, @@ -135,9 +159,11 @@ In the equilibrium, given a budget-feasible government policy $\{g_t\}_{t=0}^\in - *Household* chooses $\{c_t\}_{t=0}^\infty$, $\{n_t\}_{t=0}^\infty$, and $\{k_{t+1}\}_{t=0}^\infty$ to maximize utility{eq}`eq:utility` subject to budget constraint{eq}`eq:house_budget`, and - *Frim* chooses sequences of capital $\{k_t\}_{t=0}^\infty$ and $\{n_t\}_{t=0}^\infty$ to maximize profits + $$ \sum_{t=0}^\infty q_t [F(k_t, n_t) - \eta_t k_t - w_t n_t] $$ (eq:firm_profit) + - A **feasible allocation** is a sequence $\{c_t, x_t, n_t, k_t\}_{t=0}^\infty$ that satisfies feasibility condition {eq}`eq:tech_capital`. @@ -155,7 +181,7 @@ $$ \begin{aligned} \sum_{t=0}^\infty q_t \left[(1 + \tau_{ct})c_t \right] &\leq \sum_{t=0}^\infty q_t(1 - \tau_{nt})w_t n_t - \sum_{t=0}^\infty q_t \tau_{ht} \\ &+ \sum_{t=1}^\infty\left\{ \left[(1 - \tau_{kt})(\eta_t - \delta) + 1\right]q_t - q_{t-1}\right\}k_t \\ - &+ \left[(1 - \tau_{k0})(\eta_0 - \delta) + 1\right]q_0k_0 - \lim_{T \to \infty} q_T r k_{T+1} + &+ \left[(1 - \tau_{k0})(\eta_0 - \delta) + 1\right]q_0k_0 - \lim_{T \to \infty} q_T k_{T+1} \end{aligned} $$ (eq:constrant_house) @@ -168,7 +194,7 @@ $$ (eq:no_arb) Moreover, we have terminal condition $$ --\lim_{T \to \infty} q_T r k_{T+1} = 0. +-\lim_{T \to \infty} q_T k_{T+1} = 0. $$ (eq:terminal) Moreover, applying Euler's theorem on firm's present value gives @@ -197,6 +223,8 @@ $$ \frac{\partial \mathcal{L}}{\partial c_t} = \beta^t U_1(c_t, 1 - n_t) - \mu q_t (1 + \tau_{ct}) = 0 $$ (eq:foc_c_1) +which gives $\mu q_t = \beta^t \frac{U_1(c_t, 1 - n_t)}{(1 + \tau_{ct})}$ + and $$ @@ -221,7 +249,7 @@ $$ (eq:foc_n) Plugging {eq}`eq:foc_c` into {eq}`eq:terminal` by replacing $q_t$, we get terminal condition $$ --\lim_{T \to \infty} \frac{U_{1t}}{(1 + \tau_{ct})} r k_{T+1} = 0. +-\lim_{T \to \infty} \beta^T \frac{U_{1T}}{(1 + \tau_{cT})} k_{T+1} = 0. $$ (eq:terminal_final) ## Computing Equilibria @@ -327,7 +355,7 @@ $$ ```{code-cell} ipython3 def compute_η_path(k_path, model, S=100): """ - Compute η path: η_t = f'(k_t) = α * A * k_t^{α - 1} + Compute η path: η_t = f'(k_t) """ η_path = np.zeros_like(k_path) for t in range(S): @@ -702,6 +730,7 @@ Let's write the procedures above into a function that runs the solver and draw t ```{code-cell} ipython3 :tags: [hide-input] + def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): """ Run the shooting algorithm given a model and plot the results. From 3455bf5bea565c622cee5fec9ee10e90389e2f0b Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Mon, 30 Dec 2024 15:46:43 +0800 Subject: [PATCH 10/17] update case fiscal --- lectures/_static/quant-econ.bib | 11 + lectures/cass_fiscal.md | 388 ++++++++++++++++++++++++-------- 2 files changed, 310 insertions(+), 89 deletions(-) diff --git a/lectures/_static/quant-econ.bib b/lectures/_static/quant-econ.bib index 39231727f..b71c64372 100644 --- a/lectures/_static/quant-econ.bib +++ b/lectures/_static/quant-econ.bib @@ -2547,4 +2547,15 @@ @book{auerbach1987dynamic publisher = {Cambridge University Press}, address = {Cambridge}, year = {1987} +} + +@article{hall1971dynamic, + title={The dynamic effects of fiscal policy in an economy with foresight}, + author={Hall, Robert E}, + journal={The Review of Economic Studies}, + volume={38}, + number={2}, + pages={229--244}, + year={1971}, + publisher={Wiley-Blackwell} } \ No newline at end of file diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index acc46d92d..a4a43dc8a 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -15,7 +15,7 @@ kernelspec: ## Introduction -This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model. +This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model with features inherited from {doc}`cass_koopmans_2` We use the model as a laboratory to exhibit numerical techniques for approximating equilibria and to display the structure of dynamic models in which decision makers have perfect foresight about future government decisions. @@ -23,7 +23,7 @@ Following {cite}`hall1971dynamic`, we augment a nonstochastic version of the sta Distorting taxes prevent a competitive equilibrium allocation from solving a planning problem. -Therefore, to compute an equilibrium allocation and price system, we solve a system of nonlinear difference equations consisting of the first-order conditions for decision makers and the other equilibrium conditions. +Therefore, to compute an equilibrium allocation and price system, we solve a system of nonlinear difference equations consisting of the first-order conditions for decision makers and the other equilibrium conditions. We present two ways to solve the model: @@ -77,21 +77,14 @@ S = 100 The representative household has preferences over nonnegative streams of a single consumption good $c_t$ and leisure $1-n_t$ that are ordered by: $$ -\sum_{t=0}^{\infty} \beta^t U(c_t, 1-n_t), \quad \beta \in (0, 1) +\sum_{t=0}^{\infty} \beta^t U(c_t, 1-n_t), \quad \beta \in (0, 1), $$ (eq:utility) where -- $U$ is twice continuously differentiable, and strictly concave with $c_t \geq 0$. In this lecture, we focus on the special case. +- $U$ is strictly increasing in $c_t$, twice continuously differentiable, and strictly concave with $c_t \geq 0$ and $n_t \in [0, 1]$, -under the budget constraint - -$$ -\begin{aligned} - \sum_{t=0}^\infty& q_t \left\{ (1 + \tau_{ct})c_t + \underbrace{[k_{t+1} - (1 - \delta)k_t]}_{\text{no tax when investing}} \right\} \\ - &\leq \sum_{t=0}^\infty q_t \left\{ \eta_t k_t - \underbrace{\tau_{kt}(\eta_t - \delta)k_t}_{\text{tax on rental return}} + (1 - \tau_{nt})w_t n_t - \tau_{ht} \right\}. -\end{aligned} -$$ (eq:house_budget) +under the budget constraint {eq}`eq:house_budget`. ### Technology @@ -117,41 +110,76 @@ where - $\delta \in (0, 1)$ is depreciation rate. +It is sometimes convenient to eliminate $x_t$ from {eq}`eq:tech_capital` to write it +as + +$$ +g_t + c_t + k_{t+1} \leq F(k_t, n_t) + (1 - \delta)k_t +$$ + +### Components of a competitive equilibrium + +There is a competitive equilibrium with all trades occurring at time $0$. -### Price System +The household owns capital, makes investment decisions, and rents capital and labor to a representative production firm. -A price system is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, where +The representative firm uses capital and labor to produce goods with the production function $F(k_t, n_t)$. + +A **price system** is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, where - $q_t$ is the time $0$ pretax price of one unit of investment or consumption at time $t$ ($x_t$ or $c_t$), -- $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, +- $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, and - $w_t$ is the pretax price at time $t$ that the household receives for renting labor to the firm at time $t$. -The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0. +The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0 as in {doc}`cass_koopmans_2` -### Government +Government is the main feature that distinguishes this lecture from +{doc}`cass_koopmans_2`. -Government plans $\{ g_t \}_{t=0}^\infty$ for government purchases and taxes $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to the budget constraint +Government purchases of goods at time $t$ are $g_t \geq 0$ and a government expenditure plan is a sequence $g = \{g_t\}_{t=0}^\infty$. -$$ -\sum_{t=0}^\infty q_t g_t \leq \sum_{t=0}^\infty q_t \left\{ \tau_{ct}c_t + \tau_{kt}(\eta_t - \delta)k_t + \tau_{nt}w_t n_t + \tau_{ht} \right\}. -$$ (eq:gov_budget) +A government tax plan is a $4$-tuple of sequences $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$, +where -### Firm +- $\tau_{ct}$ is a tax rate on consumption at time $t$, +- $\tau_{kt}$ is a tax rate on rentals of capital at time $t$, +- $\tau_{nt}$ is a tax rate on wage earnings at time $t$, and +- $\tau_{ht}$ is a lump sum tax on a consumer at time $t$. -A representative firm chooses $\{k_t, n_t\}_{t=0}^\infty$ to maximize their present value of profit: +There is a sense in which we have given the government access to too many kinds +of taxes, because when lump-sum taxes $\tau_{ht}$ are available, the government should not +use any distorting taxes. -$$ -\sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right], -$$ +We include all of these taxes because, like {cite}`hall1971dynamic`, +they allow us to analyze how the +various taxes distort production and consumption decisions. -Euler's theorem for linearly homogeneous functions states that if a function $F(k, n)$ is linearly homogeneous of degree 1, then: +In the [experiment section](cf:experiments), we shall see how variations in government tax plan affects +the transition path and equilibrium. + +### Budget constraints + +Now we have all the elements to write down budget constraints for representative household +and government + +Household maximizes {eq}`eq:utility` under the budget constraint: $$ -F(k, n) = F_k k + F_n n, -$$ +\begin{aligned} + \sum_{t=0}^\infty& q_t \left\{ (1 + \tau_{ct})c_t + \underbrace{[k_{t+1} - (1 - \delta)k_t]}_{\text{no tax when investing}} \right\} \\ + &\leq \sum_{t=0}^\infty q_t \left\{ \eta_t k_t - \underbrace{\tau_{kt}(\eta_t - \delta)k_t}_{\text{tax on rental return}} + (1 - \tau_{nt})w_t n_t - \tau_{ht} \right\}. +\end{aligned} +$$ (eq:house_budget) -where $F_k = \frac{\partial F(k, n)}{\partial k}$ and $F_n = \frac{\partial F(k, n)}{\partial n}$. +Here we have assumed that the government gives a depreciation allowance $\delta k_t$ +from the gross rentals on capital $\eta_t k_t$ and so collects taxes $\tau_{kt} (\eta_t - \delta) k_t$ +on rentals from capital. +Government plans $\{ g_t \}_{t=0}^\infty$ for government purchases and taxes $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to the budget constraint + +$$ +\sum_{t=0}^\infty q_t g_t \leq \sum_{t=0}^\infty q_t \left\{ \tau_{ct}c_t + \tau_{kt}(\eta_t - \delta)k_t + \tau_{nt}w_t n_t + \tau_{ht} \right\}. +$$ (eq:gov_budget) ### Equilibrium @@ -175,6 +203,10 @@ A **competitive equilibrium with distorting taxes** is a **budget-feasible gover ## Non-arbitrage Condition +A no-arbitrage argument implies a restriction on prices and tax rates across time. + +### Household + By rearranging {eq}`eq:house_budget` and group $k_t$ at the same $t$, we can get $$ @@ -185,33 +217,53 @@ $$ \end{aligned} $$ (eq:constrant_house) -By setting the terms multiplying $k_t$ to $0$ we have the non-arbitrage condition: +The household inherits a given $k_0$ that it takes as initial condition and is free to choose $\{ c_t, n_t, k_{t+1} \}_{t=0}^\infty$. + +The household's budget constraint {eq}`eq:house_budget` must be bounded in equilibrium due to finite resources. This imposes a restriction on price and tax sequences. + +Specifically, for $t \geq 1$, the terms multiplying $k_t$ must equal zero. + +If they were strictly positive (negative), the household could arbitrarily increase (decrease) the right-hand side of {eq}`eq:house_budget` by selecting an arbitrarily large positive (negative) $k_t$, leading to unbounded profit or arbitrage opportunities. + +For strictly positive terms, the household could purchase large capital stocks $k_t$ and profit from their rental services and undepreciated value. For strictly negative terms, the household could engage in "short selling" synthetic units of capital. Both cases would make {eq}`eq:house_budget` unbounded. + +Hence, by setting the terms multiplying $k_t$ to $0$ we have the non-arbitrage condition: $$ -\frac{q_t}{q_{t+1}} = \left[(1 - \tau_{kt})(\eta_t - \delta) + 1\right] +\frac{q_t}{q_{t+1}} = \left[(1 - \tau_{kt+1})(\eta_{t+1} - \delta) + 1\right]. $$ (eq:no_arb) -Moreover, we have terminal condition +Moreover, we have terminal condition: $$ -\lim_{T \to \infty} q_T k_{T+1} = 0. $$ (eq:terminal) -Moreover, applying Euler's theorem on firm's present value gives +### Firm + +Zero-profit conditions for the representative firm impose additional restrictions on equilibrium prices and quantities. + +The present value of the firm's profits is + +$$ +\sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right]. +$$ + +Applying Euler's theorem on linearly homogeneous functions to $F(k, n)$, the firm's present value is: $$ -\sum_{t=0}^\infty q_t \left[ F(k_t, n_t) - w_t n_t - \eta_t k_t \right] = \sum_{t=0}^\infty q_t \left[ (F_{kt} - \eta_t) k_t + (F_{nt} - w_t) n_t \right] +\sum_{t=0}^\infty q_t \left[ (F_{kt} - \eta_t)k_t + (F_{nt} - w_t)n_t \right]. $$ -and no-arbitrage analogous to the household case are +No-arbitrage (or zero-profit) conditions are: $$ -\eta_t = F_{kt} \quad \text{and} \quad w_t = F_{nt}. -$$ (eq:no_arb_firms) +\eta_t = F_{kt}, \quad w_t = F_{nt}. +$$(eq:no_arb_firms) ## Household's First Order Condition -Household maximize {eq}`eq:utility` under {eq}`eq:house_budget`. Let $U_1 = \frac{\partial U}{\partial c}, U_2 = \frac{\partial U}{\partial (1-n)} = -\frac{\partial U}{\partial n} = -U_n.$, we can derive FOC from the Lagrangian +Household maximize {eq}`eq:utility` under {eq}`eq:house_budget`. Let $U_1 = \frac{\partial U}{\partial c}, U_2 = \frac{\partial U}{\partial (1-n)} = -\frac{\partial U}{\partial n}.$, we can derive FOC from the Lagrangian $$ \mathcal{L} = \sum_{t=0}^\infty \beta^t U(c_t, 1 - n_t) + \mu \left( \sum_{t=0}^\infty q_t \left[(1 + \tau_{ct})c_t - (1 - \tau_{nt})w_t n_t + \ldots \right] \right), @@ -220,15 +272,13 @@ $$ Hence we have FOC: $$ -\frac{\partial \mathcal{L}}{\partial c_t} = \beta^t U_1(c_t, 1 - n_t) - \mu q_t (1 + \tau_{ct}) = 0 +\frac{\partial \mathcal{L}}{\partial c_t} = \beta^t U_{1}(c_t, 1 - n_t) - \mu q_t (1 + \tau_{ct}) = 0 $$ (eq:foc_c_1) -which gives $\mu q_t = \beta^t \frac{U_1(c_t, 1 - n_t)}{(1 + \tau_{ct})}$ - and $$ -\frac{\partial \mathcal{L}}{\partial n_t} = \beta^t \left(-U_2(c_t, 1 - n_t)\right) - \mu q_t (1 - \tau_{nt}) w_t = 0 +\frac{\partial \mathcal{L}}{\partial n_t} = \beta^t \left(-U_{2t}(c_t, 1 - n_t)\right) - \mu q_t (1 - \tau_{nt}) w_t = 0 $$ (eq:foc_n_1) Rearranguing {eq}`eq:foc_c_1` and {eq}`eq:foc_n_1`, we have @@ -279,7 +329,7 @@ def next_k(k_t, g_t, c_t, model): By the properties of a linearly homogeneous production function, we have $F_k(k, n) = f'(k)$ and $F_n(k, 1) = f(k, 1) - f'(k)k$. -Substituting {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we obtain: +Substituting {eq}`eq:foc_c`, {eq}`eq:no_arb_firms`, and {eq}`eq:feasi_capital` into {eq}`eq:no_arb`, we obtain the Euler equation $$ \begin{aligned} @@ -287,7 +337,7 @@ $$ &- \beta \frac{u'(f(k_{t+1}) + (1 - \delta) k_{t+1} - g_{t+1} - k_{t+2})}{(1 + \tau_{ct+1})} \\ &\times [(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1] = 0. \end{aligned} -$$ +$$(eq:euler_house) This can be simplified to: @@ -297,8 +347,6 @@ u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} [(1 - \tau \end{aligned} $$ (eq:diff_second) -which represents the Euler equation for the household. - This equation is instrumental in solving for the equilibrium sequence of consumption and capital, as demonstrated in the second method. ### Steady state @@ -499,7 +547,6 @@ def f(k, model): """ Production function: f(k) = A * k^{α} """ - A, α = model.A, model.α return A * k ** α @@ -563,6 +610,7 @@ def shooting_algorithm(c0, k0, shocks, S, model): # Calculate next period's capital k_tp1 = next_k(k_t, g_t, c_t, model) + # Failure due to negative capital if k_tp1 < mpf(0): return None, None @@ -572,6 +620,7 @@ def shooting_algorithm(c0, k0, shocks, S, model): R_bar = compute_R_bar(τ_c_path[t], τ_c_path[t + 1], τ_k_path[t + 1], k_tp1, model) c_tp1 = next_c(c_t, R_bar, model) + # Failure due to negative consumption if c_tp1 < mpf(0): return None, None @@ -593,10 +642,11 @@ def bisection_c0(c0_guess, k0, shocks, S, model, c0 = c0_guess for iter_count in range(max_iter): k_path, _ = shooting_algorithm(c0, k0, shocks, S, model) + + # Adjust upper bound when shooting fails if k_path is None: if verbose: print(f"Iteration {iter_count + 1}: shooting failed with c0 = {c0}") - # Adjust upper bound when shooting fails c0_upper = c0 else: error = k_path[-1] - k_ss_final @@ -605,7 +655,6 @@ def bisection_c0(c0_guess, k0, shocks, S, model, # Check for convergence if abs(error) < tol: - # Converged successfully print(f"Converged successfully on iteration {iter_count + 1}") return c0 @@ -642,6 +691,7 @@ def run_shooting(shocks, S, model, c0_func=bisection_c0, shooting_func=shooting_ return np.column_stack([k_path, c_path]) ``` +(cf:experiments)= ### Experiments We will run a series of experiments and analyze the transition path for the equilibrium in each scenario: @@ -660,7 +710,9 @@ We will start from the steady state and then apply the shocks at the appropriate ```{code-cell} ipython3 def plot_results(solution, k_ss, c_ss, shocks, shock_param, axes, model, label='', linestyle='-', T=40): - + """ + Plot the results of the simulation replicating graphs in RMT. + """ k_path = solution[:, 0] c_path = solution[:, 1] @@ -694,7 +746,7 @@ def plot_results(solution, k_ss, c_ss, shocks, shock_param, **Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** -The experiment replicates the Figure 12.9.1 in RMT5 under $\gamma = 2$. +The figure below shows the effect of a foreseen permanent increase in $g$ at $t = T = 10$ that is financed by an increase in lump-sum taxes ```{code-cell} ipython3 # Define shocks as a dictionary @@ -726,6 +778,21 @@ plt.tight_layout() plt.show() ``` +- Steady-State Value of Capital Stock + - The steady-state value of the capital stock remains unaffected. + - This follows from the fact that $g$ disappears from the steady state version of the Euler equation ({eq}eq:diff_second_steady). + +- Gradual Reduction in Consumption + - Consumption begins to decline gradually before time $T$ due to increased government consumption. + - Households reduce consumption to offset government spending, which is financed through increased lump-sum taxes. + - The competitive economy signals households to consume less through an increase in the stream of lump-sum taxes. + - Households, caring about the present value rather than the timing of taxes, experience an adverse wealth effect on consumption, leading to an immediate response. + +- Effect on Capital Stock: + - Capital gradually accumulates between time $0$ and $T$ due to increased savings. + - After time $T$, capital stock gradually decreases. + - This temporal variation in capital stock smooths consumption over time, driven by the consumption-smoothing motive. + Let's write the procedures above into a function that runs the solver and draw the plots for a given model ```{code-cell} ipython3 @@ -735,7 +802,6 @@ def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): """ Run the shooting algorithm given a model and plot the results. """ - k0, c0 = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) print(f"Steady-state capital: {k0:.4f}") @@ -756,7 +822,11 @@ def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): plt.show() ``` -The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. +The following figure compares responses to a foreseen increase in $g$ at $t = 10$ for +two economies, our original economy with $\gamma = 2$, shown in the solid line, and an +otherwise identical economy with $\gamma = 0.2$. + +The utility curvature parameter $\gamma$ governs the household's willingness to substitute consumption over time ```{code-cell} ipython3 # Solve the model using shooting @@ -796,6 +866,17 @@ plt.tight_layout() plt.show() ``` +- Impact of Lower $\gamma$: + - Lowering $\gamma$ increases the willingness to substitute consumption across time. + - In the case of $\gamma = 0.2$, consumption becomes less smooth compared to $\gamma = 2$. + - For $\gamma = 0.2$, consumption mirrors the government expenditure path more closely, staying higher until $t = 10$. + +- Effects on Capital and Fluctuations: + - With $\gamma = 0.2$, there are smaller build-ups and drawdowns of capital stock. + - Leads to smaller fluctuations in $\bar{R}$ and $\eta$. + ++++ + Let's write another function that runs the solver and draw the plots for two models as we did above ```{code-cell} ipython3 @@ -806,7 +887,6 @@ def experiment_two_models(shocks, S, model_1, model_2, solver, plot_func, """ Compares and plots results of the shooting algorithm for two models. """ - k0, c0 = steady_states(model, shocks['g'][0], shocks['τ_k'][0]) print(f"Steady-state capital: {k0:.4f}") print(f"Steady-state consumption: {c0:.4f}") @@ -848,7 +928,9 @@ Now we plot other equilibrium quantities: ```{code-cell} ipython3 def plot_prices(solution, c_ss, shock_param, axes, model, label='', linestyle='-', T=40): - + """ + Compares and plots prices + """ α, β, δ, γ, A = model.α, model.β, model.δ, model.γ, model.A k_path = solution[:, 0] @@ -886,6 +968,9 @@ def plot_prices(solution, c_ss, shock_param, axes, axes[4].set_title(shock_param) ``` +For $\gamma = 2$ again, the next figure describes the response of $q_t$ and the term +structure of interest rates to a foreseen increase in $g_t$ at $t = 10$. + ```{code-cell} ipython3 solution = run_shooting(shocks, S, model) @@ -903,9 +988,41 @@ plt.tight_layout() plt.show() ``` +The second panel on the top compares $q_t$ for the initial steady state with $q_t$ after the +increase in $g$ is foreseen at $t = 0$, while the third panel compares the implied +short rate $r_t$. + +The fourth panel shows the term structure of interest rates at $t=0$, $t=10$, and $t=60$. + +Notice that, by $t = 60$, the system has converged to the new steady state, and the term structure of interest rates becomes flat. + +At $t = 10$, the term structure of interest rates is upward sloping. + +This upward slope reflects the expected increase in the rate of growth of consumption over time, as shown in the consumption panel. + +At $t = 0$, the term structure of interest rates exhibits a "U-shaped" pattern: + +- It declines until maturity at $s = 10$. +- After $s = 10$, it increases for longer maturities. + +This pattern corresponds to the pattern of consumption growth in the first two figures, which: + +- Declines at an increasing rate until $t = 10$. +- Then declines at a decreasing rate afterward. + ++++ + **Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10** -The experiment replicates the Figure 12.9.4. +With an inelastic labor supply, the Euler equation {eq}`eq:euler_house` +and the other equilibrium conditions show that constant consumption taxes +do not distort decisions, but that anticipated changes in them do. + +Indeed, {eq}`eq:euler_house` or {eq}`eq:diff_second` indicates that a foreseen in- +crease in $\tau_{ct}$ (i.e., a decrease in $(1+\tau_{ct})$ +$(1+\tau_{ct+1})$) operates like an increase in $\tau_{kt}$. + +The following figure portrays the response to a foreseen increase in the consumption tax $\tau_c$. ```{code-cell} ipython3 shocks = { @@ -917,9 +1034,29 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` +Notice that while all variables in the figure above eventually return to their initial +steady-state values, the anticipated increase in $\tau_{ct}$ leads to variations in consumption +across time: + +- At $t = 0$: + - Anticipation of the increase in $\tau_c$ causes an *immediate jump in consumption*. + - This is followed by a *consumption binge*, which sends the capital stock downward until $t = T = 10$. +- Between $t = 0$ and $t = T = 10$: + - The decline in the capital stock raises $\bar{R}$ over time. + - As per equilibrium conditions, this requires the growth rate of consumption to rise until $t = T$. +- At $t = T = 10$: + - The jump in $\tau_c$ depresses $\bar{R}$ below $1$, causing a *sharp drop in consumption*. +- After $T = 10$: + - The effects of anticipated distortion are over, and the economy adjusts to the lower capital stock. + - Capital must now rise, requiring *austerity*—consumption plummets after $t = T$ indicated by a lower level of consumption. + - The interest rate gradually declines, and consumption grows at a diminishing rate along the path to the terminal steady-state. + ++++ + **Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10** -The experiment replicates the Figure 12.9.5. +For the two $\gamma$ values 2 and 0.2, the next figure shows the +response to a foreseen permanent jump in $\tau_{kt}$ at $t = T = 10$. ```{code-cell} ipython3 shocks = { @@ -932,6 +1069,24 @@ experiment_two_models(shocks, S, model, model_γ2, run_shooting, plot_results, 'τ_k') ``` +The path of government expenditures remains fixed, and the increase in $\tau_{kt}$ is offset by a reduction in the present value of lump-sum taxes to keep the budget balanced. + +We note that + +- Anticipation of the increase in $\tau_{kt}$ leads to immediate decline in capital stock due to increased current consumption and growing consumption flow. +- $\bar{R}$ starts rising at $t = 0$ and peaks at $t = 9$, and at $t = 10$, $\bar{R}$ drops sharply due to the tax change. + - Variations in $\bar{R}$ reflect the impact of the tax increase at $t = 10$ on consumption across time. +- Transition dynamics push $k_t$ (capital stock) toward a new, lower steady-state level. In the new steady state: + - Consumption is lower due to reduced output from the lower capital stock. + - Smoother consumption paths are observed when $\gamma = 2$ compared to $\gamma = 0.2$. + + ++++ + +So far we have explored consequences of foreseen once-and-for-all changes +in government policy. Next we describe some experiments in which there is a +foreseen one-time change in a policy variable (a "pulse"). + **Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever** The experiment replicates the Figure 12.9.6. @@ -949,6 +1104,18 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'g') ``` +We note that such a policy change impacts consumption and capital in an interesting one: + +- Consumption: + - Drops immediately at the announcement of the policy and continues to decline over time in anticipation of the one-time surge in $g$. + - After the shock at $t = 10$, consumption begins to recover, rising at a diminishing rate toward its steady-state value. + +- Capital and $\bar{R}$: + - Before $t = 10$, capital accumulates as households prepare for the anticipated increase in government spending. + - At $t = 10$, capital stock sharply decreases as the government consumes part of it. + - $\bar{R}$ jumps above its steady-state value due to the capital reduction and then gradually declines toward its steady-state level. ++++ + ### Method 2: Residual Minimization Using the Euler Equation and Feasibility Condition The second method involves minimizing the residuals of the following equations: @@ -963,7 +1130,24 @@ The second method involves minimizing the residuals of the following equations: k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t. $$ -+++ +```{code-cell} ipython3 +# Euler's equation and feasibility condition +def euler_residual(c_t, c_tp1, τ_c_t, τ_c_tp1, τ_k_tp1, k_tp1, model): + """ + Computes the residuals for Euler's equation. + """ + β, γ, δ, α, A = model.β, model.γ, model.δ, model.α, model.A + η_tp1 = α * A * k_tp1 ** (α - 1) + return β * (c_tp1 / c_t) ** (-γ) * (1 + τ_c_t) / (1 + τ_c_tp1) * ( + (1 - τ_k_tp1) * (η_tp1 - δ) + 1) - 1 + +def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): + """ + Computes the residuals for feasibility condition. + """ + α, A, δ = model.α, model.A, model.δ + return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) +``` The algorithm is described as follows: @@ -1001,23 +1185,6 @@ The algorithm is described as follows: - Adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. ```{code-cell} ipython3 -# Euler's equation and feasibility condition -def euler_residual(c_t, c_tp1, τ_c_t, τ_c_tp1, τ_k_tp1, k_tp1, model): - """ - Computes the residuals for Euler's equation. - """ - β, γ, δ, α, A = model.β, model.γ, model.δ, model.α, model.A - η_tp1 = α * A * k_tp1 ** (α - 1) - return β * (c_tp1 / c_t) ** (-γ) * (1 + τ_c_t) / (1 + τ_c_tp1) * ( - (1 - τ_k_tp1) * (η_tp1 - δ) + 1) - 1 - -def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): - """ - Computes the residuals for feasibility condition. - """ - α, A, δ = model.α, model.A, model.δ - return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) - # Computing residuals as objective function to minimize def compute_residuals(vars_flat, k_init, S, shocks, model): """ @@ -1074,12 +1241,31 @@ Below are the results for the same experiments using the second method. This method does not have numerical stability issues, so `mp.mpf` is not necessary. -**Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** +We leave the experiments for you to replicate using the second method. + +## Exercises -The experiment replicates Figure 12.9.1 in RMT5 under the parameter $\gamma = 2$. +```{exercise} +:label: cass_fiscal_ex1 + +Replicate the plots of the four experiments we run before: +1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10, +2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10, +3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10, and +4. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ reverts to 0.2 permanently, + +using the second method of residual minimization. +``` + +```{solution-start} cass_fiscal_ex1 +:class: dropdown +``` + +Here is one solution: + +**Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** ```{code-cell} ipython3 -# Define the shocks for the simulation S = 100 shocks = { 'g': np.concatenate((np.repeat(0.2, 10), np.repeat(0.4, S - 9))), @@ -1090,15 +1276,11 @@ shocks = { experiment_model(shocks, S, model, run_min, plot_results, 'g') ``` -The experiment replicates the Figure 12.9.2 in RMT5 under $\gamma = 2$ and $\gamma = 0.2$. - ```{code-cell} ipython3 experiment_two_models(shocks, S, model, model_γ2, run_min, plot_results, 'g') ``` -Below replicates the graph 12.9.3: - ```{code-cell} ipython3 solution = run_min(shocks, S, model) @@ -1118,8 +1300,6 @@ plt.show() **Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10.** -The experiment replicates the Figure 12.9.4. - ```{code-cell} ipython3 shocks = { 'g': np.repeat(0.2, S + 1), @@ -1132,8 +1312,6 @@ experiment_model(shocks, S, model, run_min, plot_results, 'τ_c') **Experiment 3: Foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 in period 10.** -The experiment replicates the Figure 12.9.5. - ```{code-cell} ipython3 shocks = { 'g': np.repeat(0.2, S + 1), @@ -1147,8 +1325,6 @@ experiment_two_models(shocks, S, model, model_γ2, **Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever** -The experiment replicates the Figure 12.9.6. - ```{code-cell} ipython3 g_path = np.repeat(0.2, S + 1) g_path[10] = 0.4 @@ -1161,3 +1337,37 @@ shocks = { experiment_model(shocks, S, model, run_min, plot_results, 'g') ``` + +```{solution-end} +``` + + +```{exercise} +:label: cass_fiscal_ex2 + +Design a new experiment where the government expenditure $g$ increases from 0.2 to 0.4 in period 10, +and then decreases to 0.1 in period 20, after which it remains at 0.1 forever. +``` + +```{solution-start} cass_fiscal_ex2 +:class: dropdown +``` + +Here is one solution: + +```{code-cell} ipython3 +g_path = np.repeat(0.2, S + 1) +g_path[10:20] = 0.4 +g_path[20:] = 0.1 + +shocks = { + 'g': g_path, + 'τ_c': np.repeat(0.0, S + 1), + 'τ_k': np.repeat(0.0, S + 1) +} + +experiment_model(shocks, S, model, run_min, plot_results, 'g') +``` + +```{solution-end} +``` \ No newline at end of file From 866834dce498d39909b222a84a38b34b21cf6baf Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Mon, 30 Dec 2024 16:04:54 +0800 Subject: [PATCH 11/17] update cass_fiscal --- lectures/cass_fiscal.md | 72 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index a4a43dc8a..e8fd39492 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -15,7 +15,7 @@ kernelspec: ## Introduction -This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model with features inherited from {doc}`cass_koopmans_2` +This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model with features inherited from {doc}`cass_koopmans_2`. We use the model as a laboratory to exhibit numerical techniques for approximating equilibria and to display the structure of dynamic models in which decision makers have perfect foresight about future government decisions. @@ -464,7 +464,7 @@ def compute_R_bar_path(shocks, k_path, model, S=100): $$ R^{-1}_{t, t+1} = \frac{q_t}{q_{t-1}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} -$$ (eq:equil_R) +$$ (eq:equil_bigR) *Net one-period rate of interest:* @@ -473,7 +473,7 @@ $$ r_{t, t+1} \equiv R_{t, t+1} - 1 = (1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) $$ (eq:equil_r) -By {eq}`eq:equil_R`, we have +By {eq}`eq:equil_bigR`, we have $$ R_{t, t+s} = e^{s \cdot r_{t, t+s}}. @@ -696,9 +696,9 @@ def run_shooting(shocks, S, model, c0_func=bisection_c0, shooting_func=shooting_ We will run a series of experiments and analyze the transition path for the equilibrium in each scenario: -1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10. -2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10. -3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10. +1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10, +2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10, +3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10, and 4. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ reverts to 0.2 permanently. +++ @@ -778,19 +778,17 @@ plt.tight_layout() plt.show() ``` -- Steady-State Value of Capital Stock - - The steady-state value of the capital stock remains unaffected. - - This follows from the fact that $g$ disappears from the steady state version of the Euler equation ({eq}eq:diff_second_steady). +We note the following features in the figure + +- The steady-state value of the capital stock remains unaffected: + - This follows from the fact that $g$ disappears from the steady state version of the Euler equation ({eq}`eq:diff_second_steady`). -- Gradual Reduction in Consumption - - Consumption begins to decline gradually before time $T$ due to increased government consumption. +- Consumption begins to decline gradually before time $T$ due to increased government consumption: - Households reduce consumption to offset government spending, which is financed through increased lump-sum taxes. - The competitive economy signals households to consume less through an increase in the stream of lump-sum taxes. - Households, caring about the present value rather than the timing of taxes, experience an adverse wealth effect on consumption, leading to an immediate response. -- Effect on Capital Stock: - - Capital gradually accumulates between time $0$ and $T$ due to increased savings. - - After time $T$, capital stock gradually decreases. +- Capital gradually accumulates between time $0$ and $T$ due to increased savings and reduces gradually after time $T$: - This temporal variation in capital stock smooths consumption over time, driven by the consumption-smoothing motive. Let's write the procedures above into a function that runs the solver and draw the plots for a given model @@ -866,17 +864,17 @@ plt.tight_layout() plt.show() ``` -- Impact of Lower $\gamma$: +From the graph we can observe that lowering $\gamma$ affects both the consumption and capital stock paths: + +- Consumption path: - Lowering $\gamma$ increases the willingness to substitute consumption across time. - In the case of $\gamma = 0.2$, consumption becomes less smooth compared to $\gamma = 2$. - For $\gamma = 0.2$, consumption mirrors the government expenditure path more closely, staying higher until $t = 10$. -- Effects on Capital and Fluctuations: +- Capital stock path: - With $\gamma = 0.2$, there are smaller build-ups and drawdowns of capital stock. - Leads to smaller fluctuations in $\bar{R}$ and $\eta$. -+++ - Let's write another function that runs the solver and draw the plots for two models as we did above ```{code-cell} ipython3 @@ -969,7 +967,7 @@ def plot_prices(solution, c_ss, shock_param, axes, ``` For $\gamma = 2$ again, the next figure describes the response of $q_t$ and the term -structure of interest rates to a foreseen increase in $g_t$ at $t = 10$. +structure of interest rates to a foreseen increase in $g_t$ at $t = 10$ ```{code-cell} ipython3 solution = run_shooting(shocks, S, model) @@ -1035,8 +1033,10 @@ experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` Notice that while all variables in the figure above eventually return to their initial -steady-state values, the anticipated increase in $\tau_{ct}$ leads to variations in consumption -across time: +steady-state values. + +The anticipated increase in $\tau_{ct}$ leads to variations in consumption +and capital stock across time: - At $t = 0$: - Anticipation of the increase in $\tau_c$ causes an *immediate jump in consumption*. @@ -1071,7 +1071,7 @@ experiment_two_models(shocks, S, model, model_γ2, The path of government expenditures remains fixed, and the increase in $\tau_{kt}$ is offset by a reduction in the present value of lump-sum taxes to keep the budget balanced. -We note that +We note the following features in the figure: - Anticipation of the increase in $\tau_{kt}$ leads to immediate decline in capital stock due to increased current consumption and growing consumption flow. - $\bar{R}$ starts rising at $t = 0$ and peaks at $t = 9$, and at $t = 10$, $\bar{R}$ drops sharply due to the tax change. @@ -1104,7 +1104,7 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'g') ``` -We note that such a policy change impacts consumption and capital in an interesting one: +We note that such a policy change impacts consumption and capital in an interesting way: - Consumption: - Drops immediately at the announcement of the policy and continues to decline over time in anticipation of the one-time surge in $g$. @@ -1120,12 +1120,12 @@ We note that such a policy change impacts consumption and capital in an interest The second method involves minimizing the residuals of the following equations: -- *The Euler equation* {eq}`eq:diff_second`: +- The Euler equation {eq}`eq:diff_second`: $$ 1 = \beta \left(\frac{c_{t+1}}{c_t}\right)^{-\gamma} \frac{(1+\tau_{ct})}{(1+\tau_{ct+1})} \left[(1 - \tau_{kt+1})(\alpha A k_{t+1}^{\alpha-1} - \delta) + 1 \right] $$ -- *The feasibility condition* {eq}`eq:feasi_capital`: +- The feasibility condition {eq}`eq:feasi_capital`: $$ k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t. $$ @@ -1151,38 +1151,36 @@ def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): The algorithm is described as follows: -1. *Calculate the initial state $k_0$*: - - Derive $k_0$ based on the given initial government plan $z_0$. +1. Derive $k_0$ based on the given initial government plan $z_0$. -2. *Initialize a sequence of initial guesses* $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$. +2. Initialize a sequence of initial guesses $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$. -3. *Compute the residuals* $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: - - Compute the *Euler's equation* residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: +3. Compute the residuals $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: + - Compute the Euler's equation residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: $$ l_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 $$ - - Compute the *feasibility condition* residual for $t = 1, \dots, S-1$ using {eq}`eq:feasi_capital`: + - Compute the feasibility condition residual for $t = 1, \dots, S-1$ using {eq}`eq:feasi_capital`: $$ l_{tk} = k_{t+1} - f(k_t) - (1 - \delta)k_t + g_t + c_t $$ - - Compute the residual for the *initial condition for $k_0$* using {eq}`eq:diff_second_steady` and the initial capital $k_0$: + - Compute the residual for the*initial condition for $k_0$ using {eq}`eq:diff_second_steady` and the initial capital $k_0$: $$ l_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] $$ - - Compute the residual for the *terminal condition* for $t = S$ using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: + - Compute the residual for the terminal condition for $t = S$ using {eq}`eq:diff_second` under the assumptions $c_t = c_{t+1} = c_S$, $k_t = k_{t+1} = k_S$, $\tau_{ct} = \tau_{ct+1} = \tau_{cS}$, and $\tau_{kt} = \tau_{kt+1} = \tau_{kS}$: $$ l_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 $$ -4. *Residual Minimization*: - - Adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. +4. Iteratively adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. ```{code-cell} ipython3 # Computing residuals as objective function to minimize @@ -1345,8 +1343,8 @@ experiment_model(shocks, S, model, run_min, plot_results, 'g') ```{exercise} :label: cass_fiscal_ex2 -Design a new experiment where the government expenditure $g$ increases from 0.2 to 0.4 in period 10, -and then decreases to 0.1 in period 20, after which it remains at 0.1 forever. +Design a new experiment where the government expenditure $g$ increases from $0.2$ to $0.4$ in period $10$, +and then decreases to $0.1$ in period $20$ permanently. ``` ```{solution-start} cass_fiscal_ex2 From 133ecac23c7f6021005d8375067ad260f9666ccf Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Mon, 30 Dec 2024 16:16:49 +0800 Subject: [PATCH 12/17] update lecture --- lectures/cass_fiscal.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index e8fd39492..87b849aba 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -1121,11 +1121,13 @@ We note that such a policy change impacts consumption and capital in an interest The second method involves minimizing the residuals of the following equations: - The Euler equation {eq}`eq:diff_second`: + $$ 1 = \beta \left(\frac{c_{t+1}}{c_t}\right)^{-\gamma} \frac{(1+\tau_{ct})}{(1+\tau_{ct+1})} \left[(1 - \tau_{kt+1})(\alpha A k_{t+1}^{\alpha-1} - \delta) + 1 \right] $$ - The feasibility condition {eq}`eq:feasi_capital`: + $$ k_{t+1} = A k_{t}^{\alpha} + (1 - \delta) k_t - g_t - c_t. $$ @@ -1151,7 +1153,7 @@ def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): The algorithm is described as follows: -1. Derive $k_0$ based on the given initial government plan $z_0$. +1. Derive intial steady state $k_0$ based on the government plan at $t=0$. 2. Initialize a sequence of initial guesses $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$. @@ -1235,8 +1237,6 @@ def run_min(shocks, S, model): return sol.x.reshape((S + 1, 2)) ``` -Below are the results for the same experiments using the second method. - This method does not have numerical stability issues, so `mp.mpf` is not necessary. We leave the experiments for you to replicate using the second method. @@ -1246,13 +1246,11 @@ We leave the experiments for you to replicate using the second method. ```{exercise} :label: cass_fiscal_ex1 -Replicate the plots of the four experiments we run before: +Replicate the plots of the four experiments we run before using the second method of residual minimization: 1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10, 2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10, 3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10, and 4. A foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ reverts to 0.2 permanently, - -using the second method of residual minimization. ``` ```{solution-start} cass_fiscal_ex1 From 4f0d3eb4b4d7b2e060932a6c4eae9b7f3a9cdd40 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Mon, 30 Dec 2024 16:45:46 +0800 Subject: [PATCH 13/17] update cass_fiscal --- lectures/cass_fiscal.md | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 87b849aba..2f908469b 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -27,9 +27,9 @@ Therefore, to compute an equilibrium allocation and price system, we solve a sys We present two ways to solve the model: -- The first method is called shooting algorithm; +- The first method is shooting algorithm in the same spirit as in {doc}`cass_koopmans_2`. -- The second method is applying a root-finding algorithm to minimize the residuals derived from the first-order conditions. +- The second method is a root-finding algorithm to minimize the residuals derived from the first-order conditions. We will use the following imports @@ -88,7 +88,7 @@ under the budget constraint {eq}`eq:house_budget`. ### Technology -The economy's production technology is defined by: +The technology is defined by: $$ g_t + c_t + x_t \leq F(k_t, n_t), @@ -106,15 +106,13 @@ $$ k_{t+1} = (1 - \delta)k_t + x_t, $$ -where - -- $\delta \in (0, 1)$ is depreciation rate. +where $\delta \in (0, 1)$ is depreciation rate. It is sometimes convenient to eliminate $x_t$ from {eq}`eq:tech_capital` to write it as $$ -g_t + c_t + k_{t+1} \leq F(k_t, n_t) + (1 - \delta)k_t +g_t + c_t + k_{t+1} \leq F(k_t, n_t) + (1 - \delta)k_t. $$ ### Components of a competitive equilibrium @@ -131,7 +129,7 @@ A **price system** is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, - $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, and - $w_t$ is the pretax price at time $t$ that the household receives for renting labor to the firm at time $t$. -The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0 as in {doc}`cass_koopmans_2` +The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0 as in {doc}`cass_koopmans_2`. Government is the main feature that distinguishes this lecture from {doc}`cass_koopmans_2`. @@ -154,13 +152,13 @@ We include all of these taxes because, like {cite}`hall1971dynamic`, they allow us to analyze how the various taxes distort production and consumption decisions. -In the [experiment section](cf:experiments), we shall see how variations in government tax plan affects +In the [experiment section](cf:experiments), we shall see how variations in government tax plan affect the transition path and equilibrium. ### Budget constraints -Now we have all the elements to write down budget constraints for representative household -and government +Now we have all the elements to write down budget constraints for the representative household +and government. Household maximizes {eq}`eq:utility` under the budget constraint: @@ -223,9 +221,11 @@ The household's budget constraint {eq}`eq:house_budget` must be bounded in equil Specifically, for $t \geq 1$, the terms multiplying $k_t$ must equal zero. -If they were strictly positive (negative), the household could arbitrarily increase (decrease) the right-hand side of {eq}`eq:house_budget` by selecting an arbitrarily large positive (negative) $k_t$, leading to unbounded profit or arbitrage opportunities. +If they were strictly positive (negative), the household could arbitrarily increase (decrease) the right-hand side of {eq}`eq:house_budget` by selecting an arbitrarily large positive (negative) $k_t$, leading to unbounded profit or arbitrage opportunities: -For strictly positive terms, the household could purchase large capital stocks $k_t$ and profit from their rental services and undepreciated value. For strictly negative terms, the household could engage in "short selling" synthetic units of capital. Both cases would make {eq}`eq:house_budget` unbounded. +- For strictly positive terms, the household could purchase large capital stocks $k_t$ and profit from their rental services and undepreciated value. + +- For strictly negative terms, the household could engage in "short selling" synthetic units of capital. Both cases would make {eq}`eq:house_budget` unbounded. Hence, by setting the terms multiplying $k_t$ to $0$ we have the non-arbitrage condition: @@ -463,7 +463,7 @@ def compute_R_bar_path(shocks, k_path, model, S=100): *One-period discount factor:* $$ -R^{-1}_{t, t+1} = \frac{q_t}{q_{t-1}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} +R^{-1}_{t, t+1} = \frac{q_{t+1}}{q_{t}} = m_{t, t+1} = \beta \frac{u'(c_{t+1})}{u'(c_t)} \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} $$ (eq:equil_bigR) @@ -473,7 +473,7 @@ $$ r_{t, t+1} \equiv R_{t, t+1} - 1 = (1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) $$ (eq:equil_r) -By {eq}`eq:equil_bigR`, we have +By {eq}`eq:equil_bigR` and $r_{t, t+1} = - \ln(\frac{q_{t+1}}{q_t})$, we have $$ R_{t, t+s} = e^{s \cdot r_{t, t+s}}. @@ -560,7 +560,7 @@ def f_prime(k, model): ## Computation -In the following sections, we will apply two methods to solve the model: the shooting algorithm and residual minimization using the Euler equation ({eq}`eq:diff_second`) and feasibility condition ({eq}`eq:feasi_capital`). +In the following sections, we will apply two methods to solve the model: the shooting algorithm and residual minimization using the Euler equation {eq}`eq:diff_second` and feasibility condition {eq}`eq:feasi_capital`. ### Method 1: Shooting Algorithm @@ -1003,10 +1003,8 @@ At $t = 0$, the term structure of interest rates exhibits a "U-shaped" pattern: - It declines until maturity at $s = 10$. - After $s = 10$, it increases for longer maturities. -This pattern corresponds to the pattern of consumption growth in the first two figures, which: - -- Declines at an increasing rate until $t = 10$. -- Then declines at a decreasing rate afterward. +This pattern corresponds to the pattern of consumption growth in the first two figures, +which declines at an increasing rate until $t = 10$ and then declines at a decreasing rate afterward. +++ From 11f2460aa0d4f2e3ab0effba29a738ec01113e86 Mon Sep 17 00:00:00 2001 From: thomassargent30 Date: Tue, 31 Dec 2024 12:42:53 +0800 Subject: [PATCH 14/17] Tom's Dec 31 edits of cass_fiscal lecture --- lectures/cass_fiscal.md | 316 +++++++++++++++++++++------------------- 1 file changed, 170 insertions(+), 146 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 2f908469b..55b6dcf8f 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -11,84 +11,33 @@ kernelspec: name: python3 --- -# Fiscal Policy Experiments in a Non-stochastic Model +# Cass-Koopmans Model with Distorting Taxes -## Introduction +## Overview -This lecture studies effects of technology and fiscal shocks on equilibrium outcomes in a nonstochastic growth model with features inherited from {doc}`cass_koopmans_2`. +This lecture studies effects of foreseen fiscal and technology shocks on competitive equilibrium prices and quantities in a nonstochastic version of a Cass-Koopmans growth model with features described in this QuantEcon lecture {doc}`cass_koopmans_2`. -We use the model as a laboratory to exhibit numerical techniques for approximating equilibria and to display the structure of dynamic models in which decision makers have perfect foresight about future government decisions. +We use the model as a laboratory to experiment with numerical techniques for approximating equilibria and to display the structure of dynamic models in which decision makers have perfect foresight about future government decisions. -Following {cite}`hall1971dynamic`, we augment a nonstochastic version of the standard growth model with a government that purchases a stream of goods and that finances itself with an array of distorting flat-rate taxes. +Following a classic paper by Robert E. Hall {cite}`hall1971dynamic`, we augment a nonstochastic version of the Cass-Koopmans optimal growth model with a government that purchases a stream of goods and that finances its purchases with an sequences of several distorting flat-rate taxes. Distorting taxes prevent a competitive equilibrium allocation from solving a planning problem. Therefore, to compute an equilibrium allocation and price system, we solve a system of nonlinear difference equations consisting of the first-order conditions for decision makers and the other equilibrium conditions. -We present two ways to solve the model: +We present two ways to approximate an equilibrium: -- The first method is shooting algorithm in the same spirit as in {doc}`cass_koopmans_2`. +- The first is a shooting algorithm like the one that we deployed in {doc}`cass_koopmans_2`. -- The second method is a root-finding algorithm to minimize the residuals derived from the first-order conditions. +- The second method is a root-finding algorithm that minimizes residuals from the first-order conditions of a consumer and a representative firm. -We will use the following imports - -```{code-cell} ipython3 -import numpy as np -from scipy.optimize import root -import matplotlib.pyplot as plt -from collections import namedtuple -from mpmath import mp, mpf -from warnings import warn - -# Set the precision -mp.dps = 40 -mp.pretty = True -``` - -Note that we will use the `mpmath` library to perform high-precision arithmetic in the shooting algorithm in cases where the solution diverges due to numerical instability. - -We will use the following parameters - -```{code-cell} ipython3 -# Create a namedtuple to store the model parameters -Model = namedtuple("Model", - ["β", "γ", "δ", "α", "A"]) - -def create_model(β=0.95, # discount factor - γ=2.0, # relative risk aversion coefficient - δ=0.2, # depreciation rate - α=0.33, # capital share - A=1.0 # TFP - ): - """Create a model instance.""" - return Model(β=β, γ=γ, δ=δ, α=α, A=A) - -model = create_model() - -# Total number of periods -S = 100 -``` ## The Economy -### Households - -The representative household has preferences over nonnegative streams of a single consumption good $c_t$ and leisure $1-n_t$ that are ordered by: - -$$ -\sum_{t=0}^{\infty} \beta^t U(c_t, 1-n_t), \quad \beta \in (0, 1), -$$ (eq:utility) - -where - -- $U$ is strictly increasing in $c_t$, twice continuously differentiable, and strictly concave with $c_t \geq 0$ and $n_t \in [0, 1]$, - -under the budget constraint {eq}`eq:house_budget`. ### Technology -The technology is defined by: +Feasible allocations satisfy $$ g_t + c_t + x_t \leq F(k_t, n_t), @@ -96,19 +45,19 @@ $$ (eq:tech_capital) where -- $g_t$ is government expenditure +- $g_t$ is government purchases of the time $t$ good - $x_t$ is gross investment, and - $F(k_t, n_t)$ is a linearly homogeneous production function with positive and decreasing marginal products of capital $k_t$ and labor $n_t$. -The law of motion for capital is given by: +Physical capital evolves according to $$ k_{t+1} = (1 - \delta)k_t + x_t, $$ -where $\delta \in (0, 1)$ is depreciation rate. +where $\delta \in (0, 1)$ is a depreciation rate. -It is sometimes convenient to eliminate $x_t$ from {eq}`eq:tech_capital` to write it +It is sometimes convenient to eliminate $x_t$ from {eq}`eq:tech_capital` and to represent it as as $$ @@ -117,9 +66,9 @@ $$ ### Components of a competitive equilibrium -There is a competitive equilibrium with all trades occurring at time $0$. +All trades occurring at time $0$. -The household owns capital, makes investment decisions, and rents capital and labor to a representative production firm. +The representative household owns capital, makes investment decisions, and rents capital and labor to a representative production firm. The representative firm uses capital and labor to produce goods with the production function $F(k_t, n_t)$. @@ -129,12 +78,14 @@ A **price system** is a triple of sequences $\{q_t, \eta_t, w_t\}_{t=0}^\infty$, - $\eta_t$ is the pretax price at time $t$ that the household receives from the firm for renting capital at time $t$, and - $w_t$ is the pretax price at time $t$ that the household receives for renting labor to the firm at time $t$. -The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of the numeraire at time 0 as in {doc}`cass_koopmans_2`. +The prices $w_t$ and $\eta_t$ are expressed in terms of time $t$ goods, while $q_t$ is expressed in terms of a numeraire at time $0$, as in {doc}`cass_koopmans_2`. -Government is the main feature that distinguishes this lecture from +The presence of a government distinguishes this lecture from {doc}`cass_koopmans_2`. -Government purchases of goods at time $t$ are $g_t \geq 0$ and a government expenditure plan is a sequence $g = \{g_t\}_{t=0}^\infty$. +Government purchases of goods at time $t$ are $g_t \geq 0$. + +A government expenditure plan is a sequence $g = \{g_t\}_{t=0}^\infty$. A government tax plan is a $4$-tuple of sequences $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$, where @@ -144,23 +95,30 @@ where - $\tau_{nt}$ is a tax rate on wage earnings at time $t$, and - $\tau_{ht}$ is a lump sum tax on a consumer at time $t$. -There is a sense in which we have given the government access to too many kinds -of taxes, because when lump-sum taxes $\tau_{ht}$ are available, the government should not +Because lump-sum taxes $\tau_{ht}$ are available, the government actually should not use any distorting taxes. -We include all of these taxes because, like {cite}`hall1971dynamic`, -they allow us to analyze how the -various taxes distort production and consumption decisions. +Nevertheless, we include all of these taxes because, like {cite}`hall1971dynamic`, +they allow us to analyze how various taxes distort production and consumption decisions. In the [experiment section](cf:experiments), we shall see how variations in government tax plan affect the transition path and equilibrium. -### Budget constraints -Now we have all the elements to write down budget constraints for the representative household -and government. +### Representative Household + +A representative household has preferences over nonnegative streams of a single consumption good $c_t$ and leisure $1-n_t$ that are ordered by: + +$$ +\sum_{t=0}^{\infty} \beta^t U(c_t, 1-n_t), \quad \beta \in (0, 1), +$$ (eq:utility) + +where + +- $U$ is strictly increasing in $c_t$, twice continuously differentiable, and strictly concave with $c_t \geq 0$ and $n_t \in [0, 1]$. + -Household maximizes {eq}`eq:utility` under the budget constraint: +The representative hßousehold maximizes {eq}`eq:utility` subject to the single budget constraint: $$ \begin{aligned} @@ -173,15 +131,17 @@ Here we have assumed that the government gives a depreciation allowance $\delta from the gross rentals on capital $\eta_t k_t$ and so collects taxes $\tau_{kt} (\eta_t - \delta) k_t$ on rentals from capital. -Government plans $\{ g_t \}_{t=0}^\infty$ for government purchases and taxes $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to the budget constraint +### Government + +Government plans $\{ g_t \}_{t=0}^\infty$ for government purchases and taxes $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ must respect the budget constraint $$ \sum_{t=0}^\infty q_t g_t \leq \sum_{t=0}^\infty q_t \left\{ \tau_{ct}c_t + \tau_{kt}(\eta_t - \delta)k_t + \tau_{nt}w_t n_t + \tau_{ht} \right\}. $$ (eq:gov_budget) -### Equilibrium -In the equilibrium, given a budget-feasible government policy $\{g_t\}_{t=0}^\infty$ and $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to {eq}`eq:gov_budget`, + +Given a budget-feasible government policy $\{g_t\}_{t=0}^\infty$ and $\{\tau_{ct}, \tau_{kt}, \tau_{nt}, \tau_{ht}\}_{t=0}^\infty$ subject to {eq}`eq:gov_budget`, - *Household* chooses $\{c_t\}_{t=0}^\infty$, $\{n_t\}_{t=0}^\infty$, and $\{k_{t+1}\}_{t=0}^\infty$ to maximize utility{eq}`eq:utility` subject to budget constraint{eq}`eq:house_budget`, and - *Frim* chooses sequences of capital $\{k_t\}_{t=0}^\infty$ and $\{n_t\}_{t=0}^\infty$ to maximize profits @@ -192,6 +152,7 @@ In the equilibrium, given a budget-feasible government policy $\{g_t\}_{t=0}^\in - A **feasible allocation** is a sequence $\{c_t, x_t, n_t, k_t\}_{t=0}^\infty$ that satisfies feasibility condition {eq}`eq:tech_capital`. +## Equilibrium ```{prf:definition} :label: com_eq_tax @@ -199,11 +160,11 @@ In the equilibrium, given a budget-feasible government policy $\{g_t\}_{t=0}^\in A **competitive equilibrium with distorting taxes** is a **budget-feasible government policy**, **a feasible allocation**, and **a price system** for which, given the price system and the government policy, the allocation solves the household’s problem and the firm’s problem. ``` -## Non-arbitrage Condition +## No-arbitrage Condition A no-arbitrage argument implies a restriction on prices and tax rates across time. -### Household + By rearranging {eq}`eq:house_budget` and group $k_t$ at the same $t$, we can get @@ -217,7 +178,9 @@ $$ (eq:constrant_house) The household inherits a given $k_0$ that it takes as initial condition and is free to choose $\{ c_t, n_t, k_{t+1} \}_{t=0}^\infty$. -The household's budget constraint {eq}`eq:house_budget` must be bounded in equilibrium due to finite resources. This imposes a restriction on price and tax sequences. +The household's budget constraint {eq}`eq:house_budget` must be bounded in equilibrium due to finite resources. + +This imposes a restriction on price and tax sequences. Specifically, for $t \geq 1$, the terms multiplying $k_t$ must equal zero. @@ -239,7 +202,7 @@ $$ -\lim_{T \to \infty} q_T k_{T+1} = 0. $$ (eq:terminal) -### Firm + Zero-profit conditions for the representative firm impose additional restrictions on equilibrium prices and quantities. @@ -263,13 +226,15 @@ $$(eq:no_arb_firms) ## Household's First Order Condition -Household maximize {eq}`eq:utility` under {eq}`eq:house_budget`. Let $U_1 = \frac{\partial U}{\partial c}, U_2 = \frac{\partial U}{\partial (1-n)} = -\frac{\partial U}{\partial n}.$, we can derive FOC from the Lagrangian +Household maximize {eq}`eq:utility` under {eq}`eq:house_budget`. + +Let $U_1 = \frac{\partial U}{\partial c}, U_2 = \frac{\partial U}{\partial (1-n)} = -\frac{\partial U}{\partial n}.$, we can derive FOC from the Lagrangian $$ \mathcal{L} = \sum_{t=0}^\infty \beta^t U(c_t, 1 - n_t) + \mu \left( \sum_{t=0}^\infty q_t \left[(1 + \tau_{ct})c_t - (1 - \tau_{nt})w_t n_t + \ldots \right] \right), $$ -Hence we have FOC: +First-order necessary conditions for the representative household's problem are $$ \frac{\partial \mathcal{L}}{\partial c_t} = \beta^t U_{1}(c_t, 1 - n_t) - \mu q_t (1 + \tau_{ct}) = 0 @@ -281,7 +246,7 @@ $$ \frac{\partial \mathcal{L}}{\partial n_t} = \beta^t \left(-U_{2t}(c_t, 1 - n_t)\right) - \mu q_t (1 - \tau_{nt}) w_t = 0 $$ (eq:foc_n_1) -Rearranguing {eq}`eq:foc_c_1` and {eq}`eq:foc_n_1`, we have +Rearranging {eq}`eq:foc_c_1` and {eq}`eq:foc_n_1`, we have $$ \begin{aligned} @@ -296,7 +261,7 @@ $$ $$ (eq:foc_n) -Plugging {eq}`eq:foc_c` into {eq}`eq:terminal` by replacing $q_t$, we get terminal condition +Plugging {eq}`eq:foc_c` into {eq}`eq:terminal` and replacing $q_t$, we get terminal condition $$ -\lim_{T \to \infty} \beta^T \frac{U_{1T}}{(1 + \tau_{cT})} k_{T+1} = 0. @@ -304,10 +269,53 @@ $$ (eq:terminal_final) ## Computing Equilibria -To compute an equilibrium we solve a price system $\{q_t, \eta_t, w_t\}$, a budget feasible government policy $\{g_t, \tau_t\} \equiv \{g_t, \tau_{ct}, \tau_{nt}, \tau_{kt}, \tau_{ht}\}$, and an allocation $\{c_t, n_t, k_{t+1}\}$ that solve the system of nonlinear difference equations consisting of +To compute an equilibrium, we seek a price system $\{q_t, \eta_t, w_t\}$, a budget feasible government policy $\{g_t, \tau_t\} \equiv \{g_t, \tau_{ct}, \tau_{nt}, \tau_{kt}, \tau_{ht}\}$, and an allocation $\{c_t, n_t, k_{t+1}\}$ that solve a system of nonlinear difference equations consisting of - feasibility condition {eq}`eq:tech_capital`, no-arbitrage condition for household {eq}`eq:no_arb` and firms {eq}`eq:no_arb_firms`, household's first order conditions {eq}`eq:foc_c` and {eq}`eq:foc_n`. -- initial condition $k_0$, and terminal condition {eq}`eq:terminal_final`. +- an initial condition $k_0$ and a terminal condition {eq}`eq:terminal_final`. + + +## Python Code + + +We require the following imports + +```{code-cell} ipython3 +import numpy as np +from scipy.optimize import root +import matplotlib.pyplot as plt +from collections import namedtuple +from mpmath import mp, mpf +from warnings import warn + +# Set the precision +mp.dps = 40 +mp.pretty = True +``` + +We use the `mpmath` library to perform high-precision arithmetic in the shooting algorithm in cases where the solution diverges due to numerical instability. + +We set the following parameters + +```{code-cell} ipython3 +# Create a namedtuple to store the model parameters +Model = namedtuple("Model", + ["β", "γ", "δ", "α", "A"]) + +def create_model(β=0.95, # discount factor + γ=2.0, # relative risk aversion coefficient + δ=0.2, # depreciation rate + α=0.33, # capital share + A=1.0 # TFP + ): + """Create a model instance.""" + return Model(β=β, γ=γ, δ=δ, α=α, A=A) + +model = create_model() + +# Total number of periods +S = 100 +``` ### Inelastic Labor Supply @@ -347,25 +355,31 @@ u'(c_t) = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} [(1 - \tau \end{aligned} $$ (eq:diff_second) -This equation is instrumental in solving for the equilibrium sequence of consumption and capital, as demonstrated in the second method. + +Equation {eq}`eq:diff_second` will appear prominently in our equilibrium computation algorithms. + ### Steady state -Tax rates and government expenditures act as forcing functions for the difference equations {eq}`eq:feasi_capital` and {eq}`eq:diff_second`. +Tax rates and government expenditures act as **forcing functions** for difference equations {eq}`eq:feasi_capital` and {eq}`eq:diff_second`. -Define $z_t = [g_t, \tau_{kt}, \tau_{ct}]'$. We can express the second-order difference equation as: +Define $z_t = [g_t, \tau_{kt}, \tau_{ct}]'$. + +Represent the second-order difference equation as: $$ H(k_t, k_{t+1}, k_{t+2}; z_t, z_{t+1}) = 0. $$ (eq:second_ord_diff) -We assume that the government policy reaches a steady state such that $\lim_{t \to \infty} z_t = \bar z$ and that the steady state holds for $t > T$. The terminal steady-state capital stock $\bar{k}$ satisfies: +We assume that a government policy reaches a steady state such that $\lim_{t \to \infty} z_t = \bar z$ and that the steady state prevails for $t > T$. + +The terminal steady-state capital stock $\bar{k}$ satisfies: $$ H(\bar{k}, \bar{k}, \bar{k}, \bar{z}, \bar{z}) = 0. $$ -From the difference equation {eq}`eq:diff_second`, we can derive the steady-state condition: +From difference equation {eq}`eq:diff_second`, we can infer a restriction on the steady-state: $$ \begin{aligned} @@ -505,9 +519,9 @@ def compute_rts_path(q_path, S, t): return rts_path ``` -## Specifications of the model +## Some functional forms -In our model, the representative household has the following CRRA preferences over consumption: +We assume that the representative household' period utility has the following CRRA (constant relative risk aversion) form $$ u(c) = \frac{c^{1 - \gamma}}{1 - \gamma} @@ -521,7 +535,7 @@ def u_prime(c, model): return c ** (-model.γ) ``` -By substituting {eq}`eq:gross_rate` into {eq}`eq:diff_second`, we have +By substituting {eq}`eq:gross_rate` into {eq}`eq:diff_second`, we obtain $$ c_{t+1} = c_t \left[ \beta \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{k, t+1})(f'(k_{t+1}) - \delta) + 1 \right] \right]^{\frac{1}{\gamma}} = c_t \left[ \beta \overline{R}_{t+1} \right]^{\frac{1}{\gamma}} @@ -536,7 +550,7 @@ def next_c(c_t, R_bar, model): return c_t * (β * R_bar) ** (1 / γ) ``` -The production function is given by the Cobb-Douglas form with inelastic labor supply: +For the production function we assume a Cobb-Douglas form: $$ F(k, 1) = A k^\alpha @@ -560,9 +574,14 @@ def f_prime(k, model): ## Computation -In the following sections, we will apply two methods to solve the model: the shooting algorithm and residual minimization using the Euler equation {eq}`eq:diff_second` and feasibility condition {eq}`eq:feasi_capital`. +We describe two ways to compute an equilibrium: + + * a shooting algorithm + * a residual-minimization method that focuses on imposing Euler equation {eq}`eq:diff_second` and the feasibility condition {eq}`eq:feasi_capital`. -### Method 1: Shooting Algorithm +### Shooting Algorithm + +This algorithm deploys the following steps. 1. Solve the equation {eq}`eq:diff_second_steady` for the terminal steady-state capital $\bar{k}$ that corresponds to the permanent policy vector $\bar{z}$. @@ -576,6 +595,8 @@ In the following sections, we will apply two methods to solve the model: the sho 6. Adjust $c_0$ iteratively using the bisection method to find a value that ensures $\left| \hat{k}_S - \bar{k} \right| < \epsilon$. +The following code implements these steps. + ```{code-cell} ipython3 # Steady-state calculation def steady_states(model, g_ss, τ_k_ss=0.0): @@ -694,7 +715,7 @@ def run_shooting(shocks, S, model, c0_func=bisection_c0, shooting_func=shooting_ (cf:experiments)= ### Experiments -We will run a series of experiments and analyze the transition path for the equilibrium in each scenario: +Let's run some experiments. 1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10, 2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10, @@ -703,9 +724,9 @@ We will run a series of experiments and analyze the transition path for the equi +++ -Next we prepare the sequence of variables that will be used to initialize the simulation. +To start, we prepare sequences that we'll used to initialize our iterative algorithm. -We will start from the steady state and then apply the shocks at the appropriate time. +We will start from an initial steady state and apply shocks at an the indicated time. ```{code-cell} ipython3 def plot_results(solution, k_ss, c_ss, shocks, shock_param, @@ -746,7 +767,7 @@ def plot_results(solution, k_ss, c_ss, shocks, shock_param, **Experiment 1: Foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 in period 10** -The figure below shows the effect of a foreseen permanent increase in $g$ at $t = T = 10$ that is financed by an increase in lump-sum taxes +The figure below shows consequences of a foreseen permanent increase in $g$ at $t = T = 10$ that is financed by an increase in lump-sum taxes ```{code-cell} ipython3 # Define shocks as a dictionary @@ -778,7 +799,7 @@ plt.tight_layout() plt.show() ``` -We note the following features in the figure +The above figures indicate that an equilibrium **consumption smoothing** mechanism is at work, driven by the representative consumer's preference for smooth consumption paths coming from the curvature of its one-period utility function. - The steady-state value of the capital stock remains unaffected: - This follows from the fact that $g$ disappears from the steady state version of the Euler equation ({eq}`eq:diff_second_steady`). @@ -789,9 +810,9 @@ We note the following features in the figure - Households, caring about the present value rather than the timing of taxes, experience an adverse wealth effect on consumption, leading to an immediate response. - Capital gradually accumulates between time $0$ and $T$ due to increased savings and reduces gradually after time $T$: - - This temporal variation in capital stock smooths consumption over time, driven by the consumption-smoothing motive. + - This temporal variation in capital stock smooths consumption over time, driven by the representative consumer's consumption-smoothing motive. -Let's write the procedures above into a function that runs the solver and draw the plots for a given model +Let's collect the procedures used above into a function that runs the solver and draws plots for a given experiment ```{code-cell} ipython3 :tags: [hide-input] @@ -821,10 +842,12 @@ def experiment_model(shocks, S, model, solver, plot_func, policy_shock, T=40): ``` The following figure compares responses to a foreseen increase in $g$ at $t = 10$ for -two economies, our original economy with $\gamma = 2$, shown in the solid line, and an -otherwise identical economy with $\gamma = 0.2$. +two economies: + + * our original economy with $\gamma = 2$, shown in the solid line, and + * an otherwise identical economy with $\gamma = 0.2$. -The utility curvature parameter $\gamma$ governs the household's willingness to substitute consumption over time +This comparison interest us because the utility curvature parameter $\gamma$ governs the household's willingness to substitute consumption over time, and thus it preferences about smoothness of consumption paths over time. ```{code-cell} ipython3 # Solve the model using shooting @@ -864,18 +887,17 @@ plt.tight_layout() plt.show() ``` -From the graph we can observe that lowering $\gamma$ affects both the consumption and capital stock paths: +The outcomes indicate that lowering $\gamma$ affects both the consumption and capital stock paths because - it increases the representative consumer's willingness to substitute consumption across time: - Consumption path: - - Lowering $\gamma$ increases the willingness to substitute consumption across time. - - In the case of $\gamma = 0.2$, consumption becomes less smooth compared to $\gamma = 2$. + - When $\gamma = 0.2$, consumption becomes less smooth compared to $\gamma = 2$. - For $\gamma = 0.2$, consumption mirrors the government expenditure path more closely, staying higher until $t = 10$. - Capital stock path: - With $\gamma = 0.2$, there are smaller build-ups and drawdowns of capital stock. - - Leads to smaller fluctuations in $\bar{R}$ and $\eta$. + - There are also smaller fluctuations in $\bar{R}$ and $\eta$. -Let's write another function that runs the solver and draw the plots for two models as we did above +Let's write another function that runs the solver and draws plots for these two experiments ```{code-cell} ipython3 :tags: [hide-input] @@ -1003,7 +1025,7 @@ At $t = 0$, the term structure of interest rates exhibits a "U-shaped" pattern: - It declines until maturity at $s = 10$. - After $s = 10$, it increases for longer maturities. -This pattern corresponds to the pattern of consumption growth in the first two figures, +This pattern aligns with the pattern of consumption growth in the first two figures, which declines at an increasing rate until $t = 10$ and then declines at a decreasing rate afterward. +++ @@ -1011,8 +1033,9 @@ which declines at an increasing rate until $t = 10$ and then declines at a decre **Experiment 2: Foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 in period 10** With an inelastic labor supply, the Euler equation {eq}`eq:euler_house` -and the other equilibrium conditions show that constant consumption taxes -do not distort decisions, but that anticipated changes in them do. +and the other equilibrium conditions show that +- constant consumption taxes do not distort decisions, but +- anticipated changes in them do. Indeed, {eq}`eq:euler_house` or {eq}`eq:diff_second` indicates that a foreseen in- crease in $\tau_{ct}$ (i.e., a decrease in $(1+\tau_{ct})$ @@ -1030,7 +1053,7 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'τ_c') ``` -Notice that while all variables in the figure above eventually return to their initial +Evidently all variables in the figures above eventually return to their initial steady-state values. The anticipated increase in $\tau_{ct}$ leads to variations in consumption @@ -1038,15 +1061,15 @@ and capital stock across time: - At $t = 0$: - Anticipation of the increase in $\tau_c$ causes an *immediate jump in consumption*. - - This is followed by a *consumption binge*, which sends the capital stock downward until $t = T = 10$. + - This is followed by a *consumption binge* that sends the capital stock downward until $t = T = 10$. - Between $t = 0$ and $t = T = 10$: - The decline in the capital stock raises $\bar{R}$ over time. - - As per equilibrium conditions, this requires the growth rate of consumption to rise until $t = T$. + - The equilibrium conditions require the growth rate of consumption to rise until $t = T$. - At $t = T = 10$: - The jump in $\tau_c$ depresses $\bar{R}$ below $1$, causing a *sharp drop in consumption*. - After $T = 10$: - - The effects of anticipated distortion are over, and the economy adjusts to the lower capital stock. - - Capital must now rise, requiring *austerity*—consumption plummets after $t = T$ indicated by a lower level of consumption. + - The effects of anticipated distortion are over, and the economy gradually adjusts to the lower capital stock. + - Capital must now rise, requiring *austerity* —consumption plummets after $t = T$, indicated by lower levels of consumption. - The interest rate gradually declines, and consumption grows at a diminishing rate along the path to the terminal steady-state. +++ @@ -1067,16 +1090,17 @@ experiment_two_models(shocks, S, model, model_γ2, run_shooting, plot_results, 'τ_k') ``` -The path of government expenditures remains fixed, and the increase in $\tau_{kt}$ is offset by a reduction in the present value of lump-sum taxes to keep the budget balanced. +The path of government expenditures remains fixed +- the increase in $\tau_{kt}$ is offset by a reduction in the present value of lump-sum taxes to keep the budget balanced. -We note the following features in the figure: +The figure shows that: -- Anticipation of the increase in $\tau_{kt}$ leads to immediate decline in capital stock due to increased current consumption and growing consumption flow. +- Anticipation of the increase in $\tau_{kt}$ leads to immediate decline in capital stock due to increased current consumption and a growing consumption flow. - $\bar{R}$ starts rising at $t = 0$ and peaks at $t = 9$, and at $t = 10$, $\bar{R}$ drops sharply due to the tax change. - - Variations in $\bar{R}$ reflect the impact of the tax increase at $t = 10$ on consumption across time. + - Variations in $\bar{R}$ align with the impact of the tax increase at $t = 10$ on consumption across time. - Transition dynamics push $k_t$ (capital stock) toward a new, lower steady-state level. In the new steady state: - Consumption is lower due to reduced output from the lower capital stock. - - Smoother consumption paths are observed when $\gamma = 2$ compared to $\gamma = 0.2$. + - Smoother consumption paths occur when $\gamma = 2$ than when $\gamma = 0.2$. +++ @@ -1087,7 +1111,7 @@ foreseen one-time change in a policy variable (a "pulse"). **Experiment 4: Foreseen one-time increase in $g$ from 0.2 to 0.4 in period 10, after which $g$ returns to 0.2 forever** -The experiment replicates the Figure 12.9.6. + ```{code-cell} ipython3 g_path = np.repeat(0.2, S + 1) @@ -1102,21 +1126,21 @@ shocks = { experiment_model(shocks, S, model, run_shooting, plot_results, 'g') ``` -We note that such a policy change impacts consumption and capital in an interesting way: +The figure indicates how: - Consumption: - - Drops immediately at the announcement of the policy and continues to decline over time in anticipation of the one-time surge in $g$. + - Drops immediately upon announcement of the policy and continues to decline over time in anticipation of the one-time surge in $g$. - After the shock at $t = 10$, consumption begins to recover, rising at a diminishing rate toward its steady-state value. - Capital and $\bar{R}$: - - Before $t = 10$, capital accumulates as households prepare for the anticipated increase in government spending. - - At $t = 10$, capital stock sharply decreases as the government consumes part of it. + - Before $t = 10$, capital accumulates as interest rate changes induce households to prepare for the anticipated increase in government spending. + - At $t = 10$, the capital stock sharply decreases as the government consumes part of it. - $\bar{R}$ jumps above its steady-state value due to the capital reduction and then gradually declines toward its steady-state level. +++ -### Method 2: Residual Minimization Using the Euler Equation and Feasibility Condition +### Method 2: Residual Minimization -The second method involves minimizing the residuals of the following equations: +The second method involves minimizing residuals (i.e., deviations from equalities) of the following equations: - The Euler equation {eq}`eq:diff_second`: @@ -1149,14 +1173,14 @@ def feasi_residual(k_t, k_tm1, c_tm1, g_t, model): return k_t - (A * k_tm1 ** α + (1 - δ) * k_tm1 - c_tm1 - g_t) ``` -The algorithm is described as follows: +The algorithm proceeds follows: -1. Derive intial steady state $k_0$ based on the government plan at $t=0$. +1. Find initial steady state $k_0$ based on the government plan at $t=0$. 2. Initialize a sequence of initial guesses $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$. -3. Compute the residuals $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: - - Compute the Euler's equation residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: +3. Compute residuals $l_a$ and $l_k$ for $t = 0, \dots, S$, as well as $l_{k_0}$ for $t = 0$ and $l_{k_S}$ for $t = S$: + - Compute the Euler equation residual for $t = 0, \dots, S$ using {eq}`eq:diff_second`: $$ l_{ta} = \beta u'(c_{t+1}) \frac{(1 + \tau_{ct})}{(1 + \tau_{ct+1})} \left[(1 - \tau_{kt+1})(f'(k_{t+1}) - \delta) + 1 \right] - 1 @@ -1168,7 +1192,7 @@ The algorithm is described as follows: l_{tk} = k_{t+1} - f(k_t) - (1 - \delta)k_t + g_t + c_t $$ - - Compute the residual for the*initial condition for $k_0$ using {eq}`eq:diff_second_steady` and the initial capital $k_0$: + - Compute the residual for the initial condition for $k_0$ using {eq}`eq:diff_second_steady` and the initial capital $k_0$: $$ l_{k_0} = 1 - \beta \left[ (1 - \tau_{k0}) \left(f'(k_0) - \delta \right) + 1 \right] @@ -1180,7 +1204,7 @@ The algorithm is described as follows: l_{k_S} = \beta u'(c_S) \frac{(1 + \tau_{cS})}{(1 + \tau_{cS})} \left[(1 - \tau_{kS})(f'(k_S) - \delta) + 1 \right] - 1 $$ -4. Iteratively adjust the guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize the residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. +4. Iteratively adjust guesses for $\{\hat{c}_t, \hat{k}_t\}_{t=0}^{S}$ to minimize residuals $l_{k_0}$, $l_{ta}$, $l_{tk}$, and $l_{k_S}$ for $t = 0, \dots, S$. ```{code-cell} ipython3 # Computing residuals as objective function to minimize @@ -1235,16 +1259,16 @@ def run_min(shocks, S, model): return sol.x.reshape((S + 1, 2)) ``` -This method does not have numerical stability issues, so `mp.mpf` is not necessary. +We found that method 2 did not encounter numerical stability issues, so using `mp.mpf` is not necessary. -We leave the experiments for you to replicate using the second method. +We leave as exercises replicating some of our experiments by using the second method. ## Exercises ```{exercise} :label: cass_fiscal_ex1 -Replicate the plots of the four experiments we run before using the second method of residual minimization: +Replicate the plots of our four experiments using the second method of residual minimization: 1. A foreseen once-and-for-all increase in $g$ from 0.2 to 0.4 occurring in period 10, 2. A foreseen once-and-for-all increase in $\tau_c$ from 0.0 to 0.2 occurring in period 10, 3. A foreseen once-and-for-all increase in $\tau_k$ from 0.0 to 0.2 occurring in period 10, and From 0077cda15f768db1391df4ef92ced9886b7a38d1 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sat, 4 Jan 2025 13:25:12 +1100 Subject: [PATCH 15/17] install sphinx-proof for google collab compat --- lectures/cass_fiscal.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 55b6dcf8f..709e78db3 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -13,6 +13,14 @@ kernelspec: # Cass-Koopmans Model with Distorting Taxes + +```{code-cell} ipython +--- +tags: [remove-cell] +--- +!pip install sphinx-proof +``` + ## Overview This lecture studies effects of foreseen fiscal and technology shocks on competitive equilibrium prices and quantities in a nonstochastic version of a Cass-Koopmans growth model with features described in this QuantEcon lecture {doc}`cass_koopmans_2`. From 268fbb951d084de7b4e6fbb578ff8276aef3c582 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sat, 4 Jan 2025 13:40:21 +1100 Subject: [PATCH 16/17] Revert "install sphinx-proof for google collab compat" This reverts commit 0077cda15f768db1391df4ef92ced9886b7a38d1. --- lectures/cass_fiscal.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lectures/cass_fiscal.md b/lectures/cass_fiscal.md index 709e78db3..55b6dcf8f 100644 --- a/lectures/cass_fiscal.md +++ b/lectures/cass_fiscal.md @@ -13,14 +13,6 @@ kernelspec: # Cass-Koopmans Model with Distorting Taxes - -```{code-cell} ipython ---- -tags: [remove-cell] ---- -!pip install sphinx-proof -``` - ## Overview This lecture studies effects of foreseen fiscal and technology shocks on competitive equilibrium prices and quantities in a nonstochastic version of a Cass-Koopmans growth model with features described in this QuantEcon lecture {doc}`cass_koopmans_2`. From 6e17aedd90b42486b08c29b751cf3fa065c6a982 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sat, 4 Jan 2025 13:40:53 +1100 Subject: [PATCH 17/17] add sphinx-proof to collab env --- .github/workflows/collab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/collab.yml b/.github/workflows/collab.yml index 7644ff087..1fc3827f4 100644 --- a/.github/workflows/collab.yml +++ b/.github/workflows/collab.yml @@ -32,7 +32,7 @@ jobs: - name: Install Build Software shell: bash -l {0} run: | - pip install jupyter-book==0.15.1 docutils==0.17.1 quantecon-book-theme==0.7.2 sphinx-tojupyter==0.3.0 sphinxext-rediraffe==0.2.7 sphinx-reredirects sphinx-exercise==0.4.1 sphinxcontrib-youtube==1.1.0 sphinx-togglebutton==0.3.1 arviz==0.13.0 + pip install jupyter-book==0.15.1 docutils==0.17.1 quantecon-book-theme==0.7.2 sphinx-tojupyter==0.3.0 sphinxext-rediraffe==0.2.7 sphinx-reredirects sphinx-exercise==0.4.1 sphinxcontrib-youtube==1.1.0 sphinx-togglebutton==0.3.1 arviz==0.13.0 sphinx-proof # Build of HTML (Execution Testing) - name: Build HTML shell: bash -l {0}