Home > Net >  How to create non-square block diagonal matrices?
How to create non-square block diagonal matrices?

Time:12-11

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 
  • Related