Search code examples
matlabvectorizationcell-array

Broadcasted summing on cell arrays - MATLAB


Suppose I have a matrices C1,C2 as follows:

C1 = nx2 cell each cell is [5x5 double].

C2 = 1x1 cell contain a [5x5 double].

How to calculate C3 as:

C3{1,1} =  C1{1,1}+C2{1,1};
C3{1,2} =  C1{1,2}+C2{1,1};
          .
          .
C3{n,2} =  C1{n,2}+C2{1,1};

using cellfun or any other method without looping


Solution

  • A straightforward use of cellfun does exactly what you want:

    C3 = cellfun(@(x) x+C2{1,1},C1,'uniformoutput',false);
    

    This will essentially loop over each element of the cell array C1, and for each element apply the anonymous function @(x) x+C2{1,1}, i.e. each element will be added to C2{1,1}. The resulting elements are returned in a cell array of the same size as C1.


    For a few smaller test cases I compared this solution to that suggested by @Divakar. The result is not trivial, since both cellfun and cat (used in Divakar's solution) are (in)famously slow. I threw in a third version to check, in which I defined a temporary variable in my anonymous function:

    tmpvar=C2{1,1};
    C3a2=cellfun(@(x) x+tmpvar,C1,'uniformoutput',false);
    

    The rationale behind this is that accessing that single cell element should have some overhead, and I'm unsure whether the entire cell is pulled into the workspace of the anonymous function.

    I defined a separate function to test the three cases in order to let JIT do its job (but note that I'm using R2012b, a newer version could give quite different results, with the new execution engine and everything). I ran all three cases on the same random input (with a C2 cell array of size [1,1] and containing an array of the same size as C1{k,l}), choosing the shortest runtime from 10 attempts (based on tic/toc).

    1. 5x5 cell array of 10x10 matrices:
      • cellfun:                  0.000452 s
      • cellfun+tmpvar: 0.000287 s
      • bsxfun(cat):          0.002970 s
    2. 5x5 cell array of 100x100 matrices:
      • cellfun:                  0.000988 s
      • cellfun+tmpvar: 0.000963 s
      • bsxfun(cat):          0.004661 s
    3. 10x10 cell array of 5x5 matrices:
      • cellfun:                  0.001580 s
      • cellfun+tmpvar: 0.000945 s
      • bsxfun(cat):          0.011358 s
    4. 100x100 cell array of 5x5 matrices:
      • cellfun:                  0.108276 s
      • cellfun+tmpvar: 0.082675 s
      • bsxfun(cat):          1.132417 s

    Based on these small test cases I'm tempted to conclude that

    1. Using a temporary variable in the anonymous function given to cellfun can indeed count if the larger cell array is large, which makes sense (since then the function is evaluated a larger number of times).
    2. The bsxfun(cat)-based solution is a bit slower for small cell arrays, and much slower for larger cell arrays. I suspect that cat is to blame: it takes a lot for cat to put the extra dimension together. I could even imagine that using a loop with preallocation might outperform cat.
    3. It would be interesting to check the same for the new execution engine, and on much larger (n>1000) matrices and cell arrays.