SVD EigenValues and MatrixInverse Computation

Load Packages

library(knitr)
library(matlib)

Problem Set 1

Answer: I’ll first code the matrix A and its transpose (will call it A_T), in the following code chunk.

A <- matrix(c(1, -1, 2, 0, 3, 4), nrow = 2)
print(A)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   -1    0    4
A_T <- t(A)
print(A_T)
##      [,1] [,2]
## [1,]    1   -1
## [2,]    2    0
## [3,]    3    4

Now, in order to compute X = A.A_T and Y = A_T.A, I’ll code a general purpose matrix multiplication function my_mat_mult(), in below code chunk.

my_mat_mult <- function(m1, m2)
{
    m1_rows <- c(1:nrow(m1)); m1_cols <- c(1:ncol(m1))
    m2_rows <- c(1:nrow(m2)); m2_cols <- c(1:ncol(m2))
    #
    if(ncol(m1) != nrow(m2)) {
        stop('matrices are not conformable for multiplication')
    }
    #
    product <- matrix(0, nrow(m1), ncol(m2))
    #
    for(i in m1_rows) {
        for(j in m2_cols) {
            for(k in m1_cols) {
                product[i, j] = product[i, j] + m1[i, k] * m2[k, j]
            }
        }
    }
    return(product)
}

Computing X and Y, by calling my_mat_mult().

X <- my_mat_mult(A, A_T)
print(X)
##      [,1] [,2]
## [1,]   14   11
## [2,]   11   17
Y <- my_mat_mult(A_T, A)
print(Y)
##      [,1] [,2] [,3]
## [1,]    2    2   -1
## [2,]    2    4    6
## [3,]   -1    6   25

Computing eigenvectors and eigenvalues of X and Y, by R’s built-in function eigen().

e_X <- eigen(X)
e_X
## eigen() decomposition
## $values
## [1] 26.601802  4.398198
## 
## $vectors
##           [,1]       [,2]
## [1,] 0.6576043 -0.7533635
## [2,] 0.7533635  0.6576043
e_Y <- eigen(Y)
e_Y
## eigen() decomposition
## $values
## [1] 2.660180e+01 4.398198e+00 1.058982e-16
## 
## $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

Now, I’ll do Single valued Decomposition (SVD) in the following code chunk, using R’s built-in function, svd().

SVD_A <- svd(A)
SVD_A
## $d
## [1] 5.157693 2.097188
## 
## $u
##            [,1]       [,2]
## [1,] -0.6576043 -0.7533635
## [2,] -0.7533635  0.6576043
## 
## $v
##             [,1]       [,2]
## [1,]  0.01856629 -0.6727903
## [2,] -0.25499937 -0.7184510
## [3,] -0.96676296  0.1765824

Explanation: SVD_A contains the decomposed matrices of A, namely U, Sigma and V_transposed, in that order. Sigma contains a diagonal matrix in the top left, and zeros in the rest of the locations.

The column vectors of U are the left-singular vectors of A. In the above results, observe the two columns vectors under $u.

The diagonal elements of D (top left in Sigma) are singular values of A. Note that they not vectors, because they are just elements of the diagonal matrix, D. In the above results, observe the two numbers under $d. 

The column vectors of V are the right-singular vectors of A. In the above results, observe the two columns vectors $v.

Now, I’ll compare the left-singular vectors of A (i.e. U or $u), with the eigen vectors of X. In comparison_table1, we observe that the two sets of vectors (without the signs) are equal each to each.

comparison_table1 <- cbind(SVD_A$u, e_X$vectors)
colnames(comparison_table1) <- c('SVD_A_U_Col1', 'SVD_A_U_Col2', 'e_X_Col1', 'e_X_Col2')
comparison_table1
##      SVD_A_U_Col1 SVD_A_U_Col2  e_X_Col1   e_X_Col2
## [1,]   -0.6576043   -0.7533635 0.6576043 -0.7533635
## [2,]   -0.7533635    0.6576043 0.7533635  0.6576043

In the following code chunk, I’ll compare the right-singular vectors of A (i.e. V or $v), with the eigen vectors of Y. In this case, we know that while Y has 3 eigen vectors, V has 2 vectors. So, if we ignore the 3rd vector (column heading ‘IGNORE’), then the two sets of vectors (without signs) are equal, each to each.

comparison_table2 <- cbind(SVD_A$v, e_Y$vectors)
colnames(comparison_table2) <- c('SVD_A_V_Col1', 'SVD_A_V_Col2', 'e_Y_Col1', 'e_Y_Col2', 'IGNORE')
comparison_table2
##      SVD_A_V_Col1 SVD_A_V_Col2    e_Y_Col1   e_Y_Col2     IGNORE
## [1,]   0.01856629   -0.6727903 -0.01856629 -0.6727903  0.7396003
## [2,]  -0.25499937   -0.7184510  0.25499937 -0.7184510 -0.6471502
## [3,]  -0.96676296    0.1765824  0.96676296  0.1765824  0.1849001

Problem Set 2

Answer: In the following chode chunk, I’ll code myinverse() function, which accept a matrix as input, and then will first check if the input matrix is square and non-singular. If both, then it’ll return the inverse.

myinverse <- function(m)
{
    m_rows <- c(1:nrow(m)); m_cols <- c(1:ncol(m))
    #
    if(nrow(m) != ncol(m)) {
        stop('the matrix is not square')
    }
    #
    if(det(m) == 0) {
        stop('the matrix is singular')
    }
    #
    cof_m <- matrix(0, nrow(m), ncol(m))
    #
    for(i in m_rows) {
        for(j in m_cols) {
            cof_m[i, j] <- cofactor(m, i, j)
        }
    }
    #
    trans_cof_m <- t(cof_m)
    inv_m <- ( 1/det(m) ) * trans_cof_m
    return(inv_m)
}

Now, I’ll test myinverse() with the below matrix, which is a full-rank square matrix.

m <- matrix(c(1, 2, -1, 1, -1, -2, 3, 5, 4), nrow = 3)
#
print('Original matrix:')
## [1] "Original matrix:"
print(m)
##      [,1] [,2] [,3]
## [1,]    1    1    3
## [2,]    2   -1    5
## [3,]   -1   -2    4
#
inv_m <- myinverse(m)
print('inverse_m:')
## [1] "inverse_m:"
print(inv_m)
##            [,1]        [,2]        [,3]
## [1,] -0.2727273  0.45454545 -0.36363636
## [2,]  0.5909091 -0.31818182 -0.04545455
## [3,]  0.2272727 -0.04545455  0.13636364
#
product <- m %*% inv_m
print("product of m and its inverse:")
## [1] "product of m and its inverse:"
product
##      [,1]          [,2] [,3]
## [1,]    1  0.000000e+00    0
## [2,]    0  1.000000e+00    0
## [3,]    0 -2.775558e-17    1

Observe that the diagonal elements of the product are all ones. But, the other elements have some non-zero elements, which are almost 0. So, the product is an identity matrix.

Marker: 605-04