MATLAB:使用块向量高效生成块矩阵

时间:2018-10-31 20:32:28

标签: matlab performance loops linear-algebra

假设

  

x = [x1; x2; ...; xn]

其中每个xi是长度为l(i)的列向量。我们可以设置L = sum(l)的总长度x。我想基于x生成2个矩阵:

enter image description here

我们称它们为AB。例如,当x仅作为2个块x1x2时,则:

  

A = [x1 * x1'零(l(1),l(2)); zeros(l(2),l(1)),x2 * x2'];

     B = [x1个零(l(1),1);        zeros(l(2),1),x2];

在问题的表示中,A始终是L的{​​{1}},L始终是B的{​​{1}}。我可以使用循环在给定L的情况下生成nA,但这很繁琐。是否有一种聪明的(无循环)方式生成Bx。我正在使用MATLAB 2018b,但如有必要,您可以假定使用早期版本的MATLAB。

3 个答案:

答案 0 :(得分:4)

以下应该起作用。在这种情况下,我无法高效转换为单元阵列,因此可能会有更有效的实现方式。

cuml = [0; cumsum(l(:))];
get_x = @(idx) x((1:l(idx))+cuml(idx));
x_cell = arrayfun(get_x, 1:numel(l), 'UniformOutput', false);
B = blkdiag(x_cell{:});
A = B*B';

修改

运行一些基准测试后,我发现基于直接循环的实现速度大约是上述基于单元的方法的两倍。

A = zeros(sum(l));
B = zeros(sum(l), numel(l));
prev = 0;
for idx = 1:numel(l)
    xidx = (1:l(idx))+prev;
    A(xidx, xidx) = x(xidx,1) * x(xidx,1)';
    B(xidx, idx) = x(idx,1);
    prev = prev + l(idx);
end

答案 1 :(得分:4)

这是另一种方法:

s = repelem(1:numel(l), l).';
t = accumarray(s, x, [], @(x){x*x'});
A = blkdiag(t{:});
t = accumarray(s, x, [], @(x){x});
B = blkdiag(t{:});

答案 2 :(得分:4)

我认为这既简短又快速:

B = x .* (repelem((1:numel(l)).',l)==(1:numel(l)));
A = B * B.';

如果数据量较大,最好使用稀疏矩阵:

B = sparse(1:numel(x), repelem(1:numel(l), l), x);
A = B * B.';