10

Using cellfun, how do I apply a function to all the cells created by the mat2cell function? My function is defined in another file, here it is referred to by myFunc. This function takes two arguments, which should be a cell and an integer.

e.g. function H = myFunc(img,Q)

My code is as follows:

% Split into grid and process each cell
width = size(img,2) % get image width
height = size(img,1) % get image height
depth = size(img,3) % get depth
C = mat2cell(img,[height/2 height/2],[width/2 width/2],[depth/2 depth/2]); % divides image into sections
F = cellfun(@myFunc,C);
save(fout,'F');

The issue is of course with the line F = cellfun(@myFunc,C);. How do I pass the cells and a chosen integer e.g. 4 into myFunc for each cell?

Many thanks.

Divakar
  • 218,885
  • 19
  • 262
  • 358
petehallw
  • 1,014
  • 6
  • 21
  • 49

3 Answers3

14

Well, simply define a new anonymous function as @(x) myFunc(x,4) and use it this way:

F = cellfun(@(x) myFunc(x,4), C)
knedlsepp
  • 6,065
  • 3
  • 20
  • 41
5

By using an anonymous function:

F = cellfun(@(Q) myFunc(Q,4),C);
Christopher Creutzig
  • 8,656
  • 35
  • 45
1

Recently came across this problem, and noticed that while Octave has implicit cell expansion of parameters in cellfun, Matlab doesn't. Calling an anonymous function has more overhead than calling the function directly (although Matlab is not nearly as bad as Octave in that regard) so I found passing the parameter as a cell array to be a bit faster, shown here with a simple example:

abc = {magic(2), magic(3), magic(4)}
abc =
  3×1 cell array
    {2×2 double}
    {3×3 double}
    {4×4 double}
    
def = cellfun (@(x) sum(x,2), abc, "UniformOutput", false) %anonymous function method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 

expanding the parameter into a cell array and passing it as another input produces the same correct output:

def = cellfun (@sum, abc, num2cell(2*ones(size(abc))), "UniformOutput", false) % cell expansion method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 
    

a quick tic/toc check shows this to be a bit faster in Matlab 2021a:

tic; 
for idx = 1:100000
  cellfun(@(x) sum(x,2), abc,"UniformOutput",false); 
end
toc
Elapsed time is 4.017116 seconds.

tic, 
for idx = 1:100000
  cellfun(@sum, abc, num2cell(2*ones(size(abc))),"UniformOutput",false);
end
toc
Elapsed time is 1.217712 seconds

I haven't tried this with non-simple parameters, but repmat could do the same for, say, string inputs, but repmat seems to add quite a bit back to the overhead:

tic
for idx = 1:100000
    cellfun(@sum, abc, repmat({2}, size(abc)),"UniformOutput",false); 
end
toc
Elapsed time is 4.367002 seconds.

So perhaps there's a better way to expand those. Take note that this is a very simple test case with a small array, and that this time savings may not hold true as things scale up, or as you add multiple parameters. Also, you are multiplying the memory requirement for each parameter you do this with, as each is expanded to the size of the input array.

A quick test shows the same time savings hold true with a custom myfunc as with a matlab function like sum.

Nick J
  • 1,310
  • 12
  • 25
  • 1
    On my machine (and with a slightly larger `abc` of 9 small arrays), the second variant is ~3x faster than the first, but a simple loop is ~4x faster again. So if you really care about speed, don't use `cellfun`. `cellfun` is meant for shorter code, not speed. I also find the simple loop easier to read, so I tend to avoid `cellfun`. My solution: `res = cell(size(abc)); for ii = 1:numel(abc), res{ii} = sum(abc{ii},2); end`. – Cris Luengo Nov 10 '21 at 20:40
  • 1
    thanks time added. honestly i use Octave most of the time, and there loops are still slow. There the num2cell version is only 10-15% faster than the anonymous function. Octave lets you just put {2} in for second cell array and it implicitly expands, that is about 2x as fast as the anonymous function. Your loop runs about 10% slower than the anonymous function over there. One day maybe they'll get a JIT compiler working. :) – Nick J Nov 11 '21 at 23:49
  • Interesting. In MATLAB, `cellfun` is implemented as an M-file (or rather, it was the last time I checked, but it's quite some years ago), so `cellfun` always adds the overhead of a function call (with all the parameter checking), and the overhead of repeatedly calling a function through a handle, and so it just cannot be faster than spelling out the loop. I guess in Octave it is not implemented as an M-file. – Cris Luengo Nov 12 '21 at 00:08
  • ">> which cellfun" "'cellfun' is a built-in function from the file libinterp/corefcn/cellfun.cc" so it seems you are correct – Nick J Nov 13 '21 at 03:02