summing over a multi-dimensional cartesian product using nested arrayfun commands
조회 수: 9 (최근 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!