I have a matrix with diagonals equal to zero and off-diagonals all equal to one (the inverse of an identity matrix):
mat1 <- matrix(c(0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0), 5, 5)
I also have a vector that is always the same length as the dims of the matrix and always starts at zero:
vec1 <- c(0,1,2,3,4)
using these two objects I want to create a matrix that looks like this:
mat2 <- matrix(c(0,1,2,3,4,1,0,1,2,3,2,1,0,1,2,3,2,1,0,1,4,3,2,1,0), 5, 5)
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 2 3 4
[2,] 1 0 1 2 3
[3,] 2 1 0 1 2
[4,] 3 2 1 0 1
[5,] 4 3 2 1 0
I want an operation that will generalize so that if I have a matrix of dims 9 by 9, for example, and a vector of 0:8 I can achieve the equivalent result. Any ideas for how to approach this?
As vec1 starts with a zero, then you can do :
MakeMatrix <- function(x){
n <- length(x)
id <- abs(rep(1:n,n)-rep(1:n,each=n)) + 1
matrix(x[id],ncol=n)
}
MakeMatrix(vec1)
So there's no need to take the mat1 in the input, as that one is actually redundant. You can just construct the matrix within the function.
The trick is in providing a sequence of id values to select from the vector, and then transform everything to a matrix.
Edit : If you're only going to use sequences, you could as well do :
MakeMatrix <- function(n){
id <- abs(rep(1:n,n)-rep(1:n,each=n))
matrix(id,ncol=n)
}
MakeMatrix(7)
The following solution makes use of upper.tri
and lower.tri
to isolate the upper and lower triangular matrix. In addition, it makes use of sequence
to create the desired vector sequence.
n <- 9
vec <- (1:n)-1
m <- matrix(0, n, n)
m[lower.tri(m, diag=TRUE)] <- vec[sequence(n:1)] #### Edit
m <- t(m)
m[lower.tri(m, diag=TRUE)] <- vec[sequence(n:1)] #### Edit
m
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 0 1 2 3 4 5 6 7 8
[2,] 1 0 1 2 3 4 5 6 7
[3,] 2 1 0 1 2 3 4 5 6
[4,] 3 2 1 0 1 2 3 4 5
[5,] 4 3 2 1 0 1 2 3 4
[6,] 5 4 3 2 1 0 1 2 3
[7,] 6 5 4 3 2 1 0 1 2
[8,] 7 6 5 4 3 2 1 0 1
[9,] 8 7 6 5 4 3 2 1 0
How about:
genMat <- function(n){
mat <- outer(1:n,1:n,"-")%%n
tmp <- mat[lower.tri(mat)]
mat <- t(mat)
mat[lower.tri(mat)] <- tmp
mat
}
> genMat(5)
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 2 3 4
[2,] 1 0 1 2 3
[3,] 2 1 0 1 2
[4,] 3 2 1 0 1
[5,] 4 3 2 1 0
Edit
For arbitrary vec1
:
genMat2 <- function(vec){
n <- length(vec)
mat <- outer(1:n,1:n,"-")%%n
tmp <- mat[lower.tri(mat)]
mat <- t(mat)
mat[lower.tri(mat)] <- tmp
matrix(vec[mat+1],n,n)
}
> genMat2(c(0,2,4,3,9))
[,1] [,2] [,3] [,4] [,5]
[1,] 0 2 4 3 9
[2,] 2 0 2 4 3
[3,] 4 2 0 2 4
[4,] 3 4 2 0 2
[5,] 9 3 4 2 0
Edit 2
In fact, there's no need to use the modulus and then play with the matrix, abs
will work fine to make the original matrix definition a 1-liner:
abs(outer(1:n,1:n,"-"))
So,
genMat <- function(n){
abs(outer(1:n,1:n,"-"))
}
and
genMat2 <- function(vec){
n <- length(vec)
matrix(vec[abs(outer(1:n,1:n,"-"))+1],n,n)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With