summing over a multi-dimensional cartesian product using nested arrayfun commands
10 次查看(过去 30 天)
显示 更早的评论
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.
0 个评论
采纳的回答
Guillaume
2015-11-23
编辑:Guillaume
2015-11-23
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.
0 个评论
更多回答(1 个)
Stephen23
2015-11-23
编辑:Stephen23
2015-11-23
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 个评论
Guillaume
2015-11-24
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:));
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Matrices and Arrays 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!