Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cellfun versus Simple Matlab Loop performance

When I started working with matlab sometime ago in the university, my supervisor would kill me if he saw any unnecessary for loop (he would ask for exchanging it for kron or any type of indexes manipulation as possible). Later on, I was trying to avoid as much as possible any loop on matlab, searching for the darkest matlab coding ways to do black magic instead of a simple loop.

And one day I discovered the cellfun, which made the black magic quite simplier, I could change many loops working with cells and cellfun combo, but one day I saw one post about cellfun which made me question if my inherited matlab knowledge was true, that is: that matlab loops would always be slower than one builtin compiled function, which was something I had so much faith. I tested it in one of my implementations and in fact, the for loop would be faster! I was like, OMG, all those days doing obscure code wasted for nothing hahaha. Since that day, I stopped working that hard to try to optimize matlab code, normally it depends for each case and so on.

Today I saw this answer, which remembered my effort for avoiding as much matlab loops as possible (I don't know if that was the author will to avoid for performance, but anyway it reminded all this matlab loop performance thing). And one question came to my mind: Is cellfun better than for loops? When would that be true?

like image 490
Werner Avatar asked Aug 17 '13 00:08

Werner


People also ask

Is Cellfun faster than for loop Matlab?

For the example Tom gave, however, cellfun with string is much faster than a for loop (in answer to the original question). Elapsed time is 0.755874 seconds. Elapsed time is 0.913470 seconds. Elapsed time is 0.021828 seconds.

Is Arrayfun faster than for loop Matlab?

For example, I tested arrayfun vs a forloop, squaring the elements, and the speed difference was a factor of two. While this is concrete evidence that we should always use for loops instead of arrayfun, it's obvious that the benefit varies.

Is Arrayfun faster?

arrayfun can be significantly slower than an explicit loop in matlab.


2 Answers

If performance is a major factor you should avoid using cells, loops or cellfun/arrayfun. It's usually much quicker to use a vector operation (assuming this is possible).

The code below expands on Werner's add example with standard array loop and array operations.

The results are:

  • Cell Loop Time - 0.1679
  • Cellfun Time - 2.9973
  • Loop Array Time - 0.0465
  • Array Time - 0.0019

Code:

nTimes = 1000;
nValues = 1000;
myCell = repmat({0},1,nValues);
output = zeros(1,nValues);

% Basic operation
tic;
for k=1:nTimes
  for m=1:nValues
    output(m) = myCell{m} + 1;
  end
end
cell_loop_timeAdd=toc;    
fprintf(1,'Cell Loop Time %0.4f\n', cell_loop_timeAdd);

tic;        
for k=1:nTimes
  output = cellfun(@(in) in+1,myCell);
end
cellfun_timeAdd=toc;
fprintf(1,'Cellfun Time %0.4f\n', cellfun_timeAdd);


myData = repmat(0,1,nValues);
tic;
for k=1:nTimes
  for m=1:nValues
    output(m) = myData(m) + 1;
  end
end
loop_timeAdd=toc;
fprintf(1,'Loop Array Time %0.4f\n', loop_timeAdd);

tic;
for k=1:nTimes
    output = myData + 1;
end
array_timeAdd=toc;
fprintf(1,'Array Time %0.4f\n', array_timeAdd);
like image 147
grantnz Avatar answered Oct 21 '22 02:10

grantnz


I will add one answer with the results that I tested myself, but I would be glad if people contribute with their knowledge, this is just a simple test I've made.

I've tested the following conditions with cell size of 1000 and 1000 loops (results on total time, and I would probably have to run more than 1000 times, because I am having a little fluctuation on the results, but anyway, this is not a scientific article):

  • Basic operation (sum)
    • Simple for loop: 0.2663 s
    • cellfun: 9.4612 s
  • String Operation (strcmp)
    • Simple for loop: 1.3124 s
    • cellfun: 11.8099 s
  • Built-in (isempty)
    • Simple for loop: 8.9042 s
    • cellfun (string input -> see this reference): 0.0105 s
    • cellfun (fcn handle input -> see this reference): 0.9209 s
  • Non-uniform (regexp)
    • Simple for loop: 24.2157 s
    • cellfun (string input): 44.0424 s

So, it seems that cellfun with anonymous function calls are slower than a simple for loop, but if you will use a builtin matlab method, do it with cellfun and use it with the string quotation. This is not necessarily true for all cases, but at least for the tested functions.

The implemented test code (I am far from being an optimization specialist, so here is the code in case I did something wrong):

function ...
  [loop_timeAdd,cellfun_timeAdd,...
  loop_timeStr,cellfun_timeStr,...
  loop_timeBuiltIn,cellfun_timeBuiltInStrInput,...
  cellfun_timeBuiltyInFcnHandle,...
  loop_timeNonUniform,cellfun_timeNonUniform] ...
  = test_cellfun(nTimes,nCells)

myCell = repmat({0},1,nCells);
output = zeros(1,nCells);

% Basic operation
tic;
for k=1:nTimes
  for m=1:nCells
    output(m) = myCell{m} + 1;
  end
end
loop_timeAdd=toc;

tic;
for k=1:nTimes
  output = cellfun(@(in) in+1,myCell);
end
cellfun_timeAdd=toc;

% String operation
myCell = repmat({'matchStr'},1,nCells); % Add str that matches
myCell(1:2:end) = {'dontMatchStr'}; % Add another str that doesnt match
output = zeros(1,nCells);

tic;
for k=1:nTimes
  for m=1:nCells
    output(m) = strcmp(myCell{m},'matchStr');
  end
end
loop_timeStr=toc;

tic;
for k=1:nTimes
  output = cellfun(@(in) strcmp(in,'matchStr'),myCell);
end
cellfun_timeStr=toc;

% Builtin function (isempty)
myCell = cell(1,nCells); % Empty
myCell(1:2:end) = {0}; % not empty
output = zeros(1,nCells);

tic;
for k=1:nTimes
  for m=1:nCells
    output(m) = isempty(myCell{m});
  end
end
loop_timeBuiltIn=toc;

tic;
for k=1:nTimes
  output = cellfun(@isempty,myCell);
end
cellfun_timeBuiltyInFcnHandle=toc;

tic;
for k=1:nTimes
  output = cellfun('isempty',myCell);
end
cellfun_timeBuiltInStrInput=toc;

% Builtin function (isempty)
myCell = repmat({'John'},1,nCells);
myCell(1:2:end) = {'Doe'};
output = cell(1,nCells);

tic;
for k=1:nTimes
  for m=1:nCells
    output{m} = regexp(myCell{m},'John','match');
  end
end
loop_timeNonUniform=toc;

tic;
for k=1:nTimes
  output = cellfun(@(in) regexp(in,'John','match'),myCell,...
    'UniformOutput',false);
end
cellfun_timeNonUniform=toc;
like image 43
Werner Avatar answered Oct 21 '22 03:10

Werner