How to avoid for nested loops with if condition?

Hello,
I have big matrixes of same size, and am suing for loop with if statement, which is bottleneck in my code and is very slow. How would it be possible to optimize it?
for i=1:n1
for j=1:n2
if id(i,j)==1
if RR(i,j)==1
id(i,x(i,j))=0;
end
end
end
end
Maybe it is possible to vectorize or use bsxfun?

 採用された回答

Guillaume
Guillaume 2018 年 6 月 25 日
編集済み: Guillaume 2018 年 6 月 25 日

0 投票

You certainly don't need the j loop:
for row = 1:size(id)
id(row, x(id(row, :) == 1 & RR(row, :) == 1)) = 0;
end
You could get rid of the i loop as well at the expense of memory (another array the same size as id)
mask = id == 1 & RR == 1; %and if id and RR are logical, simply: mask = id & RR;
rows = repmat((1:size(id, 1)', 1, size(id, 2));
id(sub2ind(size(id), rows(mask), x(mask))) = 0;

10 件のコメント

Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
With memory expense was by far the fastest solution. However, if id value was change during loop to 0, in should be skipped. Now even if id value was changed to 0, in the solution provided it does use value of 1, that was taken in the beginning. Like if id was (1 1 0 0 1) and RR was (1 1 0 0 0), x was (2 1 5 3 3), then id should be (1 0 0 0 1), and now with your solution id would be (0 0 0 0 1). Thus, because of this I am stuck
Guillaume
Guillaume 2018 年 6 月 25 日
if id value was change during loop to 0, in should be skipped
Then the result depends on the order in which you process the columns, which to me sounds odd. However, if that is your requirement then I don't think that there is a way to vectorise that. Vectorisation only works when all the operations can be performed in parallel. Because of your requirement, the operations have to be in series.
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
Yes maybe the way I am trying is not the best. I managed to change the logic of the task, maybe here you could help as well. if x [2 1 3 4 5] and a [1 2 3 4 5] and I pair these two arrays, i need to remove duplicate pairs. for example x(1) pair with a(1) is same as x(2) paired with a(2) in that case a should change to [1 0 3 4 5]. Maybe you know the best way to tackle this?
Guillaume
Guillaume 2018 年 6 月 25 日
x = [2 1 3 4 5];
a = [1 2 3 4 5];
[~, tokeep] = unique(sort([x', a'], 2), 'rows', 'stable');
a(setdiff(1:numel(a), tokeep)) = 0
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
Wow, this worked like a charm. The last question if I may. What would be the situation if there are multiple rows like:
x = [2 1 4 5 4;5 3 4 5 1:...];
a = [1 2 3 4 5;1 2 3 4 5;...];
I did try changing the code, but it did not make any difference on second row.
Guillaume
Guillaume 2018 年 6 月 25 日
編集済み: Guillaume 2018 年 6 月 25 日
How are pairs defined in the matrix case?
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
'x' (N,M) array represent pairs of 'a' and a is always the same [1 2 3 4 5], maybe it is redundant to repeat same row for N times, thus each x (N,M) is pair of each element of a (N,1:5). I thing this should work
[w,d]=unique(sort([x', a'], 2), 'rows', 'stable'),
but I am not sore, how to implement further. Is this what you meant?
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 26 日
編集済み: Mantas Vaitonis 2018 年 6 月 26 日
I managed to do the folowing using for loop again and 3D matrix, maybe you know a way without for loop?
i
x1 = [3 1 1 5 3;2 1 1 5 3];
a2 = [1 2 3 4 5;1 2 3 4 5];
x=gpuArray(x1);
a=gpuArray(a2);
for i=1:2
r1(:,:,i)=cat(3,x(i,:),a(i,:));
[~, tokeep] = unique(sort(r1(:,:,i), 2), 'rows', 'stable');
a(i,setdiff(1:numel(a(i,:)), tokeep')) = 0;
end
Guillaume
Guillaume 2018 年 6 月 26 日
So it's replicated pairs in a single row that need to be removed, no replicated pairs across the whole matrix. If so, you can indeed use a loop over the rows as you've done but yours is overcomplicated and your transition through a 3d matrix only works by accident (your cat(3,...) is reshaped into a 2d matrix). This would be simpler:
x = [3 1 1 5 3;2 1 1 5 3];
a = repmat([1 2 3 4 5], size(x, 1), 1);
for row = 1:size(x, 1)
[~, tokeep] = unique(sort([x(row, :)', a(row, :)'], 'rows', 'stable');
a(row, setdiff(1:size(a, 2), tokeep) = 0;
end
Now, there is a way to do it without a loop. It's pretty hairy, having to go through a 4D matrix:
x = [3 1 1 5 3;2 1 1 5 3];
a = repmat([1 2 3 4 5], size(x, 1), 1);
sortedpairs = sort(cat(3, x, a), 3);
matchedpairs = all(sortedpairs == permute(sortedpairs, [1 4 3 2]), 3);
matchnotfirst = cumsum(matchedpairs, 2) > 1 & matchedpairs; %only keep 2nd and subsequent pair
toreset = any(matchnotfirst, 4);
a(toreset) = 0
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 26 日
Thank You, greate now it wokrs as it should, without for loop.

サインインしてコメントする。

その他の回答 (1 件)

Nithin Banka
Nithin Banka 2018 年 6 月 25 日

0 投票

I don't think you need to use 'for' loop. The 2 'if' statements can be easily handled in MATLAB.
index_of_1_in_id_and_RR = (id==1&RR==1); %valid as you told they have same size
You can use this variable in further steps.

3 件のコメント

Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
Thank You for your time, yes I know that Matlab can handle two if statements, but if the statement is fulfilled, i need to assign 0 value to the following id(i,x(i,j))=0, and what would be the way without for loop?
for i=1:n1
for j=1:n2
if (id(i,j)==1&&RR(i,j)==1)
id(i,x(i,j))=0;
end
end
end
Nithin Banka
Nithin Banka 2018 年 6 月 25 日
Can you provide me 'x'?
Mantas Vaitonis
Mantas Vaitonis 2018 年 6 月 25 日
Yes, for example all arrays are same size (5x5), RR,id and x. Values inside arrays can be in random 1:5 type double. Like x can be [5 3 1 1 2;....]

サインインしてコメントする。

カテゴリ

ヘルプ センター および File ExchangeLoops and Conditional Statements についてさらに検索

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by