Using only the qr function and matrix multiplication, use the QR algorithm to find the eigenvalue of the following matrix:
$$\begin{bmatrix} 1,3,4\\3,1,0\\4,0,1 \end{bmatrix}$$Use a while loop to automatically loop through the iterations. What would be an appropriate stopping/exit decision for the loop?
import numpy as np
from numpy.linalg import qr
A = np.array([[1,3,4],[3,1,0],[4,0,1]])
q, r = qr(A)
#iterate this
A_new = np.dot(r, q)
q,r = qr(A_new)
print('QR:', A_new)
QR: [[ 2.92307692 -4.44064833 -1.2579418 ] [-4.44064833 -0.78021978 -0.50429863] [-1.2579418 -0.50429863 0.85714286]]
Until convergence towards:
$$\begin{bmatrix} 6, 0, 0 \\0, -4, 0 \\0, 0, 1 \end{bmatrix}$$A_new[1,0]
-4.440648327160281
#or instead
e = np.abs(A_new[1,0])
while e>.0001:
A_new = np.dot(r, q)
q,r = qr(A_new)
e = np.abs(A_new[1,0])
print(A_new)
[[ 6.00000000e+00 -7.82264258e-05 -7.34780335e-17] [-7.82264258e-05 -4.00000000e+00 -7.51391859e-17] [-2.55880669e-22 -1.63551298e-17 1.00000000e+00]]
This is based on a lecture from the the datascience quantecon course
We consider an economy where a certain percentage, $\alpha$, of people in any given year lose their jobs and a certain percentage of people, $\theta$ find a job.
We define a transition matrix
$$A = \begin{bmatrix} 1-\alpha & \alpha \\ \theta & 1-\theta \end{bmatrix}$$Let's say that initially (period 0) there are 1,000,000 employed people and 150,000 unemployed people: we can put this in a vector:
$$x0 = \begin{bmatrix} 1.000.000 & 150.000 \end{bmatrix}$$a.) Assuming that $\alpha=0.04$ and $\theta=0.10$ Use matrix multipication to find how many employed and unemployed people there will be in period 1, $x1$. Explain the calculation.
b.) What about in periods $x2$, $x3$, ... and so on? Do the values converge to some stable numbers?
c.) What are the eigenvectors of A? How does this relate to b?
# a.) we first define our transition matrix and our vector of initial values:
import numpy as np
alpha = .04
theta = .10
A = np.array([[1-alpha, alpha],[theta, 1-theta]])
x0 = np.array([1000000,150000]).T
x0
array([1000000, 150000])
np.dot(A.T, x0)
array([975000., 175000.])
When we do this calculation we are creating the vector:
$$ x_1 = \begin{bmatrix} 1.000,000 * 1-\alpha + 150.000* \theta \\1.000,000 * 1-\alpha + 150.000* 1-\theta \end{bmatrix} = \begin{bmatrix} 975.000 \\ 175.000 \end{bmatrix}$$The first row of the new vector shows that $1-\alpha = 96\%$ of the 1 million that initially had a job still have a job after the first period, plus we add the $theta = 10\%$ of the unemployed who find a job. In the second row, we add the 4% of people who lost their job to the 90% of those who were unemployed who remain unemployed.
Now we write a little routine to do this over many periods:
T=50
#create empty array Tx2
xs = np.zeros((T, 2))
#set initial value
xs[0, :] = x0
#iterate over time
for t in range(1, T):
xs[t, :] = np.dot(A.T, xs[t-1, :])
xs
array([[1000000. , 150000. ], [ 975000. , 175000. ], [ 953500. , 196500. ], [ 935010. , 214990. ], [ 919108.6 , 230891.4 ], [ 905433.396 , 244566.604 ], [ 893672.72056 , 256327.27944 ], [ 883558.5396816 , 266441.4603184 ], [ 874860.34412618, 275139.65587382], [ 867379.89594851, 282620.10405149], [ 860946.71051572, 289053.28948428], [ 855414.17104352, 294585.82895648], [ 850656.18709743, 299343.81290257], [ 846564.32090379, 303435.67909621], [ 843045.31597726, 306954.68402274], [ 840018.97174044, 309981.02825956], [ 837416.31569678, 312583.68430322], [ 835178.03149923, 314821.96850077], [ 833253.10708934, 316746.89291066], [ 831597.67209683, 318402.32790317], [ 830173.99800327, 319826.00199673], [ 828949.63828282, 321050.36171718], [ 827896.68892322, 322103.31107678], [ 826991.15247397, 323008.84752603], [ 826212.39112761, 323787.60887239], [ 825542.65636975, 324457.34363025], [ 824966.68447798, 325033.31552202], [ 824471.34865107, 325528.65134893], [ 824045.35983992, 325954.64016008], [ 823679.00946233, 326320.99053767], [ 823363.9481376 , 326636.0518624 ], [ 823092.99539834, 326907.00460166], [ 822859.97604257, 327140.02395743], [ 822659.57939661, 327340.42060339], [ 822487.23828109, 327512.76171891], [ 822339.02492173, 327660.97507827], [ 822211.56143269, 327788.43856731], [ 822101.94283211, 327898.05716789], [ 822007.67083562, 327992.32916438], [ 821926.59691863, 328073.40308137], [ 821856.87335002, 328143.12664998], [ 821796.91108102, 328203.08891898], [ 821745.34352968, 328254.65647032], [ 821700.99543552, 328299.00456448], [ 821662.85607455, 328337.14392545], [ 821630.05622411, 328369.94377589], [ 821601.84835274, 328398.15164726], [ 821577.58958335, 328422.41041665], [ 821556.72704168, 328443.27295832], [ 821538.78525585, 328461.21474415]])
#import plt
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(xs[:,0], label='Employed')
ax.plot(xs[:,1], label='Unemployed')
ax.legend()
<matplotlib.legend.Legend at 0x7feb41e5d220>
We see that we are converging on constant values for employment and unemployment. As we continue to iterate, we get to a situation where we get:
$$\mathbf{A^T}x = x$$That should look familier. x is then a eigenvector of $\mathbf{A}$
Let us calculate the eigenvectors and eigenvalues of A:
from numpy.linalg import eig
evalues,evectors=eig(A.T)
print('Eigen value:', evalues)
print('Eigen vector', evectors)
Eigen value: [1. 0.86] Eigen vector [[ 0.92847669 -0.70710678] [ 0.37139068 0.70710678]]
# taking the eigen vector in the 0-column
evector = evectors[:,0]
#normalize so that the two values sum to 1
evector = evector/evector.sum()
evector
array([0.71428571, 0.28571429])
# we look at the last iteration of our calculation, which we also normalize
xs[-1,:]/np.sum(xs[-1,:])
array([0.71438155, 0.28561845])
We can confirm, we managed to iterate to eigenvector, representing the steady state of our system.