Skip to content

Commit 5edbb02

Browse files
committed
update square root lecture
1 parent ddeac33 commit 5edbb02

File tree

1 file changed

+90
-38
lines changed

1 file changed

+90
-38
lines changed

lectures/greek_square.md

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ In this lecture, we use the following import:
337337
338338
```{code-cell} ipython3
339339
import numpy as np
340+
import matplotlib.pyplot as plt
340341
```
341342
342343
```{code-cell} ipython3
@@ -412,7 +413,7 @@ print(f"For η_1, η_2 = (0, 1), sqrt_σ = {sqrt_σ:.5f}")
412413
```
413414
414415
```{code-cell} ipython3
415-
# Case 2: η_1, η_2 = (0, 1)
416+
# Case 2: η_1, η_2 = (1, 0)
416417
ηs = (1, 0)
417418
sqrt_σ = y(1, ηs) / y(0, ηs) - 1
418419
@@ -468,33 +469,37 @@ Now we implement the algorithm above.
468469
First we write a function that iterates $M$
469470
470471
```{code-cell} ipython3
471-
def iterate_M(x_0, M, num_steps):
472-
# Eigendecomposition of M
473-
Λ, V_inv = np.linalg.eig(M)
474-
V = np.linalg.inv(V_inv)
472+
def iterate_M(x_0, M, num_steps, dtype=np.float64):
475473
476-
print(f"eigenvalues:\n{Λ}")
477-
print(f"eigenvectors:\n{V}")
478-
print(f"inverse eigenvectors:\n{V_inv}")
474+
# Eigendecomposition of M
475+
Λ, V = np.linalg.eig(M)
476+
V_inv = np.linalg.inv(V)
479477
480478
# Initialize the array to store results
481-
x = np.zeros((x_0.shape[0], num_steps))
479+
xs = np.zeros((x_0.shape[0],
480+
num_steps + 1))
482481
483482
# Perform the iterations
483+
xs[:, 0] = x_0
484484
for t in range(num_steps):
485-
x[:, t] = V @ np.diag(Λ**t) @ V_inv @ x_0
485+
xs[:, t + 1] = M @ xs[:, t]
486486
487-
return x, Λ, V, V_inv
487+
return xs, Λ, V, V_inv
488488
489489
# Define the state transition matrix M
490-
M = np.array([[2, -(1 - σ)],
491-
[1, 0]])
490+
M = np.array([
491+
[2, -(1 - σ)],
492+
[1, 0]])
492493
493494
# Initial condition vector x_0
494495
x_0 = np.array([2, 2])
495496
496497
# Perform the iteration
497498
xs, Λ, V, V_inv = iterate_M(x_0, M, num_steps=100)
499+
500+
print(f"eigenvalues:\n{Λ}")
501+
print(f"eigenvectors:\n{V}")
502+
print(f"inverse eigenvectors:\n{V_inv}")
498503
```
499504
500505
Let's compare the eigenvalues to the roots {eq}`eq:secretweapon` of equation
@@ -507,37 +512,48 @@ print(f"roots: {np.round(roots, 8)}")
507512
508513
Hence we confirmed {eq}`eq:eigen_sqrt`.
509514
510-
**Request to Humphrey**
511-
Please beautify the following description and code.
512-
513515
Information about the square root we are after is also contained
514516
in the two eigenvectors.
515517
516-
Indeed, each eigenvector is just a two dimensional subspace of ${\bf R}^3$ pinned down
517-
by dynamics of the form
518+
Indeed, each eigenvector is just a two-dimensional subspace of ${\mathbb R}^3$ pinned down by dynamics of the form
518519
519520
$$
520-
y_{t} = \delta_i y_{t-1}, \quad i = 1, 2
521+
y_{t} = \lambda_i y_{t-1}, \quad i = 1, 2
521522
$$ (eq:invariantsub101)
522523
523524
that we encountered above in equation {eq}`eq:2diff8` above.
524525
525-
In equation {eq}`eq:invariantsub101`, the $i$th $\delta_i$ equals the $V_{i, 0}/V_{i,1}$.
526-
527-
The following code cell verifies this for our example.
526+
In equation {eq}`eq:invariantsub101`, the $i$th $\lambda_i$ equals the $V_{i, 1}/V_{i,2}$.
528527
528+
The following graph verifies this for our example.
529529
530530
```{code-cell} ipython3
531-
s1 = V[0,0] / V[0,1]
532-
s2 = V[1,0] / V[1,1]
533-
print ("(s1, s2) = ", s1, s2)
534-
g1 = 1 + np.sqrt(2)
535-
g2 = 1 - np.sqrt(2)
536-
print("(g1, g2) = ", g1, g2)
531+
# Plotting the eigenvectors
532+
plt.figure(figsize=(8, 8))
533+
534+
plt.quiver(0, 0, V[0, 0], V[0, 1], angles='xy', scale_units='xy',
535+
scale=1, color='C0', label=fr'$\lambda_1={np.round(Λ[0], 4)}$')
536+
plt.quiver(0, 0, V[1, 0], V[1, 1], angles='xy', scale_units='xy',
537+
scale=1, color='C1', label=fr'$\lambda_2={np.round(Λ[1], 4)}$')
538+
539+
# Annotating the slopes
540+
plt.text(V[0, 0]-0.5, V[0, 1]*1.2,
541+
r'slope=$\frac{V_{1,1}}{V_{1,2}}=$'+f'{np.round(V[0, 0] / V[0, 1], 4)}',
542+
fontsize=12, color='C0')
543+
plt.text(V[1, 0]-0.5, V[1, 1]*1.2,
544+
r'slope=$\frac{V_{2,1}}{V_{2,2}}=$'+f'{np.round(V[1, 0] / V[1, 1], 4)}',
545+
fontsize=12, color='C1')
546+
547+
# Adding labels
548+
plt.axhline(0, color='grey', linewidth=0.5, alpha=0.4)
549+
plt.axvline(0, color='grey', linewidth=0.5, alpha=0.4)
550+
plt.legend()
551+
552+
plt.xlim(-1.5, 1.5)
553+
plt.ylim(-1.5, 1.5)
554+
plt.show()
537555
```
538556
539-
**End of request to Humphrey**
540-
541557
## Invariant Subspace Approach
542558
543559
The preceding calculation indicates that we can use the eigenvectors $V$ to construct 2-dimensional **invariant subspaces**.
@@ -565,9 +581,9 @@ Let
565581
$$
566582

567583
V = \begin{bmatrix} V_{1,1} & V_{1,2} \cr
568-
V_{2,2} & V_{2,2} \end{bmatrix}, \quad
584+
V_{2,1} & V_{2,2} \end{bmatrix}, \quad
569585
V^{-1} = \begin{bmatrix} V^{1,1} & V^{1,2} \cr
570-
V^{2,2} & V^{2,2} \end{bmatrix}
586+
V^{2,1} & V^{2,2} \end{bmatrix}
571587
$$
572588
573589
Notice that it follows from
@@ -634,8 +650,11 @@ Let's verify {eq}`eq:deactivate1` and {eq}`eq:deactivate2` below
634650
To deactivate $\lambda_1$ we use {eq}`eq:deactivate1`
635651
636652
```{code-cell} ipython3
653+
Λ, V = np.linalg.eig(M)
654+
637655
xd_1 = np.array((x_0[0],
638-
V[1,1] * (1/V[0,1]) * x_0[0]))
656+
V[1,1]/V[0,1] * x_0[0]),
657+
dtype=np.float64)
639658
640659
# Compute x_{1,0}^*
641660
np.round(V_inv @ xd_1, 8)
@@ -649,24 +668,57 @@ Now we deactivate $\lambda_2$ using {eq}`eq:deactivate2`
649668
650669
```{code-cell} ipython3
651670
xd_2 = np.array((x_0[0],
652-
V[1,0] * (1/V[0,0]) * x_0[0]))
671+
V[1,0]/V[0,0] * x_0[0]),
672+
dtype=np.float64)
653673
654674
# Compute x_{2,0}^*
655675
np.round(V_inv @ xd_2, 8)
656676
```
657677
658678
We find $x_{2,0}^* = 0$.
659679
660-
+++
680+
```{code-cell} ipython3
681+
# Simulate the difference equation with muted λ1
682+
num_steps = 10
683+
xs_λ1, Λ, _, _ = iterate_M(xd_1, M, num_steps)
684+
685+
# Simulate the difference equation with muted λ2
686+
xs_λ2, _, _, _ = iterate_M(xd_2, M, num_steps)
687+
688+
# Compute ratios y_t / y_{t-1} with higher precision
689+
ratios_λ1 = xs_λ1[1, 1:] / xs_λ1[1, :-1] # Adjusted to second component
690+
ratios_λ2 = xs_λ2[1, 1:] / xs_λ2[1, :-1] # Adjusted to second component
691+
692+
# Plot the ratios for y_t with higher precision
693+
plt.figure(figsize=(14, 6))
694+
695+
plt.subplot(1, 2, 1)
696+
plt.plot(np.round(ratios_λ1, 6), label='Ratios $y_t / y_{t-1}$ after muting $\lambda_1$', color='blue')
697+
plt.axhline(y=Λ[1], color='red', linestyle='--', label='$\lambda_2$')
698+
plt.xlabel('Time')
699+
plt.ylabel('Ratio $y_t / y_{t-1}$')
700+
plt.title('Ratios after Muting $\lambda_1$')
701+
plt.legend()
702+
703+
plt.subplot(1, 2, 2)
704+
plt.plot(ratios_λ2, label='Ratios $y_t / y_{t-1}$ after muting $\lambda_2$', color='orange')
705+
plt.axhline(y=Λ[0], color='green', linestyle='--', label='$\lambda_1$')
706+
plt.xlabel('Time')
707+
plt.ylabel('Ratio $y_t / y_{t-1}$')
708+
plt.title('Ratios after Muting $\lambda_2$')
709+
plt.legend()
710+
711+
plt.tight_layout()
712+
plt.show()
713+
```
661714
662715
Here we compare $V_{2,2} V_{1,2}^{-1}$ and $V_{2,1} V_{1,1}^{-1}$ with the roots we computed above
663716
664717
```{code-cell} ipython3
665-
np.round((V[1,1]*(1/V[0,1]),
666-
V[1,0]*(1/V[0,0])), 8)
718+
np.round((V[1,1]/V[0,1],
719+
V[1,0]/V[0,0]), 8)
667720
```
668721
669-
670722
## Concluding Remarks
671723
672724
This lecture sets the stage for many other applications of the **invariant subspace** methods.

0 commit comments

Comments
 (0)