我想生成大小为(n(n-1)/2, n)
的矩阵,如下所示(在这种情况下为n=5
):
-1 1 0 0 0
-1 0 1 0 0
-1 0 0 1 0
-1 0 0 0 1
0 -1 1 0 0
0 -1 0 1 0
0 -1 0 0 1
0 0 -1 1 0
0 0 -1 0 1
0 0 0 -1 1
这就是我很快想出来的:
G = [];
for i = 1:n-1;
for j = i+1:n
v = sparse(1,i,-1,1,n);
w = sparse(1,j,1,1,n);
vw = v+w;
G = [G; vw];
end
end
G = full(G);
它有效,但有更快/更清洁的方法吗?
答案 0 :(得分:1)
使用nchoosek
生成非零的列的索引:
n = 5; %// number of columns
ind = nchoosek(1:n,2); %// ind(:,1): columns with "-1". ind(:,2): with "1".
m = size(ind,1);
rows = (1:m).'; %'// row indices
G = zeros(m,n);
G(rows + m*(ind(:,1)-1)) = -1;
G(rows + m*(ind(:,2)-1)) = 1;
答案 1 :(得分:0)
您有两个嵌套循环,导致非O(N^2)
非向量化操作的复杂性,这对于此任务来说太多了。看一下你的矩阵实际上有一个矩形模式:
G(n+1) = [ -1 I(n)]
[ 0 G(n)];
其中I(n)
是大小为n
的单位矩阵。这就是你在matlab中表达这种模式的方法:
function G = mat(n)
% Treat original call as G(n+1)
n = n - 1;
% Non-recursive branch for trivial case
if n == 1
G = [-1 1];
return;
end
RT = eye(n); % Right-top: I(n)
LT = repmat(-1, n, 1); % Left-top: -1
RB = mat(n); % Right-bottom: G(n), recursive
LB = zeros(size(RB, 1), 1); % Left-bottom: 0
G = [LT RT; LB RB];
end
它给我们O(N)
非矢量化操作的复杂性。如果Matlab不聪明,它可能会在递归和矩阵组合期间浪费一些内存,从而将这些内容考虑在内。如果它很重要,您可以将递归展开为循环并迭代填充原始预分配矩阵中的相应位置。