Tutorial 10 (AY24/25 Sem 1)¶
# Required imports
import sympy as sym
from ma1522 import Matrix
Question 1¶
A population of ants is put into a maze with 3 compartments labeled $a$, $b$, and $c$. If the ant is in compartment $a$, an hour later, there is a 20% chance it will go to compartment $b$, and a 40% chance it will go to compartment $c$. If it is in compartment $b$, an hour later, there is a 10% chance it will go to compartment $a$, and a 30% chance it will go to compartment $c$. If it is in compartment $c$, an hour later, there is a 50% chance it will go to compartment $a$, and a 20% chance it will go to compartment $b$. Suppose 100 ants have been placed in compartment $a$.
(a)¶
Find the transition probability matrix $\mathbf{A}$. Show that it is a stochastic matrix.
A = Matrix.from_str("0.4 0.1 0.5; 0.2 0.6 0.2; 0.4 0.3 0.3")
A
# Always work with fractions to avoid floating point errors
A.simplify(rational=True)
A
A.is_stochastic(verbosity=1)
Check if matrix is square: True Check if all entries are non-negative: True Check if each column sums to 1: True
True
(b)¶
By diagonalizing $\mathbf{A}$, find the number of ants in each compartment after 3 hours.
PDP = A.diagonalize(reals_only=True, verbosity=1)
PDP
Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
x_0 = Matrix.from_str("100; 0; 0")
x_0
x_3 = PDP.P @ PDP.D**3 @ PDP.P.inv() @ x_0
x_3
x_3.evalf()
(d)¶
In the long run (assuming no ants died), where will the majority of the ants be?
# Brute force calculation
(A**100 @ x_0).evalf()
D_100 = (PDP.D**1000).evalf()
D_100
# Therefore,
D_inf = Matrix.from_str("0 0 0; 0 0 0; 0 0 1")
D_inf
PDP.P @ D_inf @ PDP.P.inv() @ x_0
(e)¶
Suppose initially the numbers of ants in compartments a, b and c are $\alpha$, $\beta$, and $\gamma$ respectively. What is the population distribution in the long run (assuming no ants died)?
# simple random vector
Matrix.create_unk_matrix(3, 1)
# To use custom symbols, the most straightforward way is
# to use sympy's symbols function
alpha, beta, gamma = sym.symbols("alpha beta gamma")
x = Matrix([alpha, beta, gamma])
x
PDP.P @ D_inf @ PDP.P.inv() @ x
Question 2¶
By diagonalizing $\mathbf{A} = \begin{pmatrix} 1 & 0 & 3 \\ 0 & 4 & 0 \\ 0 & 0 & 4 \end{pmatrix}$, find a matrix $\mathbf{B}$ such that $\mathbf{B}^2 = \mathbf{A}$.
A = Matrix.from_str("1 0 3; 0 4 0; 0 0 4")
A
PDP = A.diagonalize(reals_only=True, verbosity=1)
PDP
Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
# Therefore, A = B**2 --> B = PDP.P @ PDP.D**0.5 @ PDP.P.inv()
# Note: sym.sqrt only produces the principal square root
B = PDP.P @ sym.sqrt(PDP.D) @ PDP.P.inv()
B
A = Matrix.from_str("3 1; 1 3")
A
A.orthogonally_diagonalize(verbosity=1)
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
(b)¶
$\mathbf{A} = \begin{pmatrix} 2 & 2 & -2 \\ 2 & -1 & 4 \\ -2 & 4 & -1 \end{pmatrix}$
A = Matrix.from_str("2 2 -2; 2 -1 4; -2 4 -1")
A
PDPT = A.orthogonally_diagonalize(verbosity=1)
PDPT
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
Eigenvalue: 3 [Gram Schmidt Process]
A = Matrix.from_str("1 -2 0 0; -2 1 0 0; 0 0 1 -2; 0 0 -2 1")
A
PDPT = A.orthogonally_diagonalize(verbosity=1)
PDPT
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
Eigenvalue: -1 [Gram Schmidt Process]
Eigenvalue: 3 [Gram Schmidt Process]
A = Matrix.from_str("3 2; 2 3; 2 -2")
A
svd = A.singular_value_decomposition(verbosity=1)
svd
A^T A
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
Extending U with its orthogonal complement. Before RREF: [self]
After RREF:
(b)¶
$\mathbf{A} = \begin{pmatrix} 3 & 2 & 2 \\ 2 & 3 & -2 \end{pmatrix}$
# Import the SVD data class to represent the result of SVD
from ma1522 import SVD
# A = U @ S @ V.T
# A.T = V @ S.T @ U.T
svdT = SVD(U=svd.V, S = svd.S.T, V=svd.U)
svdT
svdT.eval()
(c)¶
$\mathbf{A} = \begin{pmatrix} 1 & 0 & 1 \\ 0 & 1 & 1 \\ 1 & 1 & 2 \end{pmatrix}$
A = Matrix.from_str("1 0 1; 0 1 1; 1 1 2")
A
A.singular_value_decomposition(verbosity=1)
A^T A
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
Extending U with its orthogonal complement. Before RREF: [self]
After RREF:
# OR symmetric -> diagonalize == orthogonally diagonalize == svd
pdp = A.diagonalize(verbosity=1, sort=True) # This will also work
pdp # Take note that the singular values might not be in the correct order
Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
# To fix the order, you can use the following trick
order = [2, 1, 0] # specify the order of singular values as it is
newP = pdp.P.select_cols(*order)
diag_entries = pdp.D.diagonal()
newD = Matrix.diag(*[diag_entries[i] for i in order])
newP, newD
newP @ newD @ newP.inv()
pdpt = A.orthogonally_diagonalize(verbosity=1, sort=True)
pdpt
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
# Similar to diagonalization, the singular values are
# not guaranteed to be in the correct order
order = [2, 1, 0] # specify the order of singular values as it is
newP = pdpt.P.select_cols(*order)
diag_entries = pdpt.D.diagonal()
newD = Matrix.diag(*[diag_entries[i] for i in order])
newP, newD
newP @ newD @ newP.T
A = Matrix.from_str("-18 13 -4 4; 2 19 -4 12; -14 11 -12 8; -2 21 4 8")
A
A.singular_value_decomposition(verbosity=1)
A^T A
Check if matrix is symmetric: True Characteristic Polynomial
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
After RREF:
Eigenvectors:
Extending U with its orthogonal complement. Before RREF: [self]
After RREF: