# The 'for-loop' and vectorizaton

## Topics in this lab

## Introduction

In this lab, you will learn how to control the flow of execution of commands using a for loop.

Back to the top

## The 'for' loop

Up until now, commands in a script have been executed in the order in
which they appear in a script. We can control this order of execution
using *flow control* statements. The for loop is a type of flow control statement that
allows us to execute a set of commands multiple times. For example, in
the following code fragment, the statement fprintf('Hello, World\n') gets executed 10 times,
even though it only appears once in the code fragment.

for i = 1:10, fprintf('Hello, World! This is iteration %d\n',i); end

Hello, World! This is iteration 1 Hello, World! This is iteration 2 Hello, World! This is iteration 3 Hello, World! This is iteration 4 Hello, World! This is iteration 5 Hello, World! This is iteration 6 Hello, World! This is iteration 7 Hello, World! This is iteration 8 Hello, World! This is iteration 9 Hello, World! This is iteration 10

Back to the top

## The anatomy of the 'for' loop

The for loop has three basic components :
the enclosing keywords for and end which enclose the set of statements to be
carried out multiple times by the loop (the statement
fprintf('Hello, World\n'),
in the above example), a *loop index* which is
the variable that stores the current value of the loop counter (i in the above example), and an *index array*
containing the range of values over which the loop index should vary (the
array 1:10 in the above example).
See below for the "Anatomy of a "for" loop"

Anatomy of a for loop

The number of times the loop executes the statements enclosed by the for and end is determined by the length of the array describing the loop range. Consider each of the following examples :

% Example 1 for i = 0:5:10, fprintf('Three brown bears; i = %2d\n',i); end

Three brown bears; i = 0 Three brown bears; i = 5 Three brown bears; i = 10

% Example 2 for x = [3.1 5.6], fprintf('A couple of ducks; x = %4.1f\n',x); end

A couple of ducks; x = 3.1 A couple of ducks; x = 5.6

% Example 3 for j = 10:-2:0, fprintf('Six Simple Simons sitting on a stump; j = %2d\n',j); end

Six Simple Simons sitting on a stump; j = 10 Six Simple Simons sitting on a stump; j = 8 Six Simple Simons sitting on a stump; j = 6 Six Simple Simons sitting on a stump; j = 4 Six Simple Simons sitting on a stump; j = 2 Six Simple Simons sitting on a stump; j = 0

% Example 4 for j = 1:-1:10, fprintf('I am being ignored (:-((\n'); end

In each case, the statement enclosed by for loop was executed once for each entry in the loop index array. In the last example, the loop index array is empty, and so the enclosed statement did not get executed at all.

Back to the top

## The 'for' loop - using the loop index variable

In most cases, the statements enclosed by the for loop will involve the value of the loop index variable. Each of the following loop examples illustrates how we can make use of the loop index variable.

`clear all;`

% Example 1 - Print out the value of the loop index for i = 0:2:20, fprintf('i = %d\n',i); end

i = 0 i = 2 i = 4 i = 6 i = 8 i = 10 i = 12 i = 14 i = 16 i = 18 i = 20

% Example 2 - Print out the entries in an array 'x', in reverse order. x = rand(1,10); for k = 10:-1:1, fprintf('x(%2d) = %8.4f\n',k, x(k)); end

x(10) = 0.5785 x( 9) = 0.4886 x( 8) = 0.7303 x( 7) = 0.9289 x( 6) = 0.0292 x( 5) = 0.8010 x( 4) = 0.2625 x( 3) = 0.0855 x( 2) = 0.5079 x( 1) = 0.4242

Example 3 - Fill in entries in an array 'y' and print each value

for j = 1:8, y(j) = sin(pi*(j-1)/2); fprintf('y(%d) = %16.8f\n',j,y(j)); end

y(1) = 0.00000000 y(2) = 1.00000000 y(3) = 0.00000000 y(4) = -1.00000000 y(5) = -0.00000000 y(6) = 1.00000000 y(7) = 0.00000000 y(8) = -1.00000000

% Example 4 - Cumulative sums of the integers 1 through 10. s = 0; for k = 1:10, s = s + k; fprintf('Sum of the numbers 1 to %2d : %5d\n',k, s); end

Sum of the numbers 1 to 1 : 1 Sum of the numbers 1 to 2 : 3 Sum of the numbers 1 to 3 : 6 Sum of the numbers 1 to 4 : 10 Sum of the numbers 1 to 5 : 15 Sum of the numbers 1 to 6 : 21 Sum of the numbers 1 to 7 : 28 Sum of the numbers 1 to 8 : 36 Sum of the numbers 1 to 9 : 45 Sum of the numbers 1 to 10 : 55

In all of the above examples, the loop index is an integer. This is by far the most common loop index array for the for loop. However, there is nothing in Matlab to prevent us from trying the following unusual (and not particularly recommended) ways to use the loop index.

% Example 5 - A confusing example in which 'x' is an array and 'y' takes on % different values in the array 'x'. x = linspace(-1,1,7); for y = x, fprintf('y = %f\n',y); end

y = -1.000000 y = -0.666667 y = -0.333333 y = 0.000000 y = 0.333333 y = 0.666667 y = 1.000000

% Example 6 - Let's see what we can do with strings. for c = ['Hello', 'Goodbye','See Ya!'], fprintf('%s',c); end

HelloGoodbyeSee Ya!

In the first case, the loop index array x is an
array containing non-integer values, but the loop index y still takes on each value, and the print statement
is executed the expected number of times, e.g. one time for each entry in
x.

The second example is less familar, but only because we have not worked
with strings much. Here, the loop in index is the array of characters

s = ['Hello', 'Goodbye','See Ya!']

s = HelloGoodbyeSee Ya!

We can index into this array in exactly the same way as with numeric data. For example,

s(1:10)

ans = HelloGoodb

We can also use the length function to get the length of s. This length tells us the number of times the statements in the for will be executed.

length(s)

ans = 19

So in this case as well, the for loop above is behaving exactly as expected. Notice that we did not put a new line character into the fprintf statement in the the loop. If we had, our output for the odd 'string' loop would look like the following. We have added a loop counter here as well to see that the in fact, the number of times that the code inside the loop is called is equal to the length of the loop index array. In this case, the variable k acts like the loop index variable and is incremented by 1 each time the code in the loop is executed.

% add a new line character to the fprintf statement. k = 1; for c = ['Hello', 'Goodbye','See Ya!'], fprintf('%2d %s\n',k,c); k = k + 1; end

1 H 2 e 3 l 4 l 5 o 6 G 7 o 8 o 9 d 10 b 11 y 12 e 13 S 14 e 15 e 16 17 Y 18 a 19 !

A final, entertaining example involves the use of a "cell" array. We will not discuss cell arrays in detail now, but suppose you really wanted to loop over a list of words. The following syntax will allow you to do this:

for word = {'Howdy', 'Later', 'Cheerio'}, fprintf('%s\n',word{:}); end fprintf('The last word is ''%s''\n',word{:});

Howdy Later Cheerio The last word is 'Cheerio'

As this example illustrates, the value of the loop index after we have completed the loop is the last value in the loop index array.

Back to the top

## Rules for using the 'for' loop

Here are some basic principles to follow when using the for loop.

- The for loop may enclose multiple Matlab statements,
- The number of times that enclosed statements get executed is equal to the length of the loop index array,
- The loop index variable may be used by the enclosed statements,
- One for loop may be nested inside of one another loop. Statements in the inner for loops may use the loop index variable from the outer loop.
- Loop index arrays most commonly contain integer values. Loop indices are often named i, j, k, m or n. Avoid the use of variable names x, y, z or w for loop indices.

Back to the top

## When to vectorize?

Often in Matlab, loops can be avoided by *vectorizing* the
statements inside. In the following examples, a for loop can easily be replaced with a single
of vectorized code. Notice that the print statements have also been
vectorized.

Example

% for-loop : y = 10*x + 1 x = rand(1,5); y = zeros(size(x)); % Avoid warnings! for i = 1:5, y(i) = 10*x(i) + 1; fprintf('x(%d) = %8.4f; y(%d) = %8.4f\n',i,x(i),i,y(i)); end

x(1) = 0.2373; y(1) = 3.3728 x(2) = 0.4588; y(2) = 5.5885 x(3) = 0.9631; y(3) = 10.6309 x(4) = 0.5468; y(4) = 6.4681 x(5) = 0.5211; y(5) = 6.2114

% Vectorized equivalent (preferable!) y = 10*x + 1; % Vectorized print statement fprintf('x(%d) = %8.4f; y(%d) = %8.4f\n',[1:5; x; 1:5; y]);

x(1) = 0.2373; y(1) = 3.3728 x(2) = 0.4588; y(2) = 5.5885 x(3) = 0.9631; y(3) = 10.6309 x(4) = 0.5468; y(4) = 6.4681 x(5) = 0.5211; y(5) = 6.2114

Example

% for-loop : y = sin(pi*x/4) over [0,2*pi] for j = 1:9, y(j) = sin(pi*(j-1)/4); fprintf('y(%d) = %16.8f\n',j,y(j)); end

y(1) = 0.00000000 y(2) = 0.70710678 y(3) = 1.00000000 y(4) = 0.70710678 y(5) = 0.00000000 y(6) = -0.70710678 y(7) = -1.00000000 y(8) = -0.70710678 y(9) = -0.00000000

% vectorized equivalent (preferable!) y = sin(pi*((0:8)/4)); % Parenthesis around (0:8) are important here! % Vectorized print statement fprintf('y(%d) = %16.8f\n',[1:9; y]);

y(1) = 0.00000000 y(2) = 0.70710678 y(3) = 1.00000000 y(4) = 0.70710678 y(5) = 0.00000000 y(6) = -0.70710678 y(7) = -1.00000000 y(8) = -0.70710678 y(9) = -0.00000000

Example

% for-loop : Cumulative summation s = 0; y = zeros(1,10); for k = 1:10, s = s + k; y(k) = s; fprintf('Sum of the numbers 1 to %2d : %5d\n',k, y(k)); end

Sum of the numbers 1 to 1 : 1 Sum of the numbers 1 to 2 : 3 Sum of the numbers 1 to 3 : 6 Sum of the numbers 1 to 4 : 10 Sum of the numbers 1 to 5 : 15 Sum of the numbers 1 to 6 : 21 Sum of the numbers 1 to 7 : 28 Sum of the numbers 1 to 8 : 36 Sum of the numbers 1 to 9 : 45 Sum of the numbers 1 to 10 : 55

% vectorized equivalent y = cumsum(1:10); % Vectorized print statement fprintf('Sum of the numbers 1 to %2d : %5d\n',[1:10; y]);

Sum of the numbers 1 to 1 : 1 Sum of the numbers 1 to 2 : 3 Sum of the numbers 1 to 3 : 6 Sum of the numbers 1 to 4 : 10 Sum of the numbers 1 to 5 : 15 Sum of the numbers 1 to 6 : 21 Sum of the numbers 1 to 7 : 28 Sum of the numbers 1 to 8 : 36 Sum of the numbers 1 to 9 : 45 Sum of the numbers 1 to 10 : 55

Example

Sometimes, vectorization will be many times faster than an equivalent
loop. For example,

N = 1e7; th = linspace(0,2*pi,N); tic for i = 1:N, y(i) = sin(th(i)); end t1 = toc;

% Vectorized statement tic y = sin(th); t2 = toc; fprintf('Time in loop : %8.4f\n',t1); fprintf('Time in vectorized statement : %8.4f\n',t2); fprintf('The vectorized statement is %6.2f times faster\n',t1/t2);

Time in loop : 9.8038 Time in vectorized statement : 0.0539 The vectorized statement is 181.87 times faster

There are many more examples of the above in which a vectorized statement is far preferable to using a loop.

Back to the top

## Advanced vectorization example

While many common mathematical statements can be easily vectorized (and should be!) some complex programming tasks are not so obviously vectorizable. Below is an example of a programming task that is sufficiently complex, that one is tempted to leave it in a loop. Inside the loop, we are still using array vectorization, but there does not seem to be an easy way to vectorize the outer loop. As we will see, however, an advanced use of vectorization allows the computation to be done without any loops, which ultimately leads to a faster version of the code.

% ------------------------------------------------------------------- % Compute the minimum and maximum distance between all possible pairs of % points in a set of points (x(i),y(i), i = 1,...n. % ------------------------------------------------------------------- n = 15; x = rand(1,n); % x-coordinates, chosen at random from [0,1] y = rand(1,n); % y-coordinates, chosen at random from [0,1] tic; dmax = 0; dmin = 100; for i = 1:n, % Compute the distance between the point (x(i),y(i)) and the % array of points (x,y). first, remove x(i),y(i) from % list (so the minimum isn't just 0!). x1 = x; y1 = y; x1(i) = []; % Remove x(i) from list y1(i) = []; % Remove y(i) from list % This is a vectorized statement. d = sqrt((x(i) - x1).^2 + (y(i) - y1).^2); % Find the maximum value in the array [d dmax] dmax = max([d dmax]); % Find the minimum value in the array [d dmax] dmin = min([d dmin]); end t_loop = toc; fprintf('Elapsed time for loop version %8.4e\n',t_loop); for i = 1:n % Plot the line connecting the points (x(i),y(i)) each point in the % array (x,y). % This loop is "nested" inside of our outer loop. While we could % vectorize this loop, it might not be so easy to read, and probably % doesn't save us much time. for j = 1:n, plot([x(i) x(j)],[y(i),y(j)],'b-','linewidth',2); hold on; end end fprintf('The minimum distance is %8.4f\n',dmin); fprintf('The maximum distance is %8.4f\n',dmax); % Plot a symbol at each point and add a title and axes labels. plot(x,y,'r.','markersize',30,'linewidth',2); set(gca,'fontsize',16,'fontweight','bold') title('Point cloud'); xlabel('x-coordinate','fontsize',16); ylabel('y-coordinate','fontsize',16); axis([0 1 0 1]); % Fix aspect ratio so the plot is square. axis square;

Elapsed time for loop version 1.1545e-03 The minimum distance is 0.0475 The maximum distance is 1.0624

We can vectorize the part of the code that computes the minimum distance. with the following code

fprintf('Vectorized version\n'); tic; e = ones(n,1); % Main part of the code dist = sqrt((e*x-(e*x).').^2 + (e*y-(e*y).').^2); dist = dist + diag(nan*e); dmax = max(dist(:)); dmin = min(dist(:)); t_vec = toc; fprintf('Elapsed time in vectorized version : %8.4e\n',t_vec); fprintf(['Vectorized version is about %4.0f%% faster \n',... 'than the non-vectorized version\n'],100*(t_loop-t_vec)/t_loop); fprintf('The minimum distance is %8.4f\n',dmin); fprintf('The maximum distance is %8.4f\n',dmax);

Vectorized version Elapsed time in vectorized version : 4.5871e-03 Vectorized version is about -297% faster than the non-vectorized version The minimum distance is 0.0475 The maximum distance is 1.0624

Note : Timing results from Publish (used to produce this webpage) are not truly reflective of actual timing results, but relative timings for vectorized verses non-vectorized codes should be approximately correct.

Back to the top

## Lab exercises

- Using a single Matlab function
- Using a for loop

Put all of your commands into a script containing your solution to each problem. To start, first create an array $x$ of 100 random values using the rand function. For example,

x = rand(100,1);You will use this array for each of the exercises.

**Note:**In most cases, it will be preferable to use the single Matlab command than the for loop!.

- $\displaystyle{\sum_{k=1}^{n} x_k}$
- $\displaystyle{\min_{1 \le k \le n} x_k}$
- $\displaystyle{\frac{1}{n}\sum_{k=1}^n {x_k}}$
- $\displaystyle{y_j = \prod_{k=1}^j {x_k}}$, for $j = 1,2,...,n$
- $\displaystyle{\sqrt{\frac{1}{n-1}\sum_{k=1}^n (x_k - \mu)^2}}$, where $\displaystyle{\mu = \frac{1}{n}\sum_{k=1}^n x_k}$
- $\displaystyle{n}$
- Find the value $\sigma$ in $x$ such that half of the values $x_k$ are less than $\sigma$ and half are greater than $\sigma$.
- $\displaystyle{\max_{1 \le k \le n} x_k}$
- $\displaystyle{y_j = \sum_{k=1}^j {x_k}}$ for $j = 1,2,...,n$
- $\displaystyle{\prod_{k=1}^{n} x_k}$

- $$\cos(x) = \sum_{n=0}^{\infty}\frac{(-1)^{n}x^{2n}}{(2n)!}$$ at $x=5.4$.
- $$\exp(x) = \sum_{n=0}^{\infty} \frac{x^n}{n!}$$ at $x=0.2$.
- $$\ln(1+x) = \sum_{n=0}^{\infty} \frac{(-1)^{n-1}x^n}{n}$$ at $x=-0.5$.

% Example : Problem 1 below can be computing using the 'sum' function % and a 'for' loop. n = 100; x = rand(1,n); s = 0; for i = 1:n, s = s + x(i); end fprintf('Result from ''sum'' function : %24.16f\n',sum(x)); fprintf('Result from the ''for'' loop : %24.16f\n',s);

Result from 'sum' function : 48.9455387473140036 Result from the 'for' loop : 48.9455387473140036

Compare your answers with the solutions.

Back to the top

## Get the code

Do you want to try the above code fragments on your own? Download the Matlab script that produces this page here. (lab_17.m)

Published with MATLAB® 8.5