2

Apologies if this is a relatively basic question - I'm still a bit new to programming, and particularly Matlab. Essentially I want to create 4940x1 column vector where each term is equal to the sum of a 4940x4940 square matrix's corresponding row. So far, easy enough.

However, I would like each row to have a series of terms deleted from the sum, specifically the first 26 terms of the row for the first 26 rows, the 2nd 26 terms (i.e. terms 27-52) for the 2nd row, etc etc until you get to the 190th set of 26 terms (i.e. 4940,4915:4940) for the last 26 rows. I'm not sure if I'm explaining this well, so perhaps best illustrated with a magic 4 matrix :

A =

    16     3     2    13;

     5    10    11     8;

     9     6     7    12;

     4    15    14     1

In addition to calculating the sum of each row, I would like to subtract 1,1:2 (i.e. 34-16-3) from row 1, 2,1:2 from row 2 (i.e. 34-5-10), 3,3:4 from row 3 (i.e. 34-7-12) and 4,3:4 from row 4 (34-14-1).

Grateful for any help here!

Divakar
  • 218,885
  • 19
  • 262
  • 358

3 Answers3

1

bsxfun based summing and reshaping approach -

sublen = 26; %// subset length
nrows = size(A,1); %// number of rows in input matrix
nsubs = nrows/sublen; %// number of subsets

idx1 = bsxfun(@plus,[1:sublen]',[0:sublen-1]*nrows);%//'# starting block indices
idx2 = bsxfun(@plus,idx1(:),[0:nsubs-1]*(nrows*sublen+sublen));%// all block indices
exclude_sum = sum(A(reshape(idx2,sublen,sublen,[])),2); %// block elements summed 
                            %// (these would be subtracted from the wholesome sum)
out = sum(A,2) - exclude_sum(:); %// desired output

This approach seems to be 6-7x faster than an improved version of the other kron based approach.

Here are the runtimes - https://ideone.com/vZRRfe

Divakar
  • 218,885
  • 19
  • 262
  • 358
1

For the sum removing some elements, you can easily create a mask (with blkdiag) to indicate which elements are zeroed:

%// Total sum:
s1 = sum(A, 2);

%// Sum removing elements:
m = size(A, 1);
n = 26;
c = repmat({true(26)}, m/n, 1);
s2 = sum(A.* ~blkdiag(c{:}), 2)
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
0

Multiply the matrix elementwise with the following matrix:

M = 1-kron(eye(4940/26),ones(26));

In this way, you multiply the elements that you do not want to count with 0 and the others with 1.

You can now just sum the result as you did before: sum(.,2).

For the magic example, you get M =

 0     0     1     1
 0     0     1     1
 1     1     0     0
 1     1     0     0

and A .* M =

 0     0     2    13
 0     0    11     8
 9     6     0     0
 4    15     0     0

and sum(A.*M, 2) =

15
19
15
19

I updated the answer, taking the first comment of Divakar into consideration. Concerning the speed, see the additional comments below.

MeMyselfAndI
  • 1,320
  • 7
  • 12
  • `M = 1 - kron(eye(4940/26),ones(26))` would be correct I think. – Divakar Oct 10 '14 at 17:42
  • Also, a faster approach could be with logical indexing rather than elementwise mulltiplication - `A(kron(eye(4940/26),ones(26))==1)=0; result = sum(A,2);`. – Divakar Oct 10 '14 at 17:47
  • You might be right, I dont have MATLAB here so I cant check. Even faster would be A(~kron(..,..)) I guess. – MeMyselfAndI Oct 10 '14 at 18:01
  • 1
    Funny thing is I posted about this - [`Is A==0 really better than ~A?`](http://stackoverflow.com/questions/25339215/is-a-0-really-better-than-a) and I would guestimate `A==1` to be faster too. One could also try out `A~=0`. – Divakar Oct 10 '14 at 18:04