##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
##
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
##
## group_rows
#### Function to write Matrix, courtesy of Vinayak Patel :
writeMatrix <- function(x) {
begin <- "\\begin{bmatrix}"
end <- "\\end{bmatrix}"
X <- apply(x, 1, function(x) {
paste(
paste(x, collapse = "&"),
"\\\\"
)
}
)
paste(c(begin, X, end),
collapse = "")
}#### Function to write numerical Matrix, controlling decimals, adapted from above :
wnumMatrix <- function(x) {
begin <- "\\begin{bmatrix}"
end <- "\\end{bmatrix}"
X <- apply(x, 1, function(x) {
paste(
paste(format(x, digits = options()$digits), collapse = "&"),
"\\\\"
)
}
)
paste(c(begin, X, end),
collapse = "")
}## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] -1 0 4
In this problem, we’ll verify using R that SVD and Eigenvalues are related as worked out in the weekly module.
Given a 3x2 matrix \({A = \begin{bmatrix}1&2&3 \\-1&0&4 \\\end{bmatrix}}\)
write code in R to compute \(X = AA^T\) and \(Y = A^TA\) .
Then, compute the eigenvalues and eigenvectors of X and Y using the built-in commans [sic] in R.
Then, compute the left-singular, singular values, and right-singular vectors of A using the svd command.
Examine the two sets of singular vectors and show that they are indeed eigenvectors of X and Y.
In addition, the two non-zero eigenvalues (the 3rd value will be very close to zero, if not zero) of both X and Y are the same and are squares of the non-zero singular values of A.
Your code should compute all these vectors and scalars and store them in variables.
Please add enough comments in your code to show me how to interpret your steps.
## [,1] [,2]
## [1,] 14 11
## [2,] 11 17
## [,1] [,2] [,3]
## [1,] 2 2 -1
## [2,] 2 4 6
## [3,] -1 6 25
\({ X = \begin{bmatrix}14&11 \\11&17 \\\end{bmatrix} ; Y = \begin{bmatrix}2&2&-1 \\2&4&6 \\-1&6&25 \\\end{bmatrix}}\)
## eigen() decomposition
## $values
## [1] 26.60180165559 4.39819834441
##
## $vectors
## [,1] [,2]
## [1,] 0.657604286508 -0.753363526039
## [2,] 0.753363526039 0.657604286508
## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## eigen() decomposition
## $values
## [1] 26.601801655587209438635909464 4.398198344412743487907846429 0.000000000000000105898195693
##
## $vectors
## [,1] [,2] [,3]
## [1,] -0.0185662914215 -0.672790268817 0.739600261634
## [2,] 0.2549993688964 -0.718451044302 -0.647150228929
## [3,] 0.9667629568231 0.176582420208 0.184900065408
## [,1]
## [1,] 26.601801655587209438635909464
## [2,] 4.398198344412743487907846429
## [3,] 0.000000000000000105898195693
## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [3,] 0.00000000000
# examine difference between eigenvalues for X and Y
# add a zero to pretend there is a third eigenvalue for X, so the matrices can be compared
X_eigenval3 = rbind(X_eigenval2,0)
X_eigenval3## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [3,] 0.00000000000
## [,1]
## [1,] 0
## [2,] 0
## [3,] 0
## [1] TRUE
Thus, the two eigenvalues for \(X\), \({eig(X)=\begin{bmatrix}26.601801655587 \\4.398198344413 \\\end{bmatrix}}\) ,
are equal to the first two eigenvalues for \(Y\), \({eig(Y)=\begin{bmatrix}26.601801655587 \\4.398198344413 \\0 \\\end{bmatrix}}\) .
## [1] 1 -31 117
## [1] 1 -31 117 0
So, the eigenvalues for X solve \(t^2-31t^2+117=0\) ,
and the eigenvalues for Y solve \(t^3-31t^2+117t=0\) .
By the quadratic formula, the solution for eigenvalues of X is \[eigvals_X={\frac{ 31 \pm \sqrt{(-31)^2-4\cdot1\cdot117}}{2} = \frac{ 31 \pm \sqrt{493}}{2}}\]
(The square root cannot be factored further as \(493=29*17\) , both of which are prime.)
The eigenvalues for Y are going to be the above pair of values as well as 0, as Y is singular.
## [1] 26.6018016556
## [1] TRUE
## [1] 4.39819834441
## [1] TRUE
# Two roots of the characteristic polynomial for X:
Xroots = t(t(as.numeric(rev(polyroot(rev(Xpoly))))))
Xroots## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
# Three roots of the characteristic polynomial for Y:
Yroots = t(t(as.numeric(rev(polyroot(rev(Ypoly))))))
Yroots## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [3,] 0.00000000000
A_svd = svd(x=A, nu=2, nv=3) # we need to specify nv=3 so function will return the entire V
# left side
U = A_svd$u # U is 2x2
print('U: ')## [1] "U: "
## [,1] [,2]
## [1,] -0.657604286508 -0.753363526039
## [2,] -0.753363526039 0.657604286508
## [1] "D: "
## [1] 5.15769344335 2.09718819957
## [1] "sqrt(D): "
## [,1]
## [1,] 2.27105557910
## [2,] 1.44816718633
# diagonal matrix
DI = D * eye(length(D)) # Note this is "*" rather than "%*%" because
# we just want to put the diagonal entries into I
print('Diag: ')## [1] "Diag: "
## [,1] [,2]
## [1,] 5.15769344335 0.00000000000
## [2,] 0.00000000000 2.09718819957
## [1] "D as 2x3: "
## [,1] [,2] [,3]
## [1,] 5.15769344335 0.00000000000 0
## [2,] 0.00000000000 2.09718819957 0
## [1] "V: "
## [,1] [,2] [,3]
## [1,] 0.0185662914215 -0.672790268817 -0.739600261634
## [2,] -0.2549993688964 -0.718451044302 0.647150228929
## [3,] -0.9667629568231 0.176582420208 -0.184900065408
\[ U = \begin{bmatrix}-0.657604286507732&-0.753363526039492 \\-0.753363526039492&0.657604286507732 \\\end{bmatrix} \]
\[ D = \begin{bmatrix}5.15769344335113&0 \\0&2.09718819956931 \\\end{bmatrix} \] \[ V = \begin{bmatrix}0.0185662914214504&-0.672790268816595&-0.739600261633639 \\-0.254999368896366&-0.718451044302279&0.647150228929434 \\-0.966762956823082&0.176582420208403&-0.18490006540841 \\\end{bmatrix} \] To get the dimensions correct for multiplication, we need to add a blank column to D:
\[DDD = \begin{bmatrix}5.15769344335113&0&0 \\0&2.09718819956931&0 \\\end{bmatrix}\]
## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [,1]
## [1,] 26.60180165559
## [2,] 4.39819834441
## [,1]
## [1,] -0.000000000000255795384874
## [2,] 0.000000000000256683563293
## [1] TRUE
## [,1]
## [1,] TRUE
## [2,] TRUE
Remember that eigenvectors can be negated in sign – it just flips the direction – so we may have to flip signs on columns to check
## [,1] [,2]
## [1,] -0.657604286508 -0.753363526039
## [2,] -0.753363526039 0.657604286508
## [,1] [,2]
## [1,] 0.657604286508 -0.753363526039
## [2,] 0.753363526039 0.657604286508
# we need to flip the signs on the first column of the eigenvectors to get a match
# Matrix to flip the signs in column 1:
FlipSigns_col1 = matrix(c(-1,-1,1,1),2,2,F)
FlipSigns_col1## [,1] [,2]
## [1,] -1 1
## [2,] -1 1
X_eigvecs_flipsign1 = X_eigvecs * FlipSigns_col1 # Note that this uses elementwise "*"
# rather than "%*%"
X_eigvecs_flipsign1## [,1] [,2]
## [1,] -0.657604286508 -0.753363526039
## [2,] -0.753363526039 0.657604286508
## [1] TRUE
## [,1] [,2]
## [1,] 0.000000000000000222044604925 0
## [2,] 0.000000000000000000000000000 0
# If we kill the decimals far to the right, do they match?
killtiny(X_eigvecs_flipsign1) == killtiny(U)## [,1] [,2]
## [1,] TRUE TRUE
## [2,] TRUE TRUE
## [,1]
## [1,] -17.4934587975
## [2,] -20.0408270943
## [,1]
## [1,] -17.4934587975
## [2,] -20.0408270943
## [1] TRUE
## [,1]
## [1,] -3.31344221297
## [2,] 2.89227408420
## [,1]
## [1,] -3.31344221297
## [2,] 2.89227408420
## [1] TRUE
## [,1] [,2] [,3]
## [1,] 0.0185662914215 -0.672790268817 -0.739600261634
## [2,] -0.2549993688964 -0.718451044302 0.647150228929
## [3,] -0.9667629568231 0.176582420208 -0.184900065408
## [,1] [,2] [,3]
## [1,] -0.0185662914215 -0.672790268817 0.739600261634
## [2,] 0.2549993688964 -0.718451044302 -0.647150228929
## [3,] 0.9667629568231 0.176582420208 0.184900065408
# we need to flip the signs on the first and third columns of the eigenvectors to get a match
# Matrix to flip the signs in column 1
FlipSigns_col13 = matrix(c(-1,-1,-1,1,1,1,-1,-1,-1),3,3,F)
FlipSigns_col13## [,1] [,2] [,3]
## [1,] -1 1 -1
## [2,] -1 1 -1
## [3,] -1 1 -1
Y_eigvecs_flipsign13 = Y_eigvecs * FlipSigns_col13 # Note that this uses elementwise "*"
# rather than "%*%"
Y_eigvecs_flipsign13## [,1] [,2] [,3]
## [1,] 0.0185662914215 -0.672790268817 -0.739600261634
## [2,] -0.2549993688964 -0.718451044302 0.647150228929
## [3,] -0.9667629568231 0.176582420208 -0.184900065408
## [1] TRUE
## [,1] [,2] [,3]
## [1,] -0.0000000000000000589805981832 0.000000000000000222044604925 -0.000000000000000333066907388
## [2,] 0.0000000000000002220446049250 -0.000000000000000444089209850 -0.000000000000000333066907388
## [3,] -0.0000000000000003330669073875 -0.000000000000000166533453694 0.000000000000000111022302463
# If we kill the decimals far to the right, do they match?
killtiny(Y_eigvecs_flipsign13) == killtiny(V)## [,1] [,2] [,3]
## [1,] TRUE TRUE TRUE
## [2,] TRUE TRUE TRUE
## [3,] TRUE TRUE TRUE
## [,1]
## [1,] 0.493896801873
## [2,] -6.783442633681
## [3,] -25.717636425377
## [,1]
## [1,] 0.493896801873
## [2,] -6.783442633681
## [3,] -25.717636425376
## [1] TRUE
## [,1]
## [1,] -2.959065046446
## [2,] -3.159890193592
## [3,] 0.776644508213
## [,1]
## [1,] -2.959065046446
## [2,] -3.159890193592
## [3,] 0.776644508213
## [1] TRUE
## [,1]
## [1,] 0.000000000000000555111512313
## [2,] 0.000000000000000444089209850
## [3,] -0.000000000000000888178419700
## [,1]
## [1,] 0
## [2,] 0
## [3,] 0
## [1] TRUE
## [,1]
## [1,] TRUE
## [2,] TRUE
## [3,] TRUE
\[A=U \cdot D \cdot V^T = \begin{bmatrix}-0.6576&-0.7534 \\-0.7534& 0.6576 \\\end{bmatrix} \begin{bmatrix}5.158&0.000&0.000 \\0.000&2.097&0.000 \\\end{bmatrix} \begin{bmatrix} 0.01857&-0.25500&-0.96676 \\-0.6728&-0.7185& 0.1766 \\-0.7396& 0.6472&-0.1849 \\\end{bmatrix} \]
## [,1] [,2] [,3]
## [1,] 1 2.000000000000000000000000000 3
## [2,] -1 0.000000000000000111022302463 4
## [1] TRUE
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] -1 0 4
## [,1] [,2] [,3]
## [1,] TRUE TRUE TRUE
## [2,] TRUE TRUE TRUE
Using the procedure outlined in section 1 of the weekly handout, write a function to compute the inverse of a well-conditioned full-rank square matrix using co-factors.
In order to compute the co-factors, you may use built-in commands to compute the determinant.
Your function should have the following signature:
\(B = myinverse(A)\)
where \(A\) is a matrix and \(B\) is its inverse and \(A\cdot B = I\).
The off-diagonal elements of \(I\) should be close to zero, if not zero.
Likewise, the diagonal elements should be close to 1, if not 1.
Small numerical precision errors are acceptable but the function myinverse should be correct and must use co-factors and determinant of A to compute the inverse.
myinverse <- function(A){
### Function to compute the inverse of a well-conditioned full-rank square matrix using co-factors
# confirm that A is of type "matrix"
if (class(A) != "matrix") stop ("Parameter must be of type MATRIX.")
# confirm that A is square
Arows = nrow(A)
Acols = ncol(A)
if (Arows != Acols) stop ("Parameter must be a SQUARE matrix.")
# check that A is non-singular
Adet = det(A)
epsilon = 1e-10
if (abs(Adet) < epsilon) stop ("Parameter must be NON-singular.")
# check that A is well-conditioned
# condition number is obtained from the svd -
# it is the ratio of the largest and smallest singular values
Acond = cond(A)
if (Acond > 1/epsilon) stop ("Parameter must be WELL-conditioned.")
# Create an identity matrix of the same size as A, in which to populate the cofactors:
detcofactors = zeros(Arows)
for (i in 1:Arows){
for (j in 1:Acols){
# derive the cofactor by dropping the current row and column, using A[-i,-j]
# in the case of a 2x2 matrix, this would yield back a scalar,
# which would cause problems for the det() function.
# so, ensure that the cofactor is a matrix, even if it is a 1x1 matrix
cofactor = matrix(A[-i,-j],(Arows-1),(Acols-1),T)
# compute the determinant of the cofactors,
# multiplied by a negative sign in the case of odd (row+column)
detcofactors[i,j] = det(cofactor) * (-1)^(i+j)
} # for j
} # for i
# The inverse of A is calculated as the transpose of detcofactors, divided by the determinant of A
Ainverse <- t(detcofactors)/Adet
return(Ainverse)
}## [,1]
## [1,] 0
## [,1]
## [1,] 7
## [,1] [,2]
## [1,] 1 2
## [2,] 2 1
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 6 5 4
# Create a 3x3 non-singular matrix
A33 = c(
1, 2, 3,
0, 4, 5,
0, 0, 6
)
A33 = matrix(A33,nrow=3,byrow=T)
A33## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 0 4 5
## [3,] 0 0 6
# Create a 3x3 singular matrix
A33sing = c(
2, 2, -1,
2, 4, 6,
-1, 6, 25
)
A33sing = matrix(A33sing,nrow=3,byrow=T)
A33sing## [,1] [,2] [,3]
## [1,] 2 2 -1
## [2,] 2 4 6
## [3,] -1 6 25
## [1] 0
# Create a 3x3 ill-conditioned matrix
A33cond = c(
2, 2, -1,
2, 4, 6,
-1, 6, 25.00000001
)
A33cond = matrix(A33cond,nrow=3,byrow=T)
A33cond## [,1] [,2] [,3]
## [1,] 2 2 -1.00000000
## [2,] 2 4 6.00000000
## [3,] -1 6 25.00000001
## [1] 0.0000000400000015333
## [1] 77810501921.5
\[ A_0 = \begin{bmatrix}0 \\\end{bmatrix} \]
## Error in myinverse(A0) : Parameter must be NON-singular.
\[ A_{2x3} = \begin{bmatrix}1&2&3 \\6&5&4 \\\end{bmatrix} \]
## Error in myinverse(A23) : Parameter must be a SQUARE matrix.
\[ A_{3x3-sing} = \begin{bmatrix}2&2&-1 \\2&4&6 \\-1&6&25 \\\end{bmatrix} \]
## Error in myinverse(A33ns) : object 'A33ns' not found
\[ A_{3x3-ill-cond} = \begin{bmatrix}2&2&-1 \\2&4&6 \\-1&6&25.00000001 \\\end{bmatrix} \]
## Error in myinverse(A33cond) : Parameter must be WELL-conditioned.
\[ A_{1x1} = \begin{bmatrix}7 \\\end{bmatrix} \]
## [,1]
## [1,] 0.142857142857
## [,1]
## [1,] 1
## [1] TRUE
## [,1]
## [1,] 0.0000000000000000277555756156
## [1] TRUE
## [,1]
## [1,] 0.142857142857
## [,1]
## [1,] 0.142857142857
# does the inverse of the inverse of A1 give you back A1 ?
doubleinverseA1 = myinverse(myinverse(A1))
doubleinverseA1## [,1]
## [1,] 7
## [1] TRUE
\[ A_{2x2} = \begin{bmatrix}1&2 \\2&1 \\\end{bmatrix} \]
## [,1] [,2]
## [1,] -0.333333333333 0.666666666667
## [2,] 0.666666666667 -0.333333333333
## [,1] [,2]
## [1,] 1 0
## [2,] 0 1
## [1] TRUE
## [,1] [,2]
## [1,] -0.333333333333 0.666666666667
## [2,] 0.666666666667 -0.333333333333
## [,1] [,2]
## [1,] -0.0000000000000000555111512313 0.0000000000000001110223024625
## [2,] 0.0000000000000001110223024625 -0.0000000000000000555111512313
## [1] TRUE
## [,1] [,2]
## [1,] -0.333333333333 0.666666666667
## [2,] 0.666666666667 -0.333333333333
## [,1] [,2]
## [1,] -0.333333333333 0.666666666667
## [2,] 0.666666666667 -0.333333333333
# does the inverse of the inverse of A22 give you back A22 ?
doubleinverseA22 = myinverse(myinverse(A22))
doubleinverseA22## [,1] [,2]
## [1,] 1 2
## [2,] 2 1
## [1] TRUE
\[ A_{3x3} = \begin{bmatrix}1&2&3 \\0&4&5 \\0&0&6 \\\end{bmatrix} \]
## [,1] [,2] [,3]
## [1,] 1 -0.50 -0.0833333333333
## [2,] 0 0.25 -0.2083333333333
## [3,] 0 0.00 0.1666666666667
## [,1] [,2] [,3]
## [1,] 1 0 -0.000000000000000111022302463
## [2,] 0 1 -0.000000000000000111022302463
## [3,] 0 0 1.000000000000000222044604925
## [1] TRUE
## [,1] [,2] [,3]
## [1,] 1 -0.50 -0.0833333333333
## [2,] 0 0.25 -0.2083333333333
## [3,] 0 0.00 0.1666666666667
## [,1] [,2] [,3]
## [1,] 0.00000000000000044408920985 -0.0000000000000001110223024625 -0.0000000000000000277555756156
## [2,] 0.00000000000000000000000000 0.0000000000000000555111512313 -0.0000000000000001110223024625
## [3,] 0.00000000000000000000000000 0.0000000000000000000000000000 0.0000000000000000555111512313
## [1] TRUE
## [,1] [,2] [,3]
## [1,] 1 -0.50 -0.083333333333
## [2,] 0 0.25 -0.208333333333
## [3,] 0 0.00 0.166666666667
## [,1] [,2] [,3]
## [1,] 1 -0.50 -0.0833333333333
## [2,] 0 0.25 -0.2083333333333
## [3,] 0 0.00 0.1666666666667
# does the inverse of the inverse of A33 give you back A33 ?
doubleinverseA33 = myinverse(myinverse(A33))
doubleinverseA33## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 0 4 5
## [3,] 0 0 6
## [1] TRUE