cellfunc vs cell2mat speed?

David Bateman dbateman at dbateman.org
Tue Sep 9 16:53:50 CDT 2008


Levente Torok wrote:
> Hi David,
>
> On Tuesday 09 September 2008, David Bateman wrote:
>   
>> Levente Torok wrote:
>>     
>>> Hi David and others
>>>
>>> This is small speed test:
>>>
>>> function t = test( s )
>>>
>>>     t = time;
>>>     c=cell( s, 1 );
>>>     r = rand( 8, 1 );
>>>     c{:,1} = r;
>>>     cc = cell2mat( c );
>>>     t = time - t;
>>>
>>> end
>>>
>>> octave:4> test( 1000 )
>>> ans =  0.27966
>>> octave:5> test( 10000 )
>>> ans =  12.347
>>> octave:6> test( 13000 )
>>> ans =  26.865
>>> octave:3> test( 16000 )
>>> ans =  47.761
>>> octave:4> test( 19000 )
>>> ans =  83.082
>>>
>>>
>>> As it seems, each adding of 3000 elements doubles the time it needs to convert cell to matrix.
>>> I believe the slowness is due to the recursive scripting nature of the cell2mat.m function.
>>> I thought I will write a small conversion program in C with limited capabilities for my own needs 
>>> ( ie. only c{i,1} =matrix will be handled ) but I am so much confused with the interface of the 
>>> Cell class.
>>>
>>>
>>> ( NB: if I replace cell2mat with cellfun( c, "mean" ) I would get:
>>> octave:10> test( 20000 )
>>> ans =  8.0793
>>> and this increases linearly with size of the cell array)
>>> Thank you very much in advance,
>>>
>>> Levente
>>>
>>>
>>>
>>>
>>>   
>>>       
>> The code that handles this is essentially
>>
>>  t = cputime; cc = cat(1, c{:}); cputime - t
>>     
> I replaced it. This is just a little bit better now:
>
> octave:2> test( 10000 )
> ans =  9.3086
> octave:3> test( 13000 )
> ans =  20.437
> octave:4> test( 16000 )
> ans =  39.590
> The trend is the same.
>
>   
>> There are two issues with the above. The first is that the cat function 
>> is called with an enormously large number of arguments and the second is 
>> that the cat function, unlikely [], doesn't make any specializations for 
>> the same class of data in the concatenation. Compare the above with
>>
>> t = cputime; cc = [c{:}]; cputime - t;
>>     
>
> octave:7> test( 40000 )
> ans =  0.30402
>
> This is extremely fast however it does not do the thing I want since it concatenates the
> columns rowwise rather than columnwise. ie.
> c=cell(2,1)
> c{1} = [ 1;2 ; 3];
> c{2} = [ 4;2 ; 3];
> octave:12> [c{:}]
> ans =
>
>    1   4
>    2   2
>    3   3
>
> It wouldn't be the problem if I wouldn't need to handle vectors of different sizes, hence I cannot use
> reshape to it. Isn't there such a simple expression to do column wise concatenation?
>
>   
Yes something like

function c = mycell2mat (c)
  k = 1;
  while (numel (c) > 1)
    n = rows (c);
    if (n == 1)
      if (ndims (c) == 2)
    c = reshape (c, [numel(c), 1]);
      else
    c = reshape (c, size(c)(2:end));
      endif
    else
      sz = size (c)(2 : end);
      if (isscalar (sz))
    c1 = cell ([sz, 1]);
      else
    c1 = cell (sz);
    sz = prod (sz);
      endif
      if (k == 2)
    for i = 1 : sz
      c1{i} = [c{(i - 1) * n + (1 : n)}];
    endfor
      else
    ## This is faster than
    ##   for i = 1:sz, c1{i} = cat (k, c{(i - 1) * n + (1 : n)}); endfor
    idx = 1 : ndims(c);
    idx(k) = idx (2);
    idx(2) = k;
    c = cellfun(@(x) permute (x, idx), c, "UniformOutput", false);
    for i = 1:sz
      c1{i} = ipermute ([c{(i - 1) * n + (1 : n)}], idx);
    endfor
      endif
      c = c1;
    endif
    k++;
  endwhile
  c = [c{:}];
endfunction


is generic. Though the case of "k=1" could be vastly accelerated if 
there existed a transpose opertaor of a cs-list that created a 
semi-colon separated list. I don't think it exists, so maybe the above 
is the best we can do without reworking the "cat" function to make the 
same speedups as the "[]" code.

D.




More information about the Help-octave mailing list