Matrices and Array Handling

Overview:

  • Teaching: 15 mins
  • Exercises: 20 mins

Objectives:

  • Learn how to define arrays in MATLAB
  • Introduce the operations we can perform on arrays
  • How to use in-built MATLAB functions to construct matrices quickly

Vectors and Matrices

In the previous lesson we defined a few variables which stored some particular numbers, with one number per variable. However we often find in applications that we are working with matrices or vectors, and it would be inefficient and confusing to have one variable defined for each element we needed to store! Fortunately, MATLAB is built with a focus on making operations with matrices and vectors straightforward and (mathematically) intutitive.

Vectors and matrices are in fact special cases of the more general structures called arrays that MATLAB can handle. A vector is a 1-dimensional array, a matrix is a 2-dimensional array, but arrays can have as many dimensions as needed (subject to hardware limitations, of course!). In what follows it's sufficient to read "array" as "matrix or vector" throughout, although keep in mind this generalisaton. First things first, let's explore how we can define arrays.

Manual Definition

We can manually define a vector using square braces [ ] and asigning it to a variable name.

In [1]:
sample_row_vector = [1 2 3 4 5];
sample_col_vector = [1; 2; 3; 4; 5];

The code above defines two vectors in this way. The first is a row-vector of 5 elements, and the second a column vector of 5 elements. Notice how we include a semicolon ; inside the square braces to denote that we are starting a new row. Leaving a space between values means that MATLAB will interpret the values as begin in the same row.

We can check the size or dimensions of a vector using the size command:

In [2]:
disp(size(sample_row_vector))
disp(size(sample_col_vector))
   1   5
   5   1

size takes in a vector as an argument and returns another vector whose elements are the dimensions of the input. We see that sample_row_vector has dimensions $1\times5$ - $1$ row and $5$ columns - whilst sample_col_vector has dimensions $5\times1$.

Saving Sizes

We can save the output of a size command to a variable, like so,

size_row_vector = size(sample_row_vector);

so that we can access the size of a vector later on in some code that we are writing. This is useful when preallocating memory - which we will come to consider later.

We can manually define matrices in a similar way to vectors - using square braces and using semicolons to start new rows in the matrix; and use the size command to check what their shape is.

In [3]:
sample_square_matrix = [1 2 3; 4 5 6; 7 8 9;];
sample_rect_matrix = [1 2 3 4; 5 6 7 8;];
disp(size(sample_square_matrix))
disp(size(sample_rect_matrix))
   3   3
   2   4

In addition, we can also construct matrices by "sticking" vectors together, making sure that the dimensions all match up!

In [4]:
fprintf('Sticking some rows together...\n')
row_1 = sample_row_vector;
row_2 = [9 8 7 6 5];
row_sticking = [row_1 ; row_2]; %note the semicolon as we are putting row_1 on top of row_2
disp(row_sticking)

fprintf('And now to stick columns together...\n')
col_1 = sample_col_vector;
col_2 = [9; 8; 7; 6; 5];
col_sticking = [col_1 col_2]; %note the space as we are putting col_1 next to col_2
disp(col_sticking)
Sticking some rows together...
   1   2   3   4   5
   9   8   7   6   5
And now to stick columns together...
   1   9
   2   8
   3   7
   4   6
   5   5

Matrix-Vector Operations

Once we have defined some suitable matrices and vectors, we can use the operators + (addition), - (subtraction) and * (matrix-multiply) on them, provided that the calculation obeys the rules for matching dimensions when working with matrices!

Note that when dealing with scalars, multiplcation using * and division (using /) will both work element-wise, as should be expected. However MATLAB will interpret "matrix + scalar" or "vector + scalar" as "add the scalar to every element in the matrix or vector - so make sure that you double check that an operation is really doing what you want it to!

In [5]:
e_1 = [1; 0; 0];
e_2 = [0; 1; 0];
e_3 = [0; 0; 1];
change_of_basis = [0 1 0; 1 0 0; 0 0 1];

fprintf('Multiply a matrix by the sum of two vectors: \n')
disp(change_of_basis*(e_1+2*e_2))
fprintf('Adding a scalar to a matrix can have odd consequences: \n')
disp(change_of_basis + 5)
Multiply a matrix by the sum of two vectors: 
   2
   1
   0
Adding a scalar to a matrix can have odd consequences: 
   5   6   5
   6   5   5
   5   5   6

Dimension Mismatch

What happens if we try to get MATLAB to perform a matrix operation between variables whose dimensions don't agree? If we try the following code...

In [6]:
wrong_vec = [1 2 3]; %row vector of length 3
wrong_mat = [1 2 3 4; 5 6 7 8; 9 10 11 12]; %3-by-4 matrix
wrong_mat * wrong_vec
error: operator *: nonconformant arguments (op1 is 3x4, op2 is 1x3)

We get a "dimension mismatch" ("nonconformant arguments", depending on your MATLAB version) error. MATLAB is clever enough to work out that we can't perform this calculation, so stops trying and tells you about it!

Notice how MATLAB will perform the calculation if we multiply in the correct order:

In [7]:
disp(wrong_vec * wrong_mat)
   38   44   50   56

We can also perform element-wise versions of multiplication and division between vectors or matrices of the same size by using a dot (.) before the operation.

So for example...

In [8]:
fprintf('Element-wise multiply two row vectors...\n')
row_1 = [1 3 5];
row_2 = [2 4 6];
product_row = row_1 .* row_2;
disp(product_row)

fprintf('Element-wise divide two matrices...\n')
mat_1 = [1 2; 2 1];
mat_2 = [10 2; 3 5];
div_mat = mat_1 ./ mat_2;
disp(div_mat)

fprintf('Useful trick: reciprocate all elements of a vector (also works on matrices): \n')
recip_vec = 1 ./ row_1;
disp(recip_vec)
Element-wise multiply two row vectors...
    2   12   30
Element-wise divide two matrices...
   0.10000   1.00000
   0.66667   0.20000
Useful trick: reciprocate all elements of a vector (also works on matrices): 
   1.00000   0.33333   0.20000

The \ Operation

One of MATLAB's centrepiece operations is the backslash \ operator for matrices and vectors. Whilst division of matrices by vectors or other matrices is not defined mathematically, this operator is used to solve linear systems in a shorthand notation.

For example, if A is a $3\times3$ matrix and b is a column-vector of length $3$, then x = A\b finds the solution to the linear system Ax = b, and stores the answer (a column vector of length 3) in x. As an example:

In [9]:
A = 3*change_of_basis;
b = [4; 1; 9];

x = A\b;
disp(x)
   0.33333
   1.33333
   3.00000

Use of Operations

Using the command line in MATLAB (or a script if you prefer), perform the following tasks:

  1. Define three column vectors x, y, z of length 3, with your choice of entries (be adventurous but sensible, with the next task in mind).
  2. Check that the vectors are orthogonal to each other, namely that $$\sum_{i=1}^3 x_i y_i = 0 $$ and similarly for each possible pairing. To do this, try using element-wise multiplication, then applying the sum function to the result, and displaying the output.
  3. (If your vectors are not orthogonal) Alter your vectors so that they are orthogonal.
  4. Construct a matrix M whose columns correspond to the 3 vectors you have defined.
  5. Find the solution w to Mw = b where b = [1; 1; 1];, and print it to the screen.

Solution

Matrix Construction Functions

Whilst manual definition is suitable for small dimensional matrices and vectors, it is highly impractical for most computing purposes - woe betide the person who tries to define a $100\times100$ matrix by hand! Instead of manually defining a vector or matrix using square braces and filling the entries out ourselves, we can call in-built functions to construct matrices and vectors of the correct size, then use matrix operations (or the highly not recommended for-loops) to fill out the entries ourselves.

There are several functions that can help us create new matrices. The two most commonly used are zeros and ones which take in a set of dimensions as inputs, and return an array of that dimension for us. Using zeros gives us back an array filled entirely with 0, whilst ones (shock horror) will return an array filled with 1.

Normally, we would use these two functions for preallocation - more on that later.

In [11]:
example_zeros = zeros(1,10); %a row vector (1 row, 10 columns) of zeros.
example_ones = ones(5,5); %a 5-by-5 matrix of 1s.
example_zeros_2 = zeros(6,1); %a column vector (6 rows, 1 column) of zeros.
example_ones_2 = ones(3,27); %a rectanglular 3-by-27 matrix.

Other functions that we can use to construct matrices are eye (which creates the identity matrix) and diag which can create diagonal matrices. Be careful with diag - it has lots of uses subject to it's inputs!

Finally, there is also linspace and logspace - functions that create vectors of equally-spaced entries.

MATLAB help

If you are confused about what a function in MATLAB does, you can use MATLAB's help feature to access the in-built guide for it.

Simply type help followed by the function name into the command line and execute the command. For example,

help diag

will bring up all the information on diag that MATLAB holds.

Random Matrices

We can also generate matrices with random entries using the rand (uniform $[0,1]$ entries) or randn (normally distributed entries), which can be useful for creating test cases for your code.

Constructing a Finite Difference Matrix

When working with 1-dimensional Finite Differences to solve Differential Equations, we need to construct a particular matrix to compute our numerical solution.

Let $N\in\mathbb{N}$ (contextually this is the number of mesh points we have placed), then the finite difference matrix FEM_N that we want to construct is an $N\times N$ tridiagonal matrix with 2 on the leading diagonal and -1 on the super- and sub-diagonal.

Using MATLAB's help function to learn more about diag, construct FEM_N for N=5.

Solution

Key Points:

  • We can define arrays manually using square braces [ ].
  • We can also define arrays using the inbuilt commands ones,zeros,eye,diag,rand and randn.
  • We can perform matrix-matrix and matrix-vector operations using the standard +,-,*, and solve linear systems using \.
  • We can perform element-wise operations using a dot (.) before the operation.