I'm struggling with the following problem. I have $48$ square matrices (full, filled with real machine precision numbers, thus are packed, all different) of size $128$. I wolud like to place them on a diagonal of sparse array of dimension $48\times 128=6144$. The method(1)
SparseArray @ ArrayFlatten @ ReleaseHold @ DiagonalMatrix[Hold /@ matrices]
(* matrices is a list of 48 matices 128 x 128,
e.g. matrices = RandomReal[{}, {128, 128}] & /@ Range[48] *)
is too slow (it takes ~6s on my laptop). I'm suspecting that the problem is with the ArrayFlatten
function, since this produces huge matrix $6144\times 6144$ filled moslty with zeros (in some sense it unpacks sparse array). Is there any way to do the same but much faster (more efficient)? In a fraction of a second (I'm optimistic)? I've looked at "SparseArray`"
context but without much success (SparseArray`VectorToDiagonalSparseArray
seems to be equivalent to DiagonalMatrix
so accepts only vectiors/lists). (Specific numbers given here are just for tests, in the end I would like to increase size of my problem, but then it of course gets even worse.)
After posting this question I've found the code on MathWorld which gives me the result in ~3.63s. Code by ybeltukov SparseArray[Band@{1, 1} -> matrices]
is even faster (~2.48s) but still far from being ideal.
Update: I've checked that asymptotically execution time scales as (based on AbsoluteTiming
):
- $m^{2}n^{2}$ for
BlockDiagonalMatrix
- $m^{2}n^{1}$ for recent version of
blockArray
by ybeltukov
where: $n$ is a number of matrices/blocks and $m$ is a size of a single matix/block.
SparseArray[Band@{1, 1} -> matrices]
is 2 times faster. However, I think it can be improved further. $\endgroup$