3

Not sure how to explain it so here it goes as an example:

A=[1 0 0 1 4 4 4 4
   0 0 0 0 2 3 2 2
   0 0 0 0 0 0 0 1
   2 3 4 5 2 3 4 1 ]

result:

b=[ 1 1 13 12
    5 9 5  6];

Each of the elements is computed by adding a N size submatrix inside the original, in this case N=2.

so b(1,1) is A(1,1)+A(1,2)+A(2,1)+A(2,2), and b(1,4) is A(1,7)+A(2,7)+A(1,8)+A(2,8).

Visually and more clearly:

A=[|1 0| 0 1| 4 4| 4 4|
   |0 0| 0 0| 2 3| 2 2|
   ____________________
   |0 0| 0 0| 0 0| 0 1|
   |2 3| 4 5| 2 3| 4 1| ]

b is the sum of the elements on those squares, in this example of size 2.

I can imagine how to make it with loops, but its just feels vectorizable. Any ideas of how it could be done?

Assume that the matrix A has sizes that are multipliers of N.

rayryeng
  • 102,964
  • 22
  • 184
  • 193
Ander Biguri
  • 35,140
  • 11
  • 74
  • 120

3 Answers3

4

Method 1:

Using mat2cell and cellfun

n = 2;
AC = mat2cell(A,repmat(n,size(A,1)/n,1),repmat(n,size(A,2)/n,1));
out = cellfun(@(x) sum(x(:)), AC)

Method 2:

Using permute and reshape

n = 2;
[rows,cols] = size(A);
out = reshape(sum(sum(permute(reshape(A,n,rows/n,n,[]),[1 3 2 4]))),rows/n,[]);

PS: Here is a close question related to this one, which you might find useful. That question is to find mean while this one is to find sum.

Community
  • 1
  • 1
Santhan Salai
  • 3,888
  • 19
  • 29
4

If you have the Image processing toolbox blockproc could be an option as well:

B = blockproc(A,[2 2],@(x) sum(x.data(:)))
Robert Seifert
  • 25,078
  • 11
  • 68
  • 113
  • 2
    @AnderBiguri - Agreed. In fact this is the way I would have done it if this wasn't taken lol. – rayryeng Jun 10 '15 at 20:37
  • 1
    @AnderBiguri Agree with you. It looks elegant with one-liner. but if you see this [benchmarking](http://stackoverflow.com/a/30263964/2111163) from divakar for the other answer, `blockproc` is always the slowest. If efficiency is not a criteria for you, this one is the way to go :) – Santhan Salai Jun 11 '15 at 01:55
  • 1
    @SanthanSalai - Always code for readability first. When you're confident and comfortable, then you can start changing for efficiency... and that's only if you can accurately measure it. I would have started with this first... then eventually migrated to one of my answers. All part of the process! – rayryeng Jun 11 '15 at 03:12
  • 2
    @SanthanSalai I agree with rayryeng here. First readability and then efficiency. Especially for a SO answer, I feel like this one makes more sense to future matrix reducers – Ander Biguri Jun 11 '15 at 07:30
4

Here are two alternative methods:

Method #1 - im2col

Another method using the image processing toolbox is to use im2col with the distinct flag and sum over all of the resulting columns. You would then need to reshape the matrix back to the right size:

n = 2;
B = im2col(A, [n n], 'distinct');
C = reshape(sum(B, 1), size(A,1)/n, size(A,2)/n);

We get for C:

>> C

C =

     1     1    13    12
     5     9     5     6

Method #2 - accumarray and kron

We can generate an index matrix with kron which we can use as bins into accumarray and invoke sum as the custom function. We would again have to reshape the matrix back to the right size:

n = 2;
M = reshape(1:prod([size(A,1)/n, size(A,2)/n]), size(A,1)/n, size(A,2)/n);
ind = kron(M, ones(n));
C = reshape(accumarray(ind(:), A(:), [], @sum), size(A,1)/n, size(A,2)/n);

Again we get for C:

C =

     1     1    13    12
     5     9     5     6
rayryeng
  • 102,964
  • 22
  • 184
  • 193