Search code examples
rmatrixindexingsparse-matrix

Fast replacement for off-diagonal blocks in sparse matrix


I have a sparse quadratic diagonal matrix H of dimension (K*M) x (K*M). The goal is to replace the lower off-diagonal blocks of the matrix with a known quadratic matrix A with size K x K:

# dimensions of the final matrix are (K*M) x (K*M)
K        = 5
M        = 3

# initiate the matrix as diagonal
H        = Matrix::Diagonal(K*M)

# convert because off-diagonal replacement does not work for sparse diagonal class
H        = as(H, "dgCMatrix")

# matrix that will replace the lower off-diagonal blocks of size K x K
A        = matrix(runif(K^2), K, K)

The following method uses an auxiliary vector that indexes the off-diagonal blocks of appropriate size and loops over each block:

# construct vector that is used to index the lower off-diagonal blocks of size K x K
indices   = seq(1, K * (1 + M), K)

# replace all M - 1 lower off-diagonal blocks
for(ii in 1:(M-1)){
  
  H[indices[ii + 1]:(indices[ii + 2]-1), indices[ii]:(indices[ii + 1]-1)] = A

}

Unfortunately, indexing and replacing these blocks becomes extremely slow when the dimensionality of the matrix grows. Are there faster methods available that would work reasonably well in settings with, say, K=8000 and M=20 ? It does not necessarily need to be within the Matrix package setting as long as the result can be back-converted to a Matrix class.


Solution

  • The Kronecker product of a sparse banded matrix and the dense block should be "fast", but you'll want to do your own benchmarks ...

    library(Matrix)
    set.seed(0)
    K <- 5L
    M <- 3L
    
    (X <- bandSparse(M, M, -1L, list(rep.int(1, M - 1L))))
    ## 3 x 3 sparse Matrix of class "dtCMatrix"
    ##           
    ## [1,] . . .
    ## [2,] 1 . .
    ## [3,] . 1 .
    
    (Y <- matrix(round(runif(K * K), 2L), K, K))
    ##      [,1] [,2] [,3] [,4] [,5]
    ## [1,] 0.90 0.20 0.06 0.77 0.78
    ## [2,] 0.27 0.90 0.21 0.50 0.93
    ## [3,] 0.37 0.94 0.18 0.72 0.21
    ## [4,] 0.57 0.66 0.69 0.99 0.65
    ## [5,] 0.91 0.63 0.38 0.38 0.13
    
    XY <- kronecker(X, Y)
    diag(XY) <- 1
    XY
    ## 15 x 15 sparse Matrix of class "dgCMatrix"
    ##                                                                  
    ##  [1,] 1.00 .    .    .    .    .    .    .    .    .    . . . . .
    ##  [2,] .    1.00 .    .    .    .    .    .    .    .    . . . . .
    ##  [3,] .    .    1.00 .    .    .    .    .    .    .    . . . . .
    ##  [4,] .    .    .    1.00 .    .    .    .    .    .    . . . . .
    ##  [5,] .    .    .    .    1.00 .    .    .    .    .    . . . . .
    ##  [6,] 0.90 0.20 0.06 0.77 0.78 1.00 .    .    .    .    . . . . .
    ##  [7,] 0.27 0.90 0.21 0.50 0.93 .    1.00 .    .    .    . . . . .
    ##  [8,] 0.37 0.94 0.18 0.72 0.21 .    .    1.00 .    .    . . . . .
    ##  [9,] 0.57 0.66 0.69 0.99 0.65 .    .    .    1.00 .    . . . . .
    ## [10,] 0.91 0.63 0.38 0.38 0.13 .    .    .    .    1.00 . . . . .
    ## [11,] .    .    .    .    .    0.90 0.20 0.06 0.77 0.78 1 . . . .
    ## [12,] .    .    .    .    .    0.27 0.90 0.21 0.50 0.93 . 1 . . .
    ## [13,] .    .    .    .    .    0.37 0.94 0.18 0.72 0.21 . . 1 . .
    ## [14,] .    .    .    .    .    0.57 0.66 0.69 0.99 0.65 . . . 1 .
    ## [15,] .    .    .    .    .    0.91 0.63 0.38 0.38 0.13 . . . . 1