5

So I've been wondering about this for a while now. Summing up over some array variable A is as easy as

sum(A(:))
% or
sum(...sum(sum(A,n),n-2)...,1) % where n is the dimension of A

However once it gets to expressions the (:) doesn't work anymore, like

sum((A-2*A)(:))

is no valid matlab syntax, instead we need to write

foo = A-2*A;
sum(foo(:))
%or the one liner
sum(sum(...sum(A-2*A,n)...,2),1) % n is the dimension of A

The one liner above will only work, if the dimension of A is fixed which, depending on what you are doing, may not necessary be the case. The downside of the two lines is, that foo will be kept in memory until you run clear foo or may not even be possible depending on the size of A and what else is in your workspace.

Is there a general way to circumvent this issue and sum up all elements of an array valued expression in a single line / without creating temporal variables? Something like sum(A-2*A,'-all')?

Edit: It differes from How can I index a MATLAB array returned by a function without first assigning it to a local variable?, as it doesn't concern general (nor specific) indexing of array valued expressions or return values, but rather the summation over each possible index.

While it is possible to solve my problem with the answer given in the link, gnovice says himself that using subref is a rather ugly solution. Further Andras Deak posted a much cleaner way of doing this in the comments below.

Community
  • 1
  • 1
  • 1
    Why are you so eager on avoiding the temporary variable? It does hardly matter in terms of speed and also none in terms of RAM (the same variable would be created in the `sum` call anyway). I'd say `sum(sum())` could be faster, since reshaping large matrices takes a lot of time. – Adriaan Dec 01 '15 at 13:20
  • 1
    @Daniel I believe there is a simple answer to this question which does not concern the duplicate: `sum(reshape(A-2*A,1,[]))`. Please reopen if you agree so that I may answer. – Andras Deak -- Слава Україні Dec 01 '15 at 13:25
  • @AndrasDeak Both versions work, but yours looks a lot cleaner then using `subref`. Is it worth to reopen a question in this case? (I am unsure about the proper code of conduct here.) –  Dec 01 '15 at 13:35
  • FirefoxMetzger honestly it's up to @Daniel. I would say that your question is more specific than the duplicate, and so a simpler and more specific answer is applicable. The answers on the dupe question are much too general and convoluted. Question is: would other people benefit from this question? (I would say, possible). Note that your question is also valid in the form "*Sum up every element of return value from function*", which is a wider problem. – Andras Deak -- Слава Україні Dec 01 '15 at 13:37
  • @Adriaan. Reshaping large matrices using `(:)` should take virtually no time as long as the matrix is not written to. MATLAB uses lazy evaluation. Just reshaping without modifying the data means making a copy of the (tiny) internal header and changing a couple of values in it. – Mad Physicist Dec 01 '15 at 14:26
  • @MadPhysicist I was actually referring to Andras's suggestion with the actual function `reshape`, which is comparably slow. I've both experienced this and seen it pop up quite often on SO questions, and `reshape` was usually the slowest of the possibilities. – Adriaan Dec 01 '15 at 14:28
  • 1
    What about `sum(A(:) - 2*A(:))` ? – Jeff Irwin Dec 01 '15 at 14:28
  • @JeffIrwin. Whooooaaaa. Mind-blowingly simple. – Mad Physicist Dec 01 '15 at 14:31
  • @MadPhysicist It works for this simple case, but you might have to resort to nested `sum`s for more complicated cases with matrix multiplication. – Jeff Irwin Dec 01 '15 at 14:33
  • 1
    @JeffIrwin you can also say `-sum(A(:))` at that. I think this is just a dummy example. Consider the case of `fun(A)` which returns a multi-dimensional array with unknown number of dimensions... – Andras Deak -- Слава Україні Dec 01 '15 at 14:33

1 Answers1

10

While the answers to the linked duplicate can indeed be applied to your problem, the narrower scope of your question allows us to give a much simpler solution than the answers provided there.

You can sum all the elements in an expression (including the return value of a function) by reshaping your array first to 1d:

sum(reshape(A-2*A,1,[]))
%or even sum(reshape(magic(3),1,[]))

This will reshape your array-valued expression to size [1, N] where N is inferred from the size of the array, i.e. numel(A-2*A) (but the above syntax of reshape will compute the missing dimension for you, no need to evaluate your expression twice). Then a single call to sum will sum all the elements, as needed.

The actual case where you have to resort to something like this is when a function returns an array with an unknown number of dimensions, and you want to use its sum in an anonymous function (making temporary variables unavailable):

fun = @() rand(2*ones(1,randi(10))); %function returning random 2 x 2 x ... x 2 array with randi(10) dimensions
sumfun = @(A) sum(reshape(A,1,[]));
sumfun(fun()) %use it
Community
  • 1
  • 1