summing over a multi-dimensional cartesian product using nested arrayfun commands

10 visualizaciones (últimos 30 días)
I have an anonymous function with multiple arguments and I want to sum over all of them. For example, consider the simple function
U = @(i,j) i+j;
I = 1:3; J = 1:3;
The command
sumJ = @(I,J) sum(arrayfun(@(j)sum(U(I,j)),J)
will sum over all pairs in the cartesian product IxJ
I'd like to do the analogous thing for
V = @(i,j,k) i + j + k
I realize that there are many other ways of doing this simple summation, it's just an easy example. For my more complex problem, I believe I would need to use nested arrayfun commands, but can't figure out how to do this. Thanks very much for any help.

Respuesta aceptada

Guillaume
Guillaume el 23 de Nov. de 2015
Editada: Guillaume el 23 de Nov. de 2015
If I understood correctly, it may be simpler to ndgrid your arrays and have a single arrayfun
V = @(i,j,k,l) i*j/k+l; %demo function
I = 1:10; J = 1:20; K = 2:5; L = 3:7; %demo arrays
[II, JJ, KK, LL] = ndgrid(I, J, K, L);
sumall = sum(arrayfun(V, II(:), JJ(:), KK(:), LL(:)))
The downside of this method is that if your arrays are big enough, you're going to need a lot of memory for the ndgrid output.
A completely generic version of the above which works for n input arrays stored in a cell array:
fun = @(i,j,k,l) i*j/k+l; %some function with |n| input arguments.
arrays = {1:10, 1:20, 2:5, 3:7}; %|n| input arrays stored in cell array
griddedarrays = cell(size(arrays)); %variable to receive output of ndgrid
[griddedarrays{:}] = ndgrid(arrays{:});
griddedarrays = cellfun(@(m) reshape(m, [], 1), griddedarrays, 'UniformOutput', false);
sumall = sum(arrayfun(fun, griddedarrays{:}));
PS: It's a shame bsxfun is limited to two inputs as it would avoid the ndgrid entirely.

Más respuestas (1)

Stephen23
Stephen23 el 23 de Nov. de 2015
Editada: Stephen23 el 23 de Nov. de 2015
Maybe this can help:
U = @(m,n)m+n;
V = @(M,n)sum(arrayfun(@(m)U(m,n),M));
W = @(M,N)sum(arrayfun(@(n)V(M,n),N));
A = 1:3;
B = 1:3;
W(A,B)
But note that loops are often faster than arrayfun or cellfun. And even faster would be to consider using bsxfun instead of arrayfun or a loop:
X = bsxfun(@plus,A,B(:));
sum(X(:))
  4 comentarios
Leo Simon
Leo Simon el 24 de Nov. de 2015
Thanks Steven, could you please explain the role of N(:) in the definition of V, I tried replacing it with N, i.e.,
V = @(M,N,o)sum(sum(bsxfun(@(m,n)U(m,n,o),M,N)));
keeping the definitions of U and W the same, and then
W(1:3,1:3,1:4)
returned 78, not 234. So obviously, both definitions are legal, but do different things. Thanks for your patience! Leo
Guillaume
Guillaume el 24 de Nov. de 2015
The purpose of N(:) is simply to transpose N. It is the same as N.'.
In Stephen's answer bsxfun is used to apply your function to the cartesian product of the vectors. Hence one vector needs to be along one dimension, the other vector along another. bsxfun is equivalent to repmat'ing each vector along the dimension of the other (without needing the memory for the repmat'ed matrix). My answer's basically does this repmat'ing explicitly, using ndgrid.
That's why I said it was a shame that bsxfun is limited to two inputs. An hypothetical bsxfun that allowed a arbitrary number of inputs would have allowed you to write:
W = bsxfun(V, I, J', permute(K, [3 2 1]), permute(L, [4 3 2 1]);
sumall = sum(W:));

Iniciar sesión para comentar.

Categorías

Más información sobre Matrices and Arrays en Help Center y File Exchange.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by