how can i vectorize this for loop??
Mostrar comentarios más antiguos
clc;
clear all;
close all;
k = 1:0.5:10;
a = 1:0.5:5;
n1 = numel(k);
nump = kron(k,ones(1,length(a)))';
denp = repmat([ones(n2,1), a.', zeros(n2,1)] ,n1, 1);
w=[0.1,0.5,0.8,1,2,8,15,50,100];
n2 = numel(a);
delay=0;
[rn,cn]=size(nump);
[rd,cd]=size(denp);
[rw,cw]=size(w);
[rdel,cdel]=size(delay);
if rw>1,
w = w(:)';
end
if rn~=rd & (rn~=1 & rd~=1),
end
if rdel~=rn & rdel~=rd & rdel~=1,
end
i=sqrt(-1);
s=i*w;
mx = max(rn,rd);
q=1; r=1;
for h=1:mx,
q=(rn>1)*h+(rn==1); r=(rd>1)*h+(rd==1); d=(rdel>1)*h+(rdel==1);
upper = polyval(nump(q,:),s);
lower = polyval(denp(r,:),s);
cp(h,:)=(upper./lower).*exp(-s*delay(d));
end
toc
1 comentario
You need to resort the code lines: n2 is used before it is defined. The toc is useless without a tic. Omit the darn clear all, because it removes all loaded functions from the memory. The reloading from disk wastes time and interfer with measuring the run time.
i=sqrt(-1) is useless, because this is the definition of "i" already.
Omit the useless code
if rn~=rd & (rn~=1 & rd~=1),
end
if rdel~=rn & rdel~=rd & rdel~=1,
end
except if you want to confuse the readers.
Respuesta aceptada
Más respuestas (2)
Now the vectorized version:
function cp = YourFcn()
k = 1:0.5:10;
a = 1:0.5:5;
n1 = numel(k);
nump = kron(k, ones(1, length(a)))';
n2 = numel(a);
denp = repmat([ones(n2,1), a.', zeros(n2,1)], n1, 1);
w = [0.1,0.5,0.8,1,2,8,15,50,100];
delay = 0;
w = w(:)';
s = 1i * w;
upper = nump(:, 1);
for i = 2:size(nump, 2)
upper = s .* upper + nump(:, i); % requires >= R2016b !!!
end
lower = denp(:, 1);
for i = 2:size(denp, 2)
lower = s .* lower + denp(:, i); % requires >= R2016b !!!
end
cp = (upper ./ lower) .* exp(-s * delay); % requires >= R2016b !!!
end
:-) Nice. 0.023 seconds. 4 times faster than the efficient loop.
If you run this on older Matlab versions, you need some bsxfun() calls:
...
s = 1i * w;
upper = nump(:, 1);
for i = 2:size(nump, 2)
upper = bsxfun(@plus, bsxfun(@times, s, upper), nump(:, i));
end
lower = denp(:, 1);
for i = 2:size(denp, 2)
lower = bsxfun(@plus, bsxfun(@times, s, lower), denp(:, i));
end
cp = bsxfun(@times, bsxfun(@rdivide, upper, lower), exp(-s * delay));
While this code is compact and efficient, exhaustive comments are required to recognize, that this is a vectorized Horner scheme from polyval.
Note that the vectorized code does not need the case differentiation for rn>1, rd>1 and del>1 and that the number of exp() calls is reduced to the required minimum automatically.
I hope the real problem is much larger. Otherwise the absolute speed up is only some milliseconds from 0.0046 to 0.00023. For the inputs:
k = 1:0.05:10;
a = 1:0.05:5;
the original version needs 217, the efficient loop 8 and the vectorized code 1.06 seconds. And they even reply the same values ;-)
2 comentarios
nelson
el 27 de Jul. de 2017
Jan
el 28 de Jul. de 2017
@nelson: You are welcome. This was an interesting question and I was not sure at first how to vectorize this and if this increases the speed. I've posted the intermediate steps also to demonstrate how the solution can be developped.
nelson
el 28 de Jul. de 2017
0 votos
2 comentarios
Jan
el 28 de Jul. de 2017
@nelson: Please post comments as comments. When you use the section for answers, it is not clear to which answer they belong to. If you mean the Horner scheme:
upper = nump(:, 1);
for i = 2:size(nump, 2)
upper = s .* upper + nump(:, i);
end
No, this cannot be vectorized furtherly. Remember that the Horner scheme is known for its numerical stability and efficiency.
If you still need more speed, hire a programmer to create a fast C-Mex function.
nelson
el 28 de Jul. de 2017
Categorías
Más información sobre Loops and Conditional Statements en Centro de ayuda y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!