【问题标题】:In Matlab, is there a way to copy lower triangular half of a matrix to upper triangular half?在 Matlab 中,有没有办法将矩阵的下三角半部分复制到上三角半部分?
【发布时间】:2015-07-27 03:55:13
【问题描述】:

在Matlab中,有没有办法将矩阵的下三角部分复制到上三角部分?

对于一个方阵A,我希望能够做到

triu(A)=tril(A)';

为了将所有A(i,j) 设置为A(j,i) for i > j。

有没有方便/有效的方法来做到这一点?

注意:答案最好适用于稀疏矩阵。


关于效率的话题,

我对访问部分矩阵的相对时间成本进行了一些测试。我用的是R2014a版本

一些结果:逻辑索引非常慢,应该避免;稀疏矩阵的逻辑索引更差;在稀疏矩阵环境下涉及稠密矩阵的加法是曲折的,应该不惜一切代价避免。

到目前为止,数据表明tril(A,-1)+tril(A)' 可能是最好的方法。 (循环没有尝试过。但它可能至少和逻辑索引一样慢。)

% 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.

【问题讨论】:

    标签: matlab matrix sparse-matrix


    【解决方案1】:

    你可以试试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
    

    还有:

    A(triu(true(3),1)) = A(tril(true(3),-1))
    

    可能还有另一种变化......

    【讨论】:

    • 不错的答案。对于A=tril(A,-1)+tril(A)',是否会创建另一个 A 副本(已完成一半)?对于大型矩阵,即使它很稀疏,创建额外的副本也可能会出现问题。对于A(triu(true(3),1)) = A(tril(true(3),-1)),这似乎是在修改 A 本身。但是创建tril(true(n),1) 会很昂贵吗?例如,如果 A(3,1)=0,A(triu(true(3),1)) = A(tril(true(3),-1)) 会改变A(3,1) 的稀疏度吗?非常感谢!
    • @Argyll 这两点似乎都有效。我正在尝试用 Matlab 中的稀疏矩阵想出一种更好的方法。
    • @Argyll 矩阵有什么特殊结构吗?它非常稀疏吗?使用 for 循环可能会更好。我会尝试变化并为它们计时。
    • 在这个特殊的时刻,我正在研究一个由 9 点 2D 模板产生的块状三对角矩阵。所以,是的,非常稀疏
    【解决方案2】:

    这可能是bsxfun 使用logical indexing 将上三角元素设置为与下三角元素相同的一种方法-

    %// 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)
    

    在变量创建方面,会创建一个额外的逻辑数组mask,并通过函数调用,添加额外的bsxfun。

    示例运行 -

    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
    

    对于与比较基于tril/triu 和bsxfun 的等效掩码创建相关的性能数据,也可以参考Benchmarks comparing BSXFUN and TRIU。

    【讨论】:

    • 还有稀疏矩阵的 cmets 吗?
    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 2012-12-11
    • 2013-05-02
    • 2014-11-27
    • 2011-06-16
    • 1970-01-01
    • 2017-06-17
    • 2016-10-03
    相关资源
    最近更新 更多