Skip to content

Commit 9a6c27b

Browse files
Tom's edits and renaming of two prospective lectures on present values
1 parent 264cb80 commit 9a6c27b

File tree

2 files changed

+352
-40
lines changed

2 files changed

+352
-40
lines changed

sandpit/cons_smooth.md renamed to sandpit/cons_smooth_tom_v2.md

Lines changed: 213 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@ kernelspec:
1111
name: python3
1212
---
1313

14+
+++ {"user_expressions": []}
15+
1416
## Some dynamic models with matrices
1517

1618
In this notebook, we'll present some useful models of economic dynamics using only linear algebra -- matrix multiplication and matrix inversion.
1719

1820
**Present value formulas** are at the core of the models.
1921

20-
+++
22+
```{code-cell} ipython3
23+
import numpy as np
24+
import matplotlib.pyplot as plt
25+
```
26+
27+
+++ {"user_expressions": []}
2128

2229
## Consumption smoothing
2330

@@ -71,7 +78,7 @@ where $g_1 > 0, g_2 > 0$.
7178

7279
We shall see that when $\beta R = 1$ (a condition assumed by Milton Friedman and Robert Hall), this criterion assigns higher welfare to **smoother** consumption paths.
7380

74-
+++
81+
+++ {"user_expressions": []}
7582

7683
## Difference equations with linear algebra ##
7784

@@ -94,14 +101,20 @@ where $y_0$ is a given initial condition.
94101
We can cast this set of $T$ equations as a single matrix equation
95102

96103
$$
97-
\begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 \cr
98-
-\lambda & 1 & 0 & \cdots & 0 & 0 \cr
99-
0 & -\lambda & 1 & \cdots & 0 & 0 \cr
100-
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
101-
0 & 0 & 0 & \cdots & -\lambda & 1
102-
103-
\end{bmatrix} \begin{bmatrix} y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix}
104-
= \begin{bmatrix} \lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix}
104+
\begin{bmatrix}
105+
1 & 0 & 0 & \cdots & 0 & 0 \cr
106+
-\lambda & 1 & 0 & \cdots & 0 & 0 \cr
107+
0 & -\lambda & 1 & \cdots & 0 & 0 \cr
108+
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
109+
0 & 0 & 0 & \cdots & -\lambda & 1
110+
\end{bmatrix}
111+
\begin{bmatrix}
112+
y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T
113+
\end{bmatrix}
114+
=
115+
\begin{bmatrix}
116+
\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0
117+
\end{bmatrix}
105118
$$
106119

107120

@@ -110,30 +123,41 @@ $$
110123
Multiplying both sides by inverse of the matrix on the left provides the solution
111124

112125
$$
113-
\begin{bmatrix} y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix} =
114-
\begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 \cr
115-
\lambda & 1 & 0 & \cdots & 0 & 0 \cr
116-
\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr
117-
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
118-
\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & -\lambda & 1
126+
\begin{bmatrix}
127+
y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T
128+
\end{bmatrix}
129+
=
130+
\begin{bmatrix}
131+
1 & 0 & 0 & \cdots & 0 & 0 \cr
132+
\lambda & 1 & 0 & \cdots & 0 & 0 \cr
133+
\lambda^2 & \lambda & 1 & \cdots & 0 & 0 \cr
134+
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
135+
\lambda^{T-1} & \lambda^{T-2} & \lambda^{T-3} & \cdots & -\lambda & 1
136+
\end{bmatrix}
137+
\begin{bmatrix}
138+
\lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0
119139
\end{bmatrix}
120-
\begin{bmatrix} \lambda y_0 \cr 0 \cr 0 \cr \vdots \cr 0 \end{bmatrix}
121-
122140
$$
123141

124142

125143
#### Second order difference equation
126144

127145

128146
$$
129-
\begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr
130-
-\lambda_1 & 1 & 0 & \cdots & 0 & 0 & 0 \cr
131-
-\lambda_2 & -\lambda_2 & 1 & \cdots & 0 & 0 & 0 \cr
132-
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
133-
0 & 0 & 0 & \cdots & \lambda_2 & -\lambda_1 & 1
134-
135-
\end{bmatrix} \begin{bmatrix} y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T \end{bmatrix}
136-
= \begin{bmatrix} \lambda_1 y_0 + \lambda_2 y_{-1} \cr \lambda_2 y_0 \cr 0 \cr \vdots \cr 0 \end{bmatrix}
147+
\begin{bmatrix}
148+
1 & 0 & 0 & \cdots & 0 & 0 & 0 \cr
149+
-\lambda_1 & 1 & 0 & \cdots & 0 & 0 & 0 \cr
150+
-\lambda_2 & -\lambda_2 & 1 & \cdots & 0 & 0 & 0 \cr
151+
\vdots & \vdots & \vdots & \cdots & \vdots & \vdots \cr
152+
0 & 0 & 0 & \cdots & \lambda_2 & -\lambda_1 & 1
153+
\end{bmatrix}
154+
\begin{bmatrix}
155+
y_1 \cr y_2 \cr y_3 \cr \vdots \cr y_T
156+
\end{bmatrix}
157+
=
158+
\begin{bmatrix}
159+
\lambda_1 y_0 + \lambda_2 y_{-1} \cr \lambda_2 y_0 \cr 0 \cr \vdots \cr 0
160+
\end{bmatrix}
137161
$$
138162

139163
Multiplying both sides by inverse of the matrix on the left again provides the solution.
@@ -143,7 +167,7 @@ Multiplying both sides by inverse of the matrix on the left again provides the
143167
As an exercise, we ask you to represent and solve a **third order linear difference equation**.
144168
How many initial conditions must you specify?
145169

146-
+++
170+
+++ {"user_expressions": []}
147171

148172
## Friedman-Hall consumption-smoothing model
149173

@@ -152,7 +176,7 @@ A key object is what Milton Friedman called "non-human" or "non-financial" wealt
152176

153177

154178
$$
155-
h_0 \equiv \sum_{t=0}^T R^t y_t = \begin{bmatrix} 1 & R & \cdots & R^T \end{bmatrix}
179+
h_0 \equiv \sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix}
156180
\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix}
157181
$$
158182

@@ -165,7 +189,7 @@ $$
165189
it is possible to convert a sequence of budget constraints into the single intertemporal constraint
166190

167191
$$
168-
\sum_{t=0}^T R^t c_t = a_0 + h_0,
192+
\sum_{t=0}^T R^{-t} c_t = a_0 + h_0,
169193
$$
170194

171195
which says that the present value of the consumption stream equals the sum of finanical and non-financial wealth.
@@ -180,14 +204,14 @@ $$
180204
In this case, we can use the intertemporal budget constraint to write
181205

182206
$$
183-
c_0 = \left(\sum_{t=0}^T R^t\right)^{-1} (a_0 + h_0)
207+
c_0 = \left(\sum_{t=0}^T R^{-t}\right)^{-1} (a_0 + h_0)
184208
$$
185209

186210
This is the consumption-smoothing model in a nutshell.
187211

188212
We'll put the model through some paces with Python code below.
189213

190-
+++
214+
+++ {"user_expressions": []}
191215

192216
## Permanent income model of consumption
193217

@@ -203,7 +227,7 @@ In the calculations below, please we'll set default values of $R > 1$, e.g., $
203227
For some $T+1 \times 1$ $y$ vector, use matrix algebra to compute
204228

205229
$$
206-
\sum_{t=0}^T R^t y_t = \begin{bmatrix} 1 & R & \cdots & R^T \end{bmatrix}
230+
\sum_{t=0}^T R^{-t} y_t = \begin{bmatrix} 1 & R^{-1} & \cdots & R^{-T} \end{bmatrix}
207231
\begin{bmatrix} y_0 \cr y_1 \cr \vdots \cr y_T \end{bmatrix}
208232
$$
209233

@@ -215,6 +239,7 @@ $$
215239
c_0 = \left( \frac{1 - R^{-1}}{1 - R^{-(T+1)}} \right) (a_0 + \sum_{t=0}^T R^t y_t )
216240
$$
217241

242+
**Jiacheng:** The same for $R^t$ here.
218243

219244
#### Step 3 ####
220245

@@ -228,10 +253,12 @@ $$
228253
\vdots &\vdots & \vdots & \cdots & \vdots & \vdots & \vdots \cr
229254
0 & 0 & 0 & \cdots & -R & 1 & 0 \cr
230255
0 & 0 & 0 & \cdots & 0 & -R & 1
231-
\end{bmatrix} \begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1} \end{bmatrix}
232-
= R \begin{bmatrix} y_0 + a_0 - c_0 \cr y_1 - c_0 \cr y_2 - c_0 \cr \vdots\cr y_T - y_0 \cr 0
256+
\end{bmatrix}
257+
\begin{bmatrix} a_1 \cr a_2 \cr a_3 \cr \vdots \cr a_T \cr a_{T+1}
258+
\end{bmatrix}
259+
= R
260+
\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
233261
\end{bmatrix}
234-
235262
$$
236263

237264
Multiply both sides by the inverse of the matrix on the left side to compute
@@ -250,13 +277,14 @@ Let's verify this with our Python code.
250277

251278

252279

280+
253281
### Feasible consumption variations ###
254282

255283
To explore what types of consumption paths are welfare-improving, we shall create an **admissible consumption path variation sequence** $\{v_t\}_{t=0}^T$
256284
that satisfies
257285

258286
$$
259-
\sum_{t=0}^T v_t = 0
287+
\sum_{t=0}^T R^{-t} v_t = 0
260288
$$
261289

262290
We'll compute a two-parameter class of admissible variations
@@ -305,7 +333,155 @@ to compute alternative consumption paths, then evaluate their welfare.
305333
**Note to John:** We can do some fun simple experiments with these variations -- we can use
306334
graphs to show that, when $\beta R =1$ and starting from the smooth path, all nontrivial budget-feasible variations lower welfare according to the criterion above.
307335

308-
We can even use the Python numpy grad command to compute derivatives of welfare with respect to our two parameters. Notice that we are teaching the key idea beneath the calculus of variations.
336+
We can even use the Python numpy grad command to compute derivatives of welfare with respect to our two parameters.
337+
338+
We are teaching the key idea beneath the **calculus of variations**.
339+
340+
```{code-cell} ipython3
341+
class Consumption_smoothing:
342+
"A class of the Permanent Income model of consumption"
343+
344+
def __init__(self, R, y_seq, a0, g1, g2, T):
345+
self.a0, self.y_seq, self.R, self.β = a0, y_seq, R, 1/R # set β = 1/R
346+
self.g1, self.g2 = g1, g2 # welfare parameter
347+
self.T = T
348+
349+
self.β_seq = np.array([self.β**i for i in range(T+1)])
350+
351+
def compute_optimal(self, verbose=1):
352+
R, y_seq, a0, T = self.R, self.y_seq, self.a0, self.T
353+
354+
# non-financial wealth
355+
h0 = self.β_seq @ y_seq # since β = 1/R
356+
357+
# c0
358+
c0 = (1 - 1/R) / (1 - (1/R)**(T+1)) * (a0 + h0)
359+
c_seq = c0*np.ones(T+1)
360+
361+
# verify
362+
A = np.diag(-R*np.ones(T), k=-1) + np.eye(T+1)
363+
b = y_seq - c_seq
364+
b[0] = b[0] + a0
365+
366+
a_seq = np.linalg.inv(A) @ b
367+
a_seq = np.concatenate([[a0], a_seq])
368+
369+
# check that a_T+1 = 0
370+
if verbose==1:
371+
print('check a_T+1=0:', np.abs(a_seq[-1] - 0) <= 1e-8)
372+
373+
return c_seq, a_seq
374+
375+
def welfare(self, c_seq):
376+
β_seq, g1, g2 = self.β_seq, self.g1, self.g2
377+
378+
u_seq = g1 * c_seq - g2/2 * c_seq**2
379+
return β_seq @ u_seq
380+
381+
382+
def compute_variation(self, ξ1, ϕ, verbose=1):
383+
R, T, β_seq = self.R, self.T, self.β_seq
384+
385+
ξ0 = ξ1*((1 - 1/R) / (1 - (1/R)**(T+1))) * ((1 - (ϕ/R)**(T+1)) / (1 - ϕ/R))
386+
v_seq = np.array([(ξ1*ϕ**t - ξ0) for t in range(T+1)])
387+
388+
# check if it is feasible
389+
if verbose==1:
390+
print('check feasible:', np.round(β_seq @ v_seq, 7)==0) # since β = 1/R
391+
392+
c_opt, _ = self.compute_optimal(verbose=verbose)
393+
cvar_seq = c_opt + v_seq
394+
395+
return cvar_seq
396+
```
397+
398+
+++ {"user_expressions": []}
399+
400+
Below is an example where the consumer inherits $a_0<0$ (which can be interpreted as a student debt).
401+
402+
The income process $\{y_t\}_{t=0}^{T}$ is constant and positive up to $t=45$ and then becomes zero afterward.
403+
404+
```{code-cell} ipython3
405+
# parameters
406+
T=65
407+
R = 1.05
408+
g1 = 1
409+
g2 = 1/2
410+
411+
# financial wealth
412+
a0 = -2 # such as "student debt"
413+
414+
# income process
415+
y_seq = np.concatenate([np.ones(46), np.zeros(20)])
416+
417+
# create an instance
418+
mc = Consumption_smoothing(R=R, y_seq=y_seq, a0=a0, g1=g1, g2=g2, T=T)
419+
c_seq, a_seq = mc.compute_optimal()
420+
421+
# compute welfare
422+
print('Welfare:', mc.welfare(c_seq))
423+
```
424+
425+
```{code-cell} ipython3
426+
plt.plot(range(T+1), y_seq, label='income')
427+
plt.plot(range(T+1), c_seq, label='consumption')
428+
plt.plot(range(T+2), a_seq, label='asset')
429+
plt.plot(range(T+2), np.zeros(T+2), '--')
430+
431+
plt.legend()
432+
plt.xlabel(r'$t$')
433+
plt.ylabel(r'$c_t,y_t,a_t$')
434+
plt.show()
435+
```
436+
437+
+++ {"user_expressions": []}
438+
439+
We can visualize how $\xi_1$ and $\phi$ controls **budget-feasible variations**.
440+
441+
```{code-cell} ipython3
442+
# visualize variational paths
443+
cvar_seq1 = mc.compute_variation(ξ1=.01, ϕ=.95)
444+
cvar_seq2 = mc.compute_variation(ξ1=.05, ϕ=.95)
445+
cvar_seq3 = mc.compute_variation(ξ1=.01, ϕ=1.02)
446+
cvar_seq4 = mc.compute_variation(ξ1=.05, ϕ=1.02)
447+
```
448+
449+
```{code-cell} ipython3
450+
print('welfare of optimal c: ', mc.welfare(c_seq))
451+
print('variation 1: ', mc.welfare(cvar_seq1))
452+
print('variation 2:', mc.welfare(cvar_seq2))
453+
print('variation 3: ', mc.welfare(cvar_seq3))
454+
print('variation 4:', mc.welfare(cvar_seq4))
455+
```
456+
457+
```{code-cell} ipython3
458+
plt.plot(range(T+1), c_seq, color='orange', label=r'Optimal $\vec{c}$ ')
459+
plt.plot(range(T+1), cvar_seq1, color='tab:blue', label=r'$\xi_1 = 0.01, \phi = 0.95$')
460+
plt.plot(range(T+1), cvar_seq2, color='tab:blue', ls='-.', label=r'$\xi_1 = 0.05, \phi = 0.95$')
461+
plt.plot(range(T+1), cvar_seq3, color='tab:green', label=r'$\xi_1 = 0.01, \phi = 1.02$')
462+
plt.plot(range(T+1), cvar_seq4, color='tab:green', ls='-.', label=r'$\xi_1 = 0.05, \phi = 1.02$')
463+
464+
465+
plt.legend()
466+
plt.xlabel(r'$t$')
467+
plt.ylabel(r'$c_t$')
468+
plt.show()
469+
```
470+
471+
```{code-cell} ipython3
472+
def welfare_ϕ(mc, ξ1, ϕ):
473+
"Compute welfare of variation sequence for given ϕ, ξ1 with an instance of our model mc"
474+
cvar_seq = mc.compute_variation(ξ1=ξ1, ϕ=ϕ, verbose=0)
475+
return mc.welfare(cvar_seq)
476+
477+
welfare_φ = np.vectorize(welfare_φ)
478+
ξ1_arr = np.linspace(-0.5, 0.5, 20)
479+
480+
plt.plot(ξ1_arr, welfare_φ(mc, ξ1=ξ1_arr , ϕ=1.02))
481+
plt.ylabel('welfare')
482+
plt.xlabel(r'$\xi_1$')
483+
plt.show()
484+
```
309485

310486
```{code-cell} ipython3
311487

0 commit comments

Comments
 (0)