How to get rid of a loop that depends on its previous iterations

2 Ansichten (letzte 30 Tage)
JPL
JPL am 19 Okt. 2021
Kommentiert: JPL am 25 Okt. 2021
I have an old c++ program that I want to translate to Matlab. It has a loop in which every iteration depends on a decision in the previous iteration. I have a lot of data, so it takes a long time. Is there a way to do this with matrix operations instead of a loop? Here's the code:
data = rand(1,105);
for k = 100 : -1 : 6
lowerAverage = mean(data(k-5:k-1));
upperAverage = mean(data(k+1:k+5));
surroundingAverage = mean([lowerAverage,upperAverage]);
if data(k) > surroundingAverage
data(k) = upperAverage
end
end
Thanks in advance.

Akzeptierte Antwort

Jan
Jan am 19 Okt. 2021
Bearbeitet: Jan am 20 Okt. 2021
Start with calculating the average manually instead of the slower mean() function:
% Timings: R2018b, Win10, i7
data0 = rand(1, 100005);
data = data0;
tic;
for k = 100000 : -1 : 6
lowerAverage = mean(data(k-5:k-1));
upperAverage = mean(data(k+1:k+5));
surroundingAverage = mean([lowerAverage,upperAverage]);
if data(k) > surroundingAverage
data(k) = upperAverage;
end
end
toc % Elapsed time is 1.050304 seconds.
data_orig = data;
data = data0;
tic;
for k = 100000 : -1 : 6
lowerAverage = sum(data(k-5:k-1)) / 5;
upperAverage = sum(data(k+1:k+5)) / 5;
surroundingAverage = (lowerAverage + upperAverage) / 2;
if data(k) > surroundingAverage
data(k) = upperAverage;
end
end
toc % Elapsed time is 0.050326 seconds.
isequal(data, data_orig) % true
20 times faster already. Mayby this is some percent faster:
data = data0;
tic;
for k = 100000 : -1 : 6 % 1 multiplication, 1 division:
low = sum(data(k-5:k-1));
up = sum(data(k+1:k+5));
if 10 * data(k) > (low + up)
data(k) = up / 5;
end
end
toc % Elapsed time is 0.049661 seconds.
The lower average is not influenced by overwriting the data. So this can be vectorized:
data = data0;
tic;
lowv = conv(data, ones(1, 5), 'same');
for k = 100000 : -1 : 6
low = lowv(k - 3);
up = sum(data(k+1:k+5));
if 10 * data(k) > (low + up)
data(k) = up / 5;
end
end
toc % Elapsed time is 0.025510 seconds.
The last method takes significantly more time when I run it in the forums MATLAB online 2021b. So try this locally on your computer.
[EDITED] If replacing mean() increases the speed, try this with sum() also:
data = data0;
tic;
avg = conv(data, ones(1, 5), 'same');
for k = 100000 : -1 : 6
low = avg(k - 3);
up = data(k+1) + data(k+2) + data(k+3) + data(k+4) + data(k+5);
if 10 * data(k) > (low + up)
data(k) = up / 5;
end
end
toc % Elapsed time is 0.007511 seconds.
A speedup of factor 140 on my R2018b and the random test data.
  5 Kommentare
Jan
Jan am 22 Okt. 2021
A mex version needs about half of the processing time compared to the last M-version of my asnwer:
#include "mex.h"
mvoid mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *X, low, up;
mwSize i, n;
n = mxGetNumberOfElements(prhs[0]);
plhs[0] = mxDuplicateArray(prhs[0]);
X = mxGetDoubles(plhs[0]);
for (i = n - 6; i > 4; i--) {
low = X[i-5] + X[i-4] + X[i-3] + X[i-2] + X[i-1];
up = X[i+1] + X[i+2] + X[i+3] + X[i+4] + X[i+5];
if (10 * X[i] > low + up) {
X[i] = up / 5;
}
}
return;
}
JPL
JPL am 25 Okt. 2021
Thanks,
I think this will work out well.
John

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Produkte


Version

R2017a

Community Treasure Hunt

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

Start Hunting!

Translated by