how to optimize this nested for loop

4 visualizzazioni (ultimi 30 giorni)
Fariba Jangjoo
Fariba Jangjoo il 14 Dic 2017
Commentato: Jan il 23 Feb 2018
I have 2 nested loops which do the following:
  • Get two rows of a matrix
  • Check if indices meet a condition or not
  • If they do: calculate xcorr between the two rows and put it into new vector
  • Find the index of the maximum value of sub vector and replace element of LAG matrix with this value
I dont know how I can speed this code up by vectorizing or otherwise.
b=size(data,1);
F=size(data,2);
LAG= zeros(b,b);
for i=1:b
for j=1:b
if j>i
x=data(i,:);
y=data(j,:);
d=xcorr(x,y);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(i,j)=I-1;
d=xcorr(y,x);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(j,i)=I-1;
end
end
end
  2 Commenti
Jan
Jan il 14 Dic 2017
What does "0 down vote favorite" mean?
Walter Roberson
Walter Roberson il 17 Dic 2017
It means the question was posted on StackOverflow and copied to here.

Accedi per commentare.

Risposta accettata

Jan
Jan il 14 Dic 2017
Modificato: Jan il 17 Dic 2017
Just some tiny modifications:
b = size(data,1);
F = size(data,2);
LAG = zeros(b, b);
for i = 1:b
x = data(i,:);
for j = i+1:b
y = data(j,:);
d = xcorr(x,y);
[~,I] = max(d(F:(2*F)-1));
LAG(i,j) = I-1;
d = xcorr(y,x);
[~,I] = max(d(F:(2*F)-1));
LAG(j,i) = I-1;
end
end
It is a waste of time to calculate the complete xcorr, of you use (F:end) of the output only. Maybe you can create your own xcorr, which calculates the wanted part only. As far as I can see, the maxlag value will not help directly.
[EDITED] Modify the xcorr() function to be leaner:
function ck = leanXCorr(x, y)
len = length(x);
c = [zeros(1,len-1), x];
d = [y, zeros(1,len-1)];
% Compute FFTs
X1 = fft(c);
X2 = fft(d);
% Compute cross correlation
X = X1 .* conj(X2);
ck = ifft(X);
end
[EDITED 2] This was a bad idea. It works faster for input vectors of size 1x100, but the padding with zeros is inefficient for the FFT. Better use a window length based on NEXTPOW2:
function ck = leanXCorr(x, y)
m = length(x);
mxl = m - 1;
m2 = 2 ^ nextpow2(2*m - 1);
% Compute FFTs
X1 = fft(x, m2, 2);
X2 = fft(y, m2, 2);
% Compute cross correlation
c = ifft(X1 .* conj(X2), [], 2);
ck = [c((m2 - mxl + 1):m2), c(1:mxl + 1)];
end
Now I use input: data = rand(15, 41200) and get 3.66 sec instead of 3.82 with the built-in xcorr. Not impressing. But the next step is the actual improvement: If you inline the code into the loop, you can omit the repeated FFT of x and y:
b = size(data, 1);
F = size(data, 2);
LAG = zeros(b, b);
m = F;
mxl = m - 1;
m2 = 2 ^ nextpow2(2*m - 1);
for i = 1:b
X1 = fft(data(i, :), m2, 2);
for j = i+1:b
X2 = fft(data(j, :), m2, 2);
X12 = X1 .* conj(X2);
c = ifft(X12, [], 2);
d = [c((m2 - mxl + 1 + F):m2), c(1:mxl+1)];
[~, I] = max(d);
LAG(i,j) = I - 1;
c = ifft(conj(X12), [], 2);
d = [c((m2 - mxl + 1 + F):m2), c(1:mxl+1)];
[~, I] = max(d);
LAG(j,i) = I - 1;
end
end
This inlined version needs 2.14 sec instead of 3.81 of the original.
Unfortunately this still calculates fft(data(j, :), m2, 2) for the same values. If you could store fft(data, m2, 2), the code would run much faster. But your original data need more than 8GB of RAM. But on a 64GB machine, this would be faster:
FM = fft(data.', m2, 1);
for i = 1:b
X1 = FM(:,i); % fft(data(i, :), m2, 2);
for j = i+1:b
% X2 = fft(data(j, :), m2, 2);
X2 = FM(:,j);
X12 = X1 .* conj(X2);
c = ifft(X12, [], 1);
d = [c((m2 - mxl + 1 + F):m2); c(1:mxl+1)];
[~, I] = max(d);
LAG(i,j) = I - 1;
c = ifft(conj(X12), [], 1);
d = [c((m2 - mxl + 1 + F):m2); c(1:mxl+1)];
[~, I] = max(d);
LAG(j,i) = I - 1;
end
end
I have transposed the input, because it is faster to access the data in columnwise order.
  7 Commenti
Fariba Jangjoo
Fariba Jangjoo il 23 Feb 2018
thanks a lot,i got it..i can not understand the function of
m2 = 2 ^ nextpow2(2*m - 1);
and also
d = [c((m2 - mxl + 1 + F):m2), c(1:mxl+1)];
i will be so thankful if you'd mind explaining these two lines for me(really sorry:( )
Jan
Jan il 23 Feb 2018
The FFT works more efficient, if the n-point DFT uses a power of 2. Therefore:
m2 = 2 ^ nextpow2(2*m - 1);
gets such a value. Instead of padding the data with zeros, a larger window length is used. The result is the same (compare [EDITED] with [EDITED2]), but the speed is higher. But now the output after IFFT is sorted differently, such that
d = [c((m2 - mxl + 1 + F):m2), c(1:mxl+1)];
picks out the elements exactly as if they have been created using the padding.
Simply try the two versions of leanXCorr() posted above:
function ck = leanXCorr1(x, y)
len = length(x);
c = [zeros(1,len-1), x];
d = [y, zeros(1,len-1)];
% Compute FFTs
X1 = fft(c);
X2 = fft(d);
% Compute cross correlation
X = X1 .* conj(X2);
ck = ifft(X);
end
and
function ck = leanXCorr2(x, y)
m = length(x);
mxl = m - 1;
m2 = 2 ^ nextpow2(2*m - 1);
% Compute FFTs
X1 = fft(x, m2, 2);
X2 = fft(y, m2, 2);
% Compute cross correlation
c = ifft(X1 .* conj(X2), [], 2);
ck = [c((m2 - mxl + 1):m2), c(1:mxl + 1)];
end
with some small input. Step through the code line by line using the debugger and compare the contents of the variables.

Accedi per commentare.

Più risposte (0)

Categorie

Scopri di più su Systems of Nonlinear Equations in Help Center e File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by