我有一个遍历矩阵的循环,并将所有行和列设置为只有一个非零元素为全零。
例如,它将转换此矩阵:A = [ 1 0 1 1
0 0 1 0
1 1 1 1
1 0 1 1 ]
到矩阵:
A' = [ 1 0 1 1
0 0 0 0
1 0 1 1
1 0 1 1 ]
A
的行/列2中只有1个非零元素,因此行/列2中的每个元素都在A'
(假设矩阵总是对角对称)
这是我的非矢量化代码:
for ii = 1:length(A)
if nnz(A(ii,:)) == 1
A(ii,:) = 0;
A(:,ii) = 0;
end
end
有没有更有效的方法在MATLAB中编写这段代码?
修改
我在评论中被要求做一些澄清,所以我有责任。
此代码的目的是从图形中删除导致顶点为1的边。
如果A
是表示无向图G
的邻接矩阵,那么该矩阵的只有一个非零元素的行或列表示该行/列表示一度的顶点因为它只有一个边缘事件。
我的目标是从图中删除这些边,因为在我试图解决的问题的解决方案中永远不会访问这些顶点,并且减少图也会减小我的搜索算法输入的大小。
@TimeString,据我所知,在您给出的示例中,递归地将算法应用于矩阵将导致零矩阵,但是我应用它来表示大型连通图的矩阵,因此永远不会有这样的情况。回答你的问题,为什么我只检查一行中有多少元素,但清除了列和行;这是因为矩阵总是对角线对称,所以我知道如果一行是真的,那么它将是相应的列..
所以,只是为了澄清另一个例子:
我想转换此图G
:
由矩阵表示:
A = [ 0 1 1 0
1 0 1 0
1 1 0 1
0 0 1 0 ]
到此图G'
:
由此矩阵表示:
A' = [ 0 1 1 0
1 0 1 0
1 1 0 0
0 0 0 0 ]
(我知道这个矩阵实际上应该是一个3x3矩阵,因为D点已被删除,但我已经知道如何在这个例子中缩小矩阵,我的问题是关于有效设置只有1非零的列/行元素全部为0)
我希望这是一个很好的澄清......
答案 0 :(得分:3)
不确定它是否真的更快(取决于Matlab的JIT),但您可以尝试以下方法:
要找出哪些列(相当于行,因为矩阵是对称的)使用多个非零元素:
sum(A ~= 0) > 1
在您的情况下可能不需要~= 0
,因为矩阵仅包含1/0元素(如果我理解正确,则为图形边缘)。
将上述内容转换为对角矩阵,以消除不需要的列:
D = diag(sum(A~=0) > 1)
将A从左到右乘以及从右到右乘以:
res = D * A * D
答案 1 :(得分:0)
感谢nimrodm建议使用sum(A~ = 0)而不是nnz,我设法找到比原来更好的解决方案
使用我使用的一个元素清除行:
A(sum(A ~= 0) == 1,:) = 0;
然后用一个元素清除列:
A(:,sum(A ~= 0) == 1) = 0;
对于那些有兴趣的人,我做了一个“toc-toc'比较1000 x 1000矩阵:
% establish matrix
A = magic(1000);
rem_rows = [200,555,950];
A(rem_rows,:) = 0;
A(:,rem_rows) = 0;
% insert single element into empty rows/columns
A(rem_rows,500) = 5;
A(500,rem_rows) = 5;
% testing original version
A_temp = A;
for test = 1
tic
for ii = 1:length(A_temp)
if nnz(A_temp(ii,:)) == 1
A_temp(ii,:) = 0;
A_temp(:,ii) = 0;
end
end
toc
end
Elapsed time is 0.041104 seconds.
% testing new version
A_temp = A;
for test = 1
tic
A_temp(sum(A_temp ~= 0) == 1,:) = 0;
A_temp(:,sum(A_temp ~= 0) == 1) = 0;
toc
end
Elapsed time is 0.010378 seconds
% testing matrix operations based solution suggested by nimrodm
A_temp = A;
for test = 1
tic
B = diag(sum(A_temp ~= 0) > 1);
res = B * A_temp * B;
toc
end
Elapsed time is 0.258799 seconds
所以看来我提出的单线版本受到了尼姆罗姆的建议的启发,是最快的
感谢您的帮助!
答案 2 :(得分:0)
Bsxfuning
它 -
A(bsxfun(@or,(sum(A~=0,2)==1),(sum(A~=0,1)==1))) = 0
示例运行 -
>> A
A =
1 0 1 1
0 0 1 0
1 1 1 1
1 0 1 1
>> A(bsxfun(@or,(sum(A~=0,2)==1),(sum(A~=0,1)==1))) = 0
A =
1 0 1 1
0 0 0 0
1 0 1 1
1 0 1 1