From 39441a58ae9c7295264b755ec30a79f5da51b4b4 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 09:43:41 +1100 Subject: [PATCH 01/15] update cons_smooth --- lectures/cons_smooth.md | 218 ++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 2719baa8..15700e67 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -48,7 +48,7 @@ from collections import namedtuple ``` -The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{y_t\}_{t=0}^T$ of non-financial income and chooses a consumption stream $\{c_t\}_{t=0}^T$. +The model describes a consumer who lives from time $t=0, 1, \ldots, S$, receives a stream $\{y_t\}_{t=0}^S$ of non-financial income and chooses a consumption stream $\{T_t\}_{t=0}^S$. We usually think of the non-financial income stream as coming from the person's salary from supplying labor. @@ -58,45 +58,45 @@ The consumer faces a gross interest rate of $R >1$ that is constant over time, a To set up the model, let - * $T \geq 2$ be a positive integer that constitutes a time-horizon. - * $y = \{y_t\}_{t=0}^T$ be an exogenous sequence of non-negative non-financial incomes $y_t$. - * $a = \{a_t\}_{t=0}^{T+1}$ be a sequence of financial wealth. - * $c = \{c_t\}_{t=0}^T$ be a sequence of non-negative consumption rates. + * $S \geq 2$ be a positive integer that constitutes a time-horizon. + * $G = \{G_t\}_{t=0}^S$ be an exogenous sequence of non-negative non-financial incomes $G_t$. + * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of financial wealth. + * $T = \{T_t\}_{t=0}^S$ be a sequence of non-negative consumption rates. * $R \geq 1$ be a fixed gross one period rate of return on financial assets. * $\beta \in (0,1)$ be a fixed discount factor. * $a_0$ be a given initial level of financial assets - * $a_{T+1} \geq 0$ be a terminal condition on final assets. + * $B_{S+1} \geq 0$ be a terminal condition on final assets. The sequence of financial wealth $a$ is to be determined by the model. We require it to satisfy two **boundary conditions**: * it must equal an exogenous value $a_0$ at time $0$ - * it must equal or exceed an exogenous value $a_{T+1}$ at time $T+1$. + * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. -The **terminal condition** $a_{T+1} \geq 0$ requires that the consumer not leave the model in debt. +The **terminal condition** $B_{S+1} \geq 0$ requires that the consumer not leave the model in debt. (We'll soon see that a utility maximizing consumer won't want to die leaving positive assets, so she'll arrange her affairs to make -$a_{T+1} = 0$.) +$B_{S+1} = 0$.) -The consumer faces a sequence of budget constraints that constrains sequences $(y, c, a)$ +The consumer faces a sequence of budget constraints that constrains sequences $(G, T, B)$ $$ -a_{t+1} = R (a_t+ y_t - c_t), \quad t =0, 1, \ldots T -$$ (eq:a_t) +B_{t+1} = R (B_t+ G_t - T_t), \quad t =0, 1, \ldots S +$$ (eq:B_t) -Equations {eq}`eq:a_t` constitute $T+1$ such budget constraints, one for each $t=0, 1, \ldots, T$. +Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. -Given a sequence $y$ of non-financial incomes, a large set of pairs $(a, c)$ of (financial wealth, consumption) sequences satisfy the sequence of budget constraints {eq}`eq:a_t`. +Given a sequence $G$ of non-financial incomes, a large set of pairs $(a, c)$ of (financial wealth, consumption) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. Our model has the following logical flow. - * start with an exogenous non-financial income sequence $y$, an initial financial wealth $a_0$, and + * start with an exogenous non-financial income sequence $G$, an initial financial wealth $a_0$, and a candidate consumption path $c$. - * use the system of equations {eq}`eq:a_t` for $t=0, \ldots, T$ to compute a path $a$ of financial wealth + * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $a$ of financial wealth - * verify that $a_{T+1}$ satisfies the terminal wealth constraint $a_{T+1} \geq 0$. + * verify that $B_{S+1}$ satisfies the terminal wealth constraint $B_{S+1} \geq 0$. * If it does, declare that the candidate path is **budget feasible**. @@ -105,7 +105,7 @@ Our model has the following logical flow. Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. The above procedure seems like a sensible way to find "budget-feasible" consumption paths $c$, i.e., paths that are consistent -with the exogenous non-financial income stream $y$, the initial financial asset level $a_0$, and the terminal asset level $a_{T+1}$. +with the exogenous non-financial income stream $G$, the initial financial asset level $a_0$, and the terminal asset level $B_{S+1}$. In general, there are **many** budget feasible consumption paths $c$. @@ -117,12 +117,12 @@ To answer this question, we shall eventually evaluate alternative budget feasibl ```{math} :label: welfare -W = \sum_{t=0}^T \beta^t (g_1 c_t - \frac{g_2}{2} c_t^2 ) +W = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) ``` where $g_1 > 0, g_2 > 0$. -When $\beta R \approx 1$, the fact that the utility function $g_1 c_t - \frac{g_2}{2} c_t^2$ has diminishing marginal utility imparts a preference for consumption that is very smooth. +When $\beta R \approx 1$, the fact that the utility function $g_1 T_t - \frac{g_2}{2} T_t^2$ has diminishing marginal utility imparts a preference for consumption that is very smooth. Indeed, we shall see that when $\beta R = 1$ (a condition assumed by Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`), criterion {eq}`welfare` assigns higher welfare to smoother consumption paths. @@ -132,19 +132,19 @@ The preference for smooth consumption paths that is built into the model gives i Let's dive in and do some calculations that will help us understand how the model works. -Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $T = 65$. +Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. We create a Python **namedtuple** to store these parameters with default values. ```{code-cell} ipython3 ConsumptionSmoothing = namedtuple("ConsumptionSmoothing", - ["R", "g1", "g2", "β_seq", "T"]) + ["R", "g1", "g2", "β_seq", "S"]) -def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, T=65): +def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): β = 1/R - β_seq = np.array([β**i for i in range(T+1)]) + β_seq = np.array([β**i for i in range(S+1)]) return ConsumptionSmoothing(R, g1, g2, - β_seq, T) + β_seq, S) ``` @@ -154,26 +154,26 @@ A key object is what Milton Friedman called "human" or "non-financial" wealth at $$ -h_0 \equiv \sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix} -\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix} +h_0 \equiv \sum_{t=0}^S R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_S \end{bmatrix} $$ -Human or non-financial wealth at time $0$ is evidently just the present value of the consumer's non-financial income stream $y$. +Human or non-financial wealth at time $0$ is evidently just the present value of the consumer's non-financial income stream $G$. Formally it very much resembles the asset price that we computed in this QuantEcon lecture {doc}`present values `. Indeed, this is why Milton Friedman called it "human capital". -By iterating on equation {eq}`eq:a_t` and imposing the terminal condition +By iterating on equation {eq}`eq:B_t` and imposing the terminal condition $$ -a_{T+1} = 0, +B_{S+1} = 0, $$ -it is possible to convert a sequence of budget constraints {eq}`eq:a_t` into a single intertemporal constraint +it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a single intertemporal constraint $$ -\sum_{t=0}^T R^{-t} c_t = a_0 + h_0. +\sum_{t=0}^S R^{-t} T_t = a_0 + h_0. $$ (eq:budget_intertemp) Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of financial and non-financial (or human) wealth. @@ -181,7 +181,7 @@ Equation {eq}`eq:budget_intertemp` says that the present value of the consumpti Robert Hall {cite}`Hall1978` showed that when $\beta R = 1$, a condition Milton Friedman had also assumed, it is "optimal" for a consumer to smooth consumption by setting $$ -c_t = c_0 \quad t =0, 1, \ldots, T +T_t = T_0 \quad t =0, 1, \ldots, S $$ (Later we'll present a "variational argument" that shows that this constant path maximizes @@ -190,7 +190,7 @@ criterion {eq}`welfare` when $\beta R =1$.) In this case, we can use the intertemporal budget constraint to write $$ -c_t = c_0 = \left(\sum_{t=0}^T R^{-t}\right)^{-1} (a_0 + h_0), \quad t= 0, 1, \ldots, T. +T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (a_0 + h_0), \quad t= 0, 1, \ldots, S. $$ (eq:conssmoothing) Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell. @@ -204,24 +204,24 @@ In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1. ### Step 1 -For a $(T+1) \times 1$ vector $y$, use matrix algebra to compute $h_0$ +For a $(S+1) \times 1$ vector $G$, use matrix algebra to compute $h_0$ $$ -h_0 = \sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix} -\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix} +h_0 = \sum_{t=0}^S R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_S \end{bmatrix} $$ ### Step 2 -Compute an time $0$ consumption $c_0 $ : +Compute an time $0$ consumption $T_0 $ : $$ -c_t = c_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(T+1)}} \right) (a_0 + \sum_{t=0}^T R^{-t} y_t ) , \quad t = 0, 1, \ldots, T +T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (a_0 + \sum_{t=0}^S R^{-t} y_t ) , \quad t = 0, 1, \ldots, S $$ ### Step 3 -Use the system of equations {eq}`eq:a_t` for $t=0, \ldots, T$ to compute a path $a$ of financial wealth. +Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $a$ of financial wealth. To do this, we translate that system of difference equations into a single matrix equation as follows: @@ -235,25 +235,25 @@ $$ 0 & 0 & 0 & \cdots & -R & 1 & 0 \cr 0 & 0 & 0 & \cdots & 0 & -R & 1 \end{bmatrix} -\begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1} +\begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_S \cr B_{S+1} \end{bmatrix} = R -\begin{bmatrix} y_0 + a_0 - c_0 \cr y_1 - c_0 \cr y_2 - c_0 \cr \vdots\cr y_{T-1} - c_0 \cr y_T - c_0 +\begin{bmatrix} y_0 + a_0 - T_0 \cr y_1 - T_0 \cr y_2 - T_0 \cr \vdots\cr y_{S-1} - T_0 \cr y_S - T_0 \end{bmatrix} $$ Multiply both sides by the inverse of the matrix on the left side to compute $$ - \begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1} \end{bmatrix} + \begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_S \cr B_{S+1} \end{bmatrix} $$ Because we have built into our calculations that the consumer leaves the model with exactly zero assets, just barely satisfying the -terminal condition that $a_{T+1} \geq 0$, it should turn out that +terminal condition that $B_{S+1} \geq 0$, it should turn out that $$ -a_{T+1} = 0. +B_{S+1} = 0. $$ @@ -263,31 +263,31 @@ First we implement the model with `compute_optimal` ```{code-cell} ipython3 def compute_optimal(model, a0, y_seq): - R, T = model.R, model.T + R, S = model.R, model.S # non-financial wealth h0 = model.β_seq @ y_seq # since β = 1/R # c0 - c0 = (1 - 1/R) / (1 - (1/R)**(T+1)) * (a0 + h0) - c_seq = c0*np.ones(T+1) + c0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (a0 + h0) + T_seq = c0*np.ones(S+1) # verify - A = np.diag(-R*np.ones(T), k=-1) + np.eye(T+1) - b = y_seq - c_seq + A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) + b = y_seq - T_seq b[0] = b[0] + a0 a_seq = np.linalg.inv(A) @ b a_seq = np.concatenate([[a0], a_seq]) - return c_seq, a_seq, h0 + return T_seq, a_seq, h0 ``` We use an example where the consumer inherits $a_0<0$. This can be interpreted as a student debt. -The non-financial process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward. +The non-financial process $\{y_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then becomes zero afterward. The drop in non-financial income late in life reflects retirement from work. @@ -299,9 +299,9 @@ a0 = -2 # such as "student debt" y_seq = np.concatenate([np.ones(46), np.zeros(20)]) cs_model = create_consumption_smoothing_model() -c_seq, a_seq, h0 = compute_optimal(cs_model, a0, y_seq) +T_seq, a_seq, h0 = compute_optimal(cs_model, a0, y_seq) -print('check a_T+1=0:', +print('check a_S+1=0:', np.abs(a_seq[-1] - 0) <= 1e-8) ``` @@ -309,31 +309,31 @@ The graphs below show paths of non-financial income, consumption, and financia ```{code-cell} ipython3 # Sequence Length -T = cs_model.T +S = cs_model.S -plt.plot(range(T+1), y_seq, label='non-financial income') -plt.plot(range(T+1), c_seq, label='consumption') -plt.plot(range(T+2), a_seq, label='financial wealth') -plt.plot(range(T+2), np.zeros(T+2), '--') +plt.plot(range(S+1), y_seq, label='non-financial income') +plt.plot(range(S+1), T_seq, label='consumption') +plt.plot(range(S+2), a_seq, label='financial wealth') +plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$c_t,y_t,a_t$') +plt.ylabel(r'$T_t,y_t,B_t$') plt.show() ``` -Note that $a_{T+1} = 0$, as anticipated. +Note that $B_{S+1} = 0$, as anticipated. We can evaluate welfare criterion {eq}`welfare` ```{code-cell} ipython3 -def welfare(model, c_seq): +def welfare(model, T_seq): β_seq, g1, g2 = model.β_seq, model.g1, model.g2 - u_seq = g1 * c_seq - g2/2 * c_seq**2 + u_seq = g1 * T_seq - g2/2 * T_seq**2 return β_seq @ u_seq -print('Welfare:', welfare(cs_model, c_seq)) +print('Welfare:', welfare(cs_model, T_seq)) ``` ### Experiments @@ -351,20 +351,20 @@ def plot_cs(model, # consumption-smoothing model ): # Compute optimal consumption - c_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) + T_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) # Sequence length - T = cs_model.T + S = cs_model.S # Generate plot - plt.plot(range(T+1), y_seq, label='non-financial income') - plt.plot(range(T+1), c_seq, label='consumption') - plt.plot(range(T+2), a_seq, label='financial wealth') - plt.plot(range(T+2), np.zeros(T+2), '--') + plt.plot(range(S+1), y_seq, label='non-financial income') + plt.plot(range(S+1), T_seq, label='consumption') + plt.plot(range(S+2), a_seq, label='financial wealth') + plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() plt.xlabel(r'$t$') - plt.ylabel(r'$c_t,y_t,a_t$') + plt.ylabel(r'$T_t,y_t,B_t$') plt.show() ``` @@ -372,7 +372,7 @@ In the experiments below, please study how consumption and financial asset seque #### Experiment 1: one-time gain/loss -We first assume a one-time windfall of $W_0$ in year 21 of the income sequence $y$. +We first assume a one-time windfall of $W_0$ in year 21 of the income sequence $G$. We'll make $W_0$ big - positive to indicate a one-time windfall, and negative to indicate a one-time "disaster". @@ -392,7 +392,7 @@ plot_cs(cs_model, a0, y_seq_neg) #### Experiment 2: permanent wage gain/loss -Now we assume a permanent increase in income of $W$ in year 21 of the $y$-sequence. +Now we assume a permanent increase in income of $W$ in year 21 of the $G$-sequence. Again we can study positive and negative cases @@ -414,7 +414,7 @@ plot_cs(cs_model, a0, y_seq_neg) #### Experiment 3: a late starter -Now we simulate a $y$ sequence in which a person gets zero for 46 years, and then works and gets 1 for the last 20 years of life (a "late starter") +Now we simulate a $G$ sequence in which a person gets zero for 46 years, and then works and gets 1 for the last 20 years of life (a "late starter") ```{code-cell} ipython3 # Late starter @@ -426,7 +426,7 @@ plot_cs(cs_model, a0, y_seq_late) #### Experiment 4: geometric earner -Now we simulate a geometric $y$ sequence in which a person gets $y_t = \lambda^t y_0$ in first 46 years. +Now we simulate a geometric $G$ sequence in which a person gets $y_t = \lambda^t y_0$ in first 46 years. We first experiment with $\lambda = 1.05$ @@ -436,7 +436,7 @@ We first experiment with $\lambda = 1.05$ y_0 = 1 t_max = 46 -# Generate geometric y sequence +# Generate geometric G sequence geo_seq = λ ** np.arange(t_max) * y_0 y_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) @@ -471,7 +471,7 @@ plot_cs(cs_model, a0, y_seq_geo) ### Feasible consumption variations -We promised to justify our claim that a constant consumption play $c_t = c_0$ for all +We promised to justify our claim that a constant consumption play $T_t = T_0$ for all $t$ is optimal. Let's do that now. @@ -480,11 +480,11 @@ The approach we'll take is an elementary example of the "calculus of variatio Let's dive in and see what the key idea is. -To explore what types of consumption paths are welfare-improving, we shall create an **admissible consumption path variation sequence** $\{v_t\}_{t=0}^T$ +To explore what types of consumption paths are welfare-improving, we shall create an **admissible consumption path variation sequence** $\{v_t\}_{t=0}^S$ that satisfies $$ -\sum_{t=0}^T R^{-t} v_t = 0 +\sum_{t=0}^S R^{-t} v_t = 0 $$ This equation says that the **present value** of admissible consumption path variations must be zero. @@ -507,25 +507,25 @@ Let's compute that function. We require $$ -\sum_{t=0}^T R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 +\sum_{t=0}^S R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 $$ which implies that $$ -\xi_1 \sum_{t=0}^T \phi_t R^{-t} - \xi_0 \sum_{t=0}^T R^{-t} = 0 +\xi_1 \sum_{t=0}^S \phi_t R^{-t} - \xi_0 \sum_{t=0}^S R^{-t} = 0 $$ which implies that $$ -\xi_1 \frac{1 - (\phi R^{-1})^{T+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(T+1)}}{1-R^{-1} } =0 +\xi_1 \frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(S+1)}}{1-R^{-1} } =0 $$ which implies that $$ -\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(T+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{T+1}}{1 - \phi R^{-1}}\right) +\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(S+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}}\right) $$ This is our formula for $\xi_0$. @@ -540,16 +540,16 @@ Now let's compute and plot consumption path variations ```{code-cell} ipython3 def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): - R, T, β_seq = model.R, model.T, model.β_seq + R, S, β_seq = model.R, model.S, model.β_seq - ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(T+1))) * ((1 - (ϕ/R)**(T+1)) / (1 - ϕ/R)) - v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(T+1)]) + ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(S+1))) * ((1 - (ϕ/R)**(S+1)) / (1 - ϕ/R)) + v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(S+1)]) if verbose == 1: print('check feasible:', np.isclose(β_seq @ v_seq, 0)) # since β = 1/R - c_opt, _, _ = compute_optimal(model, a0, y_seq) - cvar_seq = c_opt + v_seq + T_opt, _, _ = compute_optimal(model, a0, y_seq) + cvar_seq = T_opt + v_seq return cvar_seq ``` @@ -564,7 +564,7 @@ fig, ax = plt.subplots() ϕs= [.95, 1.02] colors = {.01: 'tab:blue', .05: 'tab:green'} -params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) +params = np.array(np.meshgrid(ξ1s, ϕs)).S.reshape(-1, 2) for i, param in enumerate(params): ξ1, ϕ = param @@ -578,16 +578,16 @@ for i, param in enumerate(params): ls = '-.' else: ls = '-' - ax.plot(range(T+1), cvar_seq, ls=ls, + ax.plot(range(S+1), cvar_seq, ls=ls, color=colors[ξ1], label=fr'$\xi_1 = {ξ1}, \phi = {ϕ}$') -plt.plot(range(T+1), c_seq, +plt.plot(range(S+1), T_seq, color='orange', label=r'Optimal $\vec{c}$ ') plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$c_t$') +plt.ylabel(r'$T_t$') plt.show() ``` @@ -675,21 +675,21 @@ We'll conclude this lecture by giving a couple of examples. We'll describe a useful way of representing and "solving" linear difference equations. -To generate some $y$ vectors, we'll just write down a linear difference equation +To generate some $G$ vectors, we'll just write down a linear difference equation with appropriate initial conditions and then use linear algebra to solve it. ### First-order difference equation -We'll start with a first-order linear difference equation for $\{y_t\}_{t=0}^T$: +We'll start with a first-order linear difference equation for $\{G_t\}_{t=0}^S$: $$ -y_{t} = \lambda y_{t-1}, \quad t = 1, 2, \ldots, T +G_{t} = \lambda G_{t-1}, \quad t = 1, 2, \ldots, S $$ -where $y_0$ is a given initial condition. +where $G_0$ is a given initial condition. -We can cast this set of $T$ equations as a single matrix equation +We can cast this set of $S$ equations as a single matrix equation $$ \begin{bmatrix} @@ -700,11 +700,11 @@ $$ 0 & 0 & 0 & \cdots & -\lambda & 1 \end{bmatrix} \begin{bmatrix} -y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} = \begin{bmatrix} -\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} $$ (eq:first_order_lin_diff) @@ -715,7 +715,7 @@ Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the :label: fst_ord_inverse \begin{bmatrix} -y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} = \begin{bmatrix} @@ -723,10 +723,10 @@ y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \lambda & 1 & 0 & \cdots & 0 & 0 \cr \lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & \lambda & 1 +\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 \end{bmatrix} \begin{bmatrix} -\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} ``` @@ -741,7 +741,7 @@ $$ \lambda & 1 & 0 & \cdots & 0 & 0 \cr \lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & \lambda & 1 +\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 \end{bmatrix} $$ @@ -751,15 +751,15 @@ is the inverse of $A$ and check that $A A^{-1} = I$ ### Second-order difference equation -A second-order linear difference equation for $\{y_t\}_{t=0}^T$ is +A second-order linear difference equation for $\{G_t\}_{t=0}^S$ is $$ -y_{t} = \lambda_1 y_{t-1} + \lambda_2 y_{t-2}, \quad t = 1, 2, \ldots, T +G_{t} = \lambda_1 G_{t-1} + \lambda_2 G_{t-2}, \quad t = 1, 2, \ldots, S $$ -where now $y_0$ and $y_{-1}$ are two given initial equations determined outside the model. +where now $G_0$ and $G_{-1}$ are two given initial equations determined outside the model. -As we did with the first-order difference equation, we can cast this set of $T$ equations as a single matrix equation +As we did with the first-order difference equation, we can cast this set of $S$ equations as a single matrix equation $$ \begin{bmatrix} @@ -770,11 +770,11 @@ $$ 0 & 0 & 0 & \cdots & -\lambda_2 & -\lambda_1 & 1 \end{bmatrix} \begin{bmatrix} -y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} = \begin{bmatrix} -\lambda_1 y_0 + \lambda_2 y_{-1} \cr \lambda_2 y_0 \cr 0 \cr \vdots \cr 0 +\lambda_1 G_0 + \lambda_2 G_{-1} \cr \lambda_2 G_0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} $$ From 7e339fd2f94b195950fa67ed473850c520e9d011 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 14:23:26 +1100 Subject: [PATCH 02/15] change names --- lectures/cons_smooth.md | 170 +++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 89 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 7c42227b..7692148e 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -4,14 +4,13 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 + jupytext_version: 1.16.6 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- - # Consumption Smoothing ## Overview @@ -47,8 +46,7 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` - -The model describes a consumer who lives from time $t=0, 1, \ldots, S$, receives a stream $\{y_t\}_{t=0}^S$ of non-financial income and chooses a consumption stream $\{T_t\}_{t=0}^S$. +The model describes a consumer who lives from time $t=0, 1, \ldots, S$, receives a stream $\{G_t\}_{t=0}^S$ of non-financial income and chooses a consumption stream $\{T_t\}_{t=0}^S$. We usually think of the non-financial income stream as coming from the person's salary from supplying labor. @@ -59,19 +57,19 @@ The consumer faces a gross interest rate of $R >1$ that is constant over time, a To set up the model, let * $S \geq 2$ be a positive integer that constitutes a time-horizon. - * $G = \{G_t\}_{t=0}^S$ be an exogenous sequence of non-negative non-financial incomes $G_t$. - * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of financial wealth. - * $T = \{T_t\}_{t=0}^S$ be a sequence of non-negative consumption rates. - * $R \geq 1$ be a fixed gross one period rate of return on financial assets. + * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. + * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of government debt. + * $T = \{T_t\}_{t=0}^S$ be a sequence of tax collections. + * $R \geq 1$ be a fixed gross one period interest rate. * $\beta \in (0,1)$ be a fixed discount factor. - * $a_0$ be a given initial level of financial assets - * $B_{S+1} \geq 0$ be a terminal condition on final assets. + * $B_0$ be a given initial level of government debt + * $B_{S+1} \geq 0$ be a terminal condition on final government debt. The sequence of financial wealth $a$ is to be determined by the model. We require it to satisfy two **boundary conditions**: - * it must equal an exogenous value $a_0$ at time $0$ + * it must equal an exogenous value $B_0$ at time $0$ * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. The **terminal condition** $B_{S+1} \geq 0$ requires that the consumer not leave the model in debt. @@ -91,7 +89,7 @@ Given a sequence $G$ of non-financial incomes, a large set of pairs $(a, c)$ of Our model has the following logical flow. - * start with an exogenous non-financial income sequence $G$, an initial financial wealth $a_0$, and + * start with an exogenous non-financial income sequence $G$, an initial financial wealth $B_0$, and a candidate consumption path $c$. * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $a$ of financial wealth @@ -105,7 +103,7 @@ Our model has the following logical flow. Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. The above procedure seems like a sensible way to find "budget-feasible" consumption paths $c$, i.e., paths that are consistent -with the exogenous non-financial income stream $G$, the initial financial asset level $a_0$, and the terminal asset level $B_{S+1}$. +with the exogenous non-financial income stream $G$, the initial financial asset level $B_0$, and the terminal asset level $B_{S+1}$. In general, there are **many** budget feasible consumption paths $c$. @@ -117,7 +115,7 @@ To answer this question, we shall eventually evaluate alternative budget feasibl ```{math} :label: welfare -W = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) ``` where $g_1 > 0, g_2 > 0$. @@ -137,25 +135,24 @@ Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. We create a Python **namedtuple** to store these parameters with default values. ```{code-cell} ipython3 -ConsumptionSmoothing = namedtuple("ConsumptionSmoothing", +TaxSmoothing = namedtuple("TaxSmoothing", ["R", "g1", "g2", "β_seq", "S"]) -def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): +def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): β = 1/R β_seq = np.array([β**i for i in range(S+1)]) - return ConsumptionSmoothing(R, g1, g2, + return TaxSmoothing(R, g1, g2, β_seq, S) ``` - ## Friedman-Hall consumption-smoothing model A key object is what Milton Friedman called "human" or "non-financial" wealth at time $0$: $$ -h_0 \equiv \sum_{t=0}^S R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} -\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_S \end{bmatrix} +h_0 \equiv \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} $$ Human or non-financial wealth at time $0$ is evidently just the present value of the consumer's non-financial income stream $G$. @@ -173,7 +170,7 @@ $$ it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a single intertemporal constraint $$ -\sum_{t=0}^S R^{-t} T_t = a_0 + h_0. +\sum_{t=0}^S R^{-t} T_t = B_0 + h_0. $$ (eq:budget_intertemp) Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of financial and non-financial (or human) wealth. @@ -190,7 +187,7 @@ criterion {eq}`welfare` when $\beta R =1$.) In this case, we can use the intertemporal budget constraint to write $$ -T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (a_0 + h_0), \quad t= 0, 1, \ldots, S. +T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (B_0 + h_0), \quad t= 0, 1, \ldots, S. $$ (eq:conssmoothing) Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell. @@ -207,8 +204,8 @@ In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1. For a $(S+1) \times 1$ vector $G$, use matrix algebra to compute $h_0$ $$ -h_0 = \sum_{t=0}^S R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} -\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_S \end{bmatrix} +h_0 = \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} $$ ### Step 2 @@ -216,7 +213,7 @@ $$ Compute an time $0$ consumption $T_0 $ : $$ -T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (a_0 + \sum_{t=0}^S R^{-t} y_t ) , \quad t = 0, 1, \ldots, S +T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (B_0 + \sum_{t=0}^S R^{-t} G_t ) , \quad t = 0, 1, \ldots, S $$ ### Step 3 @@ -235,17 +232,17 @@ $$ 0 & 0 & 0 & \cdots & -R & 1 & 0 \cr 0 & 0 & 0 & \cdots & 0 & -R & 1 \end{bmatrix} -\begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_S \cr B_{S+1} +\begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} = R -\begin{bmatrix} y_0 + a_0 - T_0 \cr y_1 - T_0 \cr y_2 - T_0 \cr \vdots\cr y_{S-1} - T_0 \cr y_S - T_0 +\begin{bmatrix} G_0 + B_0 - T_0 \cr G_1 - T_0 \cr G_2 - T_0 \cr \vdots\cr G_{S-1} - T_0 \cr G_S - T_0 \end{bmatrix} $$ Multiply both sides by the inverse of the matrix on the left side to compute $$ - \begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_S \cr B_{S+1} \end{bmatrix} + \begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} $$ @@ -262,47 +259,47 @@ Let's verify this with Python code. First we implement the model with `compute_optimal` ```{code-cell} ipython3 -def compute_optimal(model, a0, y_seq): +def compute_optimal(model, B0, G_seq): R, S = model.R, model.S # non-financial wealth - h0 = model.β_seq @ y_seq # since β = 1/R + h0 = model.β_seq @ G_seq # since β = 1/R # c0 - c0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (a0 + h0) + c0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) T_seq = c0*np.ones(S+1) # verify A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) - b = y_seq - T_seq - b[0] = b[0] + a0 + b = G_seq - T_seq + b[0] = b[0] + B0 - a_seq = np.linalg.inv(A) @ b - a_seq = np.concatenate([[a0], a_seq]) + B_seq = np.linalg.inv(A) @ b + B_seq = np.concatenate([[B0], B_seq]) - return T_seq, a_seq, h0 + return T_seq, B_seq, h0 ``` -We use an example where the consumer inherits $a_0<0$. +We use an example where the consumer inherits $B_0<0$. This can be interpreted as a student debt. -The non-financial process $\{y_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then becomes zero afterward. +The non-financial process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then becomes zero afterward. The drop in non-financial income late in life reflects retirement from work. ```{code-cell} ipython3 # Financial wealth -a0 = -2 # such as "student debt" +B0 = -2 # such as "student debt" # non-financial Income process -y_seq = np.concatenate([np.ones(46), np.zeros(20)]) +G_seq = np.concatenate([np.ones(46), np.zeros(20)]) -cs_model = create_consumption_smoothing_model() -T_seq, a_seq, h0 = compute_optimal(cs_model, a0, y_seq) +cs_model = create_tax_smoothing_model() +T_seq, B_seq, h0 = compute_optimal(cs_model, B0, G_seq) -print('check a_S+1=0:', - np.abs(a_seq[-1] - 0) <= 1e-8) +print('check B_S+1=0:', + np.abs(B_seq[-1] - 0) <= 1e-8) ``` The graphs below show paths of non-financial income, consumption, and financial assets. @@ -311,14 +308,14 @@ The graphs below show paths of non-financial income, consumption, and financia # Sequence Length S = cs_model.S -plt.plot(range(S+1), y_seq, label='non-financial income') +plt.plot(range(S+1), G_seq, label='non-financial income') plt.plot(range(S+1), T_seq, label='consumption') -plt.plot(range(S+2), a_seq, label='financial wealth') +plt.plot(range(S+2), B_seq, label='financial wealth') plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$T_t,y_t,B_t$') +plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` @@ -346,25 +343,25 @@ This will help us avoid rewriting code to plot outcomes for different non-finan ```{code-cell} ipython3 def plot_cs(model, # consumption-smoothing model - a0, # initial financial wealth - y_seq # non-financial income process + B0, # initial financial wealth + G_seq # non-financial income process ): # Compute optimal consumption - T_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) + T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) # Sequence length S = cs_model.S # Generate plot - plt.plot(range(S+1), y_seq, label='non-financial income') + plt.plot(range(S+1), G_seq, label='non-financial income') plt.plot(range(S+1), T_seq, label='consumption') - plt.plot(range(S+2), a_seq, label='financial wealth') + plt.plot(range(S+2), B_seq, label='financial wealth') plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() plt.xlabel(r'$t$') - plt.ylabel(r'$T_t,y_t,B_t$') + plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` @@ -378,38 +375,38 @@ We'll make $W_0$ big - positive to indicate a one-time windfall, and negative to ```{code-cell} ipython3 # Windfall W_0 = 2.5 -y_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) +G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_pos) +plot_cs(cs_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 # Disaster W_0 = -2.5 -y_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) +G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_neg) +plot_cs(cs_model, B0, G_seq_neg) ``` #### Experiment 2: permanent wage gain/loss -Now we assume a permanent increase in income of $W$ in year 21 of the $G$-sequence. +Now we assume a permanent increase in income of $L$ in year 21 of the $G$-sequence. Again we can study positive and negative cases ```{code-cell} ipython3 -# Positive permanent income change W = 0.5 when t >= 21 -y_seq_pos = np.concatenate( +# Positive permanent income change L = 0.5 when t >= 21 +G_seq_pos = np.concatenate( [np.ones(21), 1.5*np.ones(25), np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_pos) +plot_cs(cs_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 -# Negative permanent income change W = -0.5 when t >= 21 -y_seq_neg = np.concatenate( +# Negative permanent income change L = -0.5 when t >= 21 +G_seq_neg = np.concatenate( [np.ones(21), .5*np.ones(25), np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_neg) +plot_cs(cs_model, B0, G_seq_neg) ``` #### Experiment 3: a late starter @@ -418,30 +415,30 @@ Now we simulate a $G$ sequence in which a person gets zero for 46 years, and the ```{code-cell} ipython3 # Late starter -y_seq_late = np.concatenate( +G_seq_late = np.concatenate( [np.zeros(46), np.ones(20)]) -plot_cs(cs_model, a0, y_seq_late) +plot_cs(cs_model, B0, G_seq_late) ``` #### Experiment 4: geometric earner -Now we simulate a geometric $G$ sequence in which a person gets $y_t = \lambda^t y_0$ in first 46 years. +Now we simulate a geometric $G$ sequence in which a person gets $G_t = \lambda^t G_0$ in first 46 years. We first experiment with $\lambda = 1.05$ ```{code-cell} ipython3 # Geometric earner parameters where λ = 1.05 λ = 1.05 -y_0 = 1 +G_0 = 1 t_max = 46 # Generate geometric G sequence -geo_seq = λ ** np.arange(t_max) * y_0 -y_seq_geo = np.concatenate( +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_geo) +plot_cs(cs_model, B0, G_seq_geo) ``` Now we show the behavior when $\lambda = 0.95$ @@ -449,11 +446,11 @@ Now we show the behavior when $\lambda = 0.95$ ```{code-cell} ipython3 λ = 0.95 -geo_seq = λ ** np.arange(t_max) * y_0 -y_seq_geo = np.concatenate( +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_geo) +plot_cs(cs_model, B0, G_seq_geo) ``` What happens when $\lambda$ is negative @@ -461,14 +458,13 @@ What happens when $\lambda$ is negative ```{code-cell} ipython3 λ = -0.95 -geo_seq = λ ** np.arange(t_max) * y_0 -y_seq_geo = np.concatenate( +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, a0, y_seq_geo) +plot_cs(cs_model, B0, G_seq_geo) ``` - ### Feasible consumption variations We promised to justify our claim that a constant consumption play $T_t = T_0$ for all @@ -539,7 +535,7 @@ to compute alternative consumption paths, then evaluate their welfare. Now let's compute and plot consumption path variations ```{code-cell} ipython3 -def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): +def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): R, S, β_seq = model.R, model.S, model.β_seq ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(S+1))) * ((1 - (ϕ/R)**(S+1)) / (1 - ϕ/R)) @@ -548,13 +544,12 @@ def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): if verbose == 1: print('check feasible:', np.isclose(β_seq @ v_seq, 0)) # since β = 1/R - T_opt, _, _ = compute_optimal(model, a0, y_seq) + T_opt, _, _ = compute_optimal(model, B0, G_seq) cvar_seq = T_opt + v_seq return cvar_seq ``` - We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ ```{code-cell} ipython3 @@ -564,14 +559,14 @@ fig, ax = plt.subplots() ϕs= [.95, 1.02] colors = {.01: 'tab:blue', .05: 'tab:green'} -params = np.array(np.meshgrid(ξ1s, ϕs)).S.reshape(-1, 2) +params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) for i, param in enumerate(params): ξ1, ϕ = param print(f'variation {i}: ξ1={ξ1}, ϕ={ϕ}') cvar_seq = compute_variation(model=cs_model, - ξ1=ξ1, ϕ=ϕ, a0=a0, - y_seq=y_seq) + ξ1=ξ1, ϕ=ϕ, B0=B0, + G_seq=G_seq) print(f'welfare={welfare(cs_model, cvar_seq)}') print('-'*64) if i % 2 == 0: @@ -591,7 +586,6 @@ plt.ylabel(r'$T_t$') plt.show() ``` - We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. We are teaching the key idea beneath the **calculus of variations**. @@ -606,8 +600,8 @@ def welfare_rel(ξ1, ϕ): """ cvar_seq = compute_variation(cs_model, ξ1=ξ1, - ϕ=ϕ, a0=a0, - y_seq=y_seq, + ϕ=ϕ, B0=B0, + G_seq=G_seq, verbose=0) return welfare(cs_model, cvar_seq) @@ -615,7 +609,6 @@ def welfare_rel(ξ1, ϕ): welfare_vec = np.vectorize(welfare_rel) ``` - Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 @@ -634,7 +627,6 @@ plt.xlabel(r'$\xi_1$') plt.show() ``` - The same can be done on $\phi$ ```{code-cell} ipython3 From 67ef01b40ed60b7439435e5baefaac13ff405bfa Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 16:03:47 +1100 Subject: [PATCH 03/15] update text --- lectures/cons_smooth.md | 397 ++++++++++++++++++---------------------- 1 file changed, 183 insertions(+), 214 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 7692148e..9aa53476 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -16,25 +16,15 @@ kernelspec: ## Overview -In this lecture, we'll study a famous model of the "consumption function" that Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) proposed to fit some empirical data patterns that the original Keynesian consumption function described in this QuantEcon lecture {doc}`geometric series ` missed. +In this lecture, we'll study a famous model of optimal tax policy that Robert Barro {cite}`Barro1979` proposed to explain why governments might want to use debt to smooth tax rates over time rather than balancing their budgets period by period. -In this lecture, we'll study what is often called the "consumption-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. +In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. -Formulas presented in {doc}`present value formulas` are at the core of the consumption-smoothing model because we shall use them to define a consumer's "human wealth". +Formulas presented in {doc}`present value formulas` are at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. -The key idea that inspired Milton Friedman was that a person's non-financial income, i.e., his or -her wages from working, could be viewed as a dividend stream from that person's ''human capital'' -and that standard asset-pricing formulas could be applied to compute a person's -''non-financial wealth'' that capitalizes the earnings stream. - -```{note} -As we'll see in this QuantEcon lecture {doc}`equalizing difference model `, -Milton Friedman had used this idea in his PhD thesis at Columbia University, -eventually published as {cite}`kuznets1939incomes` and {cite}`friedman1954incomes`. -``` - -It will take a while for a "present value" or asset price explicitly to appear in this lecture, but when it does it will be a key actor. +The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes gradually over time. +This approach allows the government to minimize the distortionary costs of taxation by keeping tax rates relatively stable. ## Analysis @@ -46,15 +36,15 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` -The model describes a consumer who lives from time $t=0, 1, \ldots, S$, receives a stream $\{G_t\}_{t=0}^S$ of non-financial income and chooses a consumption stream $\{T_t\}_{t=0}^S$. +The model describes a government that operates from time $t=0, 1, \ldots, S$, faces a stream of expenditures $\{G_t\}_{t=0}^S$ and chooses a stream of tax collections $\{T_t\}_{t=0}^S$. -We usually think of the non-financial income stream as coming from the person's salary from supplying labor. +We usually think of the government expenditure stream as exogenous spending requirements that the government must finance. -The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. -The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. +The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. -To set up the model, let +To set up the model, let * $S \geq 2$ be a positive integer that constitutes a time-horizon. * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. @@ -65,68 +55,67 @@ To set up the model, let * $B_0$ be a given initial level of government debt * $B_{S+1} \geq 0$ be a terminal condition on final government debt. -The sequence of financial wealth $a$ is to be determined by the model. +The sequence of government debt $B$ is to be determined by the model. -We require it to satisfy two **boundary conditions**: +We require it to satisfy two **boundary conditions**: + * it must equal an exogenous value $B_0$ at time $0$ + * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. - * it must equal an exogenous value $B_0$ at time $0$ - * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. +The **terminal condition** $B_{S+1} \geq 0$ is a constraint that prevents the government from running Ponzi schemes by requiring that it not end with negative assets. -The **terminal condition** $B_{S+1} \geq 0$ requires that the consumer not leave the model in debt. +(This no-Ponzi condition ensures that the government must ultimately pay off its debts rather than rolling them over indefinitely.) -(We'll soon see that a utility maximizing consumer won't want to die leaving positive assets, so she'll arrange her affairs to make -$B_{S+1} = 0$.) - -The consumer faces a sequence of budget constraints that constrains sequences $(G, T, B)$ +The government faces a sequence of budget constraints that constrains sequences $(G, T, B)$ $$ -B_{t+1} = R (B_t+ G_t - T_t), \quad t =0, 1, \ldots S +B_{t+1} = R (B_t + G_t - T_t), \quad t =0, 1, \ldots S $$ (eq:B_t) -Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. +Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. -Given a sequence $G$ of non-financial incomes, a large set of pairs $(a, c)$ of (financial wealth, consumption) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. +Given a sequence $G$ of government expenditures, a large set of pairs $(B, T)$ of (government debt, tax collections) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. -Our model has the following logical flow. +Our model has the following logical flow: - * start with an exogenous non-financial income sequence $G$, an initial financial wealth $B_0$, and - a candidate consumption path $c$. + * start with an exogenous government expenditure sequence $G$, an initial government debt $B_0$, and + a candidate tax collection path $T$. - * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $a$ of financial wealth + * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt - * verify that $B_{S+1}$ satisfies the terminal wealth constraint $B_{S+1} \geq 0$. + * verify that $B_{S+1}$ satisfies the terminal debt constraint $B_{S+1} \geq 0$. * If it does, declare that the candidate path is **budget feasible**. - * if the candidate consumption path is not budget feasible, propose a less greedy consumption path and start over + * if the candidate tax path is not budget feasible, propose a different tax path and start over Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. -The above procedure seems like a sensible way to find "budget-feasible" consumption paths $c$, i.e., paths that are consistent -with the exogenous non-financial income stream $G$, the initial financial asset level $B_0$, and the terminal asset level $B_{S+1}$. - -In general, there are **many** budget feasible consumption paths $c$. +The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent +with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. -Among all budget-feasible consumption paths, which one should a consumer want? +In general, there are **many** budget feasible tax paths $T$. +Among all budget-feasible tax paths, which one should a government choose? -To answer this question, we shall eventually evaluate alternative budget feasible consumption paths $c$ using the following utility functional or **welfare criterion**: +To answer this question, we shall eventually evaluate alternative budget feasible tax paths $T$ using the following cost functional: ```{math} -:label: welfare +:label: cost L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) ``` where $g_1 > 0, g_2 > 0$. -When $\beta R \approx 1$, the fact that the utility function $g_1 T_t - \frac{g_2}{2} T_t^2$ has diminishing marginal utility imparts a preference for consumption that is very smooth. +This is called the "present value of revenue-raising costs" in {citep}`Barro1979` + +When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. This creates an incentive for tax smoothing. -Indeed, we shall see that when $\beta R = 1$ (a condition assumed by Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`), criterion {eq}`welfare` assigns higher welfare to smoother consumption paths. +Indeed, we shall see that when $\beta R = 1$ (a condition assumed in many public finance models), criterion {eq}`cost` leads to smoother tax paths. -By **smoother** we mean as close as possible to being constant over time. +By **smoother** we mean tax rates that are as close as possible to being constant over time. -The preference for smooth consumption paths that is built into the model gives it the name "consumption-smoothing model". +The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {citep}`Barro1979`'s seminal work. Let's dive in and do some calculations that will help us understand how the model works. @@ -139,27 +128,29 @@ TaxSmoothing = namedtuple("TaxSmoothing", ["R", "g1", "g2", "β_seq", "S"]) def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): + """ + Creates an instance of the tax smoothing model. + """ β = 1/R β_seq = np.array([β**i for i in range(S+1)]) - return TaxSmoothing(R, g1, g2, - β_seq, S) -``` -## Friedman-Hall consumption-smoothing model + return TaxSmoothing(R, g1, g2, β_seq, S) +``` -A key object is what Milton Friedman called "human" or "non-financial" wealth at time $0$: +## Barro Tax-Smoothing Model +A key object is the present value of government expenditures at time $0$: $$ h_0 \equiv \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} \begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} $$ -Human or non-financial wealth at time $0$ is evidently just the present value of the consumer's non-financial income stream $G$. +This sum represents the present value of all future government expenditures that must be financed. -Formally it very much resembles the asset price that we computed in this QuantEcon lecture {doc}`present values `. +Formally it resembles the present value calculations we saw in this QuantEcon lecture {doc}`present values `. -Indeed, this is why Milton Friedman called it "human capital". +This present value calculation is crucial for determining the government's total financing needs. By iterating on equation {eq}`eq:B_t` and imposing the terminal condition @@ -173,35 +164,34 @@ $$ \sum_{t=0}^S R^{-t} T_t = B_0 + h_0. $$ (eq:budget_intertemp) -Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of financial and non-financial (or human) wealth. +Equation {eq}`eq:budget_intertemp` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. -Robert Hall {cite}`Hall1978` showed that when $\beta R = 1$, a condition Milton Friedman had also assumed, it is "optimal" for a consumer to smooth consumption by setting +When $\beta R = 1$, it is optimal for a government to smooth taxes by setting $$ T_t = T_0 \quad t =0, 1, \ldots, S $$ -(Later we'll present a "variational argument" that shows that this constant path maximizes -criterion {eq}`welfare` when $\beta R =1$.) +(Later we'll present a "variational argument" that shows that this constant path minimizes +criterion {eq}`cost` when $\beta R =1$.) -In this case, we can use the intertemporal budget constraint to write +In this case, we can use the intertemporal budget constraint to write $$ T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (B_0 + h_0), \quad t= 0, 1, \ldots, S. -$$ (eq:conssmoothing) - -Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell. +$$ (eq:taxsmoothing) +Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. -## Mechanics of consumption-smoothing model +## Mechanics of Tax-Smoothing Model -As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the consumption-smoothing model. +As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. -In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. +In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. ### Step 1 -For a $(S+1) \times 1$ vector $G$, use matrix algebra to compute $h_0$ +For a $(S+1) \times 1$ vector $G$ of government expenditures, use matrix algebra to compute the present value $$ h_0 = \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} @@ -210,7 +200,7 @@ $$ ### Step 2 -Compute an time $0$ consumption $T_0 $ : +Compute a constant tax rate $T_0$: $$ T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (B_0 + \sum_{t=0}^S R^{-t} G_t ) , \quad t = 0, 1, \ldots, S @@ -218,11 +208,10 @@ $$ ### Step 3 -Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $a$ of financial wealth. +Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt. To do this, we translate that system of difference equations into a single matrix equation as follows: - $$ \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr @@ -245,72 +234,71 @@ $$ \begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} $$ - -Because we have built into our calculations that the consumer leaves the model with exactly zero assets, just barely satisfying the -terminal condition that $B_{S+1} \geq 0$, it should turn out that +Because we have built into our calculations that the government must satisfy its intertemporal budget constraint and end with zero debt, just barely satisfying the +terminal condition that $B_{S+1} \geq 0$, it should turn out that $$ B_{S+1} = 0. $$ - -Let's verify this with Python code. +Let's verify this with Python code. First we implement the model with `compute_optimal` ```{code-cell} ipython3 + def compute_optimal(model, B0, G_seq): + R, S = model.R, model.S - # non-financial wealth + # present value of government expenditures h0 = model.β_seq @ G_seq # since β = 1/R - # c0 - c0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) - T_seq = c0*np.ones(S+1) + # optimal constant tax rate + T0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) + T_seq = T0*np.ones(S+1) # verify A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) b = G_seq - T_seq b[0] = b[0] + B0 - B_seq = np.linalg.inv(A) @ b B_seq = np.concatenate([[B0], B_seq]) return T_seq, B_seq, h0 ``` -We use an example where the consumer inherits $B_0<0$. +We use an example where the government starts with initial debt $B_0>0$. -This can be interpreted as a student debt. +This represents the government's inherited debt burden. -The non-financial process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then becomes zero afterward. +The government expenditure process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then drops to zero afterward. -The drop in non-financial income late in life reflects retirement from work. +The drop in government expenditures could reflect a change in spending requirements or demographic shifts. ```{code-cell} ipython3 -# Financial wealth -B0 = -2 # such as "student debt" +# Initial debt +B0 = -2 # initial government debt -# non-financial Income process +# Government expenditure process G_seq = np.concatenate([np.ones(46), np.zeros(20)]) - -cs_model = create_tax_smoothing_model() -T_seq, B_seq, h0 = compute_optimal(cs_model, B0, G_seq) +tax_model = create_tax_smoothing_model() +T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) print('check B_S+1=0:', np.abs(B_seq[-1] - 0) <= 1e-8) ``` -The graphs below show paths of non-financial income, consumption, and financial assets. +The graphs below show paths of government expenditures, tax collections, and government debt. ```{code-cell} ipython3 + # Sequence Length -S = cs_model.S +S = tax_model.S -plt.plot(range(S+1), G_seq, label='non-financial income') -plt.plot(range(S+1), T_seq, label='consumption') -plt.plot(range(S+2), B_seq, label='financial wealth') +plt.plot(range(S+1), G_seq, label='government expenditures') +plt.plot(range(S+1), T_seq, label='tax collections') +plt.plot(range(S+2), B_seq, label='government debt') plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() @@ -321,42 +309,37 @@ plt.show() Note that $B_{S+1} = 0$, as anticipated. -We can evaluate welfare criterion {eq}`welfare` +We can evaluate cost criterion {eq}`cost` which measures the total cost of taxation ```{code-cell} ipython3 -def welfare(model, T_seq): +def cost(model, T_seq): β_seq, g1, g2 = model.β_seq, model.g1, model.g2 + cost_seq = g1 * T_seq - g2/2 * T_seq**2 + return β_seq @ cost_seq - u_seq = g1 * T_seq - g2/2 * T_seq**2 - return β_seq @ u_seq - -print('Welfare:', welfare(cs_model, T_seq)) +print('Cost:', cost(tax_model, T_seq)) ``` ### Experiments - -In this section we describe how a consumption sequence would optimally respond to different sequences sequences of non-financial income. - -First we create a function `plot_cs` that generates graphs for different instances of the consumption-smoothing model `cs_model`. - -This will help us avoid rewriting code to plot outcomes for different non-financial income sequences. - +In this section we describe how a tax sequence would optimally respond to different sequences of government expenditures. +First we create a function `plot_ts` that generates graphs for different instances of the tax-smoothing model `tax_model`. +This will help us avoid rewriting code to plot outcomes for different government expenditure sequences. ```{code-cell} ipython3 -def plot_cs(model, # consumption-smoothing model - B0, # initial financial wealth - G_seq # non-financial income process +def plot_ts(model, # tax-smoothing model + B0, # initial government debt + G_seq # government expenditure process ): - # Compute optimal consumption + # Compute optimal tax path T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) # Sequence length - S = cs_model.S + S = tax_model.S # Generate plot - plt.plot(range(S+1), G_seq, label='non-financial income') - plt.plot(range(S+1), T_seq, label='consumption') - plt.plot(range(S+2), B_seq, label='financial wealth') + plt.plot(range(S+1), G_seq, label='government expenditures') + plt.plot(range(S+1), T_seq, label='tax collections') + plt.plot(range(S+2), B_seq, label='government debt') plt.plot(range(S+2), np.zeros(S+2), '--') plt.legend() @@ -364,71 +347,70 @@ def plot_cs(model, # consumption-smoothing model plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` +In the experiments below, please study how tax and government debt sequences vary across different sequences for government expenditures. -In the experiments below, please study how consumption and financial asset sequences vary across different sequences for non-financial income. +#### Experiment 1: one-time spending shock -#### Experiment 1: one-time gain/loss +We first assume a one-time spending shock of $W_0$ in year 21 of the expenditure sequence $G$. -We first assume a one-time windfall of $W_0$ in year 21 of the income sequence $G$. - -We'll make $W_0$ big - positive to indicate a one-time windfall, and negative to indicate a one-time "disaster". +We'll make $W_0$ big - positive to indicate a spending surge (like a war or disaster), and negative to indicate a spending cut. ```{code-cell} ipython3 -# Windfall W_0 = 2.5 +# Spending surge W_0 = 2.5 G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_pos) +plot_ts(tax_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 -# Disaster W_0 = -2.5 +# Spending cut W_0 = -2.5 G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_neg) +plot_ts(tax_model, B0, G_seq_neg) ``` -#### Experiment 2: permanent wage gain/loss +#### Experiment 2: permanent expenditure shift -Now we assume a permanent increase in income of $L$ in year 21 of the $G$-sequence. +Now we assume a permanent increase in government expenditures of $L$ in year 21 of the $G$-sequence. Again we can study positive and negative cases ```{code-cell} ipython3 -# Positive permanent income change L = 0.5 when t >= 21 +# Positive permanent expenditure shift L = 0.5 when t >= 21 G_seq_pos = np.concatenate( [np.ones(21), 1.5*np.ones(25), np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_pos) +plot_ts(tax_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 -# Negative permanent income change L = -0.5 when t >= 21 +# Negative permanent expenditure shift L = -0.5 when t >= 21 G_seq_neg = np.concatenate( [np.ones(21), .5*np.ones(25), np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_neg) +plot_ts(tax_model, B0, G_seq_neg) ``` -#### Experiment 3: a late starter +#### Experiment 3: delayed spending -Now we simulate a $G$ sequence in which a person gets zero for 46 years, and then works and gets 1 for the last 20 years of life (a "late starter") +Now we simulate a $G$ sequence in which government expenditures are zero for 46 years, and then rise to 1 for the last 20 years (perhaps due to demographic aging) ```{code-cell} ipython3 -# Late starter +# Delayed spending G_seq_late = np.concatenate( [np.zeros(46), np.ones(20)]) -plot_cs(cs_model, B0, G_seq_late) +plot_ts(tax_model, B0, G_seq_late) ``` -#### Experiment 4: geometric earner +#### Experiment 4: growing expenditures -Now we simulate a geometric $G$ sequence in which a person gets $G_t = \lambda^t G_0$ in first 46 years. +Now we simulate a geometric $G$ sequence in which government expenditures grow at rate $G_t = \lambda^t G_0$ in first 46 years. -We first experiment with $\lambda = 1.05$ +We first experiment with $\lambda = 1.05$ (growing expenditures) ```{code-cell} ipython3 -# Geometric earner parameters where λ = 1.05 +# Geometric growth parameters where λ = 1.05 λ = 1.05 G_0 = 1 t_max = 46 @@ -438,59 +420,54 @@ geo_seq = λ ** np.arange(t_max) * G_0 G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_geo) +plot_ts(tax_model, B0, G_seq_geo) ``` -Now we show the behavior when $\lambda = 0.95$ +Now we show the behavior when $\lambda = 0.95$ (declining expenditures) ```{code-cell} ipython3 λ = 0.95 - geo_seq = λ ** np.arange(t_max) * G_0 G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_geo) +plot_ts(tax_model, B0, G_seq_geo) ``` -What happens when $\lambda$ is negative +What happens with oscillating expenditures ```{code-cell} ipython3 λ = -0.95 - geo_seq = λ ** np.arange(t_max) * G_0 G_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_cs(cs_model, B0, G_seq_geo) +plot_ts(tax_model, B0, G_seq_geo) ``` -### Feasible consumption variations +### Feasible Tax Variations -We promised to justify our claim that a constant consumption play $T_t = T_0$ for all -$t$ is optimal. +We promised to justify our claim that a constant tax rate $T_t = T_0$ for all $t$ is optimal. Let's do that now. - -The approach we'll take is an elementary example of the "calculus of variations". +The approach we'll take is an elementary example of the "calculus of variations". Let's dive in and see what the key idea is. -To explore what types of consumption paths are welfare-improving, we shall create an **admissible consumption path variation sequence** $\{v_t\}_{t=0}^S$ +To explore what types of tax paths are welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ that satisfies $$ \sum_{t=0}^S R^{-t} v_t = 0 $$ -This equation says that the **present value** of admissible consumption path variations must be zero. +This equation says that the **present value** of admissible tax path variations must be zero. -So once again, we encounter a formula for the present value of an "asset": +So once again, we encounter a formula for the present value: - * we require that the present value of consumption path variations be zero. + * we require that the present value of tax path variations be zero to maintain budget balance. -Here we'll restrict ourselves to a two-parameter class of admissible consumption path variations -of the form +Here we'll restrict ourselves to a two-parameter class of admissible tax path variations of the form $$ v_t = \xi_1 \phi^t - \xi_0 @@ -526,13 +503,13 @@ $$ This is our formula for $\xi_0$. -**Key Idea:** if $c^o$ is a budget-feasible consumption path, then so is $c^o + v$, +**Key Idea:** if $T^o$ is a budget-feasible tax path, then so is $T^o + v$, where $v$ is a budget-feasible variation. Given $R$, we thus have a two parameter class of budget feasible variations $v$ that we can use -to compute alternative consumption paths, then evaluate their welfare. +to compute alternative tax paths, then evaluate their welfare costs. -Now let's compute and plot consumption path variations +Now let's compute and plot tax path variations ```{code-cell} ipython3 def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): @@ -542,87 +519,83 @@ def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(S+1)]) if verbose == 1: - print('check feasible:', np.isclose(β_seq @ v_seq, 0)) # since β = 1/R + print('check feasible:', np.isclose(β_seq @ v_seq, 0)) T_opt, _, _ = compute_optimal(model, B0, G_seq) - cvar_seq = T_opt + v_seq + Tvar_seq = T_opt + v_seq - return cvar_seq + return Tvar_seq ``` We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ ```{code-cell} ipython3 fig, ax = plt.subplots() - ξ1s = [.01, .05] ϕs= [.95, 1.02] colors = {.01: 'tab:blue', .05: 'tab:green'} - params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) for i, param in enumerate(params): ξ1, ϕ = param print(f'variation {i}: ξ1={ξ1}, ϕ={ϕ}') - cvar_seq = compute_variation(model=cs_model, + + Tvar_seq = compute_variation(model=tax_model, ξ1=ξ1, ϕ=ϕ, B0=B0, G_seq=G_seq) - print(f'welfare={welfare(cs_model, cvar_seq)}') + print(f'cost={cost(tax_model, Tvar_seq)}') print('-'*64) + if i % 2 == 0: ls = '-.' else: ls = '-' - ax.plot(range(S+1), cvar_seq, ls=ls, + ax.plot(range(S+1), Tvar_seq, ls=ls, color=colors[ξ1], label=fr'$\xi_1 = {ξ1}, \phi = {ϕ}$') plt.plot(range(S+1), T_seq, - color='orange', label=r'Optimal $\vec{c}$ ') + color='orange', label=r'Optimal $\vec{T}$ ') plt.legend() plt.xlabel(r'$t$') plt.ylabel(r'$T_t$') plt.show() ``` - -We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. +We can even use the Python `np.gradient` command to compute derivatives of cost with respect to our two parameters. We are teaching the key idea beneath the **calculus of variations**. - -First, we define the welfare with respect to $\xi_1$ and $\phi$ +First, we define the cost with respect to $\xi_1$ and $\phi$ ```{code-cell} ipython3 -def welfare_rel(ξ1, ϕ): +def cost_rel(ξ1, ϕ): """ - Compute welfare of variation sequence - for given ϕ, ξ1 with a consumption-smoothing model + Compute cost of variation sequence + for given ϕ, ξ1 with a tax-smoothing model """ - cvar_seq = compute_variation(cs_model, ξ1=ξ1, + Tvar_seq = compute_variation(tax_model, ξ1=ξ1, ϕ=ϕ, B0=B0, G_seq=G_seq, verbose=0) - return welfare(cs_model, cvar_seq) - + return cost(tax_model, Tvar_seq) # Vectorize the function to allow array input -welfare_vec = np.vectorize(welfare_rel) +cost_vec = np.vectorize(cost_rel) ``` - -Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives +Then we can visualize the relationship between cost and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 ξ1_arr = np.linspace(-0.5, 0.5, 20) -plt.plot(ξ1_arr, welfare_vec(ξ1_arr, 1.02)) -plt.ylabel('welfare') +plt.plot(ξ1_arr, cost_vec(ξ1_arr, 1.02)) +plt.ylabel('cost') plt.xlabel(r'$\xi_1$') plt.show() -welfare_grad = welfare_vec(ξ1_arr, 1.02) -welfare_grad = np.gradient(welfare_grad) -plt.plot(ξ1_arr, welfare_grad) -plt.ylabel('derivative of welfare') +cost_grad = cost_vec(ξ1_arr, 1.02) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') plt.xlabel(r'$\xi_1$') plt.show() ``` @@ -632,20 +605,20 @@ The same can be done on $\phi$ ```{code-cell} ipython3 ϕ_arr = np.linspace(-0.5, 0.5, 20) -plt.plot(ξ1_arr, welfare_vec(0.05, ϕ_arr)) -plt.ylabel('welfare') +plt.plot(ξ1_arr, cost_vec(0.05, ϕ_arr)) +plt.ylabel('cost') plt.xlabel(r'$\phi$') plt.show() -welfare_grad = welfare_vec(0.05, ϕ_arr) -welfare_grad = np.gradient(welfare_grad) -plt.plot(ξ1_arr, welfare_grad) -plt.ylabel('derivative of welfare') +cost_grad = cost_vec(0.05, ϕ_arr) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') plt.xlabel(r'$\phi$') plt.show() ``` -## Wrapping up the consumption-smoothing model + ## Appendix: solving difference equations with linear algebra -In the preceding sections we have used linear algebra to solve a consumption-smoothing model. +In the preceding sections we have used linear algebra to solve a tax-smoothing model. -The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. +The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. We'll conclude this lecture by giving a couple of examples. We'll describe a useful way of representing and "solving" linear difference equations. To generate some $G$ vectors, we'll just write down a linear difference equation -with appropriate initial conditions and then use linear algebra to solve it. +with appropriate initial conditions and then use linear algebra to solve it. ### First-order difference equation @@ -678,10 +651,9 @@ $$ G_{t} = \lambda G_{t-1}, \quad t = 1, 2, \ldots, S $$ -where $G_0$ is a given initial condition. +where $G_0$ is a given initial government expenditure. - -We can cast this set of $S$ equations as a single matrix equation +We can cast this set of $S$ equations as a single matrix equation $$ \begin{bmatrix} @@ -700,12 +672,10 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} $$ (eq:first_order_lin_diff) - -Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution +Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution ```{math} :label: fst_ord_inverse - \begin{bmatrix} G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} @@ -723,9 +693,9 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S ``` ```{exercise} -:label: consmooth_ex1 +:label: taxsmooth_ex1 -To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that +To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that $$ \begin{bmatrix} @@ -738,7 +708,6 @@ $$ $$ is the inverse of $A$ and check that $A A^{-1} = I$ - ``` ### Second-order difference equation @@ -749,7 +718,7 @@ $$ G_{t} = \lambda_1 G_{t-1} + \lambda_2 G_{t-2}, \quad t = 1, 2, \ldots, S $$ -where now $G_0$ and $G_{-1}$ are two given initial equations determined outside the model. +where now $G_0$ and $G_{-1}$ are two given initial expenditure levels determined outside the model. As we did with the first-order difference equation, we can cast this set of $S$ equations as a single matrix equation @@ -770,11 +739,11 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} $$ -Multiplying both sides by inverse of the matrix on the left again provides the solution. +Multiplying both sides by inverse of the matrix on the left again provides the solution. ```{exercise} -:label: consmooth_ex2 +:label: taxsmooth_ex2 As an exercise, we ask you to represent and solve a **third-order linear difference equation**. How many initial conditions must you specify? -``` +``` \ No newline at end of file From d23796fde259f5090f5d206799d450b8aec783f3 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 16:06:49 +1100 Subject: [PATCH 04/15] add tax_smooth --- lectures/_toc.yml | 1 + lectures/cons_smooth.md | 585 ++++++++++++++++--------------- lectures/tax_smooth.md | 749 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1062 insertions(+), 273 deletions(-) create mode 100644 lectures/tax_smooth.md diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 8e4de355..cc420c3e 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -25,6 +25,7 @@ parts: chapters: - file: pv - file: cons_smooth + - file: tax_smooth - file: equalizing_difference - file: cagan_ree - file: cagan_adaptive diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 9aa53476..44580989 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -4,27 +4,38 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.6 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- + # Consumption Smoothing ## Overview -In this lecture, we'll study a famous model of optimal tax policy that Robert Barro {cite}`Barro1979` proposed to explain why governments might want to use debt to smooth tax rates over time rather than balancing their budgets period by period. +In this lecture, we'll study a famous model of the "consumption function" that Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) proposed to fit some empirical data patterns that the original Keynesian consumption function described in this QuantEcon lecture {doc}`geometric series ` missed. + +In this lecture, we'll study what is often called the "consumption-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. + +Formulas presented in {doc}`present value formulas` are at the core of the consumption-smoothing model because we shall use them to define a consumer's "human wealth". -In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. +The key idea that inspired Milton Friedman was that a person's non-financial income, i.e., his or +her wages from working, could be viewed as a dividend stream from that person's ''human capital'' +and that standard asset-pricing formulas could be applied to compute a person's +''non-financial wealth'' that capitalizes the earnings stream. -Formulas presented in {doc}`present value formulas` are at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. +```{note} +As we'll see in this QuantEcon lecture {doc}`equalizing difference model `, +Milton Friedman had used this idea in his PhD thesis at Columbia University, +eventually published as {cite}`kuznets1939incomes` and {cite}`friedman1954incomes`. +``` -The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes gradually over time. +It will take a while for a "present value" or asset price explicitly to appear in this lecture, but when it does it will be a key actor. -This approach allows the government to minimize the distortionary costs of taxation by keeping tax rates relatively stable. ## Analysis @@ -36,182 +47,185 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` -The model describes a government that operates from time $t=0, 1, \ldots, S$, faces a stream of expenditures $\{G_t\}_{t=0}^S$ and chooses a stream of tax collections $\{T_t\}_{t=0}^S$. -We usually think of the government expenditure stream as exogenous spending requirements that the government must finance. +The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{y_t\}_{t=0}^T$ of non-financial income and chooses a consumption stream $\{c_t\}_{t=0}^T$. + +We usually think of the non-financial income stream as coming from the person's salary from supplying labor. -The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. -The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. +The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. -To set up the model, let +To set up the model, let - * $S \geq 2$ be a positive integer that constitutes a time-horizon. - * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. - * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of government debt. - * $T = \{T_t\}_{t=0}^S$ be a sequence of tax collections. - * $R \geq 1$ be a fixed gross one period interest rate. + * $T \geq 2$ be a positive integer that constitutes a time-horizon. + * $y = \{y_t\}_{t=0}^T$ be an exogenous sequence of non-negative non-financial incomes $y_t$. + * $a = \{a_t\}_{t=0}^{T+1}$ be a sequence of financial wealth. + * $c = \{c_t\}_{t=0}^T$ be a sequence of non-negative consumption rates. + * $R \geq 1$ be a fixed gross one period rate of return on financial assets. * $\beta \in (0,1)$ be a fixed discount factor. - * $B_0$ be a given initial level of government debt - * $B_{S+1} \geq 0$ be a terminal condition on final government debt. + * $a_0$ be a given initial level of financial assets + * $a_{T+1} \geq 0$ be a terminal condition on final assets. + +The sequence of financial wealth $a$ is to be determined by the model. -The sequence of government debt $B$ is to be determined by the model. +We require it to satisfy two **boundary conditions**: -We require it to satisfy two **boundary conditions**: - * it must equal an exogenous value $B_0$ at time $0$ - * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. + * it must equal an exogenous value $a_0$ at time $0$ + * it must equal or exceed an exogenous value $a_{T+1}$ at time $T+1$. -The **terminal condition** $B_{S+1} \geq 0$ is a constraint that prevents the government from running Ponzi schemes by requiring that it not end with negative assets. +The **terminal condition** $a_{T+1} \geq 0$ requires that the consumer not leave the model in debt. -(This no-Ponzi condition ensures that the government must ultimately pay off its debts rather than rolling them over indefinitely.) +(We'll soon see that a utility maximizing consumer won't want to die leaving positive assets, so she'll arrange her affairs to make +$a_{T+1} = 0$.) -The government faces a sequence of budget constraints that constrains sequences $(G, T, B)$ +The consumer faces a sequence of budget constraints that constrains sequences $(y, c, a)$ $$ -B_{t+1} = R (B_t + G_t - T_t), \quad t =0, 1, \ldots S -$$ (eq:B_t) +a_{t+1} = R (a_t+ y_t - c_t), \quad t =0, 1, \ldots T +$$ (eq:a_t) -Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. +Equations {eq}`eq:a_t` constitute $T+1$ such budget constraints, one for each $t=0, 1, \ldots, T$. -Given a sequence $G$ of government expenditures, a large set of pairs $(B, T)$ of (government debt, tax collections) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. +Given a sequence $y$ of non-financial incomes, a large set of pairs $(a, c)$ of (financial wealth, consumption) sequences satisfy the sequence of budget constraints {eq}`eq:a_t`. -Our model has the following logical flow: +Our model has the following logical flow. - * start with an exogenous government expenditure sequence $G$, an initial government debt $B_0$, and - a candidate tax collection path $T$. + * start with an exogenous non-financial income sequence $y$, an initial financial wealth $a_0$, and + a candidate consumption path $c$. - * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt + * use the system of equations {eq}`eq:a_t` for $t=0, \ldots, T$ to compute a path $a$ of financial wealth - * verify that $B_{S+1}$ satisfies the terminal debt constraint $B_{S+1} \geq 0$. + * verify that $a_{T+1}$ satisfies the terminal wealth constraint $a_{T+1} \geq 0$. * If it does, declare that the candidate path is **budget feasible**. - * if the candidate tax path is not budget feasible, propose a different tax path and start over + * if the candidate consumption path is not budget feasible, propose a less greedy consumption path and start over Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. -The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent -with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. +The above procedure seems like a sensible way to find "budget-feasible" consumption paths $c$, i.e., paths that are consistent +with the exogenous non-financial income stream $y$, the initial financial asset level $a_0$, and the terminal asset level $a_{T+1}$. -In general, there are **many** budget feasible tax paths $T$. +In general, there are **many** budget feasible consumption paths $c$. -Among all budget-feasible tax paths, which one should a government choose? +Among all budget-feasible consumption paths, which one should a consumer want? -To answer this question, we shall eventually evaluate alternative budget feasible tax paths $T$ using the following cost functional: + +To answer this question, we shall eventually evaluate alternative budget feasible consumption paths $c$ using the following utility functional or **welfare criterion**: ```{math} -:label: cost +:label: welfare -L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +W = \sum_{t=0}^T \beta^t (g_1 c_t - \frac{g_2}{2} c_t^2 ) ``` where $g_1 > 0, g_2 > 0$. -This is called the "present value of revenue-raising costs" in {citep}`Barro1979` - -When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. This creates an incentive for tax smoothing. +When $\beta R \approx 1$, the fact that the utility function $g_1 c_t - \frac{g_2}{2} c_t^2$ has diminishing marginal utility imparts a preference for consumption that is very smooth. -Indeed, we shall see that when $\beta R = 1$ (a condition assumed in many public finance models), criterion {eq}`cost` leads to smoother tax paths. +Indeed, we shall see that when $\beta R = 1$ (a condition assumed by Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`), criterion {eq}`welfare` assigns higher welfare to smoother consumption paths. -By **smoother** we mean tax rates that are as close as possible to being constant over time. +By **smoother** we mean as close as possible to being constant over time. -The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {citep}`Barro1979`'s seminal work. +The preference for smooth consumption paths that is built into the model gives it the name "consumption-smoothing model". Let's dive in and do some calculations that will help us understand how the model works. -Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. +Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $T = 65$. We create a Python **namedtuple** to store these parameters with default values. ```{code-cell} ipython3 -TaxSmoothing = namedtuple("TaxSmoothing", - ["R", "g1", "g2", "β_seq", "S"]) +ConsumptionSmoothing = namedtuple("ConsumptionSmoothing", + ["R", "g1", "g2", "β_seq", "T"]) -def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): - """ - Creates an instance of the tax smoothing model. - """ +def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, T=65): β = 1/R - β_seq = np.array([β**i for i in range(S+1)]) - - return TaxSmoothing(R, g1, g2, β_seq, S) + β_seq = np.array([β**i for i in range(T+1)]) + return ConsumptionSmoothing(R, g1, g2, + β_seq, T) ``` -## Barro Tax-Smoothing Model -A key object is the present value of government expenditures at time $0$: +## Friedman-Hall consumption-smoothing model + +A key object is what Milton Friedman called "human" or "non-financial" wealth at time $0$: + $$ -h_0 \equiv \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} -\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +h_0 \equiv \sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix} +\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix} $$ -This sum represents the present value of all future government expenditures that must be financed. +Human or non-financial wealth at time $0$ is evidently just the present value of the consumer's non-financial income stream $y$. -Formally it resembles the present value calculations we saw in this QuantEcon lecture {doc}`present values `. +Formally it very much resembles the asset price that we computed in this QuantEcon lecture {doc}`present values `. -This present value calculation is crucial for determining the government's total financing needs. +Indeed, this is why Milton Friedman called it "human capital". -By iterating on equation {eq}`eq:B_t` and imposing the terminal condition +By iterating on equation {eq}`eq:a_t` and imposing the terminal condition $$ -B_{S+1} = 0, +a_{T+1} = 0, $$ -it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a single intertemporal constraint +it is possible to convert a sequence of budget constraints {eq}`eq:a_t` into a single intertemporal constraint $$ -\sum_{t=0}^S R^{-t} T_t = B_0 + h_0. +\sum_{t=0}^T R^{-t} c_t = a_0 + h_0. $$ (eq:budget_intertemp) -Equation {eq}`eq:budget_intertemp` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. +Equation {eq}`eq:budget_intertemp` says that the present value of the consumption stream equals the sum of financial and non-financial (or human) wealth. -When $\beta R = 1$, it is optimal for a government to smooth taxes by setting +Robert Hall {cite}`Hall1978` showed that when $\beta R = 1$, a condition Milton Friedman had also assumed, it is "optimal" for a consumer to smooth consumption by setting $$ -T_t = T_0 \quad t =0, 1, \ldots, S +c_t = c_0 \quad t =0, 1, \ldots, T $$ -(Later we'll present a "variational argument" that shows that this constant path minimizes -criterion {eq}`cost` when $\beta R =1$.) +(Later we'll present a "variational argument" that shows that this constant path maximizes +criterion {eq}`welfare` when $\beta R =1$.) -In this case, we can use the intertemporal budget constraint to write +In this case, we can use the intertemporal budget constraint to write $$ -T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (B_0 + h_0), \quad t= 0, 1, \ldots, S. -$$ (eq:taxsmoothing) +c_t = c_0 = \left(\sum_{t=0}^T R^{-t}\right)^{-1} (a_0 + h_0), \quad t= 0, 1, \ldots, T. +$$ (eq:conssmoothing) + +Equation {eq}`eq:conssmoothing` is the consumption-smoothing model in a nutshell. -Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. -## Mechanics of Tax-Smoothing Model +## Mechanics of consumption-smoothing model -As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. +As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the consumption-smoothing model. -In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. +In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. ### Step 1 -For a $(S+1) \times 1$ vector $G$ of government expenditures, use matrix algebra to compute the present value +For a $(T+1) \times 1$ vector $y$, use matrix algebra to compute $h_0$ $$ -h_0 = \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} -\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +h_0 = \sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix} +\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix} $$ ### Step 2 -Compute a constant tax rate $T_0$: +Compute an time $0$ consumption $c_0 $ : $$ -T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (B_0 + \sum_{t=0}^S R^{-t} G_t ) , \quad t = 0, 1, \ldots, S +c_t = c_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(T+1)}} \right) (a_0 + \sum_{t=0}^T R^{-t} y_t ) , \quad t = 0, 1, \ldots, T $$ ### Step 3 -Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt. +Use the system of equations {eq}`eq:a_t` for $t=0, \ldots, T$ to compute a path $a$ of financial wealth. To do this, we translate that system of difference equations into a single matrix equation as follows: + $$ \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr @@ -221,253 +235,266 @@ $$ 0 & 0 & 0 & \cdots & -R & 1 & 0 \cr 0 & 0 & 0 & \cdots & 0 & -R & 1 \end{bmatrix} -\begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} +\begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1} \end{bmatrix} = R -\begin{bmatrix} G_0 + B_0 - T_0 \cr G_1 - T_0 \cr G_2 - T_0 \cr \vdots\cr G_{S-1} - T_0 \cr G_S - T_0 +\begin{bmatrix} y_0 + a_0 - c_0 \cr y_1 - c_0 \cr y_2 - c_0 \cr \vdots\cr y_{T-1} - c_0 \cr y_T - c_0 \end{bmatrix} $$ Multiply both sides by the inverse of the matrix on the left side to compute $$ - \begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} + \begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1} \end{bmatrix} $$ -Because we have built into our calculations that the government must satisfy its intertemporal budget constraint and end with zero debt, just barely satisfying the -terminal condition that $B_{S+1} \geq 0$, it should turn out that + +Because we have built into our calculations that the consumer leaves the model with exactly zero assets, just barely satisfying the +terminal condition that $a_{T+1} \geq 0$, it should turn out that $$ -B_{S+1} = 0. +a_{T+1} = 0. $$ -Let's verify this with Python code. + +Let's verify this with Python code. First we implement the model with `compute_optimal` ```{code-cell} ipython3 +def compute_optimal(model, a0, y_seq): + R, T = model.R, model.T -def compute_optimal(model, B0, G_seq): - - R, S = model.R, model.S + # non-financial wealth + h0 = model.β_seq @ y_seq # since β = 1/R - # present value of government expenditures - h0 = model.β_seq @ G_seq # since β = 1/R - - # optimal constant tax rate - T0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) - T_seq = T0*np.ones(S+1) + # c0 + c0 = (1 - 1/R) / (1 - (1/R)**(T+1)) * (a0 + h0) + c_seq = c0*np.ones(T+1) # verify - A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) - b = G_seq - T_seq - b[0] = b[0] + B0 - B_seq = np.linalg.inv(A) @ b - B_seq = np.concatenate([[B0], B_seq]) + A = np.diag(-R*np.ones(T), k=-1) + np.eye(T+1) + b = y_seq - c_seq + b[0] = b[0] + a0 + + a_seq = np.linalg.inv(A) @ b + a_seq = np.concatenate([[a0], a_seq]) - return T_seq, B_seq, h0 + return c_seq, a_seq, h0 ``` -We use an example where the government starts with initial debt $B_0>0$. +We use an example where the consumer inherits $a_0<0$. -This represents the government's inherited debt burden. +This can be interpreted as a student debt. -The government expenditure process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then drops to zero afterward. +The non-financial process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward. -The drop in government expenditures could reflect a change in spending requirements or demographic shifts. +The drop in non-financial income late in life reflects retirement from work. ```{code-cell} ipython3 -# Initial debt -B0 = -2 # initial government debt +# Financial wealth +a0 = -2 # such as "student debt" + +# non-financial Income process +y_seq = np.concatenate([np.ones(46), np.zeros(20)]) -# Government expenditure process -G_seq = np.concatenate([np.ones(46), np.zeros(20)]) -tax_model = create_tax_smoothing_model() -T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) +cs_model = create_consumption_smoothing_model() +c_seq, a_seq, h0 = compute_optimal(cs_model, a0, y_seq) -print('check B_S+1=0:', - np.abs(B_seq[-1] - 0) <= 1e-8) +print('check a_T+1=0:', + np.abs(a_seq[-1] - 0) <= 1e-8) ``` -The graphs below show paths of government expenditures, tax collections, and government debt. +The graphs below show paths of non-financial income, consumption, and financial assets. ```{code-cell} ipython3 - # Sequence Length -S = tax_model.S +T = cs_model.T -plt.plot(range(S+1), G_seq, label='government expenditures') -plt.plot(range(S+1), T_seq, label='tax collections') -plt.plot(range(S+2), B_seq, label='government debt') -plt.plot(range(S+2), np.zeros(S+2), '--') +plt.plot(range(T+1), y_seq, label='non-financial income') +plt.plot(range(T+1), c_seq, label='consumption') +plt.plot(range(T+2), a_seq, label='financial wealth') +plt.plot(range(T+2), np.zeros(T+2), '--') plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$T_t,G_t,B_t$') +plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` -Note that $B_{S+1} = 0$, as anticipated. +Note that $a_{T+1} = 0$, as anticipated. -We can evaluate cost criterion {eq}`cost` which measures the total cost of taxation +We can evaluate welfare criterion {eq}`welfare` ```{code-cell} ipython3 -def cost(model, T_seq): +def welfare(model, c_seq): β_seq, g1, g2 = model.β_seq, model.g1, model.g2 - cost_seq = g1 * T_seq - g2/2 * T_seq**2 - return β_seq @ cost_seq -print('Cost:', cost(tax_model, T_seq)) + u_seq = g1 * c_seq - g2/2 * c_seq**2 + return β_seq @ u_seq + +print('Welfare:', welfare(cs_model, c_seq)) ``` ### Experiments -In this section we describe how a tax sequence would optimally respond to different sequences of government expenditures. -First we create a function `plot_ts` that generates graphs for different instances of the tax-smoothing model `tax_model`. -This will help us avoid rewriting code to plot outcomes for different government expenditure sequences. + +In this section we describe how a consumption sequence would optimally respond to different sequences sequences of non-financial income. + +First we create a function `plot_cs` that generates graphs for different instances of the consumption-smoothing model `cs_model`. + +This will help us avoid rewriting code to plot outcomes for different non-financial income sequences. + ```{code-cell} ipython3 -def plot_ts(model, # tax-smoothing model - B0, # initial government debt - G_seq # government expenditure process +def plot_cs(model, # consumption-smoothing model + a0, # initial financial wealth + y_seq # non-financial income process ): - # Compute optimal tax path - T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) + # Compute optimal consumption + c_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) # Sequence length - S = tax_model.S + T = cs_model.T # Generate plot - plt.plot(range(S+1), G_seq, label='government expenditures') - plt.plot(range(S+1), T_seq, label='tax collections') - plt.plot(range(S+2), B_seq, label='government debt') - plt.plot(range(S+2), np.zeros(S+2), '--') + plt.plot(range(T+1), y_seq, label='non-financial income') + plt.plot(range(T+1), c_seq, label='consumption') + plt.plot(range(T+2), a_seq, label='financial wealth') + plt.plot(range(T+2), np.zeros(T+2), '--') plt.legend() plt.xlabel(r'$t$') - plt.ylabel(r'$T_t,G_t,B_t$') + plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` -In the experiments below, please study how tax and government debt sequences vary across different sequences for government expenditures. -#### Experiment 1: one-time spending shock +In the experiments below, please study how consumption and financial asset sequences vary across different sequences for non-financial income. -We first assume a one-time spending shock of $W_0$ in year 21 of the expenditure sequence $G$. +#### Experiment 1: one-time gain/loss -We'll make $W_0$ big - positive to indicate a spending surge (like a war or disaster), and negative to indicate a spending cut. +We first assume a one-time windfall of $W_0$ in year 21 of the income sequence $y$. + +We'll make $W_0$ big - positive to indicate a one-time windfall, and negative to indicate a one-time "disaster". ```{code-cell} ipython3 -# Spending surge W_0 = 2.5 -G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) +# Windfall W_0 = 2.5 +y_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_pos) +plot_cs(cs_model, a0, y_seq_pos) ``` ```{code-cell} ipython3 -# Spending cut W_0 = -2.5 -G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) +# Disaster W_0 = -2.5 +y_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_neg) +plot_cs(cs_model, a0, y_seq_neg) ``` -#### Experiment 2: permanent expenditure shift +#### Experiment 2: permanent wage gain/loss -Now we assume a permanent increase in government expenditures of $L$ in year 21 of the $G$-sequence. +Now we assume a permanent increase in income of $W$ in year 21 of the $y$-sequence. Again we can study positive and negative cases ```{code-cell} ipython3 -# Positive permanent expenditure shift L = 0.5 when t >= 21 -G_seq_pos = np.concatenate( +# Positive permanent income change W = 0.5 when t >= 21 +y_seq_pos = np.concatenate( [np.ones(21), 1.5*np.ones(25), np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_pos) +plot_cs(cs_model, a0, y_seq_pos) ``` ```{code-cell} ipython3 -# Negative permanent expenditure shift L = -0.5 when t >= 21 -G_seq_neg = np.concatenate( +# Negative permanent income change W = -0.5 when t >= 21 +y_seq_neg = np.concatenate( [np.ones(21), .5*np.ones(25), np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_neg) +plot_cs(cs_model, a0, y_seq_neg) ``` -#### Experiment 3: delayed spending +#### Experiment 3: a late starter -Now we simulate a $G$ sequence in which government expenditures are zero for 46 years, and then rise to 1 for the last 20 years (perhaps due to demographic aging) +Now we simulate a $y$ sequence in which a person gets zero for 46 years, and then works and gets 1 for the last 20 years of life (a "late starter") ```{code-cell} ipython3 -# Delayed spending -G_seq_late = np.concatenate( +# Late starter +y_seq_late = np.concatenate( [np.zeros(46), np.ones(20)]) -plot_ts(tax_model, B0, G_seq_late) +plot_cs(cs_model, a0, y_seq_late) ``` -#### Experiment 4: growing expenditures +#### Experiment 4: geometric earner -Now we simulate a geometric $G$ sequence in which government expenditures grow at rate $G_t = \lambda^t G_0$ in first 46 years. +Now we simulate a geometric $y$ sequence in which a person gets $y_t = \lambda^t y_0$ in first 46 years. -We first experiment with $\lambda = 1.05$ (growing expenditures) +We first experiment with $\lambda = 1.05$ ```{code-cell} ipython3 -# Geometric growth parameters where λ = 1.05 +# Geometric earner parameters where λ = 1.05 λ = 1.05 -G_0 = 1 +y_0 = 1 t_max = 46 -# Generate geometric G sequence -geo_seq = λ ** np.arange(t_max) * G_0 -G_seq_geo = np.concatenate( +# Generate geometric y sequence +geo_seq = λ ** np.arange(t_max) * y_0 +y_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_geo) +plot_cs(cs_model, a0, y_seq_geo) ``` -Now we show the behavior when $\lambda = 0.95$ (declining expenditures) +Now we show the behavior when $\lambda = 0.95$ ```{code-cell} ipython3 λ = 0.95 -geo_seq = λ ** np.arange(t_max) * G_0 -G_seq_geo = np.concatenate( + +geo_seq = λ ** np.arange(t_max) * y_0 +y_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_geo) +plot_cs(cs_model, a0, y_seq_geo) ``` -What happens with oscillating expenditures +What happens when $\lambda$ is negative ```{code-cell} ipython3 λ = -0.95 -geo_seq = λ ** np.arange(t_max) * G_0 -G_seq_geo = np.concatenate( + +geo_seq = λ ** np.arange(t_max) * y_0 +y_seq_geo = np.concatenate( [geo_seq, np.zeros(20)]) -plot_ts(tax_model, B0, G_seq_geo) +plot_cs(cs_model, a0, y_seq_geo) ``` -### Feasible Tax Variations -We promised to justify our claim that a constant tax rate $T_t = T_0$ for all $t$ is optimal. +### Feasible consumption variations + +We promised to justify our claim that a constant consumption play $c_t = c_0$ for all +$t$ is optimal. Let's do that now. -The approach we'll take is an elementary example of the "calculus of variations". + +The approach we'll take is an elementary example of the "calculus of variations". Let's dive in and see what the key idea is. -To explore what types of tax paths are welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ +To explore what types of consumption paths are welfare-improving, we shall create an **admissible consumption path variation sequence** $\{v_t\}_{t=0}^T$ that satisfies $$ -\sum_{t=0}^S R^{-t} v_t = 0 +\sum_{t=0}^T R^{-t} v_t = 0 $$ -This equation says that the **present value** of admissible tax path variations must be zero. +This equation says that the **present value** of admissible consumption path variations must be zero. -So once again, we encounter a formula for the present value: +So once again, we encounter a formula for the present value of an "asset": - * we require that the present value of tax path variations be zero to maintain budget balance. + * we require that the present value of consumption path variations be zero. -Here we'll restrict ourselves to a two-parameter class of admissible tax path variations of the form +Here we'll restrict ourselves to a two-parameter class of admissible consumption path variations +of the form $$ v_t = \xi_1 \phi^t - \xi_0 @@ -480,145 +507,153 @@ Let's compute that function. We require $$ -\sum_{t=0}^S R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 +\sum_{t=0}^T R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 $$ which implies that $$ -\xi_1 \sum_{t=0}^S \phi_t R^{-t} - \xi_0 \sum_{t=0}^S R^{-t} = 0 +\xi_1 \sum_{t=0}^T \phi_t R^{-t} - \xi_0 \sum_{t=0}^T R^{-t} = 0 $$ which implies that $$ -\xi_1 \frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(S+1)}}{1-R^{-1} } =0 +\xi_1 \frac{1 - (\phi R^{-1})^{T+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(T+1)}}{1-R^{-1} } =0 $$ which implies that $$ -\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(S+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}}\right) +\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(T+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{T+1}}{1 - \phi R^{-1}}\right) $$ This is our formula for $\xi_0$. -**Key Idea:** if $T^o$ is a budget-feasible tax path, then so is $T^o + v$, +**Key Idea:** if $c^o$ is a budget-feasible consumption path, then so is $c^o + v$, where $v$ is a budget-feasible variation. Given $R$, we thus have a two parameter class of budget feasible variations $v$ that we can use -to compute alternative tax paths, then evaluate their welfare costs. +to compute alternative consumption paths, then evaluate their welfare. -Now let's compute and plot tax path variations +Now let's compute and plot consumption path variations ```{code-cell} ipython3 -def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): - R, S, β_seq = model.R, model.S, model.β_seq +def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): + R, T, β_seq = model.R, model.T, model.β_seq - ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(S+1))) * ((1 - (ϕ/R)**(S+1)) / (1 - ϕ/R)) - v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(S+1)]) + ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(T+1))) * ((1 - (ϕ/R)**(T+1)) / (1 - ϕ/R)) + v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(T+1)]) if verbose == 1: - print('check feasible:', np.isclose(β_seq @ v_seq, 0)) + print('check feasible:', np.isclose(β_seq @ v_seq, 0)) # since β = 1/R - T_opt, _, _ = compute_optimal(model, B0, G_seq) - Tvar_seq = T_opt + v_seq + c_opt, _, _ = compute_optimal(model, a0, y_seq) + cvar_seq = c_opt + v_seq - return Tvar_seq + return cvar_seq ``` + We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ ```{code-cell} ipython3 fig, ax = plt.subplots() + ξ1s = [.01, .05] ϕs= [.95, 1.02] colors = {.01: 'tab:blue', .05: 'tab:green'} + params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) for i, param in enumerate(params): ξ1, ϕ = param print(f'variation {i}: ξ1={ξ1}, ϕ={ϕ}') - - Tvar_seq = compute_variation(model=tax_model, - ξ1=ξ1, ϕ=ϕ, B0=B0, - G_seq=G_seq) - print(f'cost={cost(tax_model, Tvar_seq)}') + cvar_seq = compute_variation(model=cs_model, + ξ1=ξ1, ϕ=ϕ, a0=a0, + y_seq=y_seq) + print(f'welfare={welfare(cs_model, cvar_seq)}') print('-'*64) - if i % 2 == 0: ls = '-.' else: ls = '-' - ax.plot(range(S+1), Tvar_seq, ls=ls, + ax.plot(range(T+1), cvar_seq, ls=ls, color=colors[ξ1], label=fr'$\xi_1 = {ξ1}, \phi = {ϕ}$') -plt.plot(range(S+1), T_seq, - color='orange', label=r'Optimal $\vec{T}$ ') +plt.plot(range(T+1), c_seq, + color='orange', label=r'Optimal $\vec{c}$ ') plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$T_t$') +plt.ylabel(r'$c_t$') plt.show() ``` -We can even use the Python `np.gradient` command to compute derivatives of cost with respect to our two parameters. + + +We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. We are teaching the key idea beneath the **calculus of variations**. -First, we define the cost with respect to $\xi_1$ and $\phi$ + +First, we define the welfare with respect to $\xi_1$ and $\phi$ ```{code-cell} ipython3 -def cost_rel(ξ1, ϕ): +def welfare_rel(ξ1, ϕ): """ - Compute cost of variation sequence - for given ϕ, ξ1 with a tax-smoothing model + Compute welfare of variation sequence + for given ϕ, ξ1 with a consumption-smoothing model """ - Tvar_seq = compute_variation(tax_model, ξ1=ξ1, - ϕ=ϕ, B0=B0, - G_seq=G_seq, + cvar_seq = compute_variation(cs_model, ξ1=ξ1, + ϕ=ϕ, a0=a0, + y_seq=y_seq, verbose=0) - return cost(tax_model, Tvar_seq) + return welfare(cs_model, cvar_seq) + # Vectorize the function to allow array input -cost_vec = np.vectorize(cost_rel) +welfare_vec = np.vectorize(welfare_rel) ``` -Then we can visualize the relationship between cost and $\xi_1$ and compute its derivatives + + +Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 ξ1_arr = np.linspace(-0.5, 0.5, 20) -plt.plot(ξ1_arr, cost_vec(ξ1_arr, 1.02)) -plt.ylabel('cost') +plt.plot(ξ1_arr, welfare_vec(ξ1_arr, 1.02)) +plt.ylabel('welfare') plt.xlabel(r'$\xi_1$') plt.show() -cost_grad = cost_vec(ξ1_arr, 1.02) -cost_grad = np.gradient(cost_grad) -plt.plot(ξ1_arr, cost_grad) -plt.ylabel('derivative of cost') +welfare_grad = welfare_vec(ξ1_arr, 1.02) +welfare_grad = np.gradient(welfare_grad) +plt.plot(ξ1_arr, welfare_grad) +plt.ylabel('derivative of welfare') plt.xlabel(r'$\xi_1$') plt.show() ``` + The same can be done on $\phi$ ```{code-cell} ipython3 ϕ_arr = np.linspace(-0.5, 0.5, 20) -plt.plot(ξ1_arr, cost_vec(0.05, ϕ_arr)) -plt.ylabel('cost') +plt.plot(ξ1_arr, welfare_vec(0.05, ϕ_arr)) +plt.ylabel('welfare') plt.xlabel(r'$\phi$') plt.show() -cost_grad = cost_vec(0.05, ϕ_arr) -cost_grad = np.gradient(cost_grad) -plt.plot(ξ1_arr, cost_grad) -plt.ylabel('derivative of cost') +welfare_grad = welfare_vec(0.05, ϕ_arr) +welfare_grad = np.gradient(welfare_grad) +plt.plot(ξ1_arr, welfare_grad) +plt.ylabel('derivative of welfare') plt.xlabel(r'$\phi$') plt.show() ``` - +remains active today. ## Appendix: solving difference equations with linear algebra -In the preceding sections we have used linear algebra to solve a tax-smoothing model. +In the preceding sections we have used linear algebra to solve a consumption-smoothing model. -The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. +The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. We'll conclude this lecture by giving a couple of examples. We'll describe a useful way of representing and "solving" linear difference equations. -To generate some $G$ vectors, we'll just write down a linear difference equation -with appropriate initial conditions and then use linear algebra to solve it. +To generate some $y$ vectors, we'll just write down a linear difference equation +with appropriate initial conditions and then use linear algebra to solve it. ### First-order difference equation -We'll start with a first-order linear difference equation for $\{G_t\}_{t=0}^S$: +We'll start with a first-order linear difference equation for $\{y_t\}_{t=0}^T$: $$ -G_{t} = \lambda G_{t-1}, \quad t = 1, 2, \ldots, S +y_{t} = \lambda y_{t-1}, \quad t = 1, 2, \ldots, T $$ -where $G_0$ is a given initial government expenditure. +where $y_0$ is a given initial condition. + -We can cast this set of $S$ equations as a single matrix equation +We can cast this set of $T$ equations as a single matrix equation $$ \begin{bmatrix} @@ -664,20 +700,22 @@ $$ 0 & 0 & 0 & \cdots & -\lambda & 1 \end{bmatrix} \begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix} = \begin{bmatrix} -\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} $$ (eq:first_order_lin_diff) -Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution + +Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution ```{math} :label: fst_ord_inverse + \begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix} = \begin{bmatrix} @@ -685,17 +723,17 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \lambda & 1 & 0 & \cdots & 0 & 0 \cr \lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 +\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & \lambda & 1 \end{bmatrix} \begin{bmatrix} -\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} ``` ```{exercise} -:label: taxsmooth_ex1 +:label: consmooth_ex1 -To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that +To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that $$ \begin{bmatrix} @@ -703,24 +741,25 @@ $$ \lambda & 1 & 0 & \cdots & 0 & 0 \cr \lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 +\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & \lambda & 1 \end{bmatrix} $$ is the inverse of $A$ and check that $A A^{-1} = I$ + ``` ### Second-order difference equation -A second-order linear difference equation for $\{G_t\}_{t=0}^S$ is +A second-order linear difference equation for $\{y_t\}_{t=0}^T$ is $$ -G_{t} = \lambda_1 G_{t-1} + \lambda_2 G_{t-2}, \quad t = 1, 2, \ldots, S +y_{t} = \lambda_1 y_{t-1} + \lambda_2 y_{t-2}, \quad t = 1, 2, \ldots, T $$ -where now $G_0$ and $G_{-1}$ are two given initial expenditure levels determined outside the model. +where now $y_0$ and $y_{-1}$ are two given initial equations determined outside the model. -As we did with the first-order difference equation, we can cast this set of $S$ equations as a single matrix equation +As we did with the first-order difference equation, we can cast this set of $T$ equations as a single matrix equation $$ \begin{bmatrix} @@ -731,18 +770,18 @@ $$ 0 & 0 & 0 & \cdots & -\lambda_2 & -\lambda_1 & 1 \end{bmatrix} \begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix} = \begin{bmatrix} -\lambda_1 G_0 + \lambda_2 G_{-1} \cr \lambda_2 G_0 \cr 0 \cr \vdots \cr 0 +\lambda_1 y_0 + \lambda_2 y_{-1} \cr \lambda_2 y_0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} $$ -Multiplying both sides by inverse of the matrix on the left again provides the solution. +Multiplying both sides by inverse of the matrix on the left again provides the solution. ```{exercise} -:label: taxsmooth_ex2 +:label: consmooth_ex2 As an exercise, we ask you to represent and solve a **third-order linear difference equation**. How many initial conditions must you specify? diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md new file mode 100644 index 00000000..84259c89 --- /dev/null +++ b/lectures/tax_smooth.md @@ -0,0 +1,749 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.6 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Tax Smoothing + +## Overview + + +In this lecture, we'll study a famous model of optimal tax policy that Robert Barro {cite}`Barro1979` proposed to explain why governments might want to use debt to smooth tax rates over time rather than balancing their budgets period by period. + +In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. + +Formulas presented in {doc}`present value formulas` are at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. + +The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes gradually over time. + +This approach allows the government to minimize the distortionary costs of taxation by keeping tax rates relatively stable. + +## Analysis + +As usual, we'll start by importing some Python modules. + +```{code-cell} ipython3 +import numpy as np +import matplotlib.pyplot as plt +from collections import namedtuple +``` + +The model describes a government that operates from time $t=0, 1, \ldots, S$, faces a stream of expenditures $\{G_t\}_{t=0}^S$ and chooses a stream of tax collections $\{T_t\}_{t=0}^S$. + +We usually think of the government expenditure stream as exogenous spending requirements that the government must finance. + +The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. + +The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. + +To set up the model, let + + * $S \geq 2$ be a positive integer that constitutes a time-horizon. + * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. + * $B = \{B_t\}_{t=0}^{S+1}$ be a sequence of government debt. + * $T = \{T_t\}_{t=0}^S$ be a sequence of tax collections. + * $R \geq 1$ be a fixed gross one period interest rate. + * $\beta \in (0,1)$ be a fixed discount factor. + * $B_0$ be a given initial level of government debt + * $B_{S+1} \geq 0$ be a terminal condition on final government debt. + +The sequence of government debt $B$ is to be determined by the model. + +We require it to satisfy two **boundary conditions**: + * it must equal an exogenous value $B_0$ at time $0$ + * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. + +The **terminal condition** $B_{S+1} \geq 0$ is a constraint that prevents the government from running Ponzi schemes by requiring that it not end with negative assets. + +(This no-Ponzi condition ensures that the government must ultimately pay off its debts rather than rolling them over indefinitely.) + +The government faces a sequence of budget constraints that constrains sequences $(G, T, B)$ + +$$ +B_{t+1} = R (B_t + G_t - T_t), \quad t =0, 1, \ldots S +$$ (eq:B_t) + +Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t=0, 1, \ldots, S$. + +Given a sequence $G$ of government expenditures, a large set of pairs $(B, T)$ of (government debt, tax collections) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. + +Our model has the following logical flow: + + * start with an exogenous government expenditure sequence $G$, an initial government debt $B_0$, and + a candidate tax collection path $T$. + + * use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt + + * verify that $B_{S+1}$ satisfies the terminal debt constraint $B_{S+1} \geq 0$. + + * If it does, declare that the candidate path is **budget feasible**. + + * if the candidate tax path is not budget feasible, propose a different tax path and start over + +Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. + +The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent +with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. + +In general, there are **many** budget feasible tax paths $T$. + +Among all budget-feasible tax paths, which one should a government choose? + +To answer this question, we shall eventually evaluate alternative budget feasible tax paths $T$ using the following cost functional: + +```{math} +:label: cost + +L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +``` + +where $g_1 > 0, g_2 > 0$. + +This is called the "present value of revenue-raising costs" in {citep}`Barro1979` + +When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. This creates an incentive for tax smoothing. + +Indeed, we shall see that when $\beta R = 1$ (a condition assumed in many public finance models), criterion {eq}`cost` leads to smoother tax paths. + +By **smoother** we mean tax rates that are as close as possible to being constant over time. + +The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {citep}`Barro1979`'s seminal work. + +Let's dive in and do some calculations that will help us understand how the model works. + +Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. + +We create a Python **namedtuple** to store these parameters with default values. + +```{code-cell} ipython3 +TaxSmoothing = namedtuple("TaxSmoothing", + ["R", "g1", "g2", "β_seq", "S"]) + +def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): + """ + Creates an instance of the tax smoothing model. + """ + β = 1/R + β_seq = np.array([β**i for i in range(S+1)]) + + return TaxSmoothing(R, g1, g2, β_seq, S) +``` + +## Barro Tax-Smoothing Model + +A key object is the present value of government expenditures at time $0$: + +$$ +h_0 \equiv \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +$$ + +This sum represents the present value of all future government expenditures that must be financed. + +Formally it resembles the present value calculations we saw in this QuantEcon lecture {doc}`present values `. + +This present value calculation is crucial for determining the government's total financing needs. + +By iterating on equation {eq}`eq:B_t` and imposing the terminal condition + +$$ +B_{S+1} = 0, +$$ + +it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a single intertemporal constraint + +$$ +\sum_{t=0}^S R^{-t} T_t = B_0 + h_0. +$$ (eq:budget_intertemp) + +Equation {eq}`eq:budget_intertemp` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. + +When $\beta R = 1$, it is optimal for a government to smooth taxes by setting + +$$ +T_t = T_0 \quad t =0, 1, \ldots, S +$$ + +(Later we'll present a "variational argument" that shows that this constant path minimizes +criterion {eq}`cost` when $\beta R =1$.) + +In this case, we can use the intertemporal budget constraint to write + +$$ +T_t = T_0 = \left(\sum_{t=0}^S R^{-t}\right)^{-1} (B_0 + h_0), \quad t= 0, 1, \ldots, S. +$$ (eq:taxsmoothing) + +Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. + +## Mechanics of Tax-Smoothing Model + +As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. + +In the calculations below, we'll set default values of $R > 1$, e.g., $R = 1.05$, and $\beta = R^{-1}$. + +### Step 1 + +For a $(S+1) \times 1$ vector $G$ of government expenditures, use matrix algebra to compute the present value + +$$ +h_0 = \sum_{t=0}^S R^{-t} G_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-S} \end{bmatrix} +\begin{bmatrix} G_0 \cr G_1 \cr \vdots \cr G_S \end{bmatrix} +$$ + +### Step 2 + +Compute a constant tax rate $T_0$: + +$$ +T_t = T_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(S+1)}} \right) (B_0 + \sum_{t=0}^S R^{-t} G_t ) , \quad t = 0, 1, \ldots, S +$$ + +### Step 3 + +Use the system of equations {eq}`eq:B_t` for $t=0, \ldots, S$ to compute a path $B$ of government debt. + +To do this, we translate that system of difference equations into a single matrix equation as follows: + +$$ +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr +-R & 1 & 0 & \cdots & 0 & 0 & 0 \cr +0 & -R & 1 & \cdots & 0 & 0 & 0 \cr +\vdots &\vdots & \vdots & \cdots & \vdots & \vdots & \vdots \cr +0 & 0 & 0 & \cdots & -R & 1 & 0 \cr +0 & 0 & 0 & \cdots & 0 & -R & 1 +\end{bmatrix} +\begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} +\end{bmatrix} += R +\begin{bmatrix} G_0 + B_0 - T_0 \cr G_1 - T_0 \cr G_2 - T_0 \cr \vdots\cr G_{S-1} - T_0 \cr G_S - T_0 +\end{bmatrix} +$$ + +Multiply both sides by the inverse of the matrix on the left side to compute + +$$ + \begin{bmatrix} B_1 \cr B_2 \cr B_3 \cr \vdots \cr B_S \cr B_{S+1} \end{bmatrix} +$$ + +Because we have built into our calculations that the government must satisfy its intertemporal budget constraint and end with zero debt, just barely satisfying the +terminal condition that $B_{S+1} \geq 0$, it should turn out that + +$$ +B_{S+1} = 0. +$$ + +Let's verify this with Python code. + +First we implement the model with `compute_optimal` + +```{code-cell} ipython3 + +def compute_optimal(model, B0, G_seq): + + R, S = model.R, model.S + + # present value of government expenditures + h0 = model.β_seq @ G_seq # since β = 1/R + + # optimal constant tax rate + T0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) + T_seq = T0*np.ones(S+1) + + # verify + A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) + b = G_seq - T_seq + b[0] = b[0] + B0 + B_seq = np.linalg.inv(A) @ b + B_seq = np.concatenate([[B0], B_seq]) + + return T_seq, B_seq, h0 +``` + +We use an example where the government starts with initial debt $B_0>0$. + +This represents the government's inherited debt burden. + +The government expenditure process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then drops to zero afterward. + +The drop in government expenditures could reflect a change in spending requirements or demographic shifts. + +```{code-cell} ipython3 +# Initial debt +B0 = -2 # initial government debt + +# Government expenditure process +G_seq = np.concatenate([np.ones(46), np.zeros(20)]) +tax_model = create_tax_smoothing_model() +T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) + +print('check B_S+1=0:', + np.abs(B_seq[-1] - 0) <= 1e-8) +``` + +The graphs below show paths of government expenditures, tax collections, and government debt. + +```{code-cell} ipython3 + +# Sequence Length +S = tax_model.S + +plt.plot(range(S+1), G_seq, label='government expenditures') +plt.plot(range(S+1), T_seq, label='tax collections') +plt.plot(range(S+2), B_seq, label='government debt') +plt.plot(range(S+2), np.zeros(S+2), '--') + +plt.legend() +plt.xlabel(r'$t$') +plt.ylabel(r'$T_t,G_t,B_t$') +plt.show() +``` + +Note that $B_{S+1} = 0$, as anticipated. + +We can evaluate cost criterion {eq}`cost` which measures the total cost of taxation + +```{code-cell} ipython3 +def cost(model, T_seq): + β_seq, g1, g2 = model.β_seq, model.g1, model.g2 + cost_seq = g1 * T_seq - g2/2 * T_seq**2 + return β_seq @ cost_seq + +print('Cost:', cost(tax_model, T_seq)) +``` + +### Experiments +In this section we describe how a tax sequence would optimally respond to different sequences of government expenditures. +First we create a function `plot_ts` that generates graphs for different instances of the tax-smoothing model `tax_model`. +This will help us avoid rewriting code to plot outcomes for different government expenditure sequences. +```{code-cell} ipython3 +def plot_ts(model, # tax-smoothing model + B0, # initial government debt + G_seq # government expenditure process + ): + + # Compute optimal tax path + T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) + + # Sequence length + S = tax_model.S + + # Generate plot + plt.plot(range(S+1), G_seq, label='government expenditures') + plt.plot(range(S+1), T_seq, label='tax collections') + plt.plot(range(S+2), B_seq, label='government debt') + plt.plot(range(S+2), np.zeros(S+2), '--') + + plt.legend() + plt.xlabel(r'$t$') + plt.ylabel(r'$T_t,G_t,B_t$') + plt.show() +``` +In the experiments below, please study how tax and government debt sequences vary across different sequences for government expenditures. + +#### Experiment 1: one-time spending shock + +We first assume a one-time spending shock of $W_0$ in year 21 of the expenditure sequence $G$. + +We'll make $W_0$ big - positive to indicate a spending surge (like a war or disaster), and negative to indicate a spending cut. + +```{code-cell} ipython3 +# Spending surge W_0 = 2.5 +G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_pos) +``` + +```{code-cell} ipython3 +# Spending cut W_0 = -2.5 +G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_neg) +``` + +#### Experiment 2: permanent expenditure shift + +Now we assume a permanent increase in government expenditures of $L$ in year 21 of the $G$-sequence. + +Again we can study positive and negative cases + +```{code-cell} ipython3 +# Positive permanent expenditure shift L = 0.5 when t >= 21 +G_seq_pos = np.concatenate( + [np.ones(21), 1.5*np.ones(25), np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_pos) +``` + +```{code-cell} ipython3 +# Negative permanent expenditure shift L = -0.5 when t >= 21 +G_seq_neg = np.concatenate( + [np.ones(21), .5*np.ones(25), np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_neg) +``` + +#### Experiment 3: delayed spending + +Now we simulate a $G$ sequence in which government expenditures are zero for 46 years, and then rise to 1 for the last 20 years (perhaps due to demographic aging) + +```{code-cell} ipython3 +# Delayed spending +G_seq_late = np.concatenate( + [np.zeros(46), np.ones(20)]) + +plot_ts(tax_model, B0, G_seq_late) +``` + +#### Experiment 4: growing expenditures + +Now we simulate a geometric $G$ sequence in which government expenditures grow at rate $G_t = \lambda^t G_0$ in first 46 years. + +We first experiment with $\lambda = 1.05$ (growing expenditures) + +```{code-cell} ipython3 +# Geometric growth parameters where λ = 1.05 +λ = 1.05 +G_0 = 1 +t_max = 46 + +# Generate geometric G sequence +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( + [geo_seq, np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +Now we show the behavior when $\lambda = 0.95$ (declining expenditures) + +```{code-cell} ipython3 +λ = 0.95 +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( + [geo_seq, np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +What happens with oscillating expenditures + +```{code-cell} ipython3 +λ = -0.95 +geo_seq = λ ** np.arange(t_max) * G_0 +G_seq_geo = np.concatenate( + [geo_seq, np.zeros(20)]) + +plot_ts(tax_model, B0, G_seq_geo) +``` + +### Feasible Tax Variations + +We promised to justify our claim that a constant tax rate $T_t = T_0$ for all $t$ is optimal. + +Let's do that now. +The approach we'll take is an elementary example of the "calculus of variations". + +Let's dive in and see what the key idea is. + +To explore what types of tax paths are welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ +that satisfies + +$$ +\sum_{t=0}^S R^{-t} v_t = 0 +$$ + +This equation says that the **present value** of admissible tax path variations must be zero. + +So once again, we encounter a formula for the present value: + + * we require that the present value of tax path variations be zero to maintain budget balance. + +Here we'll restrict ourselves to a two-parameter class of admissible tax path variations of the form + +$$ +v_t = \xi_1 \phi^t - \xi_0 +$$ + +We say two and not three-parameter class because $\xi_0$ will be a function of $(\phi, \xi_1; R)$ that guarantees that the variation sequence is feasible. + +Let's compute that function. + +We require + +$$ +\sum_{t=0}^S R^{-t}\left[ \xi_1 \phi^t - \xi_0 \right] = 0 +$$ + +which implies that + +$$ +\xi_1 \sum_{t=0}^S \phi_t R^{-t} - \xi_0 \sum_{t=0}^S R^{-t} = 0 +$$ + +which implies that + +$$ +\xi_1 \frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}} - \xi_0 \frac{1 - R^{-(S+1)}}{1-R^{-1} } =0 +$$ + +which implies that + +$$ +\xi_0 = \xi_0(\phi, \xi_1; R) = \xi_1 \left(\frac{1 - R^{-1}}{1 - R^{-(S+1)}}\right) \left(\frac{1 - (\phi R^{-1})^{S+1}}{1 - \phi R^{-1}}\right) +$$ + +This is our formula for $\xi_0$. + +**Key Idea:** if $T^o$ is a budget-feasible tax path, then so is $T^o + v$, +where $v$ is a budget-feasible variation. + +Given $R$, we thus have a two parameter class of budget feasible variations $v$ that we can use +to compute alternative tax paths, then evaluate their welfare costs. + +Now let's compute and plot tax path variations + +```{code-cell} ipython3 +def compute_variation(model, ξ1, ϕ, B0, G_seq, verbose=1): + R, S, β_seq = model.R, model.S, model.β_seq + + ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(S+1))) * ((1 - (ϕ/R)**(S+1)) / (1 - ϕ/R)) + v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(S+1)]) + + if verbose == 1: + print('check feasible:', np.isclose(β_seq @ v_seq, 0)) + + T_opt, _, _ = compute_optimal(model, B0, G_seq) + Tvar_seq = T_opt + v_seq + + return Tvar_seq +``` + +We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ + +```{code-cell} ipython3 +fig, ax = plt.subplots() +ξ1s = [.01, .05] +ϕs= [.95, 1.02] +colors = {.01: 'tab:blue', .05: 'tab:green'} +params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) + +for i, param in enumerate(params): + ξ1, ϕ = param + print(f'variation {i}: ξ1={ξ1}, ϕ={ϕ}') + + Tvar_seq = compute_variation(model=tax_model, + ξ1=ξ1, ϕ=ϕ, B0=B0, + G_seq=G_seq) + print(f'cost={cost(tax_model, Tvar_seq)}') + print('-'*64) + + if i % 2 == 0: + ls = '-.' + else: + ls = '-' + ax.plot(range(S+1), Tvar_seq, ls=ls, + color=colors[ξ1], + label=fr'$\xi_1 = {ξ1}, \phi = {ϕ}$') + +plt.plot(range(S+1), T_seq, + color='orange', label=r'Optimal $\vec{T}$ ') + +plt.legend() +plt.xlabel(r'$t$') +plt.ylabel(r'$T_t$') +plt.show() +``` +We can even use the Python `np.gradient` command to compute derivatives of cost with respect to our two parameters. + +We are teaching the key idea beneath the **calculus of variations**. +First, we define the cost with respect to $\xi_1$ and $\phi$ + +```{code-cell} ipython3 +def cost_rel(ξ1, ϕ): + """ + Compute cost of variation sequence + for given ϕ, ξ1 with a tax-smoothing model + """ + + Tvar_seq = compute_variation(tax_model, ξ1=ξ1, + ϕ=ϕ, B0=B0, + G_seq=G_seq, + verbose=0) + return cost(tax_model, Tvar_seq) +# Vectorize the function to allow array input +cost_vec = np.vectorize(cost_rel) +``` +Then we can visualize the relationship between cost and $\xi_1$ and compute its derivatives + +```{code-cell} ipython3 +ξ1_arr = np.linspace(-0.5, 0.5, 20) + +plt.plot(ξ1_arr, cost_vec(ξ1_arr, 1.02)) +plt.ylabel('cost') +plt.xlabel(r'$\xi_1$') +plt.show() + +cost_grad = cost_vec(ξ1_arr, 1.02) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') +plt.xlabel(r'$\xi_1$') +plt.show() +``` + +The same can be done on $\phi$ + +```{code-cell} ipython3 +ϕ_arr = np.linspace(-0.5, 0.5, 20) + +plt.plot(ξ1_arr, cost_vec(0.05, ϕ_arr)) +plt.ylabel('cost') +plt.xlabel(r'$\phi$') +plt.show() + +cost_grad = cost_vec(0.05, ϕ_arr) +cost_grad = np.gradient(cost_grad) +plt.plot(ξ1_arr, cost_grad) +plt.ylabel('derivative of cost') +plt.xlabel(r'$\phi$') +plt.show() +``` + + + + +## Appendix: solving difference equations with linear algebra + +In the preceding sections we have used linear algebra to solve a tax-smoothing model. + +The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. + +We'll conclude this lecture by giving a couple of examples. + +We'll describe a useful way of representing and "solving" linear difference equations. + +To generate some $G$ vectors, we'll just write down a linear difference equation +with appropriate initial conditions and then use linear algebra to solve it. + +### First-order difference equation + +We'll start with a first-order linear difference equation for $\{G_t\}_{t=0}^S$: + +$$ +G_{t} = \lambda G_{t-1}, \quad t = 1, 2, \ldots, S +$$ + +where $G_0$ is a given initial government expenditure. + +We can cast this set of $S$ equations as a single matrix equation + +$$ +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 \cr +-\lambda & 1 & 0 & \cdots & 0 & 0 \cr +0 & -\lambda & 1 & \cdots & 0 & 0 \cr + \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr +0 & 0 & 0 & \cdots & -\lambda & 1 +\end{bmatrix} +\begin{bmatrix} +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +\end{bmatrix} += +\begin{bmatrix} +\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\end{bmatrix} +$$ (eq:first_order_lin_diff) + +Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution + +```{math} +:label: fst_ord_inverse +\begin{bmatrix} +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +\end{bmatrix} += +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 \cr +\lambda & 1 & 0 & \cdots & 0 & 0 \cr +\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr + \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr +\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 +\end{bmatrix} +\begin{bmatrix} +\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 +\end{bmatrix} +``` + +```{exercise} +:label: taxsmooth_ex1 + +To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that + +$$ +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 \cr +\lambda & 1 & 0 & \cdots & 0 & 0 \cr +\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr + \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr +\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 +\end{bmatrix} +$$ + +is the inverse of $A$ and check that $A A^{-1} = I$ +``` + +### Second-order difference equation + +A second-order linear difference equation for $\{G_t\}_{t=0}^S$ is + +$$ +G_{t} = \lambda_1 G_{t-1} + \lambda_2 G_{t-2}, \quad t = 1, 2, \ldots, S +$$ + +where now $G_0$ and $G_{-1}$ are two given initial expenditure levels determined outside the model. + +As we did with the first-order difference equation, we can cast this set of $S$ equations as a single matrix equation + +$$ +\begin{bmatrix} +1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr +-\lambda_1 & 1 & 0 & \cdots & 0 & 0 & 0 \cr +-\lambda_2 & -\lambda_1 & 1 & \cdots & 0 & 0 & 0 \cr + \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr +0 & 0 & 0 & \cdots & -\lambda_2 & -\lambda_1 & 1 +\end{bmatrix} +\begin{bmatrix} +G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S +\end{bmatrix} += +\begin{bmatrix} +\lambda_1 G_0 + \lambda_2 G_{-1} \cr \lambda_2 G_0 \cr 0 \cr \vdots \cr 0 +\end{bmatrix} +$$ + +Multiplying both sides by inverse of the matrix on the left again provides the solution. + +```{exercise} +:label: taxsmooth_ex2 + +As an exercise, we ask you to represent and solve a **third-order linear difference equation**. +How many initial conditions must you specify? +``` \ No newline at end of file From f4ca4eb5bc88cdc1451235ac920741fc8a1a3f2e Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 16:26:07 +1100 Subject: [PATCH 05/15] update tax smooth lecture --- lectures/tax_smooth.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 84259c89..609e7fc5 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -20,7 +20,11 @@ In this lecture, we'll study a famous model of optimal tax policy that Robert Ba In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. -Formulas presented in {doc}`present value formulas` are at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. +This lecture is a sister lecture to the consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978` that we studied in this QuantEcon lecture {doc}`consumption-smoothing `. + +Formulas presented in {doc}`present value formulas` are again at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. + +The government's optimization problem is to choose a tax collection path that minimizes the present value of the costs of raising revenue. The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes gradually over time. @@ -38,9 +42,9 @@ from collections import namedtuple The model describes a government that operates from time $t=0, 1, \ldots, S$, faces a stream of expenditures $\{G_t\}_{t=0}^S$ and chooses a stream of tax collections $\{T_t\}_{t=0}^S$. -We usually think of the government expenditure stream as exogenous spending requirements that the government must finance. +The government expenditure stream is exogenous spending requirements that the government must finance. -The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +Analogous to {doc}`consumption-smoothing `, The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. @@ -107,7 +111,7 @@ L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) where $g_1 > 0, g_2 > 0$. -This is called the "present value of revenue-raising costs" in {citep}`Barro1979` +This is called the "present value of revenue-raising costs" in {cite}`Barro1979`. When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. This creates an incentive for tax smoothing. @@ -115,7 +119,7 @@ Indeed, we shall see that when $\beta R = 1$ (a condition assumed in many public By **smoother** we mean tax rates that are as close as possible to being constant over time. -The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {citep}`Barro1979`'s seminal work. +The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {cite}`Barro1979`'s seminal work. Let's dive in and do some calculations that will help us understand how the model works. @@ -162,9 +166,9 @@ it is possible to convert a sequence of budget constraints {eq}`eq:B_t` into a s $$ \sum_{t=0}^S R^{-t} T_t = B_0 + h_0. -$$ (eq:budget_intertemp) +$$ (eq:budget_intertemp_tax) -Equation {eq}`eq:budget_intertemp` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. +Equation {eq}`eq:budget_intertemp_tax` says that the present value of tax collections must equal the sum of initial debt and the present value of government expenditures. When $\beta R = 1$, it is optimal for a government to smooth taxes by setting @@ -670,12 +674,12 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \begin{bmatrix} \lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix} -$$ (eq:first_order_lin_diff) +$$ (eq:first_order_lin_diff_tax) -Multiplying both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix on the left provides the solution +Multiplying both sides of {eq}`eq:first_order_lin_diff_tax` by the inverse of the matrix on the left provides the solution ```{math} -:label: fst_ord_inverse +:label: eq:fst_ord_inverse_tax \begin{bmatrix} G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S \end{bmatrix} @@ -695,7 +699,7 @@ G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S ```{exercise} :label: taxsmooth_ex1 -To get {eq}`fst_ord_inverse`, we multiplied both sides of {eq}`eq:first_order_lin_diff` by the inverse of the matrix $A$. Please confirm that +To get {eq}`eq:fst_ord_inverse_tax`, we multiplied both sides of {eq}`eq:first_order_lin_diff_tax` by the inverse of the matrix $A$. Please confirm that $$ \begin{bmatrix} From 33fdd7803790267888b90a7a40b759024683f4e0 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 17:15:05 +1100 Subject: [PATCH 06/15] update lecture --- lectures/tax_smooth.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 609e7fc5..4e774d4d 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -325,9 +325,13 @@ print('Cost:', cost(tax_model, T_seq)) ``` ### Experiments + In this section we describe how a tax sequence would optimally respond to different sequences of government expenditures. + First we create a function `plot_ts` that generates graphs for different instances of the tax-smoothing model `tax_model`. + This will help us avoid rewriting code to plot outcomes for different government expenditure sequences. + ```{code-cell} ipython3 def plot_ts(model, # tax-smoothing model B0, # initial government debt @@ -351,6 +355,7 @@ def plot_ts(model, # tax-smoothing model plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` + In the experiments below, please study how tax and government debt sequences vary across different sequences for government expenditures. #### Experiment 1: one-time spending shock @@ -361,14 +366,16 @@ We'll make $W_0$ big - positive to indicate a spending surge (like a war or disa ```{code-cell} ipython3 # Spending surge W_0 = 2.5 -G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), np.ones(24), np.zeros(20)]) +G_seq_pos = np.concatenate([np.ones(21), np.array([2.5]), +np.ones(24), np.zeros(20)]) plot_ts(tax_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 # Spending cut W_0 = -2.5 -G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), np.ones(24), np.zeros(20)]) +G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), +np.ones(24), np.zeros(20)]) plot_ts(tax_model, B0, G_seq_neg) ``` @@ -454,6 +461,7 @@ plot_ts(tax_model, B0, G_seq_geo) We promised to justify our claim that a constant tax rate $T_t = T_0$ for all $t$ is optimal. Let's do that now. + The approach we'll take is an elementary example of the "calculus of variations". Let's dive in and see what the key idea is. @@ -462,7 +470,7 @@ To explore what types of tax paths are welfare-improving, we shall create an **a that satisfies $$ -\sum_{t=0}^S R^{-t} v_t = 0 +\sum_{t=0}^S R^{-t} v_t = 0. $$ This equation says that the **present value** of admissible tax path variations must be zero. @@ -474,7 +482,7 @@ So once again, we encounter a formula for the present value: Here we'll restrict ourselves to a two-parameter class of admissible tax path variations of the form $$ -v_t = \xi_1 \phi^t - \xi_0 +v_t = \xi_1 \phi^t - \xi_0. $$ We say two and not three-parameter class because $\xi_0$ will be a function of $(\phi, \xi_1; R)$ that guarantees that the variation sequence is feasible. @@ -566,6 +574,7 @@ plt.xlabel(r'$t$') plt.ylabel(r'$T_t$') plt.show() ``` + We can even use the Python `np.gradient` command to compute derivatives of cost with respect to our two parameters. We are teaching the key idea beneath the **calculus of variations**. @@ -583,9 +592,11 @@ def cost_rel(ξ1, ϕ): G_seq=G_seq, verbose=0) return cost(tax_model, Tvar_seq) + # Vectorize the function to allow array input cost_vec = np.vectorize(cost_rel) ``` + Then we can visualize the relationship between cost and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 @@ -749,5 +760,6 @@ Multiplying both sides by inverse of the matrix on the left again provides the s :label: taxsmooth_ex2 As an exercise, we ask you to represent and solve a **third-order linear difference equation**. + How many initial conditions must you specify? ``` \ No newline at end of file From e2fcdd24296eaceb613d6a86380f2a4d645de000 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 18:47:54 +1100 Subject: [PATCH 07/15] update tax lecture --- lectures/tax_smooth.md | 59 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 4e774d4d..c143fd79 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -20,13 +20,15 @@ In this lecture, we'll study a famous model of optimal tax policy that Robert Ba In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. -This lecture is a sister lecture to the consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978` that we studied in this QuantEcon lecture {doc}`consumption-smoothing `. +This lecture is a sister lecture to our previous lecture on {doc}`consumption-smoothing `. + +We will see how "reinterpretating" the paramters in the consumption-smoothing model can lead to the tax-smoothing model. Formulas presented in {doc}`present value formulas` are again at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. The government's optimization problem is to choose a tax collection path that minimizes the present value of the costs of raising revenue. -The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes gradually over time. +The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes *gradually* over time. This approach allows the government to minimize the distortionary costs of taxation by keeping tax rates relatively stable. @@ -44,7 +46,7 @@ The model describes a government that operates from time $t=0, 1, \ldots, S$, fa The government expenditure stream is exogenous spending requirements that the government must finance. -Analogous to {doc}`consumption-smoothing `, The model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +Analogous to {doc}`consumption-smoothing `, the model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. @@ -106,26 +108,37 @@ To answer this question, we shall eventually evaluate alternative budget feasibl ```{math} :label: cost -L = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +L = - \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) ``` where $g_1 > 0, g_2 > 0$. + This is called the "present value of revenue-raising costs" in {cite}`Barro1979`. -When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. This creates an incentive for tax smoothing. +When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. -Indeed, we shall see that when $\beta R = 1$ (a condition assumed in many public finance models), criterion {eq}`cost` leads to smoother tax paths. +This creates an incentive for tax smoothing. + +Indeed, we shall see that when $\beta R = 1$, criterion {eq}`cost` leads to smoother tax paths. By **smoother** we mean tax rates that are as close as possible to being constant over time. The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {cite}`Barro1979`'s seminal work. +Or equivalently, we can transform this into the same problem as in the {doc}`consumption-smoothing ` lecture by maximizing the welfare criterion: + +```{math} +:label: welfare_tax + +J = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +``` + Let's dive in and do some calculations that will help us understand how the model works. Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $S = 65$. -We create a Python **namedtuple** to store these parameters with default values. +We create a Python ``namedtuple`` to store these parameters with default values. ```{code-cell} ipython3 TaxSmoothing = namedtuple("TaxSmoothing", @@ -141,7 +154,7 @@ def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): return TaxSmoothing(R, g1, g2, β_seq, S) ``` -## Barro Tax-Smoothing Model +## Barro tax-smoothing model A key object is the present value of government expenditures at time $0$: @@ -177,7 +190,7 @@ T_t = T_0 \quad t =0, 1, \ldots, S $$ (Later we'll present a "variational argument" that shows that this constant path minimizes -criterion {eq}`cost` when $\beta R =1$.) +criterion {eq}`cost` and maximizes {eq}`welfare_tax` when $\beta R =1$.) In this case, we can use the intertemporal budget constraint to write @@ -187,7 +200,7 @@ $$ (eq:taxsmoothing) Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. -## Mechanics of Tax-Smoothing Model +## Mechanics of tax-smoothing model As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. @@ -262,7 +275,6 @@ def compute_optimal(model, B0, G_seq): T0 = (1 - 1/R) / (1 - (1/R)**(S+1)) * (B0 + h0) T_seq = T0*np.ones(S+1) - # verify A = np.diag(-R*np.ones(S), k=-1) + np.eye(S+1) b = G_seq - T_seq b[0] = b[0] + B0 @@ -282,7 +294,7 @@ The drop in government expenditures could reflect a change in spending requireme ```{code-cell} ipython3 # Initial debt -B0 = -2 # initial government debt +B0 = 2 # initial government debt # Government expenditure process G_seq = np.concatenate([np.ones(46), np.zeros(20)]) @@ -313,15 +325,20 @@ plt.show() Note that $B_{S+1} = 0$, as anticipated. -We can evaluate cost criterion {eq}`cost` which measures the total cost of taxation +We can evaluate cost criterion {eq}`cost` which measures the total cost / welfare of taxation ```{code-cell} ipython3 def cost(model, T_seq): β_seq, g1, g2 = model.β_seq, model.g1, model.g2 cost_seq = g1 * T_seq - g2/2 * T_seq**2 - return β_seq @ cost_seq + return - β_seq @ cost_seq print('Cost:', cost(tax_model, T_seq)) + +def welfare(model, T_seq): + return - cost(model, T_seq) + +print('Welfare:', welfare(tax_model, T_seq)) ``` ### Experiments @@ -372,14 +389,6 @@ np.ones(24), np.zeros(20)]) plot_ts(tax_model, B0, G_seq_pos) ``` -```{code-cell} ipython3 -# Spending cut W_0 = -2.5 -G_seq_neg = np.concatenate([np.ones(21), np.array([-2.5]), -np.ones(24), np.zeros(20)]) - -plot_ts(tax_model, B0, G_seq_neg) -``` - #### Experiment 2: permanent expenditure shift Now we assume a permanent increase in government expenditures of $L$ in year 21 of the $G$-sequence. @@ -466,7 +475,7 @@ The approach we'll take is an elementary example of the "calculus of variations" Let's dive in and see what the key idea is. -To explore what types of tax paths are welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ +To explore what types of tax paths are cost-minimizing / welfare-improving, we shall create an **admissible tax path variation sequence** $\{v_t\}_{t=0}^S$ that satisfies $$ @@ -547,6 +556,7 @@ fig, ax = plt.subplots() ϕs= [.95, 1.02] colors = {.01: 'tab:blue', .05: 'tab:green'} params = np.array(np.meshgrid(ξ1s, ϕs)).T.reshape(-1, 2) +wel_opt = welfare(tax_model, T_seq) for i, param in enumerate(params): ξ1, ϕ = param @@ -555,7 +565,8 @@ for i, param in enumerate(params): Tvar_seq = compute_variation(model=tax_model, ξ1=ξ1, ϕ=ϕ, B0=B0, G_seq=G_seq) - print(f'cost={cost(tax_model, Tvar_seq)}') + print(f'welfare={welfare(tax_model, Tvar_seq)}') + print(f'welfare < optimal: {welfare(tax_model, Tvar_seq) < wel_opt}') print('-'*64) if i % 2 == 0: From d569dcbdb9d42cb4b6bbb28903dda88142b18a80 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 18:57:18 +1100 Subject: [PATCH 08/15] J to W --- lectures/tax_smooth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index c143fd79..8a6d1c99 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -131,7 +131,7 @@ Or equivalently, we can transform this into the same problem as in the {doc}`con ```{math} :label: welfare_tax -J = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) +W = \sum_{t=0}^S \beta^t (g_1 T_t - \frac{g_2}{2} T_t^2 ) ``` Let's dive in and do some calculations that will help us understand how the model works. From 3d5acfcb1e4f0cdd3d57ff820ddc31fe65f3481a Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Thu, 30 Jan 2025 22:33:57 +1100 Subject: [PATCH 09/15] update text --- lectures/tax_smooth.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 8a6d1c99..7fb525f6 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -116,15 +116,15 @@ where $g_1 > 0, g_2 > 0$. This is called the "present value of revenue-raising costs" in {cite}`Barro1979`. -When $\beta R \approx 1$, the quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. +The quadratic term $-\frac{g_2}{2} T_t^2$ captures increasing marginal costs of taxation, implying that tax distortions rise more than proportionally with tax rates. -This creates an incentive for tax smoothing. +This creates an incentive for tax smoothing. Indeed, we shall see that when $\beta R = 1$, criterion {eq}`cost` leads to smoother tax paths. By **smoother** we mean tax rates that are as close as possible to being constant over time. -The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model", following {cite}`Barro1979`'s seminal work. +The preference for smooth tax paths that is built into the model gives it the name "tax-smoothing model". Or equivalently, we can transform this into the same problem as in the {doc}`consumption-smoothing ` lecture by maximizing the welfare criterion: From 03262954fc412d2fcd0853ab6e3632135c4bedd7 Mon Sep 17 00:00:00 2001 From: thomassargent30 Date: Thu, 30 Jan 2025 16:49:06 -0500 Subject: [PATCH 10/15] Tom's Jan30 edits of tax-smooth lecture --- lectures/tax_smooth.md | 175 ++++++++--------------------------------- 1 file changed, 31 insertions(+), 144 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 7fb525f6..f800feed 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -16,21 +16,26 @@ kernelspec: ## Overview -In this lecture, we'll study a famous model of optimal tax policy that Robert Barro {cite}`Barro1979` proposed to explain why governments might want to use debt to smooth tax rates over time rather than balancing their budgets period by period. +This is a sister lecture to our lecture on {doc}`consumption-smoothing `. -In this lecture, we'll study what is often called the "tax-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. -This lecture is a sister lecture to our previous lecture on {doc}`consumption-smoothing `. +By renaming variables, we obtain a a version of a model "tax-smoothing model" that Robert Barro {cite}`Barro1979` used to explain why governments sometimes choose not to balance their budgets every period but instead use issue debt to smooth tax rates over time. + +The government chooses a tax collection path that minimizes the present value of its costs of raising revenue. + + +The government minimize those costs by varying tax collections little over time. + + +The present value of government expenditures is at the core of the tax-smoothing model, +so we'll again use formulas presented in {doc}`present value formulas`. + +We'll use the matrix multiplication and matrix inversion tools that we used in {doc}`present value formulas `. -We will see how "reinterpretating" the paramters in the consumption-smoothing model can lead to the tax-smoothing model. -Formulas presented in {doc}`present value formulas` are again at the core of the tax-smoothing model because we shall use them to compute the present value of government expenditures. -The government's optimization problem is to choose a tax collection path that minimizes the present value of the costs of raising revenue. -The key idea that inspired Barro was that temporary government spending surges (like wars or natural disasters) create a stream of expenditure requirements that could be optimally financed by issuing debt and raising taxes *gradually* over time. -This approach allows the government to minimize the distortionary costs of taxation by keeping tax rates relatively stable. ## Analysis @@ -42,15 +47,17 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` -The model describes a government that operates from time $t=0, 1, \ldots, S$, faces a stream of expenditures $\{G_t\}_{t=0}^S$ and chooses a stream of tax collections $\{T_t\}_{t=0}^S$. +A government exists at times $t=0, 1, \ldots, S$ and faces an exogenous stream of expenditures $\{G_t\}_{t=0}^S$. + +It chooses chooses a stream of tax collections $\{T_t\}_{t=0}^S$. -The government expenditure stream is exogenous spending requirements that the government must finance. +The model takes a government expenditure stream as an "exogenous" input that is somehow determined outside the model. -Analogous to {doc}`consumption-smoothing `, the model takes a government expenditure stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +The government faces a gross interest rate of $R >1$ that is constant over time. -The government faces a gross interest rate of $R >1$ that is constant over time, at which it is free to borrow or lend, subject to limits that we'll describe below. +The government can borrow or lend at interest rate $R$, subject to some limits on the amount of debt that it can issue that we'll describe below. -To set up the model, let +Let * $S \geq 2$ be a positive integer that constitutes a time-horizon. * $G = \{G_t\}_{t=0}^S$ be a sequence of government expenditures. @@ -59,7 +66,7 @@ To set up the model, let * $R \geq 1$ be a fixed gross one period interest rate. * $\beta \in (0,1)$ be a fixed discount factor. * $B_0$ be a given initial level of government debt - * $B_{S+1} \geq 0$ be a terminal condition on final government debt. + * $B_{S+1} \geq 0$ be a terminal condition. The sequence of government debt $B$ is to be determined by the model. @@ -67,11 +74,11 @@ We require it to satisfy two **boundary conditions**: * it must equal an exogenous value $B_0$ at time $0$ * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. -The **terminal condition** $B_{S+1} \geq 0$ is a constraint that prevents the government from running Ponzi schemes by requiring that it not end with negative assets. +The **terminal condition** $B_{S+1} \geq 0$ requires that it not end with negative assets. -(This no-Ponzi condition ensures that the government must ultimately pay off its debts rather than rolling them over indefinitely.) +(This no-Ponzi condition ensures that the government ultimately pays off its debts -- it can't simply roll them over indefinitely.) -The government faces a sequence of budget constraints that constrains sequences $(G, T, B)$ +The government faces a sequence of budget constraints that constrain sequences $(G, T, B)$ $$ B_{t+1} = R (B_t + G_t - T_t), \quad t =0, 1, \ldots S @@ -81,7 +88,7 @@ Equations {eq}`eq:B_t` constitute $S+1$ such budget constraints, one for each $t Given a sequence $G$ of government expenditures, a large set of pairs $(B, T)$ of (government debt, tax collections) sequences satisfy the sequence of budget constraints {eq}`eq:B_t`. -Our model has the following logical flow: +The model follows the following logical flow: * start with an exogenous government expenditure sequence $G$, an initial government debt $B_0$, and a candidate tax collection path $T$. @@ -96,14 +103,13 @@ Our model has the following logical flow: Below, we'll describe how to execute these steps using linear algebra -- matrix inversion and multiplication. -The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent -with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. +The above procedure seems like a sensible way to find "budget-feasible" tax paths $T$, i.e., paths that are consistent with the exogenous government expenditure stream $G$, the initial debt level $B_0$, and the terminal debt level $B_{S+1}$. In general, there are **many** budget feasible tax paths $T$. Among all budget-feasible tax paths, which one should a government choose? -To answer this question, we shall eventually evaluate alternative budget feasible tax paths $T$ using the following cost functional: +To answer this question, we assess alternative budget feasible tax paths $T$ using the following cost functional: ```{math} :label: cost @@ -144,7 +150,7 @@ We create a Python ``namedtuple`` to store these parameters with default values. TaxSmoothing = namedtuple("TaxSmoothing", ["R", "g1", "g2", "β_seq", "S"]) -def create_tax_smoothing_model(R=1.05, g1=1, g2=1/2, S=65): +def create_tax_smoothing_model(R=1.01, g1=1, g2=1/2, S=65): """ Creates an instance of the tax smoothing model. """ @@ -200,7 +206,7 @@ $$ (eq:taxsmoothing) Equation {eq}`eq:taxsmoothing` is the tax-smoothing model in a nutshell. -## Mechanics of tax-smoothing model +## Mechanics of tax-smoothing As promised, we'll provide step-by-step instructions on how to use linear algebra, readily implemented in Python, to compute all objects in play in the tax-smoothing model. @@ -294,10 +300,10 @@ The drop in government expenditures could reflect a change in spending requireme ```{code-cell} ipython3 # Initial debt -B0 = 2 # initial government debt +B0 = 0 # initial government debt # Government expenditure process -G_seq = np.concatenate([np.ones(46), np.zeros(20)]) +G_seq = np.concatenate([np.ones(46), 5*np.ones(5),np.ones(15)]) tax_model = create_tax_smoothing_model() T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) @@ -655,122 +661,3 @@ the original Keynesian consumption function presented in {doc}`geometric series Friedman's work opened the door to an enlightening literature on the aggregate consumption function and associated government expenditure multipliers that remains active today. --> - -## Appendix: solving difference equations with linear algebra - -In the preceding sections we have used linear algebra to solve a tax-smoothing model. - -The same tools from linear algebra -- matrix multiplication and matrix inversion -- can be used to study many other dynamic models. - -We'll conclude this lecture by giving a couple of examples. - -We'll describe a useful way of representing and "solving" linear difference equations. - -To generate some $G$ vectors, we'll just write down a linear difference equation -with appropriate initial conditions and then use linear algebra to solve it. - -### First-order difference equation - -We'll start with a first-order linear difference equation for $\{G_t\}_{t=0}^S$: - -$$ -G_{t} = \lambda G_{t-1}, \quad t = 1, 2, \ldots, S -$$ - -where $G_0$ is a given initial government expenditure. - -We can cast this set of $S$ equations as a single matrix equation - -$$ -\begin{bmatrix} -1 & 0 & 0 & \cdots & 0 & 0 \cr --\lambda & 1 & 0 & \cdots & 0 & 0 \cr -0 & -\lambda & 1 & \cdots & 0 & 0 \cr - \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -0 & 0 & 0 & \cdots & -\lambda & 1 -\end{bmatrix} -\begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S -\end{bmatrix} -= -\begin{bmatrix} -\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 -\end{bmatrix} -$$ (eq:first_order_lin_diff_tax) - -Multiplying both sides of {eq}`eq:first_order_lin_diff_tax` by the inverse of the matrix on the left provides the solution - -```{math} -:label: eq:fst_ord_inverse_tax -\begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S -\end{bmatrix} -= -\begin{bmatrix} -1 & 0 & 0 & \cdots & 0 & 0 \cr -\lambda & 1 & 0 & \cdots & 0 & 0 \cr -\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr - \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 -\end{bmatrix} -\begin{bmatrix} -\lambda G_0 \cr 0 \cr 0 \cr \vdots \cr 0 -\end{bmatrix} -``` - -```{exercise} -:label: taxsmooth_ex1 - -To get {eq}`eq:fst_ord_inverse_tax`, we multiplied both sides of {eq}`eq:first_order_lin_diff_tax` by the inverse of the matrix $A$. Please confirm that - -$$ -\begin{bmatrix} -1 & 0 & 0 & \cdots & 0 & 0 \cr -\lambda & 1 & 0 & \cdots & 0 & 0 \cr -\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr - \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -\lambda^{S-1} & \lambda^{S-2} & \lambda^{S-3} & \cdots & \lambda & 1 -\end{bmatrix} -$$ - -is the inverse of $A$ and check that $A A^{-1} = I$ -``` - -### Second-order difference equation - -A second-order linear difference equation for $\{G_t\}_{t=0}^S$ is - -$$ -G_{t} = \lambda_1 G_{t-1} + \lambda_2 G_{t-2}, \quad t = 1, 2, \ldots, S -$$ - -where now $G_0$ and $G_{-1}$ are two given initial expenditure levels determined outside the model. - -As we did with the first-order difference equation, we can cast this set of $S$ equations as a single matrix equation - -$$ -\begin{bmatrix} -1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr --\lambda_1 & 1 & 0 & \cdots & 0 & 0 & 0 \cr --\lambda_2 & -\lambda_1 & 1 & \cdots & 0 & 0 & 0 \cr - \vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr -0 & 0 & 0 & \cdots & -\lambda_2 & -\lambda_1 & 1 -\end{bmatrix} -\begin{bmatrix} -G_1 \cr G_2 \cr G_3 \cr \vdots \cr G_S -\end{bmatrix} -= -\begin{bmatrix} -\lambda_1 G_0 + \lambda_2 G_{-1} \cr \lambda_2 G_0 \cr 0 \cr \vdots \cr 0 -\end{bmatrix} -$$ - -Multiplying both sides by inverse of the matrix on the left again provides the solution. - -```{exercise} -:label: taxsmooth_ex2 - -As an exercise, we ask you to represent and solve a **third-order linear difference equation**. - -How many initial conditions must you specify? -``` \ No newline at end of file From 37f2951c0edc91c4db778db32a9b59c3b7e2bff4 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 31 Jan 2025 11:38:37 +1100 Subject: [PATCH 11/15] update graphs in tax_smooth --- lectures/tax_smooth.md | 67 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index f800feed..c9b416fd 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.6 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -269,7 +269,6 @@ Let's verify this with Python code. First we implement the model with `compute_optimal` ```{code-cell} ipython3 - def compute_optimal(model, B0, G_seq): R, S = model.R, model.S @@ -300,10 +299,10 @@ The drop in government expenditures could reflect a change in spending requireme ```{code-cell} ipython3 # Initial debt -B0 = 0 # initial government debt +B0 = 2 # initial government debt # Government expenditure process -G_seq = np.concatenate([np.ones(46), 5*np.ones(5),np.ones(15)]) +G_seq = np.concatenate([np.ones(46), 4*np.ones(5), np.ones(15)]) tax_model = create_tax_smoothing_model() T_seq, B_seq, h0 = compute_optimal(tax_model, B0, G_seq) @@ -314,18 +313,24 @@ print('check B_S+1=0:', The graphs below show paths of government expenditures, tax collections, and government debt. ```{code-cell} ipython3 - # Sequence Length S = tax_model.S -plt.plot(range(S+1), G_seq, label='government expenditures') -plt.plot(range(S+1), T_seq, label='tax collections') -plt.plot(range(S+2), B_seq, label='government debt') -plt.plot(range(S+2), np.zeros(S+2), '--') +fig, axes = plt.subplots(1, 2, figsize=(12,5)) + +axes[0].plot(range(S+1), G_seq, label='expenditures', lw=2) +axes[0].plot(range(S+1), T_seq, label='tax', lw=2) +axes[1].plot(range(S+2), B_seq, label='debt', color='green', lw=2) +axes[0].set_ylabel(r'$T_t,G_t$') +axes[1].set_ylabel(r'$B_t$') + +for ax in axes: + ax.plot(range(S+2), np.zeros(S+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') + -plt.legend() plt.xlabel(r'$t$') -plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` @@ -364,18 +369,24 @@ def plot_ts(model, # tax-smoothing model # Compute optimal tax path T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) - # Sequence length + # Sequence Length S = tax_model.S - # Generate plot - plt.plot(range(S+1), G_seq, label='government expenditures') - plt.plot(range(S+1), T_seq, label='tax collections') - plt.plot(range(S+2), B_seq, label='government debt') - plt.plot(range(S+2), np.zeros(S+2), '--') + fig, axes = plt.subplots(1, 2, figsize=(12,5)) + + axes[0].plot(range(S+1), G_seq, label='expenditures', lw=2) + axes[0].plot(range(S+1), T_seq, label='tax', lw=2) + axes[1].plot(range(S+2), B_seq, label='debt', color='green', lw=2) + axes[0].set_ylabel(r'$T_t,G_t$') + axes[1].set_ylabel(r'$B_t$') + + for ax in axes: + ax.plot(range(S+2), np.zeros(S+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') + - plt.legend() plt.xlabel(r'$t$') - plt.ylabel(r'$T_t,G_t,B_t$') plt.show() ``` @@ -464,9 +475,9 @@ What happens with oscillating expenditures ```{code-cell} ipython3 λ = -0.95 -geo_seq = λ ** np.arange(t_max) * G_0 +geo_seq = λ ** np.arange(t_max) * G_0 + 1 G_seq_geo = np.concatenate( - [geo_seq, np.zeros(20)]) + [geo_seq, np.ones(20)]) plot_ts(tax_model, B0, G_seq_geo) ``` @@ -648,16 +659,4 @@ plt.plot(ξ1_arr, cost_grad) plt.ylabel('derivative of cost') plt.xlabel(r'$\phi$') plt.show() -``` - - - +``` \ No newline at end of file From ca9a267fca4595a6bbe8515a23e2dbe85e65efc7 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 31 Jan 2025 11:45:42 +1100 Subject: [PATCH 12/15] update graphs for cons_smooth --- lectures/cons_smooth.md | 59 +++++++++++++++++++++-------------------- lectures/tax_smooth.md | 16 ++++++++--- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 44580989..64ad91e6 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -4,14 +4,13 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- - # Consumption Smoothing ## Overview @@ -47,7 +46,6 @@ import matplotlib.pyplot as plt from collections import namedtuple ``` - The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{y_t\}_{t=0}^T$ of non-financial income and chooses a consumption stream $\{c_t\}_{t=0}^T$. We usually think of the non-financial income stream as coming from the person's salary from supplying labor. @@ -147,7 +145,6 @@ def create_consumption_smoothing_model(R=1.05, g1=1, g2=1/2, T=65): β_seq, T) ``` - ## Friedman-Hall consumption-smoothing model A key object is what Milton Friedman called "human" or "non-financial" wealth at time $0$: @@ -311,14 +308,19 @@ The graphs below show paths of non-financial income, consumption, and financia # Sequence Length T = cs_model.T -plt.plot(range(T+1), y_seq, label='non-financial income') -plt.plot(range(T+1), c_seq, label='consumption') -plt.plot(range(T+2), a_seq, label='financial wealth') -plt.plot(range(T+2), np.zeros(T+2), '--') +fig, axes = plt.subplots(1, 2, figsize=(12,5)) + +axes[0].plot(range(T+1), y_seq, label='non-financial income', lw=2) +axes[0].plot(range(T+1), c_seq, label='consumption', lw=2) +axes[1].plot(range(T+2), a_seq, label='financial wealth', color='green', lw=2) +axes[0].set_ylabel(r'$c_t,y_t$') +axes[1].set_ylabel(r'$a_t$') + +for ax in axes: + ax.plot(range(T+2), np.zeros(T+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') -plt.legend() -plt.xlabel(r'$t$') -plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` @@ -353,18 +355,22 @@ def plot_cs(model, # consumption-smoothing model # Compute optimal consumption c_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) - # Sequence length + # Sequence Length T = cs_model.T - # Generate plot - plt.plot(range(T+1), y_seq, label='non-financial income') - plt.plot(range(T+1), c_seq, label='consumption') - plt.plot(range(T+2), a_seq, label='financial wealth') - plt.plot(range(T+2), np.zeros(T+2), '--') + fig, axes = plt.subplots(1, 2, figsize=(12,5)) + + axes[0].plot(range(T+1), y_seq, label='non-financial income', lw=2) + axes[0].plot(range(T+1), c_seq, label='consumption', lw=2) + axes[1].plot(range(T+2), a_seq, label='financial wealth', color='green', lw=2) + axes[0].set_ylabel(r'$c_t,y_t$') + axes[1].set_ylabel(r'$a_t$') + + for ax in axes: + ax.plot(range(T+2), np.zeros(T+2), '--', lw=1, color='black') + ax.legend() + ax.set_xlabel(r'$t$') - plt.legend() - plt.xlabel(r'$t$') - plt.ylabel(r'$c_t,y_t,a_t$') plt.show() ``` @@ -419,7 +425,7 @@ Now we simulate a $y$ sequence in which a person gets zero for 46 years, and the ```{code-cell} ipython3 # Late starter y_seq_late = np.concatenate( - [np.zeros(46), np.ones(20)]) + [np.ones(46), 2*np.ones(20)]) plot_cs(cs_model, a0, y_seq_late) ``` @@ -461,14 +467,13 @@ What happens when $\lambda$ is negative ```{code-cell} ipython3 λ = -0.95 -geo_seq = λ ** np.arange(t_max) * y_0 +geo_seq = λ ** np.arange(t_max) * y_0 + 1 y_seq_geo = np.concatenate( - [geo_seq, np.zeros(20)]) + [geo_seq, np.ones(20)]) plot_cs(cs_model, a0, y_seq_geo) ``` - ### Feasible consumption variations We promised to justify our claim that a constant consumption play $c_t = c_0$ for all @@ -554,7 +559,6 @@ def compute_variation(model, ξ1, ϕ, a0, y_seq, verbose=1): return cvar_seq ``` - We visualize variations for $\xi_1 \in \{.01, .05\}$ and $\phi \in \{.95, 1.02\}$ ```{code-cell} ipython3 @@ -591,7 +595,6 @@ plt.ylabel(r'$c_t$') plt.show() ``` - We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. We are teaching the key idea beneath the **calculus of variations**. @@ -615,7 +618,6 @@ def welfare_rel(ξ1, ϕ): welfare_vec = np.vectorize(welfare_rel) ``` - Then we can visualize the relationship between welfare and $\xi_1$ and compute its derivatives ```{code-cell} ipython3 @@ -634,7 +636,6 @@ plt.xlabel(r'$\xi_1$') plt.show() ``` - The same can be done on $\phi$ ```{code-cell} ipython3 @@ -785,4 +786,4 @@ Multiplying both sides by inverse of the matrix on the left again provides the As an exercise, we ask you to represent and solve a **third-order linear difference equation**. How many initial conditions must you specify? -``` \ No newline at end of file +``` diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index c9b416fd..721ac026 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -329,8 +329,6 @@ for ax in axes: ax.legend() ax.set_xlabel(r'$t$') - -plt.xlabel(r'$t$') plt.show() ``` @@ -386,7 +384,6 @@ def plot_ts(model, # tax-smoothing model ax.set_xlabel(r'$t$') - plt.xlabel(r'$t$') plt.show() ``` @@ -659,4 +656,15 @@ plt.plot(ξ1_arr, cost_grad) plt.ylabel('derivative of cost') plt.xlabel(r'$\phi$') plt.show() -``` \ No newline at end of file +``` + + From 2b3b71e54aca3cb0040f47d718da7a9a8d635a81 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 31 Jan 2025 11:48:09 +1100 Subject: [PATCH 13/15] remove the commented text --- lectures/tax_smooth.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 721ac026..27766d8d 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -656,15 +656,4 @@ plt.plot(ξ1_arr, cost_grad) plt.ylabel('derivative of cost') plt.xlabel(r'$\phi$') plt.show() -``` - - +``` \ No newline at end of file From 3cc1be7afa24ea22d8d02dd07a1ea87315516605 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Fri, 31 Jan 2025 11:49:40 +1100 Subject: [PATCH 14/15] remove capitalization --- lectures/cons_smooth.md | 4 ++-- lectures/tax_smooth.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index 64ad91e6..cc7c6ec2 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -305,7 +305,7 @@ print('check a_T+1=0:', The graphs below show paths of non-financial income, consumption, and financial assets. ```{code-cell} ipython3 -# Sequence Length +# Sequence length T = cs_model.T fig, axes = plt.subplots(1, 2, figsize=(12,5)) @@ -355,7 +355,7 @@ def plot_cs(model, # consumption-smoothing model # Compute optimal consumption c_seq, a_seq, h0 = compute_optimal(model, a0, y_seq) - # Sequence Length + # Sequence length T = cs_model.T fig, axes = plt.subplots(1, 2, figsize=(12,5)) diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index 27766d8d..e219fc56 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -313,7 +313,7 @@ print('check B_S+1=0:', The graphs below show paths of government expenditures, tax collections, and government debt. ```{code-cell} ipython3 -# Sequence Length +# Sequence length S = tax_model.S fig, axes = plt.subplots(1, 2, figsize=(12,5)) @@ -367,7 +367,7 @@ def plot_ts(model, # tax-smoothing model # Compute optimal tax path T_seq, B_seq, h0 = compute_optimal(model, B0, G_seq) - # Sequence Length + # Sequence length S = tax_model.S fig, axes = plt.subplots(1, 2, figsize=(12,5)) From a5fa03b6e1c52a84911626717d0f9c97ee03fa81 Mon Sep 17 00:00:00 2001 From: thomassargent30 Date: Fri, 31 Jan 2025 12:51:34 -0500 Subject: [PATCH 15/15] Tom's Jan 31 edits of two smoothing lectures --- lectures/cons_smooth.md | 38 ++++++++++++++++++++------------------ lectures/tax_smooth.md | 24 ++++++++++++------------ 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/lectures/cons_smooth.md b/lectures/cons_smooth.md index cc7c6ec2..626f5956 100644 --- a/lectures/cons_smooth.md +++ b/lectures/cons_smooth.md @@ -18,14 +18,16 @@ kernelspec: In this lecture, we'll study a famous model of the "consumption function" that Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) proposed to fit some empirical data patterns that the original Keynesian consumption function described in this QuantEcon lecture {doc}`geometric series ` missed. -In this lecture, we'll study what is often called the "consumption-smoothing model" using matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. +We'll study what is often called the "consumption-smoothing model." + +We'll use matrix multiplication and matrix inversion, the same tools that we used in this QuantEcon lecture {doc}`present values `. Formulas presented in {doc}`present value formulas` are at the core of the consumption-smoothing model because we shall use them to define a consumer's "human wealth". The key idea that inspired Milton Friedman was that a person's non-financial income, i.e., his or -her wages from working, could be viewed as a dividend stream from that person's ''human capital'' -and that standard asset-pricing formulas could be applied to compute a person's -''non-financial wealth'' that capitalizes the earnings stream. +her wages from working, can be viewed as a dividend stream from ''human capital'' +and that standard asset-pricing formulas can be applied to compute +''non-financial wealth'' that capitalizes that earnings stream. ```{note} As we'll see in this QuantEcon lecture {doc}`equalizing difference model `, @@ -48,13 +50,13 @@ from collections import namedtuple The model describes a consumer who lives from time $t=0, 1, \ldots, T$, receives a stream $\{y_t\}_{t=0}^T$ of non-financial income and chooses a consumption stream $\{c_t\}_{t=0}^T$. -We usually think of the non-financial income stream as coming from the person's salary from supplying labor. +We usually think of the non-financial income stream as coming from the person's earnings from supplying labor. -The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense of not being determined by the model. +The model takes a non-financial income stream as an input, regarding it as "exogenous" in the sense that it is determined outside the model. -The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. +The consumer faces a gross interest rate of $R >1$ that is constant over time, at which she is free to borrow or lend, up to limits that we'll describe below. -To set up the model, let +Let * $T \geq 2$ be a positive integer that constitutes a time-horizon. * $y = \{y_t\}_{t=0}^T$ be an exogenous sequence of non-negative non-financial incomes $y_t$. @@ -128,7 +130,10 @@ By **smoother** we mean as close as possible to being constant over time. The preference for smooth consumption paths that is built into the model gives it the name "consumption-smoothing model". -Let's dive in and do some calculations that will help us understand how the model works. +We'll postpone verifying our claim that a constant consumption path is optimal when $\beta R=1$ +by comparing welfare levels that comes from a constant path with ones that involve non-constant paths. + +Before doing that, let's dive in and do some calculations that will help us understand how the model works in practice when we provide the consumer with some different streams on non-financial income. Here we use default parameters $R = 1.05$, $g_1 = 1$, $g_2 = 1/2$, and $T = 65$. @@ -282,7 +287,7 @@ def compute_optimal(model, a0, y_seq): We use an example where the consumer inherits $a_0<0$. -This can be interpreted as a student debt. +This can be interpreted as student debt with which the consumer begins his or her working life. The non-financial process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward. @@ -476,8 +481,7 @@ plot_cs(cs_model, a0, y_seq_geo) ### Feasible consumption variations -We promised to justify our claim that a constant consumption play $c_t = c_0$ for all -$t$ is optimal. +We promised to justify our claim that when $\beta R =1$ as Friedman assumed, a constant consumption play $c_t = c_0$ for all $t$ is optimal. Let's do that now. @@ -597,7 +601,7 @@ plt.show() We can even use the Python `np.gradient` command to compute derivatives of welfare with respect to our two parameters. -We are teaching the key idea beneath the **calculus of variations**. +(We are actually discovering the key idea beneath the **calculus of variations**.) First, we define the welfare with respect to $\xi_1$ and $\phi$ @@ -656,14 +660,12 @@ plt.show() ## Wrapping up the consumption-smoothing model -The consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) is a cornerstone of modern macro that has important ramifications for the size of the Keynesian "fiscal policy multiplier" described briefly in +The consumption-smoothing model of Milton Friedman {cite}`Friedman1956` and Robert Hall {cite}`Hall1978`) is a cornerstone of modern economics that has important ramifications for the size of the Keynesian "fiscal policy multiplier" that we described in QuantEcon lecture {doc}`geometric series `. -In particular, it **lowers** the government expenditure multiplier relative to one implied by -the original Keynesian consumption function presented in {doc}`geometric series `. +The consumption-smoothingmodel **lowers** the government expenditure multiplier relative to one implied by the original Keynesian consumption function presented in {doc}`geometric series `. -Friedman's work opened the door to an enlightening literature on the aggregate consumption function and associated government expenditure multipliers that -remains active today. +Friedman's work opened the door to an enlightening literature on the aggregate consumption function and associated government expenditure multipliers that remains active today. ## Appendix: solving difference equations with linear algebra diff --git a/lectures/tax_smooth.md b/lectures/tax_smooth.md index e219fc56..a35f6dcd 100644 --- a/lectures/tax_smooth.md +++ b/lectures/tax_smooth.md @@ -24,13 +24,13 @@ By renaming variables, we obtain a a version of a model "tax-smoothing model" The government chooses a tax collection path that minimizes the present value of its costs of raising revenue. -The government minimize those costs by varying tax collections little over time. +The government minimizes those costs by smoothing tax collections over time and by issuing government debt during temporary surges in government expenditures. The present value of government expenditures is at the core of the tax-smoothing model, so we'll again use formulas presented in {doc}`present value formulas`. -We'll use the matrix multiplication and matrix inversion tools that we used in {doc}`present value formulas `. +We'll again use the matrix multiplication and matrix inversion tools that we used in {doc}`present value formulas `. @@ -74,7 +74,7 @@ We require it to satisfy two **boundary conditions**: * it must equal an exogenous value $B_0$ at time $0$ * it must equal or exceed an exogenous value $B_{S+1}$ at time $S+1$. -The **terminal condition** $B_{S+1} \geq 0$ requires that it not end with negative assets. +The **terminal condition** $B_{S+1} \geq 0$ requires that the government not end up with negative assets. (This no-Ponzi condition ensures that the government ultimately pays off its debts -- it can't simply roll them over indefinitely.) @@ -291,7 +291,7 @@ def compute_optimal(model, B0, G_seq): We use an example where the government starts with initial debt $B_0>0$. -This represents the government's inherited debt burden. +This represents the government's initial debt burden. The government expenditure process $\{G_t\}_{t=0}^{S}$ is constant and positive up to $t=45$ and then drops to zero afterward. @@ -373,7 +373,7 @@ def plot_ts(model, # tax-smoothing model fig, axes = plt.subplots(1, 2, figsize=(12,5)) axes[0].plot(range(S+1), G_seq, label='expenditures', lw=2) - axes[0].plot(range(S+1), T_seq, label='tax', lw=2) + axes[0].plot(range(S+1), T_seq, label='taxes', lw=2) axes[1].plot(range(S+2), B_seq, label='debt', color='green', lw=2) axes[0].set_ylabel(r'$T_t,G_t$') axes[1].set_ylabel(r'$B_t$') @@ -410,29 +410,29 @@ Now we assume a permanent increase in government expenditures of $L$ in year 21 Again we can study positive and negative cases ```{code-cell} ipython3 -# Positive permanent expenditure shift L = 0.5 when t >= 21 +# Positive temporary expenditure shift L = 0.5 when t >= 21 G_seq_pos = np.concatenate( - [np.ones(21), 1.5*np.ones(25), np.zeros(20)]) + [np.ones(21), 1.5*np.ones(25), np.ones(20)]) plot_ts(tax_model, B0, G_seq_pos) ``` ```{code-cell} ipython3 -# Negative permanent expenditure shift L = -0.5 when t >= 21 +# Negative temporary expenditure shift L = -0.5 when t >= 21 G_seq_neg = np.concatenate( - [np.ones(21), .5*np.ones(25), np.zeros(20)]) + [np.ones(21), .5*np.ones(25), np.ones(20)]) plot_ts(tax_model, B0, G_seq_neg) ``` -#### Experiment 3: delayed spending +#### Experiment 3: delayed spending surge Now we simulate a $G$ sequence in which government expenditures are zero for 46 years, and then rise to 1 for the last 20 years (perhaps due to demographic aging) ```{code-cell} ipython3 # Delayed spending G_seq_late = np.concatenate( - [np.zeros(46), np.ones(20)]) + [np.ones(46), 2*np.ones(20)]) plot_ts(tax_model, B0, G_seq_late) ``` @@ -452,7 +452,7 @@ t_max = 46 # Generate geometric G sequence geo_seq = λ ** np.arange(t_max) * G_0 G_seq_geo = np.concatenate( - [geo_seq, np.zeros(20)]) + [geo_seq, np.max(geo_seq)*np.ones(20)]) plot_ts(tax_model, B0, G_seq_geo) ```