Problem Set 1

Given a 3 × 2 matrix A, A = [1 2 3, -1 0 4], (1) write code in R to compute X = AAT and Y = ATA.

First we will initialize matrix A, to ensure it’s been created in the proper form. Then we’ll compute and display X and Y by the equations noted above.

#Initialize matrix A
A <- matrix(data = c(1, 2, 3, -1, 0, 4), nrow = 2, byrow = TRUE)
A
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   -1    0    4
#Compute X = AAT
#3x2 matrix multiplied by a 2x3 matrix results in 3x3 matrix
X = A %*% t(A) 
X
##      [,1] [,2]
## [1,]   14   11
## [2,]   11   17
#Compute Y= ATA
#2x3 matrix multiplied by a 3x2 matrix results in 2x2 matrix
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 X and Y using the built-in commands in R.

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 (to be computed later).

Using the built in eigen() function, we compute the eigenvalues and eigenvector of X and Y, and return the corresponding values and vectors.

#Compute and display the eigenvalues and eigenvectors of X and Y.
eX <- eigen(X)
eY <- eigen(Y)

eX$values
## [1] 26.601802  4.398198
eY$values
## [1] 2.660180e+01 4.398198e+00 1.058982e-16
eX$vectors
##           [,1]       [,2]
## [1,] 0.6576043 -0.7533635
## [2,] 0.7533635  0.6576043
eY$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

From the output above we see that the 2 non-zero eigenvalues for X and Y are the same, while the 3rd eigenvalue for Y approaches 0.

Compute the left-singular, singular values, and right-singular vectors of A using the svd command.

SVD computes the singular-value decomposition of a rectangular matrix (in our case A). A = U D VT is the factorization of A into the product of 3 matrices described as follows:

D ($d): a vector containing singular values of A sorted decreasingly

U ($u): a matrix whose columns contain the left singular values of A

VT ($v): a matrix whose columns contain the right singular vectors of x.

#Factorize A for product matrices using svd() function
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
round(eX$values, digits = 3)
## [1] 26.602  4.398
round((svd_A$d)^2, digits = 3)
## [1] 26.602  4.398

We can confirm above that (after rounding to same decimal point), X and Y (which have the same 1st 2 values) are equivalent to the squares of the non-zero singular values of A.

Next we will examine / compare eigenvectors of X and Y with the eigenvectors of the singular vectors.

Examine the two sets of singular vectors and show that they are indeed eigenvectors of X and Y.

#First we will compare the eigenvectors of X to those of U.
eX$vectors
##           [,1]       [,2]
## [1,] 0.6576043 -0.7533635
## [2,] 0.7533635  0.6576043
svd_A$u
##            [,1]       [,2]
## [1,] -0.6576043 -0.7533635
## [2,] -0.7533635  0.6576043
#The 1st vector (column 1) has different signs so we invert the sign of this eigenvector - the result is still an eigenvector.

eX$vectors[,1] <- eX$vectors[,1] * -1

#We compare again ...

round(eX$vectors, digits = 3)
##        [,1]   [,2]
## [1,] -0.658 -0.753
## [2,] -0.753  0.658
round(svd_A$u, digits = 3)
##        [,1]   [,2]
## [1,] -0.658 -0.753
## [2,] -0.753  0.658

Voila! We confirm above that (after rounding to same decimal point), X and U have equivalent eigenvectors.

Now we do the same for Y and V.

#First we will compare the eigenvectors of Y to those of V.
eY$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
svd_A$v
##             [,1]       [,2]
## [1,]  0.01856629 -0.6727903
## [2,] -0.25499937 -0.7184510
## [3,] -0.96676296  0.1765824
#The same case as before - we invert the 1st column.

eY$vectors[,1] <- eY$vectors[,1] * -1

#We compare again, this time discounting the 3rd column (associated with a 0 eigenvalue).

round(eY$vectors[,1:2], digits = 3)
##        [,1]   [,2]
## [1,]  0.019 -0.673
## [2,] -0.255 -0.718
## [3,] -0.967  0.177
round(svd_A$v, digits = 3)
##        [,1]   [,2]
## [1,]  0.019 -0.673
## [2,] -0.255 -0.718
## [3,] -0.967  0.177

Thus confirming that (after rounding to same decimal point), Y and V have equivalent eigenvectors.

Problem Set 2

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.

To compute the inverse of a well-conditioned full-rank matrix, we’ll initalize the matrix of cofactors, flag for non full rank inputs, construct the matrix of cofactors (via the procedure referenced above), initialize and output matrix B as the inverse of matrix A.

myinverse = function(A){
  
  #Initialize matrix of cofactors
  coMatrix = A * 0
  
  #Flag non full rank matrices:
  if(det(A) == 0){ 
    return('Please enter a full rank, square matrix.') 
    }
  
  #Construct matrix of cofactors:
  for(i in 1:ncol(A)) {
    for(j in 1:nrow(A)) {
      coMatrix[i,j] = det(A[-i,-j]) * (-1)^(i+j) 
    }}
  
  #Initialize inverse of B as inv(A) = CT / det(A)
  B = t(coMatrix / det(A))
  
  return(B)
}

Now that we have our function built, we can test for (1) a full rank, square matrix, (2) a non full rank matrix, and (3) a non square matrix.

Your function should have the following signature: B = myinverse(A) where A is a matrix and B is its inverse and A×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.

#Test 1: a full rank, square 3x3 matrix
A = matrix(c(1,0,2,2,1,0,3,2,1), nrow=  3, ncol = 3, byrow = TRUE)
A
##      [,1] [,2] [,3]
## [1,]    1    0    2
## [2,]    2    1    0
## [3,]    3    2    1
B = myinverse(A)
round(B, digits = 3)
##        [,1]   [,2]   [,3]
## [1,]  0.333  1.333 -0.667
## [2,] -0.667 -1.667  1.333
## [3,]  0.333 -0.667  0.333
#confirm that the matrix product of A and B is indeed the identity matrix
round(A %*% B, digits = 3)
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    1    0
## [3,]    0    0    1
#Test 2: a non full rank matrix
A = matrix(c(0,1,2,1,2,1,2,7,8), nrow = 3, ncol = 3, byrow = TRUE)
A
##      [,1] [,2] [,3]
## [1,]    0    1    2
## [2,]    1    2    1
## [3,]    2    7    8
B=myinverse(A)
B
## [1] "Please enter a full rank, square matrix."
#Test 3: a non square matrix ---COMMENTED OUT---
#A = matrix(c(1,2,3,2,1,1), nrow = 2, ncol = 3, byrow = TRUE)
#A

#B=myinverse(A)
#B

The full rank, square matrix returned a perfect matrix inverse which was confirmed via the product of A and B as the identity matrix.

The non full rank matrix was flagged as designed and the non-square matrix is automatically flagged (as an error message) because of the determinant function.

Test matrices were pulled from: https://stattrek.com/matrix-algebra/matrix-rank.aspx

LS0tDQp0aXRsZTogIkRBVEEgNjA1IEFzc2lnbm1lbnQgNCINCmF1dGhvcjogIk1hZ251cyBTa29uYmVyZyINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogDQogIG9wZW5pbnRybzo6bGFiX3JlcG9ydDogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KYGBge3IgbGlicmFyaWVzLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShtYXRyaXhjYWxjKQ0KYGBgDQoNCiMjIyBQcm9ibGVtIFNldCAxICANCg0KPHN0eWxlPg0KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9DQo8L3N0eWxlPg0KPGRpdiBjbGFzcyA9ICJibHVlIj4NCg0KR2l2ZW4gYSAzIMOXIDIgbWF0cml4IEEsIEEgPSBbMSAyIDMsIC0xIDAgNF0sICgxKSB3cml0ZSBjb2RlIGluIFIgdG8gY29tcHV0ZSBYID0gQUFUIGFuZCBZID0gQVRBLg0KDQo8L2Rpdj4gXGhmaWxsXGJyZWFrDQoNCkZpcnN0IHdlIHdpbGwgaW5pdGlhbGl6ZSBtYXRyaXggQSwgdG8gZW5zdXJlIGl0J3MgYmVlbiBjcmVhdGVkIGluIHRoZSBwcm9wZXIgZm9ybS4gKlRoZW4qIHdlJ2xsIGNvbXB1dGUgYW5kIGRpc3BsYXkgWCBhbmQgWSBieSB0aGUgZXF1YXRpb25zIG5vdGVkIGFib3ZlLg0KDQpgYGB7cn0NCiNJbml0aWFsaXplIG1hdHJpeCBBDQpBIDwtIG1hdHJpeChkYXRhID0gYygxLCAyLCAzLCAtMSwgMCwgNCksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQpBDQoNCiNDb21wdXRlIFggPSBBQVQNCiMzeDIgbWF0cml4IG11bHRpcGxpZWQgYnkgYSAyeDMgbWF0cml4IHJlc3VsdHMgaW4gM3gzIG1hdHJpeA0KWCA9IEEgJSolIHQoQSkgDQpYDQoNCiNDb21wdXRlIFk9IEFUQQ0KIzJ4MyBtYXRyaXggbXVsdGlwbGllZCBieSBhIDN4MiBtYXRyaXggcmVzdWx0cyBpbiAyeDIgbWF0cml4DQpZID0gdChBKSAlKiUgQSANClkNCg0KYGBgDQoNCjxzdHlsZT4NCmRpdi5ibHVlIHsgYmFja2dyb3VuZC1jb2xvcjojZTZmMGZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDIwcHg7fQ0KPC9zdHlsZT4NCjxkaXYgY2xhc3MgPSAiYmx1ZSI+DQoNCkNvbXB1dGUgdGhlIGVpZ2VudmFsdWVzIGFuZCBlaWdlbnZlY3RvcnMgb2YgWCBhbmQgWSB1c2luZyB0aGUgYnVpbHQtaW4gY29tbWFuZHMgaW4gUi4NCg0KKlRoZSB0d28gbm9uLXplcm8gZWlnZW52YWx1ZXMgKHRoZSAzcmQgdmFsdWUgd2lsbCBiZSB2ZXJ5IGNsb3NlIHRvIHplcm8sIGlmIG5vdCB6ZXJvKSBvZiBib3RoIFggYW5kIFkgYXJlIHRoZSBzYW1lIGFuZCBhcmUgc3F1YXJlcyBvZiB0aGUgbm9uLXplcm8gc2luZ3VsYXIgdmFsdWVzIG9mIEEgKHRvIGJlIGNvbXB1dGVkIGxhdGVyKS4qIA0KDQo8L2Rpdj4gXGhmaWxsXGJyZWFrDQoNClVzaW5nIHRoZSBidWlsdCBpbiBlaWdlbigpIGZ1bmN0aW9uLCB3ZSBjb21wdXRlIHRoZSBlaWdlbnZhbHVlcyBhbmQgZWlnZW52ZWN0b3Igb2YgWCBhbmQgWSwgYW5kIHJldHVybiB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZXMgYW5kIHZlY3RvcnMuDQoNCmBgYHtyfQ0KDQojQ29tcHV0ZSBhbmQgZGlzcGxheSB0aGUgZWlnZW52YWx1ZXMgYW5kIGVpZ2VudmVjdG9ycyBvZiBYIGFuZCBZLg0KZVggPC0gZWlnZW4oWCkNCmVZIDwtIGVpZ2VuKFkpDQoNCmVYJHZhbHVlcw0KZVkkdmFsdWVzDQoNCmVYJHZlY3RvcnMNCmVZJHZlY3RvcnMNCg0KYGBgDQoNCkZyb20gdGhlIG91dHB1dCBhYm92ZSB3ZSBzZWUgdGhhdCB0aGUgMiBub24temVybyBlaWdlbnZhbHVlcyBmb3IgWCBhbmQgWSBhcmUgdGhlIHNhbWUsIHdoaWxlIHRoZSAzcmQgZWlnZW52YWx1ZSBmb3IgWSBhcHByb2FjaGVzIDAuDQoNCjxzdHlsZT4NCmRpdi5ibHVlIHsgYmFja2dyb3VuZC1jb2xvcjojZTZmMGZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDIwcHg7fQ0KPC9zdHlsZT4NCjxkaXYgY2xhc3MgPSAiYmx1ZSI+DQoNCkNvbXB1dGUgdGhlIGxlZnQtc2luZ3VsYXIsIHNpbmd1bGFyIHZhbHVlcywgYW5kIHJpZ2h0LXNpbmd1bGFyIHZlY3RvcnMgb2YgQSB1c2luZyB0aGUgc3ZkIGNvbW1hbmQuDQoNCjwvZGl2PiBcaGZpbGxcYnJlYWsNCg0KU1ZEIGNvbXB1dGVzIHRoZSBzaW5ndWxhci12YWx1ZSBkZWNvbXBvc2l0aW9uIG9mIGEgcmVjdGFuZ3VsYXIgbWF0cml4IChpbiBvdXIgY2FzZSBBKS4gQSA9IFUgRCBWVCBpcyB0aGUgZmFjdG9yaXphdGlvbiBvZiBBIGludG8gdGhlIHByb2R1Y3Qgb2YgMyBtYXRyaWNlcyBkZXNjcmliZWQgYXMgZm9sbG93czogDQoNCioqRCAoJGQpOioqIGEgdmVjdG9yIGNvbnRhaW5pbmcgc2luZ3VsYXIgdmFsdWVzIG9mIEEgc29ydGVkIGRlY3JlYXNpbmdseQ0KDQoqKlUgKCR1KToqKiBhIG1hdHJpeCB3aG9zZSBjb2x1bW5zIGNvbnRhaW4gdGhlIGxlZnQgc2luZ3VsYXIgdmFsdWVzIG9mIEENCg0KKipWVCAoJHYpOioqIGEgbWF0cml4IHdob3NlIGNvbHVtbnMgY29udGFpbiB0aGUgcmlnaHQgc2luZ3VsYXIgdmVjdG9ycyBvZiB4Lg0KDQpgYGB7cn0NCiNGYWN0b3JpemUgQSBmb3IgcHJvZHVjdCBtYXRyaWNlcyB1c2luZyBzdmQoKSBmdW5jdGlvbg0Kc3ZkX0EgPC0gc3ZkKEEpDQpzdmRfQQ0KDQpyb3VuZChlWCR2YWx1ZXMsIGRpZ2l0cyA9IDMpDQpyb3VuZCgoc3ZkX0EkZCleMiwgZGlnaXRzID0gMykNCg0KYGBgDQoNCldlIGNhbiBjb25maXJtIGFib3ZlIHRoYXQgKGFmdGVyIHJvdW5kaW5nIHRvIHNhbWUgZGVjaW1hbCBwb2ludCksIFggYW5kIFkgKHdoaWNoIGhhdmUgdGhlIHNhbWUgMXN0IDIgdmFsdWVzKSBhcmUgZXF1aXZhbGVudCB0byB0aGUgc3F1YXJlcyBvZiB0aGUgbm9uLXplcm8gc2luZ3VsYXIgdmFsdWVzIG9mIEEuIA0KDQpOZXh0IHdlIHdpbGwgZXhhbWluZSAvIGNvbXBhcmUgZWlnZW52ZWN0b3JzIG9mIFggYW5kIFkgd2l0aCB0aGUgZWlnZW52ZWN0b3JzIG9mIHRoZSBzaW5ndWxhciB2ZWN0b3JzLg0KDQo8c3R5bGU+DQpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I2U2ZjBmZjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30NCjwvc3R5bGU+DQo8ZGl2IGNsYXNzID0gImJsdWUiPg0KDQpFeGFtaW5lIHRoZSB0d28gc2V0cyBvZiBzaW5ndWxhciB2ZWN0b3JzIGFuZCBzaG93IHRoYXQgdGhleSBhcmUgaW5kZWVkIGVpZ2VudmVjdG9ycyBvZiBYIGFuZCBZLg0KDQo8L2Rpdj4gXGhmaWxsXGJyZWFrDQoNCmBgYHtyfQ0KI0ZpcnN0IHdlIHdpbGwgY29tcGFyZSB0aGUgZWlnZW52ZWN0b3JzIG9mIFggdG8gdGhvc2Ugb2YgVS4NCmVYJHZlY3RvcnMNCnN2ZF9BJHUNCg0KI1RoZSAxc3QgdmVjdG9yIChjb2x1bW4gMSkgaGFzIGRpZmZlcmVudCBzaWducyBzbyB3ZSBpbnZlcnQgdGhlIHNpZ24gb2YgdGhpcyBlaWdlbnZlY3RvciAtIHRoZSByZXN1bHQgaXMgc3RpbGwgYW4gZWlnZW52ZWN0b3IuDQoNCmVYJHZlY3RvcnNbLDFdIDwtIGVYJHZlY3RvcnNbLDFdICogLTENCg0KI1dlIGNvbXBhcmUgYWdhaW4gLi4uDQoNCnJvdW5kKGVYJHZlY3RvcnMsIGRpZ2l0cyA9IDMpDQpyb3VuZChzdmRfQSR1LCBkaWdpdHMgPSAzKQ0KDQpgYGANCg0KVm9pbGEhIFdlIGNvbmZpcm0gYWJvdmUgdGhhdCAoYWZ0ZXIgcm91bmRpbmcgdG8gc2FtZSBkZWNpbWFsIHBvaW50KSwgWCBhbmQgVSBoYXZlIGVxdWl2YWxlbnQgZWlnZW52ZWN0b3JzLg0KDQpOb3cgd2UgZG8gdGhlIHNhbWUgZm9yIFkgYW5kIFYuDQoNCmBgYHtyfQ0KI0ZpcnN0IHdlIHdpbGwgY29tcGFyZSB0aGUgZWlnZW52ZWN0b3JzIG9mIFkgdG8gdGhvc2Ugb2YgVi4NCmVZJHZlY3RvcnMNCnN2ZF9BJHYNCg0KI1RoZSBzYW1lIGNhc2UgYXMgYmVmb3JlIC0gd2UgaW52ZXJ0IHRoZSAxc3QgY29sdW1uLg0KDQplWSR2ZWN0b3JzWywxXSA8LSBlWSR2ZWN0b3JzWywxXSAqIC0xDQoNCiNXZSBjb21wYXJlIGFnYWluLCB0aGlzIHRpbWUgZGlzY291bnRpbmcgdGhlIDNyZCBjb2x1bW4gKGFzc29jaWF0ZWQgd2l0aCBhIDAgZWlnZW52YWx1ZSkuDQoNCnJvdW5kKGVZJHZlY3RvcnNbLDE6Ml0sIGRpZ2l0cyA9IDMpDQpyb3VuZChzdmRfQSR2LCBkaWdpdHMgPSAzKQ0KDQpgYGANCg0KVGh1cyBjb25maXJtaW5nIHRoYXQgKGFmdGVyIHJvdW5kaW5nIHRvIHNhbWUgZGVjaW1hbCBwb2ludCksIFkgYW5kIFYgaGF2ZSBlcXVpdmFsZW50IGVpZ2VudmVjdG9ycy4NCg0KIyMjIFByb2JsZW0gU2V0IDIgIA0KDQo8c3R5bGU+DQpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I2U2ZjBmZjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30NCjwvc3R5bGU+DQo8ZGl2IGNsYXNzID0gImJsdWUiPg0KDQpVc2luZyB0aGUgcHJvY2VkdXJlIG91dGxpbmVkIGluIHNlY3Rpb24gMSBvZiB0aGUgd2Vla2x5IGhhbmRvdXQsIHdyaXRlIGEgZnVuY3Rpb24gdG8gY29tcHV0ZSB0aGUgaW52ZXJzZSBvZiBhIHdlbGwtY29uZGl0aW9uZWQgZnVsbC1yYW5rIHNxdWFyZSBtYXRyaXggdXNpbmcgY28tZmFjdG9ycy4gDQoNCjwvZGl2PiBcaGZpbGxcYnJlYWsNCg0KVG8gY29tcHV0ZSB0aGUgaW52ZXJzZSBvZiBhIHdlbGwtY29uZGl0aW9uZWQgZnVsbC1yYW5rIG1hdHJpeCwgd2UnbGwgaW5pdGFsaXplIHRoZSBtYXRyaXggb2YgY29mYWN0b3JzLCBmbGFnIGZvciAgbm9uIGZ1bGwgcmFuayBpbnB1dHMsIGNvbnN0cnVjdCB0aGUgbWF0cml4IG9mIGNvZmFjdG9ycyAodmlhIHRoZSBwcm9jZWR1cmUgcmVmZXJlbmNlZCBhYm92ZSksIGluaXRpYWxpemUgYW5kIG91dHB1dCBtYXRyaXggQiBhcyB0aGUgaW52ZXJzZSBvZiBtYXRyaXggQS4NCg0KYGBge3J9DQpteWludmVyc2UgPSBmdW5jdGlvbihBKXsNCiAgDQogICNJbml0aWFsaXplIG1hdHJpeCBvZiBjb2ZhY3RvcnMNCiAgY29NYXRyaXggPSBBICogMA0KICANCiAgI0ZsYWcgbm9uIGZ1bGwgcmFuayBtYXRyaWNlczoNCiAgaWYoZGV0KEEpID09IDApeyANCiAgICByZXR1cm4oJ1BsZWFzZSBlbnRlciBhIGZ1bGwgcmFuaywgc3F1YXJlIG1hdHJpeC4nKSANCiAgICB9DQogIA0KICAjQ29uc3RydWN0IG1hdHJpeCBvZiBjb2ZhY3RvcnM6DQogIGZvcihpIGluIDE6bmNvbChBKSkgew0KICAgIGZvcihqIGluIDE6bnJvdyhBKSkgew0KICAgICAgY29NYXRyaXhbaSxqXSA9IGRldChBWy1pLC1qXSkgKiAoLTEpXihpK2opIA0KICAgIH19DQogIA0KICAjSW5pdGlhbGl6ZSBpbnZlcnNlIG9mIEIgYXMgaW52KEEpID0gQ1QgLyBkZXQoQSkNCiAgQiA9IHQoY29NYXRyaXggLyBkZXQoQSkpDQogIA0KICByZXR1cm4oQikNCn0NCmBgYA0KDQpOb3cgdGhhdCB3ZSBoYXZlIG91ciBmdW5jdGlvbiBidWlsdCwgd2UgY2FuIHRlc3QgZm9yICgxKSBhIGZ1bGwgcmFuaywgc3F1YXJlIG1hdHJpeCwgKDIpIGEgbm9uIGZ1bGwgcmFuayBtYXRyaXgsIGFuZCAoMykgYSBub24gc3F1YXJlIG1hdHJpeC4NCg0KPHN0eWxlPg0KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9DQo8L3N0eWxlPg0KPGRpdiBjbGFzcyA9ICJibHVlIj4NCg0KWW91ciBmdW5jdGlvbiBzaG91bGQgaGF2ZSB0aGUgZm9sbG93aW5nIHNpZ25hdHVyZTogQiA9IG15aW52ZXJzZShBKSB3aGVyZSBBIGlzIGEgbWF0cml4IGFuZCBCIGlzIGl0cyBpbnZlcnNlIGFuZCBBw5dCID0gSS4gVGhlIG9mZi1kaWFnb25hbCBlbGVtZW50cyBvZiBJIHNob3VsZCBiZSBjbG9zZSB0byB6ZXJvLCBpZiBub3QgemVyby4gTGlrZXdpc2UsIHRoZSBkaWFnb25hbCBlbGVtZW50cyBzaG91bGQgYmUgY2xvc2UgdG8gMSwgaWYgbm90IDEuIFNtYWxsIG51bWVyaWNhbCBwcmVjaXNpb24gZXJyb3JzIGFyZSBhY2NlcHRhYmxlIGJ1dCB0aGUgZnVuY3Rpb24gbXlpbnZlcnNlIHNob3VsZCBiZSBjb3JyZWN0IGFuZCBtdXN0IHVzZSBjby1mYWN0b3JzIGFuZCBkZXRlcm1pbmFudCBvZiBBIHRvIGNvbXB1dGUgdGhlIGludmVyc2UuIA0KDQo8L2Rpdj4gXGhmaWxsXGJyZWFrDQoNCmBgYHtyfQ0KI1Rlc3QgMTogYSBmdWxsIHJhbmssIHNxdWFyZSAzeDMgbWF0cml4DQpBID0gbWF0cml4KGMoMSwwLDIsMiwxLDAsMywyLDEpLCBucm93PSAgMywgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSkNCkENCg0KQiA9IG15aW52ZXJzZShBKQ0Kcm91bmQoQiwgZGlnaXRzID0gMykNCg0KI2NvbmZpcm0gdGhhdCB0aGUgbWF0cml4IHByb2R1Y3Qgb2YgQSBhbmQgQiBpcyBpbmRlZWQgdGhlIGlkZW50aXR5IG1hdHJpeA0Kcm91bmQoQSAlKiUgQiwgZGlnaXRzID0gMykNCg0KDQojVGVzdCAyOiBhIG5vbiBmdWxsIHJhbmsgbWF0cml4DQpBID0gbWF0cml4KGMoMCwxLDIsMSwyLDEsMiw3LDgpLCBucm93ID0gMywgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSkNCkENCg0KQj1teWludmVyc2UoQSkNCkINCg0KDQojVGVzdCAzOiBhIG5vbiBzcXVhcmUgbWF0cml4IC0tLUNPTU1FTlRFRCBPVVQtLS0NCiNBID0gbWF0cml4KGMoMSwyLDMsMiwxLDEpLCBucm93ID0gMiwgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSkNCiNBDQoNCiNCPW15aW52ZXJzZShBKQ0KI0INCmBgYA0KDQoqKlRoZSBmdWxsIHJhbmssIHNxdWFyZSBtYXRyaXggcmV0dXJuZWQgYSBwZXJmZWN0IG1hdHJpeCBpbnZlcnNlIHdoaWNoIHdhcyBjb25maXJtZWQgdmlhIHRoZSBwcm9kdWN0IG9mIEEgYW5kIEIgYXMgdGhlIGlkZW50aXR5IG1hdHJpeC4qKg0KDQpUaGUgbm9uIGZ1bGwgcmFuayBtYXRyaXggd2FzIGZsYWdnZWQgYXMgZGVzaWduZWQgYW5kIHRoZSBub24tc3F1YXJlIG1hdHJpeCBpcyBhdXRvbWF0aWNhbGx5IGZsYWdnZWQgKGFzIGFuIGVycm9yIG1lc3NhZ2UpIGJlY2F1c2Ugb2YgdGhlIGRldGVybWluYW50IGZ1bmN0aW9uLg0KDQoqVGVzdCBtYXRyaWNlcyB3ZXJlIHB1bGxlZCBmcm9tOiBodHRwczovL3N0YXR0cmVrLmNvbS9tYXRyaXgtYWxnZWJyYS9tYXRyaXgtcmFuay5hc3B4Kg0K