【问题标题】:Sub-setting symmetric matrices along the diagonal沿对角线设置对称矩阵
【发布时间】:2019-05-17 22:42:13
【问题描述】:

我有一个 8x8 矩阵,例如A=rand(8,8)。我需要做的是沿对角线对所有 2x2 矩阵进行子集化。这意味着我需要保存矩阵A(1:2,1:2)A(3:4,3:4)A(5:6,5:6)A(7:8,7:8)。为了更好地解释我自己,我正在使用的当前版本如下:

 AA = rand(8,8);
 BB = zeros(8,2);
 for i = 1:4
     BB(2*i-1:2*i,:) = AA(2*i-1:2*i,2*i-1:2*i);
 end

这适用于小型AA 矩阵和小型AA 子矩阵,但是随着大小显着增长(甚至可以达到50,000x50,000),使用for 循环就像上面的那样不可行.有没有办法在没有循环的情况下实现上述目标?我想到了其他可能利用上三角矩阵和下三角矩阵的方法,但是即使这些方法在某些时候似乎也需要一个循环。任何帮助表示赞赏!

【问题讨论】:

  • AA 的大小总是能被 2 整除吗?
  • 不一定。我们需要子集化的矩阵的大小可能会发生变化,但它们始终是原始矩阵的完美除法器。例如,对于当前矩阵,我们还可以沿对角线对所有 4x4 矩阵进行子集化(但不是 3x3 或 5x5 例如)。对于 9x9 矩阵,我们将沿对角线对 3x3 矩阵进行子集化,等等。

标签: arrays matlab matrix


【解决方案1】:

这是一种方法:

AA = rand(8,8); % example matrix. Assumed square
n = 2; % submatrix size. Assumed to divide the size of A
mask = repelem(logical(eye(size(AA,1)/n)), n, n);
BB = reshape(permute(reshape(AA(mask), n, n, []), [1 3 2]), [], n);

这会生成一个logical mask 来选择所需的元素,然后使用reshapepermute 根据需要重新排列它们。

【讨论】:

  • LM,这很漂亮
  • @greengrass62 谢谢 :-)
  • 这太棒了!我永远不会自己想出如此优雅的东西。非常感谢LM!
  • @J.Avra 很高兴你喜欢它
  • 你会恨我的。无论如何,您可能已经这样做了。 OP 的循环代码比我电脑上的这个解决方案快大约 20 倍。 :)
【解决方案2】:

这里有一个替代方案,它不会生成完整的矩阵来选择块对角线,如Luis Mendo' answer,而是直接生成这些元素的索引。对于非常大的矩阵,这可能会更快,因为在这种情况下创建索引矩阵会很昂贵。

AA = rand(8,8); % example matrix. Assumed square
n = 2; % submatrix size. Assumed to divide the size of A

m=size(AA,1);
bi = (1:n)+(0:m:n*m-1).'; % indices for elements of one block
bi = bi(:);               % turn into column vector
di = 1:n*(m+1):m*m;       % indices for first element of each block
BB = AA(di+bi-1);         % extract the relevant elements
BB = reshape(BB,n,[]).'   % put these elements in the desired order

基准测试

AA = rand(5000); % couldn't do 50000x50000 because that's too large!
n = 2;

BB1 = method1(AA,n);
BB2 = method2(AA,n);
BB3 = method3(AA,n);
assert(isequal(BB1,BB2))
assert(isequal(BB1,BB3))

timeit(@()method1(AA,n))
timeit(@()method2(AA,n))
timeit(@()method3(AA,n))

% OP's loop
function BB = method1(AA,n)
m = size(AA,1);
BB = zeros(m,n);
for i = 1:m/n
   BB(n*(i-1)+1:n*i,:) = AA(n*(i-1)+1:n*i,n*(i-1)+1:n*i);
end
end

% Luis' mask matrix
function BB = method2(AA,n)
mask = repelem(logical(eye(size(AA,1)/n)), n, n);
BB = reshape(permute(reshape(AA(mask), n, n, []), [1 3 2]), [], n);
end

% Cris' indices
function BB = method3(AA,n)
m = size(AA,1);
bi = (1:n)+(0:m:n*m-1).';
bi = bi(:);
di = 0:n*(m+1):m*m-1;
BB = reshape(AA(di+bi),n,[]).';
end

在我的计算机上,使用 MATLAB R2017a 我得到:

  • method1(OP 的循环):0.0034 秒
  • method2(Luis 的掩码矩阵):0.0599 秒
  • method3(克里斯的指数):1.5617e-04 s

请注意,对于 5000x5000 数组,此答案中的方法比循环快约 20 倍,而循环比 Luis 的解决方案快约 20 倍。

对于较小的矩阵,情况略有不同,Luis 的方法几乎是 50x50 矩阵的循环代码的两倍(尽管这种方法仍然比它快 3 倍)。

【讨论】:

    猜你喜欢
    • 2021-12-12
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    • 2023-02-01
    相关资源
    最近更新 更多