How to vectorize nested loops with conditional statements?

3 views (last 30 days)
I am trying to vectorize given code in order to speed up the performance of code. I tried with preallocation, but I am unable to resolve this. Any suggestion or correction in the given code would be appreciated.
tributary = randn([81, 126]);
cp_mesh = randn([81, 126, 49792]);
cp_B1_2 = zeros(49792,1);
for i=1:49792
temp3 = [];
for k=9:118 %k is column
if k<=117
for j=1:8 %j is row
if j<=7
temp1 = sum(cp_mesh(j:j+1,k:k+1,i));
temp2 = sum(temp1)/sum(sum(tributary(j:j+1,k:k+1)));
temp3 = min([temp3 temp2]);
clear temp1 temp2
else
break
end
end
else
break
end
end
cp_B1_2(i) = temp3;
clear temp3
end
cp_B1_2
Where,
cp_mesh = (81 x 126 x 49792) matrix
  2 Comments
dpb
dpb on 15 Jan 2023
Firstly, don't bury "magic numbers" inside the code -- use variables so you can change them -- it's always much easier to debug small problems that you can see the results for at a glance and then, once the algorithm is correct, change the constants to final sizes.
I didn't take the time here, but all those dimensions buried in there should be variables...
There's no need for logic; just run the loops over the sizes needed to avoid running off the end...and definitely no need to clear variables you're writing over in their entirety anyway...
tributary = randn([81, 126]);
cp_mesh = randn([81, 126, 49792]);
cp_B1_2 = zeros(49792,1);
for i=1:49792
for k=9:118-1 % Subtract one from the upper limit -- should be a constant, not buried in code
for j=1:8-1 % ditto above
temp1 = sum(cp_mesh(j:j+1,k:k+1,i));
temp2 = sum(temp1)/sum(sum(tributary(j:j+1,k:k+1)));
temp3 = min([temp3 temp2]);
end
end
cp_B1_2(i) = temp3;
end
In general, with the JIT compiler, for...end loops are quite quick in MATLAB; it's not likely you'll gain much by trying to vectorize the above since all is dependent on all three indices.
If you could rearrange to operate linearly in column-major order rather than bouncing around in the array would be the ticket to improving speed, probably, but I've not got the time at the moment to really try to dig into what is going on here to that level, sorry.
The above probably won't make much difference in run time, but will certainly make it easier to debug/maintain...

Sign in to comment.

Accepted Answer

Jan
Jan on 15 Jan 2023
Edited: Jan on 15 Jan 2023
tributary = randn([81, 126]);
cp_mesh = randn([81, 126, 49792]);
tic
cp_B1_2 = zeros(49792, 1);
for i = 1:4979 % 49792
temp3 = Inf;
for k = 9:117
for j = 1:7
temp1 = sum(cp_mesh(j:j+1, k:k+1,i), 'all');
temp2 = temp1 / sum(tributary(j:j+1, k:k+1), 'all');
temp3 = min(temp3, temp2);
end
end
cp_B1_2(i) = temp3;
end
toc
Elapsed time is 5.492228 seconds.
This uses the shorter input, because the full set let exceed the runtime the allowed 55 seconds in the forum's online Matlab.
As dpb has mentioned already, cleaning the loops instead of breaking them earlier is more efficient and the clear commands waste time only.
You get save about 10%, if you calculate sum(tributary(j:j+1,k:k+1), 'all') before the loop and store it in a temporary array.
Now this is a fair point for a comparison with a vectorized approach:
tic;
out = Inf;
for k = 9:117
for j = 1:7
temp1 = sum(cp_mesh(j:j+1, k:k+1, 1:4979), [1, 2]);
temp2 = temp1 ./ sum(tributary(j:j+1, k:k+1), 'all');
out = min(out, temp2(:));
end
end
toc
Elapsed time is 0.217914 seconds.
For the full input data:
temp1 = sum(cp_mesh(j:j+1, k:k+1, :), [1, 2]);
Elapsed time is 2.315909 seconds.

More Answers (0)

Categories

Find more on Function Creation in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!