Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have several SparseArray objects, say sa11, sa12, sa21, sa22, which I would like to combine into the equivalent of {{sa11, sa12}, {sa21, sa22}}. As an example, I have :

sa11 = SparseArray[Band[{1, 1}, {4, 4 3}] -> {{ConstantArray[1, 3]}}] 
sa12 = SparseArray[Join[Band[{1, #}, {4, 4 3}] -> 1 & /@ Range[1,  4 3, 4]]]
sa21 = SparseArray[Join[Band[{1, #}, {3, 4 3}] -> 1 & /@ Range[1, 4 3, 3]]] 
sa22 = SparseArray[Band[{1, 1}, {3, 4 3}] -> {{ConstantArray[1, 4]}}] 

I am able to generate the big SparseArray with :

sa = SparseArray[Join[{Band[{1, 1}, {4, 4 3}] -> {{ConstantArray[1, 3]}}}, Band[{1,     #},{4, 2 4 3}] -> 1 & /@ Range[4 3 + 1, 2  4 3, 4], Band[{4 + 1, #}, {4 + 3, 4 3}] -> 1 & /@ Range[1, 4 3, 3], {Band[{4 + 1, 4 3 + 1}, {4 + 3, 2 4 3}] -> {{ConstantArray[1, 4]}}}], {4 + 3, 2 4 3}]

Is there an efficient way to achieve this in general ?

share|improve this question

3 Answers 3

up vote 13 down vote accepted

ArrayFlatten[{{sa11, sa12}, {sa21, sa22}}] seems to be what you need. It automatically merges everything into one big SparseArray[].

share|improve this answer
    
+1 for this insightful answer :) –  acl Jan 19 '12 at 14:38
    
ohhh, there goes my checkmark! –  acl Jan 19 '12 at 16:07

How about ArrayFlatten (docs):

sa2 = ArrayFlatten[{{sa11, sa12}, {sa21, sa22}}]
sa==sa2
(*
True
*)
share|improve this answer
    
Thanks, I didn't know ArrayFlatten worked on SparseArray[] too. –  b.gatessucks Jan 19 '12 at 14:37
    
I see I was only 18 seconds ahead of you. I upvoted your fine answer as well. :) –  J. M. Jan 19 '12 at 14:40

In addition to the answers given (ArrayFlatten), there may be cases when the SparseArray-s need to be accumulated one-by-one, and keeping them all in memory at the same time may be too expensive. I've written a generic function to gradually accumulate SparseArray-s. Here is the code:

This is the low-level API for SparseArray construction / deconstruction, explained in details here (where the code slightly differs):

ClearAll[spart, getIC, getJR, getSparseData, getDefaultElement, 
  makeSparseArray];
HoldPattern[spart[SparseArray[s___], p_]] := {s}[[p]];
getIC[s_SparseArray] := spart[s, 4][[2, 1]];
getJR[s_SparseArray] := spart[s, 4][[2, 2]];
getSparseData[s_SparseArray] := spart[s, 4][[3]];
getDefaultElement[s_SparseArray] := spart[s, 3];
makeSparseArray[dims_List, jc_List, ir_List, data_List, defElem_: 0] :=
     SparseArray @@ {Automatic, dims, defElem, {1, {jc, ir}, data}};

This is the function itself. It accepts the code which is supposed to generate the next piece, wrapped in Hold.

Clear[accumulateSparseArray];
accumulateSparseArray[Hold[getDataChunkCode_]] :=
  Module[{start, ic, jr, sparseData, dims, dataChunk},
   start = getDataChunkCode;
   ic = getIC[start];
   jr = getJR[start];
   sparseData = getSparseData[start];
   dims = Dimensions[start];
   While[True, 
     dataChunk = getDataChunkCode;
     If[dataChunk === {}, Break[]];
     ic = Join[ic, Rest@getIC[dataChunk] + Last@ic];
     jr = Join[jr, getJR[dataChunk]];
     sparseData = Join[sparseData, getSparseData[dataChunk]];
     dims[[1]] += First[Dimensions[dataChunk]];
  ];
  makeSparseArray[dims, ic, jr, sparseData]];

Based on this function, it is not difficult to write a function that will do what you need:

Clear[sparseArrayFlatten]
sparseArrayFlatten[m_?(MatrixQ[#, MatchQ[#, _SparseArray] &] &)] :=
 Module[{joinRow, code},
   joinRow[row_List] :=
     Module[{i = 1},
        With[{l = Append[row, {{}}]}, code := l[[i++]]];
        accumulateSparseArray[Hold[Transpose[code]]]
     ];
   joinRow[joinRow /@ m]]

Now:

In[109]:= 
sparseArrayFlatten[{{sa11,sa12},{sa21,sa22}}]==ArrayFlatten[{{sa11,sa12},{sa21,sa22}}]
Out[109]= True

Note that my solution will only pay off if you do have a situation with a huge number of SparseArray-s, which you would like to process lazily (or, which are created one by one). One of situations when this happens is during the data transfer, as explained in my post here. I was also able to significantly improve efficiency by using this technique for efficient initialization of a certain sparse array, in my answer to this question. I consider this to be a rather general technique.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.