@@ -49,6 +49,7 @@ We will use the following imports:
4949import numpy as np
5050%matplotlib inline
5151import matplotlib.pyplot as plt
52+ from matplotlib import cm
5253plt.rcParams["figure.figsize"] = (11, 5) #set default figure size
5354```
5455
@@ -75,10 +76,12 @@ Equation {eq}`tswm_1` is called a **second-order linear difference equation**.
7576But actually, it is a collection of $T$ simultaneous linear
7677equations in the $T$ variables $y_1, y_2, \ldots, y_T$.
7778
78- ** Note:** To be able to solve a second-order linear difference
79+ ``` {note}
80+ To be able to solve a second-order linear difference
7981equation, we require two **boundary conditions** that can take the form
8082either of two **initial conditions** or two **terminal conditions** or
8183possibly one of each.
84+ ```
8285
8386Letโs write our equations as a stacked system
8487
@@ -144,12 +147,12 @@ y_1 = 28. # y_{-1}
144147y0 = 24.
145148```
146149
150+ Now we construct $A$ and $b$.
151+
147152``` {code-cell} python3
148- # construct A and b
149- A = np.zeros((T, T))
153+ A = np.identity(T) # The T x T identity matrix
150154
151155for i in range(T):
152- A[i, i] = 1
153156
154157 if i-1 >= 0:
155158 A[i, i-1] = -๐ผ1
@@ -174,12 +177,38 @@ Now letโs solve for the path of $y$.
174177If $y_t$ is GNP at time $t$, then we have a version of
175178Samuelsonโs model of the dynamics for GNP.
176179
180+ To solve $y = A^{-1} b$ we can either invert $A$ directly, as in
181+
177182``` {code-cell} python3
178183A_inv = np.linalg.inv(A)
179184
180185y = A_inv @ b
181186```
182187
188+ or we can use ` np.linalg.solve ` :
189+
190+
191+ ``` {code-cell} python3
192+ y_second_method = np.linalg.solve(A, b)
193+ ```
194+
195+ Here make sure the two methods give the same result, at least up to floating
196+ point precision:
197+
198+ ``` {code-cell} python3
199+ np.allclose(y, y_second_method)
200+ ```
201+
202+ ``` {note}
203+ In general, `np.linalg.solve` is more numerically stable than using
204+ `np.linalg.inv` directly.
205+ However, stability is not an issue for this small example. Moreover, we will
206+ repeatedly use `A_inv` in what follows, so there is added value in computing
207+ it directly.
208+ ```
209+
210+ Now we can plot.
211+
183212``` {code-cell} python3
184213plt.plot(np.arange(T)+1, y)
185214plt.xlabel('t')
@@ -188,17 +217,20 @@ plt.ylabel('y')
188217plt.show()
189218```
190219
191- If we set both initial values at the ** steady state** value of $y_t$, namely,
220+ The ** steady state** value $y^* $ of $y_t$ is obtained by setting $y_t = y_ {t-1} =
221+ y_ {t-2} = y^* $ in {eq}` tswm_1 ` , which yields
192222
193223$$
194- y_{0} = y_{-1} = \frac{\alpha_{0}}{1 - \alpha_{1} - \alpha_{2}}
224+ y^* = \frac{\alpha_{0}}{1 - \alpha_{1} - \alpha_{2}}
195225$$
196226
197- then $y_ {t}$ will be constant
227+ If we set the initial values to $y_ {0} = y_ {-1} = y^* $, then $y_ {t}$ will be
228+ constant:
198229
199230``` {code-cell} python3
200- y_1_steady = ๐ผ0 / (1 - ๐ผ1 - ๐ผ2) # y_{-1}
201- y0_steady = ๐ผ0 / (1 - ๐ผ1 - ๐ผ2)
231+ y_star = ๐ผ0 / (1 - ๐ผ1 - ๐ผ2)
232+ y_1_steady = y_star # y_{-1}
233+ y0_steady = y_star
202234
203235b_steady = np.full(T, ๐ผ0)
204236b_steady[0] = ๐ผ0 + ๐ผ1 * y0_steady + ๐ผ2 * y_1_steady
@@ -288,9 +320,10 @@ We can simulate $N$ paths.
288320N = 100
289321
290322for i in range(N):
323+ col = cm.viridis(np.random.rand()) # Choose a random color from viridis
291324 u = np.random.normal(0, ๐u, size=T)
292325 y = A_inv @ (b + u)
293- plt.plot(np.arange(T)+1, y, lw=0.5)
326+ plt.plot(np.arange(T)+1, y, lw=0.5, color=col )
294327
295328plt.xlabel('t')
296329plt.ylabel('y')
@@ -305,9 +338,10 @@ steady state.
305338N = 100
306339
307340for i in range(N):
341+ col = cm.viridis(np.random.rand()) # Choose a random color from viridis
308342 u = np.random.normal(0, ๐u, size=T)
309343 y_steady = A_inv @ (b_steady + u)
310- plt.plot(np.arange(T)+1, y_steady, lw=0.5)
344+ plt.plot(np.arange(T)+1, y_steady, lw=0.5, color=col )
311345
312346plt.xlabel('t')
313347plt.ylabel('y')
0 commit comments