3
votes

I'm looking for a (build-in) function, which efficiently returns the list of building blocks of a block-diagonal matrix in the following way (rather than iterating over the slots to get the list manually):

#construct bdiag-matrix
library("Matrix")
listElems <- list(matrix(1:4,ncol=2,nrow=2),matrix(5:8,ncol=2,nrow=2))
mat <- bdiag(listElems)

#get back the list
res <- theFunctionImLookingFor(mat)

The result res yields the building blocks:

[[1]]
      [,1] [,2]
[1,]    1    3
[2,]    2    4

[[2]]
      [,1] [,2]
[1,]    5    7
[2,]    6    8

Edit: Regarding my use case, the list elements in listElems are square and symmetric matrices. If the block is a diagonal matrix, theFunctionImLookingFor should return a list element for each diagonal element.

However, the function should be able to deal with building block matrices like

       [,1] [,2] [,3]
[1,]    1    1    0
[2,]    1    1    1
[3,]    0    1    1

or

       [,1] [,2] [,3]
[1,]    1    0    1
[2,]    0    1    1
[3,]    1    1    1

i.e. deal with zeros in blocks, which are not diagonal matrices.

1
You should be able to use mat@i for this. However, although my brain's pattern recognition is able to identify the blocks from something like [1] 0 1 0 1 2 3 4 2 3 4 2 3 4 5 (this is for a little bit more complex example) easily, I can't find a good algorithm right now.Roland
What about theFunctionImLookingFor <- list? It always return one block... We need more details for this to be a well-posed problem.flodel
@flodel They are looking for the inverse function of bdiag.Roland
I understand and I maintain my argument. mat can be broken into many blocks, in what way is the one the OP chose special apart from the fact they are those that were used to build mat (that info is lost, isn't it?).flodel
@flodel To me this is a very well posed problem. They want to extract the blocks from a block-diagonal sparse matrix.Roland

1 Answers

4
votes

I hope this will work for all your cases, the test at the bottom includes a block that contains zeroes.

theFunctionImLookingFor <- function(mat, plot.graph = FALSE) {
   stopifnot(nrow(mat) == ncol(mat))
   x <- mat
   diag(x) <- 1
   edges <- as.matrix(summary(x)[c("i", "j")])
   library(igraph)
   g <- graph.edgelist(edges, directed = FALSE)
   if (plot.graph) plot(g)
   groups <- unique(Map(sort, neighborhood(g, nrow(mat))))
   sub.Mat <- Map(`[`, list(mat), groups, groups, drop = FALSE)
   sub.mat <- Map(as.matrix, sub.Mat)
   return(sub.mat)
}

listElems <- list(matrix(1:4,ncol=2,nrow=2),
                  matrix(5:8,ncol=2,nrow=2),
                  matrix(c(0, 1, 0, 0, 0, 1, 0, 0, 1),ncol=3,nrow=3),
                  matrix(1:1,ncol=1, nrow=1))

mat <- bdiag(listElems)

theFunctionImLookingFor(mat, plot.graph = TRUE)
# [[1]]
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

# [[2]]
#      [,1] [,2]
# [1,]    5    7
# [2,]    6    8

# [[3]]
#      [,1] [,2] [,3]
# [1,]    0    0    0
# [2,]    1    0    0
# [3,]    0    1    1

# [[4]]
#      [,1]
# [1,]    1

enter image description here