In my program in matlab I have several instances where I need to create a matrix, which entries depends on its indices and perform matrix-vector operations with it. I wonder how I can implement this most efficiently.
For example, I need to speed up:
N = 1e4;
x = rand(N,1);
% Option 1
tic
I = 1:N;
J = 1:N;
S = zeros(N,N);
for i = 1:N
for j = 1:N
S(i,j) = (i+j)/(abs(i-j)+1);
end
end
a = x'*S*x
fprintf('Option 1 takes %.4f sec\n',toc)
clearvars -except x N
I try to speed this up, so I have tried the following options:
% Option 2
tic
I = 1:N;
J = 1:N;
Sx = zeros(N,1);
for i = 1:N
Srow_i = (i+J)./(abs(i-J)+1);
Sx(i)= Srow_i*x;
end
a = x'*Sx
fprintf('Option 2 takes %.4f sec\n',toc)
clearvars -except x N
and
% Option 3
tic
I = 1:N;
J = 1:N;
S = bsxfun(@plus,I',J)./(abs(bsxfun(@minus,I',J))+1);
a = x'*S*x
fprintf('Option 3 takes %.4f sec\n',toc)
clearvars -except x N
and (thanks to one of the answers)
% options 4
tic
[I , J] = meshgrid(1:N,1:N);
S = (I+J) ./ (abs(I-J) + 1);
a = x' * S * x;
fprintf('Option 4 takes %.4f sec\n',toc)
clearvars -except x N
Otion 2 is the most efficient. Is there a faster option of doing this operation?
Update:
I have also tried the option by Abhinav:
% Option 5 using Tony's Trick
tic
i = 1:N;
j = (1:N)';
I = i(ones(N,1),:);
J = j(:,ones(N,1));
S = (I+J)./(abs(I-J)+1);
a = x'*S*x;
fprintf('Option 5 takes %.4f sec\n',toc)
clearvars -except x N
It seems that the most efficient procedure depends on the size of N. For different N I get the following output:
N = 100:
Option 1 takes 0.00233 sec
Option 2 takes 0.00276 sec
Option 3 takes 0.00183 sec
Option 4 takes 0.00145 sec
Option 5 takes 0.00185 sec
N = 10000:
Option 1 takes 3.29824 sec
Option 2 takes 0.41597 sec
Option 3 takes 0.72224 sec
Option 4 takes 1.23450 sec
Option 5 takes 1.27717 sec
So, for small N, option 2 is the slowest but it becomes the most efficient for larger N. Maybe because of memory? Could somebody explain this?