关于Matlab:如何向量化矩阵的行对角线化

How to vectorize row-wise diagonalization of a matrix

我有一个n×m矩阵,我想将其转换为mn×m矩阵,结果的每个m×m块都包含每一行的对角线。

例如,如果输入为:

1
[1 2; 3 4; 5 6]

输出应为:

1
[1 0; 0 2; 3 0; 0 4; 5 0; 0 6]

当然,我不想用for循环一步一步地组装矩阵。
有矢量化的简单方法可以实现这一目标吗?


这是一个简单的矢量化解决方案,假设X是输入矩阵:

1
2
Y = repmat(eye(size(X, 2)), size(X, 1), 1);
Y(find(Y)) = X;

另一种替代方法是使用sparse,这可以写成整齐的单线:

1
Y = full(sparse(1:numel(X), repmat(1:size(X, 2), 1, size(X, 1)), X'));


对于执行此操作的矢量化方法,将对角元素的线性索引创建到结果矩阵中,然后直接进行赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
%# create some input data
inArray = [10 11;12 13;14 15];

%# make the index array
[nr,nc]=size(inArray);

idxArray = reshape(1:nr*nc,nc,nr)';
idxArray = bsxfun(@plus,idxArray,0:nr*nc:nr*nc^2-1);

%# create output
out = zeros(nr*nc,nc);
out(idxArray) = inArray(:);

out =

    10     0
     0    11
    12     0
     0    13
    14     0
     0    15


我看到的最简单的方法实际上是非常简单的,使用简单的索引引用和reshape函数:

1
2
3
I = [1 2; 3 4; 5 6];
J(:,[1,4]) = I;
K = reshape(J',2,6)';

如果您检查J,它看起来像这样:

1
2
3
4
J =
     1     0     0     2
     3     0     0     4
     5     0     0     6

矩阵K正是想要的:

1
2
3
4
5
6
7
K =
     1     0
     0     2
     3     0
     0     4
     5     0
     0     6

正如Eitan T在评论中指出的那样,以上内容仅适用于示例,并不涵盖一般解决方案。因此,下面是一般的解决方案,如问题中所述,具有m和n。

1
2
J(:,1:(m+1):m^2) = I;
K=reshape(J',m,m*n)';

如果要对其进行测试以使其正常运行,请使用

1
I=reshape(1:(m*n),m,n)';

注意:如果J已经存在,则可能会导致问题。在这种情况下,您还需要使用

1
J=zeros(n,m^2);


这可能不是计算效率最高的解决方案,但这是使用kron的1-liner:

1
2
3
4
5
6
7
8
9
A = [1 2; 3 4; 5 6];
B = diag(reshape(A', 6, 1) * kron(ones(3, 1), eye(2))
% B =
%     1     0
%     0     2
%     3     0
%     0     4
%     5     0
%     0     6

如果A为n x m,则可以概括为:

1
diag(reshape(A.', n*m, 1)) * kron(ones(n,1), eye(m))