Calculating diagonal elements of a matrix product without a loop or redundant calculations

23 views (last 30 days)
I have a problem wich invovles calculating the product of the ith row of a matrix, say F, and another matrix, say B, and then multiplying again by the ith row of F as a column (for each row of F). Basically, something like this:
A = [];
for i = 1:length(F)
A(i) = F(i,:)*B*F(i,:)';
end
This code works, but it is not ideal because it uses a loop rather than Matlab's native interpreted language. The following code also achieves the same result:
A = diag(F*B*F');
The problem here is that it is calculating all the elements of F*B*F', and then only selecting the diagonal elements (which is all I ultimately want). So this is also extremely inefficient (especially for larger matrices F and B) because there are many redundant calculations.
Is there a way to get this result without using loops or redundant calculations, for example, using element-wise algebra (i.e. using the ".*" operator)? I tried F*B.*F' but this does not give the same result.
Thanks.
  1 Comment
Daniel Shub
Daniel Shub on 11 Mar 2012
One can no longer simply say that loops are slow in MATLAB. A lot of improvements have happened in the past 10(?) years. Even the concept of preallocate or die is less rigid (although I would preallocate your A here instead of initializing it to empty).

Sign in to comment.

Accepted Answer

Oleg Komarov
Oleg Komarov on 11 Mar 2012
% Example inputs
F = rand(10);
B = rand(10);
out1 = sum(F*B.*F,2); % Elementwise
out2 = diag(F*B*F');
isequal(out1,out2)
However I don't see an improvement in the timing, it could actually be the case that diag(F*B*F') doesn't calculate all the cross products.

More Answers (1)

Earl
Earl on 11 Mar 2012
Thanks for the reply Oleg. Yes, I think this is the answer I am after, although I'm not entirely sure what the sum() function is doing here.
And you are right about the timing - there does not appear to be any significant difference:
F = rand(1000);
B = rand(1000);
tic; out1 = sum(F*B.*F,2); toc; % Elementwise
tic; out2 = diag(F*B*F'); toc;
I get a difference of about 0.03 seconds. However, I'm fairly sure Matlab does actually compute the off-diagonals because:
F = rand(1000);
B = rand(1000);
tic; out2 = diag(F*B*F'); toc;
tic; out2a = F*B*F'; out2b = diag(out2a); toc;
gives almost the same computation time. This is a little puzzling because I would have thought the redundant calculations to be of the order n squared where n is the dimensions of F*B*F'. But apparently it makes little difference.
Thanks again for the insight.
  3 Comments
Jan
Jan on 12 Mar 2012
I get this under Win7/Matlab 2009a/64:
tic; out1 = sum(F*B.*F,2); toc;
>> Elapsed time is 0.165536 seconds.
tic; out2 = diag(F*B*F'); toc;
>> Elapsed time is 0.288225 seconds.
Oleg Komarov
Oleg Komarov on 12 Mar 2012
Average on 100 iterations and size 1000x1000, Win7 R2012a 64bit:
out1 = sum(F*B.*F,2): 0.04818
out2 = diag(F*B*F') : 0.08834

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!