This lecture considered rotation matrices, which led naturally to the topic on orthogonal matrices.
A matrix $\boldsymbol{A}$ is orthogonal if $\boldsymbol{A}^{-1} = \boldsymbol{A}^{T}$. A $n \times n$ matrix is orthogonal if its columns form and orthonormal basis.
# Import NumPy and seed random number generator to make generated matrices deterministic
import numpy as np
np.random.seed(1)
# Create a matrix with random entries
A = np.random.rand(4, 4)
# Use QR factorisation of A to create an orthogonal matrix Q (QR is covered in IB)
Q, R = np.linalg.qr(A, mode='complete')
We can now verify that Q is an orthognal matrix. We first check that $\boldsymbol{Q}^{-1} = \boldsymbol{Q}^{T}$ by computing $\boldsymbol{Q}\boldsymbol{Q}^{-1}$
print(Q.dot(Q.T))
[[ 1.00000000e+00 4.33680869e-17 4.64038530e-17 9.48676901e-17] [ 4.33680869e-17 1.00000000e+00 0.00000000e+00 -1.94289029e-16] [ 4.64038530e-17 0.00000000e+00 1.00000000e+00 0.00000000e+00] [ 9.48676901e-17 -1.94289029e-16 0.00000000e+00 1.00000000e+00]]
We can see that $\boldsymbol{Q}\boldsymbol{Q}^{-1} = \boldsymbol{I}$ (within numerical precision). We can check that the colums of $\boldsymbol{Q}$ are orthonormal
import itertools
# Build pairs (0,0), (0,1), . . . (0, n-1), (1, 2), (1, 3), . . .
pairs = itertools.combinations_with_replacement(range(len(Q)), 2)
# Compute dot product of column vectors q_{i} \cdot q_{j}
for p in pairs:
col0, col1 = p[0], p[1]
print ("Dot product of column vectors {}, {}: {}".format(col0, col1, Q[:, col0].dot(Q[:, col1])))
Dot product of column vectors 0, 0: 1.0000000000000002 Dot product of column vectors 0, 1: -5.551115123125783e-17 Dot product of column vectors 0, 2: -1.3877787807814457e-16 Dot product of column vectors 0, 3: -6.938893903907228e-18 Dot product of column vectors 1, 1: 1.0000000000000002 Dot product of column vectors 1, 2: 5.551115123125783e-17 Dot product of column vectors 1, 3: -1.942890293094024e-16 Dot product of column vectors 2, 2: 1.0000000000000002 Dot product of column vectors 2, 3: 1.3877787807814457e-17 Dot product of column vectors 3, 3: 1.0000000000000002
The columns of $\boldsymbol{Q}$ are orthonormal, and $\boldsymbol{Q}^{T}$ is also a rotation matrix and has orthonormal columns. Therefore, the rows of $\boldsymbol{Q}$ are also orthonormal.
# Compute dot product of row vectors q_{i} \cdot q_{j}
pairs = itertools.combinations_with_replacement(range(len(Q)), 2)
for p in pairs:
row0, row1 = p[0], p[1]
print ("Dot product of row vectors {}, {}: {}".format(row0, row1, Q[row0, :].dot(Q[row1, :])))
Dot product of row vectors 0, 0: 1.0000000000000002 Dot product of row vectors 0, 1: 4.336808689942018e-17 Dot product of row vectors 0, 2: 4.640385298237959e-17 Dot product of row vectors 0, 3: 9.486769009248164e-17 Dot product of row vectors 1, 1: 1.0000000000000002 Dot product of row vectors 1, 2: 0.0 Dot product of row vectors 1, 3: -1.942890293094024e-16 Dot product of row vectors 2, 2: 1.0 Dot product of row vectors 2, 3: 0.0 Dot product of row vectors 3, 3: 1.0000000000000002
Finally, we check the determinant of $\boldsymbol{Q}$:
print("Determinant of Q: {}".format(np.linalg.det(Q)))
Determinant of Q: -1.0000000000000002