问题
In Matlab, is there a way to copy lower triangular half of a matrix to upper triangular half?
For a square matrix A, I want to be able to do
triu(A)=tril(A)';
in order to set all A(i,j)
as A(j,i)
for i > j.
Is there a convenient/efficient way to do this?
Note: Preferably, the answer can apply to sparse matrices.
On the topic of efficiency,
I did some testing regarding the relative time cost for accessing part of a matrix. I used version R2014a
Some results: logical indexing is painfully slow and should be avoided; logical indexing with sparse matrices is worse; addition involving dense matrices under sparse matrix environment is torturous, and should be avoided at all cost.
So far the data suggests that tril(A,-1)+tril(A)'
is likely the best method.
(Looping has not been tried. But it is likely at least as slow as logical indexing.)
% Note: In each case, the posted results are those after a few "warm up" trials.
% providing the arrays
>> e=ones(1000,1);
>> temp=[e,zeros(1000,999)];
>> A=magic(1000);
>> temp2=[true(1000,1),false(1000,999)];
% matrix addition (without sparse matrix support)
>> tic;for i=1:1000; A=A+temp; A=A-temp; end; toc
Elapsed time is 1.903718 seconds.
>> tic;for i=1:1000; A=A+temp; A=A-temp; end; toc
Elapsed time is 1.898125 seconds.
>> tic;for i=1:1000; A=A+temp; A=A-temp; end; toc
Elapsed time is 1.896766 seconds.
% logical indexing to modify part of a matrix by a smaller matrix (a column vector)
>> tic;for i=1:1000; A(temp2)=A(temp2)+e; A(temp2)=A(temp2)-e; end; toc
Elapsed time is 4.916888 seconds.
>> tic;for i=1:1000; A(temp2)=A(temp2)+e; A(temp2)=A(temp2)-e; end; toc
Elapsed time is 4.926484 seconds.
>> tic;for i=1:1000; A(temp2)=A(temp2)+e; A(temp2)=A(temp2)-e; end; toc
Elapsed time is 4.929350 seconds.
% logical indexing to modify part of a matrix by a scalar
>> tic;for i=1:1000; A(temp2)=A(temp2)+1; A(temp2)=A(temp2)-1; end; toc
Elapsed time is 4.914185 seconds.
>> tic;for i=1:1000; A(temp2)=A(temp2)+1; A(temp2)=A(temp2)-1; end; toc
Elapsed time is 4.909323 seconds.
>> tic;for i=1:1000; A(temp2)=A(temp2)+1; A(temp2)=A(temp2)-1; end; toc
Elapsed time is 4.905367 seconds.
>> tic;for i=1:1000; A(temp2)=1; A(temp2)=-1; end; toc
Elapsed time is 2.472018 seconds.
>> tic;for i=1:1000; A(temp2)=1; A(temp2)=-1; end; toc
Elapsed time is 2.463884 seconds.
>> tic;for i=1:1000; A(temp2)=1; A(temp2)=-1; end; toc
Elapsed time is 2.462588 seconds.
% matrix addition with sparse matrix support (astounding?)
>> A=sparse(A); temp3=sparse(temp2);
>> tic;for i=1:1000; A=A+temp3; A=A-temp3; end; toc
Elapsed time is 13.648472 seconds.
>> tic;for i=1:1000; A=A+temp3; A=A-temp3; end; toc
Elapsed time is 13.485242 seconds.
>> tic;for i=1:1000; A=A+temp3; A=A-temp3; end; toc
Elapsed time is 13.551307 seconds.
% matrix addition with sparse matrix support between matrices with identical sparsity structure
>> tic;for i=1:1000; temp3=temp3+temp3; temp3=temp3-temp3; end; toc
Elapsed time is 0.013174 seconds.
>> tic;for i=1:1000; temp3=temp3+temp3; temp3=temp3-temp3; end; toc
Elapsed time is 0.018456 seconds.
>> tic;for i=1:1000; temp3=temp3+temp3; temp3=temp3-temp3; end; toc
Elapsed time is 0.009555 seconds.
% matrix addition with sparsity support between two very sparse matrix of completely different sparsity structure
>> temp4=sparse([zeros(1000,999),ones(1000,1)]);
>> tic;for i=1:1000; temp4=temp4+temp3; temp4=temp4-temp3; end; toc
Elapsed time is 0.019596 seconds.
>> tic;for i=1:1000; temp4=temp4+temp3; temp4=temp4-temp3; end; toc
Elapsed time is 0.014397 seconds.
>> tic;for i=1:1000; temp4=temp4+temp3; temp4=temp4-temp3; end; toc
Elapsed time is 0.010127 seconds.
>> tic;for i=1:1000; temp4=temp4+temp3; temp4=temp4-temp3; end; toc
% logical indexing with very sparse matrix
>> tic;for i=1:1000; temp4(temp2)=1; temp4(temp2)=-1; end; toc
Elapsed time is 6.333907 seconds.
>> tic;for i=1:1000; temp4(temp2)=1; temp4(temp2)=-1; end; toc
Elapsed time is 6.378107 seconds.
>> tic;for i=1:1000; temp4(temp2)=1; temp4(temp2)=-1; end; toc
Elapsed time is 6.486917 seconds.
% cost for creating logical arrays
>> tic;temp2=[true(10000,1),false(10000,9999)];toc
Elapsed time is 0.060349 seconds.
>> tic;temp2=[true(10000,1),false(10000,9999)];toc
Elapsed time is 0.063874 seconds.
>> tic;temp2=[true(10000,1),false(10000,9999)];toc
Elapsed time is 0.060837 seconds.
回答1:
You can try tril(A,-1)+tril(A)'
.
>> A = rand(3);
A =
0.2277 0.9234 0.9049
0.4357 0.4302 0.9797
0.3111 0.1848 0.4389
>> tril(A,-1)+tril(A)'
ans =
0.2277 0.4357 0.3111
0.4357 0.4302 0.1848
0.3111 0.1848 0.4389
Also:
A(triu(true(3),1)) = A(tril(true(3),-1))
There's probably another variation too...
回答2:
This could be one approach with bsxfun to use logical indexing
to set upper triangular elements same as the lower ones -
%// Get size of square-sized input array
N = size(A,1);
%// Create lower triangular mask
mask = bsxfun(@gt,[1:N]',[1:N]) %//'
%// Replace transposed masked (upper triangular) elements with lower ones
A(mask.') = A(mask)
In terms of variable creation, there is an additional logical array mask
being created and with function call, there is additional bsxfun
being added.
Sample run -
A =
0.39223 0.70605 0.046171
0.65548 0.031833 0.097132
0.17119 0.27692 0.82346
mask =
0 0 0
1 0 0
1 1 0
A =
0.39223 0.65548 0.17119
0.65548 0.031833 0.27692
0.17119 0.27692 0.82346
For performance numbers related to comparing tril/triu
and bsxfun
based equivalent mask creation, Benchmarks comparing BSXFUN and TRIU could be referred to as well.
来源:https://stackoverflow.com/questions/31644737/in-matlab-is-there-a-way-to-copy-lower-triangular-half-of-a-matrix-to-upper-tri