I want to expedite my code and, therefore, I am trying to avoid for
loop. Also, I want to use the fact that the inverse of BD matrices is the inverse of each block. I am just trying to create a BD matrix.
Consider the following r
code
x = matrix(1:12, 4)
# Now, I want each of the repeated x to be in a block diagonal matrix
# The final result should look like the following
res = matrix(c(1,2,0,0,
5,6,0,0,
9,10,0,0,
0,0,3,4,
0,0,7,8,
0,0,11,12), ncol = 6)
I was suggested using the split
function, but it seems that it drops a row and messes up the elements' order.
I can create a sparse identity matrix and extract each block then combine them together; however, the main goal is to expedite my code performance. Thus, a one-shot built-in optimized function is preferred.
The example I put here is for a square matrix, yet what I am dealing with is usually the number of rows is much larger than the number of columns.
CodePudding user response:
We can use bdiag from Matrix. Note that the Matrix package comes with R and does not have to be installed, just loaded with a library
statement. Try any of these:
library(Matrix)
# 1
as.matrix(bdiag(x[1:2,], x[3:4, ]))
# 2
as.matrix(bdiag(lapply(split(as.data.frame(x), rep(1:2, each = 2)), as.matrix)))
# 3
x |>
as.data.frame() |>
split(rep(1:2, each = 2)) |>
lapply(as.matrix) |>
bdiag() |>
as.matrix()
CodePudding user response:
Successively setting a part of the matrix to zero and cbind
.
Map(\(x, y) {m[-(x*y), ] <- 0; m}, list(1:(nrow(m)/2)), c(1, -1)) |> do.call(what=cbind)
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 1 5 9 0 0 0
# [2,] 2 6 10 0 0 0
# [3,] 0 0 0 3 7 11
# [4,] 0 0 0 4 8 12