Pedro Vieira
Pedro Vieira

Reputation: 2316

Using vectorization to reduce for loops, how to use conditional if?

I'm working in a Matlab project and I have a function that is working, but I want to optimize it, reducing the number of for loops that I have in my code. I read about vectorization, I could use it but how would I include the if conditional statement if I have to test every single value at a time?

function [y, zf] = MyFunction(x, b, zi)

y = zeros([length(x) 1]);

for n = 1:length(x)
  for k=1:length(zi)
       if n<k
           y(n) = y(n) + b(k)*zi(length(zi)+(n-k)+1);
       else
           y(n) = y(n) + b(k)*x(n-k+1);
       end
   end
end

zf = x(length(x)-length(zi)+1:length(x));

I manage to do the vectorization, but I can't figure how to do the conditional, I get the warning:

Variable 'n' might be set by a nonscalar operator

function [y, zf] = MyFunction(x, b, zi)

y = zeros([length(x) 1]);

n=1:1:length(x); % use of vectorization
for k=1:length(zi)
   if n<k % problem with if
       y = y + b(k)*zi(length(zi)+(n-k)+1);
   else
       y = y + b(k)*x(n-k+1);
   end
end

zf = x(length(x)-length(zi)+1:length(x));

Upvotes: 0

Views: 83

Answers (1)

RibomBalt
RibomBalt

Reputation: 475

Currently n is a vector and k is a scalar, and n<k returns a logical vector. If you directly use if, it would be the same as if all(n), which will only return true when everything in that vector is true! That's unexpected behavior.

I don't know if there's a general way to vectorize codes with if. But in your case, I can do it this way.

% use indice to deal with if
for k=1:length(zi)
   y(1:k-1)=y(1:k-1)+b(k)*zi(length(zi)+2-k:end);
   y(k:end)=y(k:end)+b(k)*x(1:length(x)-k+1);
end

I also notice that actually if you cat zi and x, it's no need to use 2 individual statement.

% assume both zi & x to be column vector
ziandx=[zi;x];
for k=1:length(zi)
   y=y+b(k)*ziandx(length(zi)+2-k:length(zi)+length(x)-k+1);
end

Finally, even this for-loop is no need if you use conv. (check the doc for more detail)

ziandx=[zi;x];
s=conv(b(1:length(zi)),ziandx);
y=s(length(zi)+1:length(zi)+length(x))

I recommend you to read all three methods and understand the idea, thus you can do it yourself next time.

Upvotes: 3

Related Questions