Notes 02: Arrays in MATLAB


Scalars

Most data in MATLAB is formally represented as an array (a.k.a. matrix). For example, a scalar value (e.g., 5) is formally a 1-by-1 array. By default, all numeric values are represented with double-precision floating point format.

age = 39;
gravity = 9.8;              % meters/second^2
speedOfLight = 2.9979e8;    % meters/second

Predefined constants

variable value
pi π
i
j
square root of -1
Inf infinity (e.g., 1/0)
NaN "not a number" (e.g., 0/0)

Note: The standard mathematical value e (the base of the natural log) is not a predefined constant. However, there is a predefined function exp(x) that calculates the value ex. So the constant e can be computed using the syntax exp(1), as that calculates e1.

Common scalar operators

Arithmetic operators, ordered from lowest to highest precedence (with ties broken left-to-right)
syntax semantics
a + b
a - b
addition
subtraction
a * b
a / b
a \ b
multiplication
a divided by b
b divided by a (equivalent to b / a)
-a unary negation
a ^ b exponentiation (ab)

Relational operators
syntax semantics
< less than
<= less than or equal to
> greater than
>= greater than or equal to
== equal to
~= not equal to

Common mathematical functions

syntax semantics
sqrt(x) square root of x
abs(x) absolute value of x
factorial(x) x! = 1 * 2 * ... * x
mod(x,n) returns remainder of x divided by n
exp(x) ex
log(x) natural logarithm of x
log10(x) base 10 logarithm of x
log2(x) base 2 logarithm of x
forms of rounding
round(x) returns nearest integer to x
fix(x) truncates fractional part of x
ceil(x) returns smallest integer that is greater than or equal to x
floor(x) returns greatest integer that is less than or equal to x
trigonometry
sin(x) sine of x (measured in radians)
cos(x) cosine of x (measured in radians)
tan(x) tangent of x (measured in radians)
sind(x)
cosd(x)
tand(x)
similar as above, but with x measured in degrees
floating point
eps distance between 1.0 and the next floating point number
eps(x) distance between x and other floating point numbers of equal precision. See "help eps" to see commonly used values

Vectors

Many applications rely upon one-dimensional data sets. As a special case of an array, we will term such a structure a "vector".

Creating vectors

There are several convenient ways to create a vector.

Indexing vectors

Individual elements of a vector can be accessed using indices, numbered from v1, v2, ... vlength(v). As an example,

v = [6 3 1 0 2];
v(1);                % the value 6
v(5);                % the value 2
v(length(v));        % a more general form for v(5)
v(end);              % even more convenient syntax

Indexing can also be used to change the contents of a vector. Using our previous example,

v(2) = 17;           % v now has data [6 17 1 0 2];
v(end) = -4;         % v now has data [6 17 1 0 -4];

Note well, it is illegal to use an index less than 1. However, if you use an index that is greater than the current length, the vector will automatically be padded with zeros to extend to the new element.

v(8) = 32;           % v now has data [6 17 1 0 2 0 0 32];

We can effectively delete an element by setting it to an empty subvector.

v(2) = [];           % 17 removed; v now has data [6 1 0 2 0 0 32];

We can succinctly express multiple indices by using another vector as an index.

v = primes(25);      % results in [2 3 5 7 11 13 17 19 23]
v([3 8]);            % evaluates to result [5 19]
v(4:7);              % evaluates to result [7 11 13 17]
v(1:2:end);          % evaluates to result [2 5 11 17 23]
v(4:7) = [1 2 3 4];  % v is now [2 3 5 1 2 3 4 19 23]
v(1:2:end) = 0       % v is now [0 3 0 1 0 3 0 19 0]
v(1:2:end) = []      % v is now [3 1 3 19]

Vector operations

MATLAB allows us to batch calculations on vector elements. Let's use addition as an example. There are two forms we wish to consider. The first is vector + scalar. This produces a new vector by adding the scalar to each individual element of the given vector.
v = 10:15;           % results in [ 10  11  12  13  14  15]
v + 8;               % results in [ 18  19  20  21  22  23]
v - 8;               % results in [  2   3   4   5   6   7]
8 - v;               % results in [ -2  -3  -4  -5  -6  -7]
-v;                  % results in [-10 -11 -12 -13 -14 -15]
We can similarly perform multiplications, divisions, and exponentation involving a vector and a scalar. However, we wish to introduce new forms of those operators that are preceeded by a period, for example using .* for multiplication (we will revisit the "undotted" form of those operators when we discuss matrix operations).
v = 1:4;             % results in [1      2      3      4    ]
v .* 8;              % results in [8     16     24     32    ]
v ./ 8;              % results in [0.125  0.250  0.375  0.500]
8 ./ v;              % results in [8.000  4.000  2.667  2.000]
3 .^ v;              % results in [3      9     27     81    ]
v .^ 3;              % results in [1      8     27     64    ]

These same operators can be used to perform element-by-element arithmetic on two vectors, so long as the two vectors have the same length.

u = 9:-2:3;          % results in [ 9      7      5      3    ]
v = 1:4;             % results in [ 1      2      3      4    ]
u + v;               % results in [10      9      8      7    ]
u - v;               % results in [ 8      5      2     -1    ]
u .* v;              % results in [ 9     14     15     12    ]
u ./ v;              % results in [ 9.00   3.50   1.67   0.75 ]
u .^ v;              % results in [ 9     49    125     81    ]

You can concatenate two vectors by building a new vector as a literal as follows.

u = 9:-2:5;          % results in [ 9  7  5 ]
v = 1:4;             % results in [ 1  2  3  4 ]
w = [u v];           % results in [ 9  7  5  1  2  3  4 ]
In fact, a standard literal such as [2 3 5] is technically the concatenation of three single-element vectors. Notice as well that when concatenating, the lengths of the vectors do not need to be the same.

Applying scalar functions

When discussing scalars, we introduced many common functions such as sqrt. Many of MATLAB's built-in scalar functions can be applied en masse to a vector of numbers, in which case they are evaluated on an element-by-element basis.

v = 1:4;          % results in [ 1      2      3      4      ]
sqrt(v);          % results in [ 1.0000 1.4142 1.7321 2.0000 ]

In the context of scalars, we also introduced relational operators, such as <. When working with scalars, an expression such as x < y will result in a logical value of either true or false. These operators can also be applied between a vector and a scalar, or between two equal length vectors. The result will be a vector of logical values.

u = 9:-2:3;          % results in [    9      7      5      3 ]
v = 1:4;             % results in [    1      2      3      4 ]
u > 6;               % results in [ true   true  false  false ]
u <= v;              % results in [false  false  false   true ]

Special vector functions

Although most functions, when applied to a vector, operator on an element-by-element basis, there are several functions that are specially defined for use with vectors.

The length function returns the length of the vector (and more generally, the largest dimension of an array).

v = 10:15;           % results in [ 10  11  12  13  14  15]
length(v);           % returns 6

A closely related function is size. Rather than return a single number, this method returns a vector giving the size of each dimension of a vector. Since the vectors we have considered are technically 1-by-n arrays, we observe the following.

v = 10:15;           % results in [ 10  11  12  13  14  15]
size(v);             % returns the vector [1 6]

Various statistical measures can be computed on a vector of numbers.

u = [ 17 28 4 18 20 35 12 ];
sum(u);                         % returns 134
mean(u);                        % returns 19.143
min(u);                         % returns 4
max(u);                         % returns 35
u = [ 17 28 4 18 20 35 12 ];
[val pos] = max(u);        % val is 35, pos is 6

A reversed image of a vector can be created by performing a left-to-right flip.

u = [ 35 20 18 4 28 17];
v = fliplr(u);              % produces [ 17 28 4 18 20 35 ]
                            % note that u is still [ 35 20 18 4 28 17]

A sorted image of a vector can be created by performing as follows

u = [ 35 20 18 4 28 17];
v = sort(u);                % produces [ 4 17 28 20 28 35 ]
                            % note that u is still [ 35 20 18 4 28 17]

The find function returns the set of indices at which non-zero values are found.

v = [ 0 0 1 0 1 1 0];
find(v);                    % returns [3 5 6]

When applied to a logical vector, true entries are treated as non-zero. It is common to combine find with a relational operator as in the following example

v = [ 35 20 18 4 28 17];
find(v lt; 25);             % returns [ 2 3 4 6 ]

Two-Dimensional Arrays

The vectors we have seen thus far are one-dimensional in nature. However, they are really special cases of matlab two-dimensional arrays that happen to have one dimension equal to 1.

Creating Arrays

The zeros and ones functions that we used for creating vectors are more general. Earlier we gave the example

>> v = ones(1,6)
v =
      1  1  1  1  1  1
The two parameters to that function call specify respectively the number of rows and number of columns. So we could have produced a column vector with the call
>> v = ones(6,1)
v =
      1
      1
      1
      1
      1
      1
or more generally a two-dimensional array with 4 rows and 2 columns
>> m = ones(4,2)
m =
     1     1
     1     1
     1     1
     1     1

It is also possible to create two-dimensional arrays using a literal form similar to that which we used for row-vectors (e.g., [1 8 -5 3]). When using this syntax, a semicolon is used to designate the end of a row.

>> m = [1 8 -5 3; 2 -3 0 4]
m =
     1     8    -5     3
     2    -3     0     4
When using such a syntax, you are required to ensure that each row has the same number of entries. Violating this condition results in an error.
>> m = [1 8 -5 3; 2 -3 0 4 5]
??? Error using ==> vertcat
CAT arguments dimensions are not consistent.

Much as we could concatenate vectors to make a larger vector, we can concatenate arrays to make a larger array, so long as the aligned dimensions agree. Here is an example of a horizontal concatenation of arrays.

>> m = [ zeros(3,2) ones(3,4) ]
m =
     0     0     1     1     1     1
     0     0     1     1     1     1
     0     0     1     1     1     1
and here is a vertical concatenation
>> m = [ zeros(2,5); ones(3,5) ]      % note the use of semicolon
m =
     0     0     0     0     0
     0     0     0     0     0
     1     1     1     1     1
     1     1     1     1     1
     1     1     1     1     1

Indexing arrays

For a two-dimensional array, you may access a single entry by using a (row,column) pair as an index. Consider the following example

>> m = magic(4)      % a so-called "magic" square
m =
    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1
For this example, m(2,3) is 10 as that is the second row, third column. Entry m(1,4) is 13 as that is the first row, fourth column.

It is also possible to access one-dimensional or two-dimensional slices of an array, for example by using the "colon" notation for one or both index parameters. Continuing with the magic square above,

>> m(3:4, 2)          % rows 3 and 4, column 2
ans =
     7
    14
>> m(4, 1:2:3)        % row 4,  columns 1 and 3
ans =
     4    15
>> m(1:2, 3:4)        % rows 1 and 2, columns 3 and 4
ans =
     3    13
    10     8

Array operations

We already introduced the size(m) function earlier. It returns a vector of length two, designating [ numRows numColumns ]

The contents of a matrix can be flipped along several axes of symmetry. A left-to-right flip can be computed with fliplr as in the following example with the earlier magic square.

>> fliplr(m)
ans =
    13     3     2    16
     8    10    11     5
    12     6     7     9
     1    15    14     4
An top-to-bottom flip can be accomplished with flipud (i.e., up/down)
>> flipud(m)
ans =
     4    14    15     1
     9     7     6    12
     5    11    10     8
    16     2     3    13
The transpose (a flip across the main diagonal) can be computed with the ' operator.
>> m'
ans =
    16     5     9     4
     2    11     7    14
     3    10     6    15
    13     8    12     1
Notice that transposes can also be useful for converting between row-vectors and column vectors, as in
>> 1:5
ans =
     1     2     3     4     5

>> (1:5)'
ans =
     1
     2
     3
     4
     5

Matrix operations

Arrays can be used as a storage mechanism for many purposes. When using them for the mathematical abstraction of a matrix, MATLAB offers many specialized operations.

As an example, let's explore the distinction between the operators .* and *. The dotted version is an element-by-element operation. Consider the following example

>> A = [1 2; 3 4]
A =
     1     2
     3     4

>> B = [5 6; 7 8]
B =
     5     6
     7     8

>> A .* B
ans =
     5    12
    21    32

>> A * B
ans =
    19    22
    43    50
In the case of A .* B, each entry of the result is the product of the corresponding elements of A and B. For example, ans(1,1) is 5 because that is A(1,1) * B(1,1).

In the case of the true matrix multiplication, A * B , entry ans(1,1) is 19 as is computed as A(1,1) * B(1,1) + A(1,2) * B(2,1). More generally, ans(r,c) is computed as the mathematical dot product of row r of A and column c of B.

There are many additional functions to aide when working with mathematical matrices. For example, the syntax eye(n) produces an n-by-n matrix with ones along the diagonal and zeros elsewhere. A square matrix with some other diagonal can be computed using a syntax such as diag([5 8 -2 0 1]), producing the result

     5     0     0     0     0
     0     8     0     0     0
     0     0    -2     0     0
     0     0     0     0     0
     0     0     0     0     1
The diag can also be called with an existing matrix as the parameter, in which case the result is a vector representing the entires along the diagonal.

For serious linear algebra, there is far more support in MATLAB. It is possible to compute matrix inverses, eigenvalues, to solve a system of linear equations, and much more.


A MATLAB Secret

Although we can think about two-dimensional arrays as an abtraction, their underlying layout in the computer's memory is actually one-dimensional. MATLAB uses what is known as column-major order. For example, the magic square that we have used in an example

m =
    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1
is actually stored internally in 16 consecutive memory cells, as if the following column vector
   16
    5
    9
    4
    2
   11
    7
   14
    3
   10
    6
   15
   13
    8
   12
    1
If you look carefully, you will see that it stores the first column, followed by the second column, and so on.
16
5
9
4
2
11
7
14
3
10
6
15
13
8
12
1

Knowing that we consider it to be a 4x4 array, MATLAB can convert the underlying data to a nicely formatted matrix when displayed. A syntax such as m(2,3) can be interpreted by MATLAB and mapped to the proper underlying element of the stored data (the 11th element, in this case).

Although this storage mechanism may seem unimportant to a programmer, it becomes relevant in occasional circumstances. For example, even with a 4x4 matrix, MATLAB accepts the syntax m(11) to access the 11th underlying element.

The find method can be applied to a matrix, such as find(m >= 10) to find elements of m that are greater than or equal to 10. Yet in its standard form, the function returns a vector of underlying indices, in this example,

    1               % i.e. m(1,1)
    6               % i.e. m(2,2)
    8               % i.e. m(4,2)
   10               % i.e. m(2,3)
   12               % i.e. m(4,3)
   13               % i.e. m(1,4)
   15               % i.e. m(3,4)

Given the underlying representation, MATLAB can easy "reshape" the array to some other set of dimensions, so long as the overall number of elements is the same. In reality, little changes behind the scene other than the designation as to the number of rows and columns in the abstraction. Given an existing matrix m, the syntax to reshape is reshape(m, rows, columsn), as shown in the following example.

>> m = reshape(1:12, 3, 4)
m =
     1     4     7    10
     2     5     8    11
     3     6     9    12