3

I have a matrix like A and I want to calculate the sum of each diagonal of this matrix and show it in a vector like Y.

A=[1 2 3; 4 5 6; 7 8 9]

Y=[3 8 15 12 7]

I know the code

[sum(diag(y,2)),sum(diag(y,1)),sum(diag(y,0)),sum(diag (y,-1)),sum(diag (y,-2))]

but i want to write it as a function.

obchardon
  • 8,679
  • 1
  • 12
  • 26

3 Answers3

5

spdiags can do exactly what you want:

dsum = sum(spdiags(A))

You can reverse the vector with fliplr and create a function:

function dsum = diagsum(A)
    dsum = fliplr(sum(spdiags(A)));
end

RESULT

dsum =

    3    8   15   12    7
Stewie Griffin
  • 14,159
  • 11
  • 36
  • 66
obchardon
  • 8,679
  • 1
  • 12
  • 26
3

Here is a possible solution:

[r ,c]=size(A);
idx=bsxfun(@plus,(r:-1:1)',0:c-1);
s=flipud(accumarray(idx(:),A(:)));

Comparing this with spdiags that proposed in other answer this method performs much much better in Octave. Benchmark:

A = rand(1000);
disp('---------bsxfun+accumarray----------')
tic
    [r ,c]=size(A);
    idx=bsxfun(@plus,(r:-1:1)',0:c-1);
    s=flipud(accumarray(idx(:),A(:)));
toc
disp('---------spdiags----------')
tic
    dsum = fliplr(sum(spdiags(A)));
toc

Result:

---------bsxfun+accumarray----------
Elapsed time is 0.0114651 seconds.
---------spdiags----------
Elapsed time is 8.62041 seconds.
rahnema1
  • 14,144
  • 2
  • 12
  • 26
  • 2
    since matlab R2016b, you can now remove the use of `bsxfun` and directly use `(r:-1:1)' + (0:c-1)` :) ! – TwistedSim Jul 24 '18 at 14:06
  • @TwistedSim But as of 2018 [some seasoned](https://stackoverflow.com/questions/51060328/how-to-sum-parts-of-a-matrix-of-different-sizes-without-using-for-loops/51060619#comment89111415_51060619) MATLAB users prefer `bsxfun` over implicit expansion! :) – rahnema1 Jul 24 '18 at 20:08
  • When you come from a numpy background, it still make more sense to use broadcasting ;). And I now realize that I'm not the first one to say that... oopsidoopsi – TwistedSim Jul 25 '18 at 13:31
1

Similar to the answer from rahnema1, you can also generate your indices using toeplitz before applying accumarray:

[r, c] = size(A);
index = toeplitz(c:(r+c-1), c:-1:1);
Y = accumarray(index(:), A(:)).';
gnovice
  • 123,396
  • 14
  • 248
  • 352