Updating a matrix based on conditions in other matrixes

1 view (last 30 days)
I have coded the attached loop to update matrix Lr but I would ideally like to use code that can achieve what the shown loop is doing in one sweep (i.e. without needing to loop); the actual matrixes I have can be extremely large.
The code is also shown below, but the layout is off:
k = 1;
pos_neg = [1;1;0];
E = [round(rand(1,3));round(rand(1,3));round(rand(1,3))];
Lr = zeros(numel(pos_neg(:,1)),numel(E(:,1)));
L = 0.5;
for i = 1:numel(E(:,1))
for ii = 1:numel(E(:,1))
if sum(E(i,:)) <= k
if E(i,ii) == 0
Lr(i,ii) = L;
end
if E(i,ii) == 1
Lr(i,ii) = -L;
end
end
if sum(E(i,:)) >= k
if E(i,ii) == 1
Lr(i,ii) = L;
end
if E(i,ii) == 0
Lr(i,ii) = -L;
end
end
end
end
  2 Comments
Ngonidzashe Nedziwe
Ngonidzashe Nedziwe on 10 Jul 2017
hi i would like to help but im confused about what u exactly mean or are trying to achieve when u say in one sweep
Ulrik William Nash
Ulrik William Nash on 10 Jul 2017
Thank you, Ngonidzashe, what I mean is without looping.

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 10 Jul 2017
If I work through the logic correctly,
Lr = L*(1 - 2 * bsxfun( @eq, sum(E,2) <= k, E));
Or if you have R2016b or later,
Lr = L*(1 - 2 * ((sum(E,2) <= k) == E));
  4 Comments
Ulrik William Nash
Ulrik William Nash on 10 Jul 2017
Thank you Walter, no problem. In the mean time I will look at your approach. Maybe I can figure it out.
Ulrik William Nash
Ulrik William Nash on 10 Jul 2017
Edited: Ulrik William Nash on 10 Jul 2017
Hi Walter,
I think your mistake was very small. As far as I can tell, all that is required is the following change:
From: Lr = L*(1 - 2 * bsxfun( @eq, sum(E,2) <= k, E))
To:
Lr = L*(2 * bsxfun( @eq, sum(E,2) >= k, E)-1)

Sign in to comment.

More Answers (1)

Jan
Jan on 10 Jul 2017
Edited: Jan on 10 Jul 2017
Start with cleaning the code by avoiding all repeated calculations inside the loop:
k = 1;
pos_neg = [1;1;0];
E = [round(rand(1,3));round(rand(1,3));round(rand(1,3))];
Lr = zeros(numel(pos_neg(:,1)),numel(E(:,1)));
L = 0.5;
sE = size(E, 1);
for i = 1:sE
sumEi = sum(E(i,:));
for ii = 1:sE
if sumEi <= k
if E(i,ii) == 0
Lr(i,ii) = L;
end
if E(i,ii) == 1
Lr(i,ii) = -L;
end
end
if sumEi >= k
if E(i,ii) == 1
Lr(i,ii) = L;
end
if E(i,ii) == 0
Lr(i,ii) = -L;
end
end
end
end
Now you see that the "if sumEi <= k" test does not depend on the "for ii" loop. Then move it outside this loop:
sE = size(E, 1);
for i = 1:sE
sumEi = sum(E(i,:));
if sumEi <= k
for ii = 1:sE
if E(i,ii) == 0
Lr(i,ii) = L;
elseif E(i,ii) == 1
Lr(i,ii) = -L;
end
end
elseif sumEi >= k
for ii = 1:sE
if E(i,ii) == 1
Lr(i,ii) = L;
elseif E(i,ii) == 0
Lr(i,ii) = -L;
end
end
end
end
Now see, shat you want to achieve actually (this should be contained as a clear and exhaustive comment in the code): Lr is set to L or -L. So start with set all elements to L and swap the sign for the specific elements:
Lr = repmat(L size(pos_neg, 1), size(E,1));
size(E, 1) is more efficient than numel(E(:,1)), because the latter creates a temporary vector only to measure its length.
sumEi = sum(E, 1);
index = ((sumEi <= k) & (E == 1)) | ...
(sumEi >= k) & (E == 0)); % >= R2016b
Note that sumEi == k belongs to both cases. I assume one of them should be a > or < .
If the values of E are either 1 or 0, this can be expressed in one logical comparison only. I cannot test this currently, but it is something like:#
Lr = repmat(L, size(pos_neg, 1), size(E,1));
index = xor(sum(E, 1) <= k, E == 1); % Or E==0? Or < instead of <= ? Try this by your own
Lr(index) = -L;
  2 Comments
Ulrik William Nash
Ulrik William Nash on 10 Jul 2017
Hi Jan,
This was very instructive! I have been making some inefficiencies in my coding.
Regarding the specific solution you find, perhaps it is dependent on the Matlab version (I have 2015), because I obtain the following error:
xor(sum(E,1) <= k, E == 1) Error using xor Matrix dimensions must agree.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!