Back to Main Page

Adding rules: Logic, flow control and loops

Dr Lincoln Colling

ljc65@cam.ac.uk

http://pbs2.mindsci.net

Lecture 2


Functions


Functions

  • In addition to storing information in variables me might also want to do things to that information
  • To process information we need functions
  • Functions take inputs and (usually) produce outputs
  • Functions work like mathematical functions, e.g., y = x2

if x = 2 then y =4

  • They’re just self-contained bits of code with rules for transforming the information

Some examples of functions

  • At the very start we introduced a couple of functions: they help function and the doc
  • The help function takes 1 input (the name of another function) and produced an output (a print out of some information about that function)
help sin % get help on the sin() function
help('sin') % same as above but more explicitly

>> help('sin')
 sin    Sine of argument in radians.
    sin(X) is the sine of the elements of X.
 
    See also asin, sind.

    Reference page for sin
    Other functions named sin

>> 

Some more functions…

  • Notice that when we called the help function we didn’t input a variable for where to put the output. That’s because the output just printed to the CommandWindow. The disp function in our first script does the same…
  • With other functions, we might want to store the output in a variable. The num2str() function is like this
>> number = 1;
>> string = num2str(1);
>> string

string =

    '1'

>> 

Specifying multiple inputs

  • Functions can take any arbitrary number of inputs.
  • Inputs are just separated with , in between the (/)
>> x = rand(10,1);
>> y = rand(10,1);
>> corr(x,y)

ans =

   -0.0341

Specifying multiple outputs

  • Functions can also produce any arbitrary number of outputs
  • To specify multiple outputs we put them inside [/] separated with a space or ,
>> x = [5 6 1 4];
>> [value, index] = min(x);
>> value

value =

     1

>> index

index =

     3

Note: Sometimes you might want your function to do different things depending on how many inputs or outputs it receives. At home explore the nargin() and nargout() functions. Type doc nargin and doc nargout to do this


Understanding our first script… again


OurFirstScript.m

% A simple script
name = input('What is your name? ','s'); % ask your name
disp(['Hello ' name '! Pleased to meet you']); % say hello
  1. A comment that tells us what the script does
  2. Call to the input() function with two inputs—two string inputs—and an output
    • input 1 is displayed at the CommandWindow when the function is run
    • input 2 tells the function to store the output as a string
    • the output is stored in the variable called name
  3. Call to the disp() function with one input—three strings joined together

Writing your own functions


Why write functions?

  • Functions are the most import bits of code you’ll write
  • The key to their usefulness is that they’re reusable. That is, me might write 1 function and then re-use it in 100s of different scripts

Our first function

Lets write a function that works out a mean

function meanValue = OurMeanFunc(inputVector) 

    % return the mean of some inputs

    numberOfItems = length(inputVector) % how long is the vector
    sumOfItems = sum(inputVector) % add all the numbers together

    meanValue = sumOfItems / numberOfItems % work out a mean

Our second function

Lets output a couple more values

function [meanValue,minValue,maxValue] = DescStats(inputVector) 

    % return the mean of some inputs, the minimum value, and the maximum value
    
    numberOfItems = length(inputVector) % how long is the vector
    sumOfItems = sum(inputVector) % add all the numbers together
    
    meanValue = sumOfItems / numberOfItems % work out a mean
    minValue = min(inputVector) % get the minimum value
    maxValue = max(inputVector) % get the maximum value

Variable scope

  • All variables have a scope
  • Variables are only available within their scope
  • Variables used within a script are available to any script that is run after it
  • Variable used within a function are only available within that function

Scope in scripts

Script1.m

A = 1; % set A to 1
B = 2; % set B to 2
C = A + B; % Add A and B and store it as C

Script2.m

dips(num2str(C * 2)) % multiply C x 2, convert to string and display

If we run Script1 and then Script2 we’ll see ‘4’ printed out


Scope in functions

Function1.m
function [] = Function1()
% This function takes no inputs and produces no output
% But it contains the same code as Script1.m

    A = 1;
    B = 2;
    C = A + B;
  • None of the variables used in the function are available anywhere else other than inside Function1
    • To access them we must set them as outputs
  • Running Function1 and then Script2 will produce an error

Note: You can explicitly ask Matlab to make some variables available everywhere. You can do this using the global command. But often there are better ways to reuse common variables between functions (e.g., by organising commonly used variables in a structure that is defined as an input and output for all functions in a set of related functions). Using global can often lead to problems so its best to avoid it if possible.


Logic

  • The core of many programs can be broken down into a series of yes/no or true/false questions
  • Matlab has a few different ways of asking true/false questions depending on the data type (e.g., numbers, letters) you’re dealing with
    • The operators ==, ~=, >, <, <=, and >= for integers and doubles
    • The functions strcmp() and strcmpi() for string
    • The ismember() function for cell arrays

Logic with numbers

The simplest question we can ask is whether two variables are equal. For this we use ==
aNumber = 89 % set aNumber to 89
bNumber = aNumber % set bNumber to the same as aNumber
aNumber == bNumber % returns 1 or TRUE

bNumber = aNumber - 1 % change bNumber to 1 less than aNumber
aNumber == bNumber % returns 0 or FALSE
But we can also ask slightly more complex questions
aNumber > bNumber % returns 1 or TRUE
aNumber < bNumber % return 0 or FALSE

aNumber ~= bNumber % returns 1 or TRUE

Logic with vectors

In the previous examples we just used single numbers but we can do the same on a vector of number
aVector = [1 5 6 8 0]
aVector >= 5 % returns: [0 1 1 1 0]
We can use the output as a filter
% return all the values in aVector that are greater than or equal to 5
aVector(aVector >= 5) % returns: [5 6 8]

% return the locations of the values in aVector that are greater than or equal to 5
find(aVector >= 5) % returns: [2 3 4]

Logical operators

  • Sometimes we might want to string together several questions. To do this we can use logical operators
    • && means AND
    • || means OR
    • ~ means NOT

Testing multiple conditions

% set some values
x = 10; y = 5; 

(x > 1) && (y > 1) % returns 1 
(x > 1) && (y < 1) % returns 0

(x < 6) || (y < 6) % returns 1

(x > 0) % returns 1
~(x > 0) % returns 0

Comparing strings

  • strings work a little differently to comparing numbers
  • instead of == you use either the strcmp() or strcmpi() functions
aString = 'Lincoln'
bString = 'John'

% aString == bString would returns an error 
strcmp(aString,bString) % returns 0

bString = 'lincoln'
strcmp(aString,bString) % returns 0

strcmpi(aString,bString) % ignore case, returns 1

Flow control

  • Flow control allows your code to take different paths depending whether certain conditions are met
  • Their basic form can be thought of as IF A THEN B rules
  • In Matlab we use the if statement
birthyear = 1998
if birthyear <  1999
    disp('You are old enough to buy beer')
end % notice that we put end when we've finished the rule

  • You can also use else to specify what to do if the condition isn’t met
  • You can use any conditional that can return a TRUE or a FALSE
if birthyear < 1999
    disp('You are old enough to buy beer')
else
    disp('You are not old enough to buy beer!')
end
if birthyear < 1999
    disp('You are old enough to buy beer')
elseif birthyear == 2000 
    disp('You might be old enough to buy beer')
else 
    disp('You are not old enough to buy beer!)
end
% some examples of conditionals you can use
x < n
x > n && b == y
strcmp(aString,'name')

Nested if statements

  • You can also nest if statements inside other if statements for more complex flow control
  • But be careful, because it can get difficult to read, so it might be better to break down the problem into a set of functions
if a == 5
    if x < 10
        %do something 
    elseif x > 10 
        %do something else
    end
end

switch and case

  • When you have many conditions that need to be checked you can string together several if, elseif, and else statements or you can use switch and case
n = 10 % set n to a number

switch n 
    case 1
        disp('one')
    case 2
        disp('two')
    otherwise 
        disp('I can only count to two')
end

  • switch and case also works with strings the same way they work with numbers
n = 'one'

switch n
    case 'one'
        disp('1')
    case 'two'
        disp('2')
    case {'three','four'}
        disp('more than 2 less than 5')
end

Loops

  • Sometimes you might want to run a bit of code many times
    • For example, you might want to apply a function to a series of numbers
    • Or some code that presents a stimulus and collects responses for n trials
  • Do to this, we can use a loop. And we can use different types of loops depending on the nature of our problem.

The for loop

  • The simplest type of loop is the for loop
  • If we pass a range of values (e.g., a vector or cell array) to a for statement then one value of that range will be available on each iteration of the loop
for i = 1 : 10
    disp(num2str(i))
end
for n = {'one','two','three'}
    disp(n)
end

The while loop

  • for loops loop over some series of values
  • while loops, other the hand, loop continuously until some condition is met
x = 1
y = 0
while y < 100
    y = x^2
    disp(['x squared is ' num2str(y)])
    x = x + 1
end 
while ~feof(fid)
    fgetl(fid)
end

Vectorising code

  • An alternative you using a loop is to pass a range of values to a function and get a range of values back
y = [] 
for x = 1 : 5
    y(x) = log10(x)
end
x = 1:5
y = log10(x)

The cellfun/arrayfun approach

y = 1 : 5
arrayfun(@(x) log(x),y)

y = {'1','2','3','4','5'}
cellfun(@(x) str2num(x), y)

y = {'a','1','2','3','4','5'}
cellfun(@(x) str2num(x), y) 
function y = word2number(x)
    switch x
        case 'one'
            y = 1
        case 'two'
            y = 2
        otherwise
            y = 'I can not count that high'
    end
y = {'one','two','three'}
cellfun(@(x) word2number(x), y) % produces an error because the output is a mix of numbers and strings

cellfun(@(x) word2number(x), y,'UniformOutput',false) % tell matlab that the output won't be uniform and that it must package each output in a cell instead of outputting a vector