Question 1

Verify using R that SVD and Eigenvalues are related. Given a \(3 \times 2\) matrix \(A\):

\[A = \begin{bmatrix} 1 & 2 & 3\\ -1 & 0 & 4\\ \end{bmatrix} \]



Compute \(\text{X} = \text{AA}^T\) and \(\text{Y} = \text{A}^T\text{A}\).

The product of a matrix with its transpose always results in a matrix that is square and symmetric, which are prerequisites to perform diagonalization. Diagonalization decomposes a complex matrix into an easier-to-use product of scalars and vectors.

When we take the product of \(A\) with its transpose (using the built-in t() function), we see that \(X\) and \(Y\) are both square and symmetric.

# Given a matrix A
A <- matrix(c(1, -1, 2, 0, 3, 4), nrow = 2, ncol = 3)
A
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   -1    0    4
# X is equal to A * AT
X <- A %*% t(A)
X
##      [,1] [,2]
## [1,]   14   11
## [2,]   11   17
# Y is equal to AT * A
Y <- t(A) %*% A
Y
##      [,1] [,2] [,3]
## [1,]    2    2   -1
## [2,]    2    4    6
## [3,]   -1    6   25


Compute the eigenvalues and eigenvectors of \(\text{X}\) and \(\text{Y}\).

We can use the eigen() function to get the normalized eigenvalues and eigenvectors of \(X\) and \(Y\).

Eigenvectors and eigenvalues help us diagonalize the matrices \(X\) and \(Y\), which is necessary to find the singular value decomposition of \(A\).

# Get the eigen decomposition of X
eigen_x <- eigen(X)

# Nonzero eigenvalues for X
x_values <- eigen_x$values
x_values
## [1] 26.601802  4.398198
# Eigenvectors for X
x_vectors <- eigen_x$vectors
x_vectors
##           [,1]       [,2]
## [1,] 0.6576043 -0.7533635
## [2,] 0.7533635  0.6576043
# Get the eigen decomposition of Y
eigen_y <- eigen(Y)

# Nonzero eigenvalues for Y
y_values <- eigen_y$values[1:2]
y_values
## [1] 26.601802  4.398198
# Eigenvectors for Y
y_vectors <- eigen_y$vectors
y_vectors
##             [,1]       [,2]       [,3]
## [1,] -0.01856629 -0.6727903  0.7396003
## [2,]  0.25499937 -0.7184510 -0.6471502
## [3,]  0.96676296  0.1765824  0.1849001


Compute the left-singular, singular values, and right-singular vectors of \(\text{A}\).

We can use the svd() function to compute the singular value decomposition of \(A\).

  • The left-singular values are equal to \(U\), the normalized eigenvalues of \(X\)

  • The singular values are \(\sqrt{\lambda_i}\), or the square root of the eigenvalues of \(X\) or \(Y\)

  • The right-singular values are equal to \(V\), the normalized eigenvalues of \(Y\)

# Calculate the singular value decomposition of A
svd_A <- svd(A)

# Set the left-singular matrix to be U
left_singular <- svd_A$u
left_singular
##            [,1]       [,2]
## [1,] -0.6576043 -0.7533635
## [2,] -0.7533635  0.6576043
# Set the singular values to be D
singular_values <- svd_A$d
singular_values
## [1] 5.157693 2.097188
# Set the right-singular matrix to be V
right_singular <- svd_A$v
right_singular
##             [,1]       [,2]
## [1,]  0.01856629 -0.6727903
## [2,] -0.25499937 -0.7184510
## [3,] -0.96676296  0.1765824


Examine the two sets of singular vectors and show they are indeed eigenvectors of \(\text{X}\) and \(\text{Y}\).

When we compare the two sets of singular vectors to the two sets of eigenvectors from \(X\) and \(Y\), we see they are extremely similar, only differing by a sign.

Here is a comparison between \(X\) and the left-singular matrix of \(A\):

# Eigenvector of X
round(solve(x_vectors), 3)
##        [,1]  [,2]
## [1,]  0.658 0.753
## [2,] -0.753 0.658
# Left singular matrix of A
round(left_singular, 3)
##        [,1]   [,2]
## [1,] -0.658 -0.753
## [2,] -0.753  0.658

Here is a comparison between \(Y\) and the right-singular matrix of \(A\):

# Eigenvector of Y
round(y_vectors, 3)
##        [,1]   [,2]   [,3]
## [1,] -0.019 -0.673  0.740
## [2,]  0.255 -0.718 -0.647
## [3,]  0.967  0.177  0.185
# Right singular matrix of A
round(right_singular, 3)
##        [,1]   [,2]
## [1,]  0.019 -0.673
## [2,] -0.255 -0.718
## [3,] -0.967  0.177

We see that the right-singular matrix zeroed out the last column of eigenvectors for \(Y\), in order to match the original dimensions of \(A\).


Confirm that the two non-zero eigenvalues of both \(\text{X}\) and \(\text{Y}\) are the same, and are squares of the non-zero singular values of \(\text{A}\).

We see that nonzero eigenvalues of \(X\) are equal to those of \(Y\).

# Test whether the nonzero eigenvalues of X equal those of Y
round(x_values, 3) == round(y_values, 3)
## [1] TRUE TRUE
round(x_values, 3)
## [1] 26.602  4.398
round(y_values, 3)
## [1] 26.602  4.398

We also see that singular values squared are equal to the eigenvalues of \(X\) and \(Y\).

# Test whether the square of the singular values is equal to the eigenvalues of X / Y
round(singular_values ^ 2, 3) == round(y_values, 3)
## [1] TRUE TRUE
round(singular_values ^ 2, 3)
## [1] 26.602  4.398
round(y_values, 3)
## [1] 26.602  4.398

Question 2

Write a function to compute the inverse of a well-conditioned full-rank square matrix using co-factors.

To find the inverse of a matrix \(A\), we can use this formula:

\[ \begin{align} A^{-1} &= \frac{1}{\text{det}(A)} \ \text{adjugate}(A) \\ &= \frac{1}{\text{det}(A)} \ \text{cofactor}(A)^T \end{align} \]

where the adjugate of \(A\) is equal to the transpose of its cofactor matrix. To get a cofactor matrix:

  • Create a matrix of minors by replacing each element in a matrix with the determinant of the submatrix created from removing the row and column of the element in question.

  • Flip the signs of the matrix of minors in a checkerboard pattern – first positive, then negagtive, then positive, etc.

myInverse <- function(A) {
  
  # Check whether the matrix is square
  if (nrow(A) == ncol(A)) {
    
    # Create a copy of the matrix to preserve the rows and columns
    cofactor_A <- A
    
    # Populate the cofactor matrix
    for (i in 1:nrow(A)) {
      for (j in 1:ncol(A)) {
        cofactor_A[i, j] <- (det(A[-i,-j])*(-1)^(i+j))
      }
    }
    
    # Calculate the adjugate matrix as the transpose of the cofactor
    adjugate_A <- t(cofactor_A)
    
    # Calculate the inverse using the determinant of A
    inverse_A <- (1 / det(A)) * adjugate_A
    
    # Print the inverse
    print(inverse_A)
  
  }
  
  # If the matrix is not square
  else {
    print("Choose a square matrix!")
  }
}


Let’s test whether my function is accurate by comparing its output to the built-in solve function.

# Test matrix
A <- matrix(c(-1,2,3,-2,1,4,2,1,5), nrow=3)

myInverse(A)
##             [,1]        [,2]       [,3]
## [1,]  0.04347826  0.78260870 -0.1739130
## [2,] -0.30434783 -0.47826087  0.2173913
## [3,]  0.21739130 -0.08695652  0.1304348
solve(A)
##             [,1]        [,2]       [,3]
## [1,]  0.04347826  0.78260870 -0.1739130
## [2,] -0.30434783 -0.47826087  0.2173913
## [3,]  0.21739130 -0.08695652  0.1304348
round(myInverse(A), 3) == round(solve(A), 3)
##             [,1]        [,2]       [,3]
## [1,]  0.04347826  0.78260870 -0.1739130
## [2,] -0.30434783 -0.47826087  0.2173913
## [3,]  0.21739130 -0.08695652  0.1304348
##      [,1] [,2] [,3]
## [1,] TRUE TRUE TRUE
## [2,] TRUE TRUE TRUE
## [3,] TRUE TRUE TRUE


The outputs match, so my function accurately calculates the inverse of a square matrix.