簡體   English   中英

如何在MATLAB中向量化此循環

[英]How can I vectorise this loop in MATLAB

我有一個循環,可以在矩陣上進行迭代,並將只有一個非零元素的所有行和列都設置為全零。

因此,例如,它將轉換此矩陣:

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個非零元素,因此A'行/列2中的每個元素都設置為0

(假設矩陣將始終是對角對稱的)

這是我的非矢量化代碼:

for ii = 1:length(A)
    if nnz(A(ii,:)) == 1
        A(ii,:) = 0;
        A(:,ii) = 0;
    end
end

有沒有在MATLAB中編寫此代碼的更有效方法?

編輯:

有人在評論中要求我進行澄清,所以我將負責。

該代碼的目的是從圖形中刪除導致階數為1的頂點的邊。

如果A是表示無向圖G的鄰接矩陣,則該矩陣的僅包含一個非零元素的行或列表示該行/列表示一個度為1的頂點,因為它只有一個入射的邊。

我的目標是從圖中除去這些邊緣,因為在我要解決的問題的解決方案中將永遠不會訪問這些頂點,並且縮小圖也將減小搜索算法的輸入大小。

@TimeString,我知道在您提供的示例中,將算法遞歸地應用於矩陣將導致矩陣為零,但是我將其應用於表示大型連通圖的矩陣,因此永遠不會出現這種情況。 在回答您的問題時,為什么我只檢查一行中有多少個元素,但同時清除列和行; 這是因為矩陣始終是對角線對稱的,所以我知道如果某行為真,則對應的列為真。

因此,僅使用另一個示例進行說明:

我想把這個圖變成G

圖G

用矩陣表示:

A = [ 0 1 1 0
      1 0 1 0
      1 1 0 1
      0 0 1 0 ]

到該圖G'

圖G'

由此矩陣表示:

A' = [ 0 1 1 0
       1 0 1 0
       1 1 0 0
       0 0 0 0 ]

(我意識到這個矩陣實際上應該是3x3矩陣,因為點D已被刪除,但我已經知道在這種情況下如何縮小矩陣,我的問題是關於僅將1個非零元素都有效地設置為0)

我希望這是足夠的澄清。

不知道它是否真的更快(取決於Matlab的JIT),但是您可以嘗試以下方法:

要找出哪些列(由於矩陣是對稱的,所以等同於行)具有多個非零元素,請使用:

sum(A ~= 0) > 1 

在這種情況下,可能不需要~= 0 ,因為矩陣僅由1/0元素組成(如果我正確理解,則為圖形邊緣)。

將以上內容轉換為對角矩陣,以消除不需要的列:

D = diag(sum(A~=0) > 1)

並從左到零行和從右到零列乘以A:

res = D * A * D

由於nimrodm建議使用sum(A〜= 0)而不是nnz,所以我設法找到了比原始解決方案更好的解決方案

用一個元素清除行:

A(sum(A ~= 0) == 1,:) = 0;

然后使用一個元素清除列:

A(:,sum(A ~= 0) == 1) = 0;

對於那些您感興趣的人,我在1000 x 1000矩陣上進行了'tic-toc'比較:

% 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

因此看來,受nimrodm建議的啟發,我想出的單行版本是最快的

感謝你的幫助!

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM