Creating Matrix

Using matrix() to create matrix:

matrix(c(1:8,99), nrow=3, byrow=T)  # nrow - defining row number
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8   99
matrix(c(1:8,99), ncol=3, byrow=T)  # ncol - defining column number
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8   99
mat<-matrix(c(1:8,99), nrow=3, ncol=3, byrow=F)  # fills by column
mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6   99

byrow is set to false by default.
To know details write help(matrix) or ?matrix and hit enter To check if the class of an object is matrix or not use is.matrix() -

is.matrix(mat)
[1] TRUE

Using rbind() to create matrix

rbind stands for row bind.

rbind(1:3,
      5:7,
      c(8,12,9))
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    5    6    7
[3,]    8   12    9

Using cbind() to create matrix

cbind stands for column bind.

cmat <- cbind(1:3,
              5:7,
              c(8,12,9))
cmat
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    2    6   12
[3,]    3    7    9

Dimension

Use dim():

dim(mat)
[1] 3 3

Which shows that mat is a 3*3 matrix.

To know the number of columns use ncol():

ncol(mat)
[1] 3

To know the number of rows use nrow():

nrow(mat)
[1] 3

Dimension names

dmat<-matrix(data=10:18, nrow=3,
             dimnames=list(c("A","B","C"),
                           c("D","E","F")))
dmat
   D  E  F
A 10 13 16
B 11 14 17
C 12 15 18

To know the attributes of a matrix:

attributes(dmat)
$dim
[1] 3 3

$dimnames
$dimnames[[1]]
[1] "A" "B" "C"

$dimnames[[2]]
[1] "D" "E" "F"

Determinant

Use det():

m<-matrix(c(3,2,4,3), ncol=2)
m
     [,1] [,2]
[1,]    3    4
[2,]    2    3
det(m)
[1] 1

Selecting element

Let’s recall the matrix cmat:

cmat
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    2    6   12
[3,]    3    7    9

Use matrixname[rowNumber,colNumber] to select elements:

cmat[1,2] #element of 1st row and 2nd column
[1] 5
cmat[1:2,3] #element of 1st and 2nd row, and 3rd column
[1]  8 12
cmat[,2]  #select 2nd column
[1] 5 6 7
cmat[3,]  #select 3rd row
[1] 3 7 9
cmat[c(1,3),]  #select element from 1st and 3rd row
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    3    7    9
cmat[,c(1,3)]  #select element from 1st and 3rd column
     [,1] [,2]
[1,]    1    8
[2,]    2   12
[3,]    3    9

Notice when we select a row or column, the matrix becomes a vector. To select the data as matrix instead of vector, we can use drop=FALSE:

cmat[,1] 
[1] 1 2 3
cmat[,1,drop=FALSE] 
     [,1]
[1,]    1
[2,]    2
[3,]    3

Replacing element

let’s recall the cmat matrix that we created:

cmat
     [,1] [,2] [,3]
[1,]    1    5    8
[2,]    2    6   12
[3,]    3    7    9

If we wish to replace the 1st element then simply select the first element and replace it using <- :

cmat[1,1] <- 0
cmat
     [,1] [,2] [,3]
[1,]    0    5    8
[2,]    2    6   12
[3,]    3    7    9

In a similar way we can replace multiple elements:

cmat[,1]<-c(9,9,9) #replace 1st column by 9,9,9
cmat
     [,1] [,2] [,3]
[1,]    9    5    8
[2,]    9    6   12
[3,]    9    7    9

Removing rows or columns

Let’s recall the mat matrix we created:

mat<-matrix(c(1:8,99), nrow=3, ncol=3,byrow=F)
mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6   99

To remove the 1st column:

mat[,-1]
     [,1] [,2]
[1,]    4    7
[2,]    5    8
[3,]    6   99

mat isn’t replaced by the new matrix. We have to assign it to a new matrix or the old one:

mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6   99
mat<- mat[,-1]
mat
     [,1] [,2]
[1,]    4    7
[2,]    5    8
[3,]    6   99

Similarly to remove the 2nd row,

mat[-2,]
     [,1] [,2]
[1,]    4    7
[2,]    6   99

Diagonal

To find the diagonal elements of a matrix:

diag(cmat)
[1] 9 6 9

To create a diagonal matrix:

diag(c(12,1,99))
     [,1] [,2] [,3]
[1,]   12    0    0
[2,]    0    1    0
[3,]    0    0   99

To create an identity matrix:

diag(3)
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1
diag(5)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    0    0    0
[2,]    0    1    0    0    0
[3,]    0    0    1    0    0
[4,]    0    0    0    1    0
[5,]    0    0    0    0    1

Minor of Matrix

Transpose

Let’s construct a matrix of order 3:

mat<-matrix(c(1:8,99), nrow=3,byrow=F)
mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6   99

To transpose it simply use t():

t(mat)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8   99

Minor

A <- matrix(c(4, 2, 7, 8, 0, 2, 3, 9, 1), ncol = 3, byrow = TRUE)
A
     [,1] [,2] [,3]
[1,]    4    2    7
[2,]    8    0    2
[3,]    3    9    1

Minor of the element in 1st row and 1st column -

det(A[-1,-1])
[1] -18

Minor of the element in 3rd row and 2nd column -

det(A[-3,-2])
[1] -48

Creating function -

minor <- function(A, i, j) {
  det(A[-i,-j])
}
minor(A, 3, 2)
[1] -48

Co-factor

Co-factor of the element in 1st row and 2nd column -

(-1)^(1+2)*det(A[-1,-2])
[1] -2

In other way using the minor() function -

(-1)^(1+2)*minor(A, 1, 2)
[1] -2

Creating a new function -

cofactor <- function(A, i, j) (-1)^(i+j) * minor(A,i,j)
cofactor(A, 1, 2)
[1] -2

Adjoint Matrix

To calculate the adjoint matrix of the square matrix A -

A
     [,1] [,2] [,3]
[1,]    4    2    7
[2,]    8    0    2
[3,]    3    9    1

Required portion of code -

t(outer(1:nrow(A), 1:nrow(A),
        FUN = Vectorize(function(i,j) cofactor(A,i,j))))
     [,1] [,2] [,3]
[1,]  -18   61    4
[2,]   -2  -17   48
[3,]   72  -30  -16

Creating function -

adjoint <- function(mat) {
  t(outer(1:nrow(mat), 1:nrow(mat), 
          FUN = Vectorize(function(i,j) cofactor(mat,i,j))))
}
adjoint(A)
     [,1] [,2] [,3]
[1,]  -18   61    4
[2,]   -2  -17   48
[3,]   72  -30  -16

Thus inverse of A -

adjoint(A)/det(A)
             [,1]        [,2]         [,3]
[1,] -0.042056075  0.14252336  0.009345794
[2,] -0.004672897 -0.03971963  0.112149533
[3,]  0.168224299 -0.07009346 -0.037383178

Note: Vectorize() vetorizes functions. Example -

sdf <- Vectorize(runif)  # vectorizing runif
set.seed(0)
sdf(n=c(10,10,5,6))   
[[1]]
 [1] 0.8966972 0.2655087 0.3721239 0.5728534 0.9082078 0.2016819 0.8983897
 [8] 0.9446753 0.6607978 0.6291140

[[2]]
 [1] 0.06178627 0.20597457 0.17655675 0.68702285 0.38410372 0.76984142
 [7] 0.49769924 0.71761851 0.99190609 0.38003518

[[3]]
[1] 0.7774452 0.9347052 0.2121425 0.6516738 0.1255551

[[4]]
[1] 0.26722067 0.38611409 0.01339033 0.38238796 0.86969085 0.34034900
cat("Not Vectorized\n"); runif(n=c(10,10,5,6))   # doesn't show what I want
Not Vectorized
[1] 0.4820801 0.5995658 0.4935413 0.1862176

Note: outer() performs outer product on arrays. Example -

outer(1:3, 4:7)  # default function performed = "*"
     [,1] [,2] [,3] [,4]
[1,]    4    5    6    7
[2,]    8   10   12   14
[3,]   12   15   18   21

Inverse Matrix

The function solve() does the work -

mat2<- rbind(c(1,5),
             c(9,5))
mat2
     [,1] [,2]
[1,]    1    5
[2,]    9    5
solve(mat2)
       [,1]   [,2]
[1,] -0.125  0.125
[2,]  0.225 -0.025

Multiplication

Scalar Multiplication

mat2<- rbind(c(1,5),
             c(9,5))
mat2*2
     [,1] [,2]
[1,]    2   10
[2,]   18   10
mat2*5
     [,1] [,2]
[1,]    5   25
[2,]   45   25

Matrix Multiplication

%*% is used for matrix multiplication:

A<-rbind(c(2,10),
         c(6,1))
A%*%A # matrix multiplication
     [,1] [,2]
[1,]   64   30
[2,]   18   61
A%*%solve(A) # proof of A*A^(-1) = I 
     [,1] [,2]
[1,]    1    0
[2,]    0    1

Other matrix algebra

A<-rbind(c(2,10,9),
         c(6,1,5))
B<-rbind(c(1,5,2),
         c(1,1,-4))
A-B  # Subtraction
     [,1] [,2] [,3]
[1,]    1    5    7
[2,]    5    0    9
A+B  # addition
     [,1] [,2] [,3]
[1,]    3   15   11
[2,]    7    2    1
A/B  # division
     [,1] [,2]  [,3]
[1,]    2    2  4.50
[2,]    6    1 -1.25

Rank of Matrix

Using the qr() function for QR Decomposition of a Matrix rank of a matrix can be obtained -

X <- matrix(c(1, 3, 9,
              2, 4, 0,
              3, 9, 27), ncol = 3, byrow = T)
qr(X)$rank
[1] 2

Eigen Values and Eigen Vectors

Let’s say we have a matrix X of 3*3 -

Y <- matrix(c(4, 10, -5,
              10, -8, 1,
              2, 8, -3), nrow = 3, byrow = T)
Y
     [,1] [,2] [,3]
[1,]    4   10   -5
[2,]   10   -8    1
[3,]    2    8   -3

To get the eigenvalues and eigenvectors use eigen() -

eig <- eigen(Y)
eig
eigen() decomposition
$values
[1] -15.1863790   7.3231657   0.8632133

$vectors
           [,1]      [,2]      [,3]
[1,] -0.5032161 0.7012153 0.2406474
[2,]  0.7579852 0.4913323 0.3726309
[3,] -0.4150084 0.5166137 0.8962338

To extract the values -

eig$values
[1] -15.1863790   7.3231657   0.8632133

To extract the eigen vectors -

eig$vectors
           [,1]      [,2]      [,3]
[1,] -0.5032161 0.7012153 0.2406474
[2,]  0.7579852 0.4913323 0.3726309
[3,] -0.4150084 0.5166137 0.8962338

Diagonalization

A square matrix \(A\) will be called diagonalizable if there exists an invertible matrix \(P\) such that \(P^{-1}AP\) is diagonal, then the matrix \(P\) is said to diagonalize matrix \(A\).

A = matrix(c(1,9,4,1), nrow = 2)
A
     [,1] [,2]
[1,]    1    4
[2,]    9    1

Then the matrix \(P\) that diagonalizes \(A\) can is the matrix that contains the eigen vectors -

P = eigen(A)$vectors
P       
          [,1]       [,2]
[1,] 0.5547002 -0.5547002
[2,] 0.8320503  0.8320503

So the diagonalized matrix will be -

d <- solve(P) %*% A %*% P
round(d, 2)
     [,1] [,2]
[1,]    7    0
[2,]    0   -5

Notice that the diagonal elements are actually the eigen values -

eigen(A)$values
[1]  7 -5
LS0tDQp0aXRsZTogIk1hdHJpeCBpbiBSIg0KYXV0aG9yOiAiTUQgQUhTQU5VTCBJU0xBTSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiIsIHByb21wdCA9IEYsIG1lc3NhZ2U9Riwgd2FybmluZyA9Rg0KKQ0KYGBgDQoNCi0tLQ0KDQojIyAgQ3JlYXRpbmcgTWF0cml4DQoNClVzaW5nIGBtYXRyaXgoKWAgdG8gY3JlYXRlIG1hdHJpeDoNCmBgYHtyfQ0KbWF0cml4KGMoMTo4LDk5KSwgbnJvdz0zLCBieXJvdz1UKSAgIyBucm93IC0gZGVmaW5pbmcgcm93IG51bWJlcg0KbWF0cml4KGMoMTo4LDk5KSwgbmNvbD0zLCBieXJvdz1UKSAgIyBuY29sIC0gZGVmaW5pbmcgY29sdW1uIG51bWJlcg0KbWF0PC1tYXRyaXgoYygxOjgsOTkpLCBucm93PTMsIG5jb2w9MywgYnlyb3c9RikgICMgZmlsbHMgYnkgY29sdW1uDQptYXQNCmBgYA0KDQpgYnlyb3dgIGlzIHNldCB0byBmYWxzZSBieSBkZWZhdWx0LiAgICANClRvIGtub3cgZGV0YWlscyB3cml0ZSBgaGVscChtYXRyaXgpYCBvciBgP21hdHJpeGAgYW5kIGhpdCBlbnRlcg0KVG8gY2hlY2sgaWYgdGhlIGNsYXNzIG9mIGFuIG9iamVjdCBpcyBtYXRyaXggb3Igbm90IHVzZSBgaXMubWF0cml4KClgIC0gDQpgYGB7cn0NCmlzLm1hdHJpeChtYXQpDQpgYGANCg0KDQojIyMgIFVzaW5nIHJiaW5kKCkgdG8gY3JlYXRlIG1hdHJpeA0KDQpyYmluZCBzdGFuZHMgZm9yIHJvdyBiaW5kLg0KYGBge3J9DQpyYmluZCgxOjMsDQogICAgICA1OjcsDQogICAgICBjKDgsMTIsOSkpDQpgYGANCg0KDQojIyMgIFVzaW5nIGNiaW5kKCkgdG8gY3JlYXRlIG1hdHJpeA0KDQpjYmluZCBzdGFuZHMgZm9yIGNvbHVtbiBiaW5kLg0KYGBge3J9DQpjbWF0IDwtIGNiaW5kKDE6MywNCiAgICAgICAgICAgICAgNTo3LA0KICAgICAgICAgICAgICBjKDgsMTIsOSkpDQpjbWF0DQpgYGANCg0KIyMgIERpbWVuc2lvbg0KDQpVc2UgYGRpbSgpYDoNCmBgYHtyfQ0KZGltKG1hdCkNCmBgYA0KV2hpY2ggc2hvd3MgdGhhdCBtYXQgaXMgYSAzKjMgbWF0cml4Lg0KDQpUbyBrbm93IHRoZSBudW1iZXIgb2YgY29sdW1ucyB1c2UgYG5jb2woKWA6DQpgYGB7cn0NCm5jb2wobWF0KQ0KYGBgDQpUbyBrbm93IHRoZSBudW1iZXIgb2Ygcm93cyB1c2UgYG5yb3coKWA6DQpgYGB7cn0NCm5yb3cobWF0KQ0KYGBgDQoNCg0KIyMgIERpbWVuc2lvbiBuYW1lcw0KYGBge3J9DQpkbWF0PC1tYXRyaXgoZGF0YT0xMDoxOCwgbnJvdz0zLA0KICAgICAgICAgICAgIGRpbW5hbWVzPWxpc3QoYygiQSIsIkIiLCJDIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJEIiwiRSIsIkYiKSkpDQpkbWF0DQpgYGANClRvIGtub3cgdGhlICoqYXR0cmlidXRlcyoqIG9mIGEgbWF0cml4Og0KYGBge3J9DQphdHRyaWJ1dGVzKGRtYXQpDQpgYGANCg0KIyMgIERldGVybWluYW50DQoNClVzZSBgZGV0KClgOg0KYGBge3J9DQptPC1tYXRyaXgoYygzLDIsNCwzKSwgbmNvbD0yKQ0KbQ0KZGV0KG0pDQpgYGANCg0KDQoNCg0KDQojIyBTZWxlY3RpbmcgZWxlbWVudA0KDQpMZXQncyByZWNhbGwgdGhlIG1hdHJpeCBjbWF0Og0KYGBge3J9DQpjbWF0DQpgYGANCg0KVXNlIGBtYXRyaXhuYW1lW3Jvd051bWJlcixjb2xOdW1iZXJdYCB0byBzZWxlY3QgZWxlbWVudHM6DQpgYGB7cn0NCmNtYXRbMSwyXSAjZWxlbWVudCBvZiAxc3Qgcm93IGFuZCAybmQgY29sdW1uDQpjbWF0WzE6MiwzXSAjZWxlbWVudCBvZiAxc3QgYW5kIDJuZCByb3csIGFuZCAzcmQgY29sdW1uDQpjbWF0WywyXSAgI3NlbGVjdCAybmQgY29sdW1uDQpjbWF0WzMsXSAgI3NlbGVjdCAzcmQgcm93DQpjbWF0W2MoMSwzKSxdICAjc2VsZWN0IGVsZW1lbnQgZnJvbSAxc3QgYW5kIDNyZCByb3cNCmNtYXRbLGMoMSwzKV0gICNzZWxlY3QgZWxlbWVudCBmcm9tIDFzdCBhbmQgM3JkIGNvbHVtbg0KYGBgDQoNCk5vdGljZSB3aGVuIHdlIHNlbGVjdCBhIHJvdyBvciBjb2x1bW4sIHRoZSBtYXRyaXggYmVjb21lcyBhIHZlY3Rvci4gVG8gc2VsZWN0IHRoZSBkYXRhIGFzIG1hdHJpeCBpbnN0ZWFkIG9mIHZlY3Rvciwgd2UgY2FuIHVzZSBgZHJvcD1GQUxTRWA6DQpgYGB7cn0NCmNtYXRbLDFdIA0KY21hdFssMSxkcm9wPUZBTFNFXSANCmBgYA0KDQoNCg0KIyMgUmVwbGFjaW5nIGVsZW1lbnQNCg0KbGV0J3MgcmVjYWxsIHRoZSBjbWF0IG1hdHJpeCB0aGF0IHdlIGNyZWF0ZWQ6DQpgYGB7cn0NCmNtYXQNCmBgYA0KDQpJZiB3ZSB3aXNoIHRvIHJlcGxhY2UgdGhlIDFzdCBlbGVtZW50IHRoZW4gc2ltcGx5IHNlbGVjdCB0aGUgZmlyc3QgZWxlbWVudCBhbmQgcmVwbGFjZSBpdCB1c2luZyA8LSA6DQpgYGB7cn0NCmNtYXRbMSwxXSA8LSAwDQpjbWF0DQpgYGANCg0KSW4gYSBzaW1pbGFyIHdheSB3ZSBjYW4gcmVwbGFjZSBtdWx0aXBsZSBlbGVtZW50czoNCmBgYHtyfQ0KY21hdFssMV08LWMoOSw5LDkpICNyZXBsYWNlIDFzdCBjb2x1bW4gYnkgOSw5LDkNCmNtYXQNCmBgYA0KDQojIyBSZW1vdmluZyByb3dzIG9yIGNvbHVtbnMNCg0KTGV0J3MgcmVjYWxsIHRoZSBtYXQgbWF0cml4IHdlIGNyZWF0ZWQ6DQpgYGB7cn0NCm1hdDwtbWF0cml4KGMoMTo4LDk5KSwgbnJvdz0zLCBuY29sPTMsYnlyb3c9RikNCm1hdA0KYGBgDQoNClRvIHJlbW92ZSB0aGUgMXN0IGNvbHVtbjoNCmBgYHtyfQ0KbWF0WywtMV0NCmBgYA0KbWF0IGlzbid0IHJlcGxhY2VkIGJ5IHRoZSBuZXcgbWF0cml4LiBXZSBoYXZlIHRvIGFzc2lnbiBpdCB0byBhIG5ldyBtYXRyaXggb3IgdGhlIG9sZCBvbmU6DQpgYGB7cn0NCm1hdA0KbWF0PC0gbWF0WywtMV0NCm1hdA0KYGBgDQpTaW1pbGFybHkgdG8gcmVtb3ZlIHRoZSAybmQgcm93LA0KYGBge3J9DQptYXRbLTIsXQ0KYGBgDQoNCiMjIERpYWdvbmFsDQoNClRvIGZpbmQgdGhlIGRpYWdvbmFsIGVsZW1lbnRzIG9mIGEgbWF0cml4Og0KYGBge3J9DQpkaWFnKGNtYXQpDQpgYGANCg0KVG8gY3JlYXRlIGEgZGlhZ29uYWwgbWF0cml4Og0KYGBge3J9DQpkaWFnKGMoMTIsMSw5OSkpDQpgYGANCg0KVG8gY3JlYXRlIGFuIGlkZW50aXR5IG1hdHJpeDoNCmBgYHtyfQ0KZGlhZygzKQ0KZGlhZyg1KQ0KYGBgDQoNCiMjIE1pbm9yIG9mIE1hdHJpeCANCg0KYGBge3J9DQoNCmBgYA0KDQoNCg0KDQojIyBUcmFuc3Bvc2UNCg0KTGV0J3MgY29uc3RydWN0IGEgbWF0cml4IG9mIG9yZGVyIDM6DQpgYGB7cn0NCm1hdDwtbWF0cml4KGMoMTo4LDk5KSwgbnJvdz0zLGJ5cm93PUYpDQptYXQNCmBgYA0KDQpUbyB0cmFuc3Bvc2UgaXQgc2ltcGx5IHVzZSBgdCgpYDoNCmBgYHtyfQ0KdChtYXQpDQpgYGANCg0KIyMgTWlub3IgDQoNCmBgYHtyfQ0KQSA8LSBtYXRyaXgoYyg0LCAyLCA3LCA4LCAwLCAyLCAzLCA5LCAxKSwgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSkNCkENCmBgYA0KDQpNaW5vciBvZiB0aGUgZWxlbWVudCBpbiAxc3Qgcm93IGFuZCAxc3QgY29sdW1uIC0gDQpgYGB7cn0NCmRldChBWy0xLC0xXSkNCmBgYA0KDQpNaW5vciBvZiB0aGUgZWxlbWVudCBpbiAzcmQgcm93IGFuZCAybmQgY29sdW1uIC0gDQpgYGB7cn0NCmRldChBWy0zLC0yXSkNCmBgYA0KDQpDcmVhdGluZyBmdW5jdGlvbiAtIA0KYGBge3J9DQptaW5vciA8LSBmdW5jdGlvbihBLCBpLCBqKSB7DQogIGRldChBWy1pLC1qXSkNCn0NCm1pbm9yKEEsIDMsIDIpDQpgYGANCg0KIyMgQ28tZmFjdG9yDQoNCkNvLWZhY3RvciBvZiB0aGUgZWxlbWVudCBpbiAxc3Qgcm93IGFuZCAybmQgY29sdW1uIC0gDQpgYGB7cn0NCigtMSleKDErMikqZGV0KEFbLTEsLTJdKQ0KYGBgDQoNCkluIG90aGVyIHdheSB1c2luZyB0aGUgbWlub3IoKSBmdW5jdGlvbiAtIA0KYGBge3J9DQooLTEpXigxKzIpKm1pbm9yKEEsIDEsIDIpDQpgYGANCg0KQ3JlYXRpbmcgYSBuZXcgZnVuY3Rpb24gLSANCmBgYHtyfQ0KY29mYWN0b3IgPC0gZnVuY3Rpb24oQSwgaSwgaikgKC0xKV4oaStqKSAqIG1pbm9yKEEsaSxqKQ0KY29mYWN0b3IoQSwgMSwgMikNCmBgYA0KDQojIyBBZGpvaW50IE1hdHJpeA0KDQpUbyBjYWxjdWxhdGUgdGhlIGFkam9pbnQgbWF0cml4IG9mIHRoZSBzcXVhcmUgbWF0cml4IEEgLSANCmBgYHtyfQ0KQQ0KYGBgDQoNClJlcXVpcmVkIHBvcnRpb24gb2YgY29kZSAtIA0KYGBge3J9DQp0KG91dGVyKDE6bnJvdyhBKSwgMTpucm93KEEpLA0KICAgICAgICBGVU4gPSBWZWN0b3JpemUoZnVuY3Rpb24oaSxqKSBjb2ZhY3RvcihBLGksaikpKSkNCmBgYA0KDQpDcmVhdGluZyBmdW5jdGlvbiAtIA0KYGBge3J9DQphZGpvaW50IDwtIGZ1bmN0aW9uKG1hdCkgew0KICB0KG91dGVyKDE6bnJvdyhtYXQpLCAxOm5yb3cobWF0KSwgDQogICAgICAgICAgRlVOID0gVmVjdG9yaXplKGZ1bmN0aW9uKGksaikgY29mYWN0b3IobWF0LGksaikpKSkNCn0NCmFkam9pbnQoQSkNCmBgYA0KDQpUaHVzIGludmVyc2Ugb2YgQSAtIA0KYGBge3J9DQphZGpvaW50KEEpL2RldChBKQ0KYGBgDQoNCk5vdGU6IGBWZWN0b3JpemUoKWAgdmV0b3JpemVzIGZ1bmN0aW9ucy4gRXhhbXBsZSAtIA0KYGBge3J9DQpzZGYgPC0gVmVjdG9yaXplKHJ1bmlmKSAgIyB2ZWN0b3JpemluZyBydW5pZg0Kc2V0LnNlZWQoMCkNCnNkZihuPWMoMTAsMTAsNSw2KSkgICANCmNhdCgiTm90IFZlY3Rvcml6ZWRcbiIpOyBydW5pZihuPWMoMTAsMTAsNSw2KSkgICAjIGRvZXNuJ3Qgc2hvdyB3aGF0IEkgd2FudA0KYGBgDQoNCk5vdGU6IGBvdXRlcigpYCBwZXJmb3JtcyBvdXRlciBwcm9kdWN0IG9uIGFycmF5cy4gRXhhbXBsZSAtIA0KYGBge3J9DQpvdXRlcigxOjMsIDQ6NykgICMgZGVmYXVsdCBmdW5jdGlvbiBwZXJmb3JtZWQgPSAiKiINCmBgYA0KDQoNCg0KIyMgSW52ZXJzZSBNYXRyaXgNCg0KVGhlIGZ1bmN0aW9uIGBzb2x2ZSgpYCBkb2VzIHRoZSB3b3JrIC0NCmBgYHtyfQ0KbWF0MjwtIHJiaW5kKGMoMSw1KSwNCiAgICAgICAgICAgICBjKDksNSkpDQptYXQyDQpzb2x2ZShtYXQyKQ0KYGBgDQoNCiMjIE11bHRpcGxpY2F0aW9uDQoNCiMjIyBTY2FsYXIgTXVsdGlwbGljYXRpb24NCg0KYGBge3J9DQptYXQyPC0gcmJpbmQoYygxLDUpLA0KICAgICAgICAgICAgIGMoOSw1KSkNCm1hdDIqMg0KbWF0Mio1DQpgYGANCg0KDQojIyMgTWF0cml4IE11bHRpcGxpY2F0aW9uDQoNCmAlKiVgIGlzIHVzZWQgZm9yIG1hdHJpeCBtdWx0aXBsaWNhdGlvbjoNCmBgYHtyfQ0KQTwtcmJpbmQoYygyLDEwKSwNCiAgICAgICAgIGMoNiwxKSkNCkElKiVBICMgbWF0cml4IG11bHRpcGxpY2F0aW9uDQpBJSolc29sdmUoQSkgIyBwcm9vZiBvZiBBKkFeKC0xKSA9IEkgDQpgYGANCg0KIyMgT3RoZXIgbWF0cml4IGFsZ2VicmENCmBgYHtyfQ0KQTwtcmJpbmQoYygyLDEwLDkpLA0KICAgICAgICAgYyg2LDEsNSkpDQpCPC1yYmluZChjKDEsNSwyKSwNCiAgICAgICAgIGMoMSwxLC00KSkNCkEtQiAgIyBTdWJ0cmFjdGlvbg0KQStCICAjIGFkZGl0aW9uDQpBL0IgICMgZGl2aXNpb24NCmBgYA0KDQojIyBSYW5rIG9mIE1hdHJpeA0KDQpVc2luZyB0aGUgYHFyKClgIGZ1bmN0aW9uIGZvciBRUiBEZWNvbXBvc2l0aW9uIG9mIGEgTWF0cml4IHJhbmsgb2YgYSBtYXRyaXggY2FuIGJlIG9idGFpbmVkIC0gDQpgYGB7cn0NClggPC0gbWF0cml4KGMoMSwgMywgOSwNCiAgICAgICAgICAgICAgMiwgNCwgMCwNCiAgICAgICAgICAgICAgMywgOSwgMjcpLCBuY29sID0gMywgYnlyb3cgPSBUKQ0KcXIoWCkkcmFuaw0KYGBgDQoNCg0KIyMgRWlnZW4gVmFsdWVzIGFuZCBFaWdlbiBWZWN0b3JzDQoNCkxldCdzIHNheSB3ZSBoYXZlIGEgbWF0cml4IGBYYCBvZiAzKjMgLSANCmBgYHtyfQ0KWSA8LSBtYXRyaXgoYyg0LCAxMCwgLTUsDQogICAgICAgICAgICAgIDEwLCAtOCwgMSwNCiAgICAgICAgICAgICAgMiwgOCwgLTMpLCBucm93ID0gMywgYnlyb3cgPSBUKQ0KWQ0KYGBgDQoNClRvIGdldCB0aGUgZWlnZW52YWx1ZXMgYW5kIGVpZ2VudmVjdG9ycyB1c2UgYGVpZ2VuKClgIC0NCmBgYHtyfQ0KZWlnIDwtIGVpZ2VuKFkpDQplaWcNCmBgYA0KDQpUbyBleHRyYWN0IHRoZSB2YWx1ZXMgLSANCmBgYHtyfQ0KZWlnJHZhbHVlcw0KYGBgDQoNClRvIGV4dHJhY3QgdGhlIGVpZ2VuIHZlY3RvcnMgLSANCmBgYHtyfQ0KZWlnJHZlY3RvcnMNCmBgYA0KDQojIyBEaWFnb25hbGl6YXRpb24NCg0KQSBzcXVhcmUgbWF0cml4ICRBJCB3aWxsIGJlIGNhbGxlZCBkaWFnb25hbGl6YWJsZSBpZiB0aGVyZSBleGlzdHMgYW4gaW52ZXJ0aWJsZSBtYXRyaXggJFAkIHN1Y2ggdGhhdCAkUF57LTF9QVAkIGlzIGRpYWdvbmFsLCB0aGVuIHRoZSBtYXRyaXggJFAkIGlzIHNhaWQgdG8gZGlhZ29uYWxpemUgbWF0cml4ICRBJC4NCg0KYGBge3J9DQpBID0gbWF0cml4KGMoMSw5LDQsMSksIG5yb3cgPSAyKQ0KQQ0KYGBgDQoNClRoZW4gdGhlIG1hdHJpeCAkUCQgdGhhdCBkaWFnb25hbGl6ZXMgJEEkIGNhbiBpcyB0aGUgbWF0cml4IHRoYXQgY29udGFpbnMgdGhlIGVpZ2VuIHZlY3RvcnMgLSANCmBgYHtyfQ0KUCA9IGVpZ2VuKEEpJHZlY3RvcnMNClAgICAgICAgDQpgYGANCg0KU28gdGhlIGRpYWdvbmFsaXplZCBtYXRyaXggd2lsbCBiZSAtIA0KYGBge3J9DQpkIDwtIHNvbHZlKFApICUqJSBBICUqJSBQDQpyb3VuZChkLCAyKQ0KYGBgDQoNCk5vdGljZSB0aGF0IHRoZSBkaWFnb25hbCBlbGVtZW50cyBhcmUgYWN0dWFsbHkgdGhlIGVpZ2VuIHZhbHVlcyAtDQpgYGB7cn0NCmVpZ2VuKEEpJHZhbHVlcw0KYGBgDQoNCg0KDQoNCg0KDQoNCg0K