How to make and sum up a matrix with upper diagonal direction without for-loop condition [The fastest way!]

2 views (last 30 days)
A = [1 7 13 0 0 0 0 0 ; 2 8 14 0 0 0 0 0; 3 9 15 0 0 0 0 0 ; 4 10 16 0 0 0 0 0; 5 11 17 0 0 0 0 0; 6 12 18 0 0 0 0 0];
A =
1 7 13 0 0 0 0 0
2 8 14 0 0 0 0 0
3 9 15 0 0 0 0 0
4 10 16 0 0 0 0 0
5 11 17 0 0 0 0 0
6 12 18 0 0 0 0 0
B = [1 7 13 0 0 0 0 0 ; 0 2 8 14 0 0 0 0; 0 0 3 9 15 0 0 0; 0 0 0 4 10 16 0 0; 0 0 0 0 5 11 17 0; 0 0 0 0 0 6 12 18];
B=
1 7 13 0 0 0 0 0
0 2 8 14 0 0 0 0
0 0 3 9 15 0 0 0
0 0 0 4 10 16 0 0
0 0 0 0 5 11 17 0
0 0 0 0 0 6 12 18
How to make the B matrix with the fastest way? After making the B matrix, I will column-wisely sum up the B matrix using "sum" function. This process should be fast due to I am going to do 100 times of this processing with the 100 by 300000 matrix.
Please help me out!

Accepted Answer

Patrik Ek
Patrik Ek on 1 Apr 2014
Edited: Patrik Ek on 1 Apr 2014
This is a fully vectorized operation. And it should be quite efficient. Requires making 2 matrices however.
a = [1 2 0 0;3 4 0 0;5 6 0 0]
vertind = mod(find(a)-1,size(a,1))+1;
aind = find(a);
b = aind+(vertind-1)*size(a,1);
z = zeros(size(a));
z(b) = a(aind)
thesum = sum(b)
The operation on a matrix of your size (100x300000) take 0.1 seconds per iteration (creation of a excluded) and the maximal memory consumption (a included) is ~twice the size of a. The catch is that this does not allow values to go from end to 1, but that can be fixed, by some thinking. The method is based on the way create matrix indice, so to say columnwise. so in a 4x3 matrix element (2,1) have index 5.
The solution is 9 times slower than the one supported by Dishant Arora, but that solution does not return the B matrix.

More Answers (3)

Dishant Arora
Dishant Arora on 1 Apr 2014
C = mat2cell(A, ones(1, size(A,1)), size(A,2));
ii = mat2cell(0:size(A,1)-1, 1, ones(1,size(A,1)))';
B = cellfun(@(x,y) circshift(x,[1,y]), C, ii, 'Un', 0);
B = cell2mat(B)

lvn
lvn on 1 Apr 2014
Here is one way, which avoids making the B matrix (it directly gives the sum you want, so should be faster on large matrices)
A = [1 7 13 0 0 0 0 0 ; 2 8 14 0 0 0 0 0; 3 9 15 0 0 0 0 0 ; 4 10 16 0 0 0 0 0; 5 11 17 0 0 0 0 0; 6 12 18 0 0 0 0 0];
B = [1 7 13 0 0 0 0 0 ; 0 2 8 14 0 0 0 0; 0 0 3 9 15 0 0 0; 0 0 0 4 10 16 0 0; 0 0 0 0 5 11 17 0; 0 0 0 0 0 6 12 18];
[nrrows,~]=size(A);
C=zeros(1,nrrows+2);
for r=1:nrrows+2
columncounter=max(0,r-nrrows);
for rowcounter=min(r,nrrows):-1:max(1,r-2)
columncounter=columncounter+1;
C(r)=C(r)+A(rowcounter,columncounter);
end
end
C
sum(B)
C =
1 9 24 27 30 33 29 18
ans =
1 9 24 27 30 33 29 18

Andrei Bobrov
Andrei Bobrov on 1 Apr 2014
Edited: Andrei Bobrov on 2 Apr 2014
[m,n] = size(A);
B = spdiags(A,0:n-1,m,n);
ADD other way
[m,n] = size(A);
B = zeros(size(A));
ii = reshape(find(A),m,[]);
B(bsxfun(@plus,ii,(0:n-size(ii,2))'*m)) = ii;
or
m = size(A);
n = 3;
[ii,jj] = ndgrid(1:m(1),1:n);
B = zeros(m);
B(sub2ind(m,ii,bsxfun(@plus,jj,(0:m(1)-1)'))) = A(1:m(1),1:n);
  2 Comments
HYUNCHUL
HYUNCHUL on 1 Apr 2014
Thank you for the correction. your code is really simple and good. However, computational time takes amount time when matrix is large...

Sign in to comment.

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!