Monthly Archives: November 2016

Creating a Matrix Class in Swift 3.0

(Build for Swift 3.0 on GitHub)

There is no better way to learn a language than to use it and so, along with a number of other experiments, I decided to build a Matrix class using some of the cool features of Swift in its latest (3.0) incarnation.

What are Matrices?

Wikipedia will do a far better job than me, but suffice to say that Matrices are mathematical objects, like functions are, that look like tables and that allow us to do various types of calculations where there are a number of quantities that are mutually effecting each other.

For an intuitive understanding of matrices I always use the following example: “Once upon a time, there was a village and a city. Every year, a tenth of the villagers would leave and settle permanently in the city, looking for better work opportunities. In the same year there would always be some 5% of city dwellers who, tired of their hectic lives, would retire back in the village.” Given some initial populations, what is the predicted population of village and city respectively in the next n number of years?

The problem can be represented in a table.

And with a random initial population of say:

To answer how many people are there going to be in the year 1936 in each location we will do:

v = 150*0.9 + 3000*0.03

c = 150*0.1 + 3000*0.97

This means that the population of the village will be the sum of the people who stayed, plus the city dwellers that came over. Respectively for the city. Here is where matrices shine, when we have quantities that influence each other in an additive or subtractive way to yield a result.

delim{[}{matrix{1}{2}{150 3000}}{]}  *delim{[}{matrix{2}{2}{0.9 0.1 0.03 0.97}}{]}  = delim{[}{matrix{1}{2}{225 2925}}{]}

To calculate the next year (1937) we just need to feed the result in the same matrix:

delim{[}{matrix{1}{2}{225 2925}}{]}  *delim{[}{matrix{2}{2}{0.9 0.1 0.03 0.97}}{]}  = delim{[}{matrix{1}{2}{290 2859}}{]}

So for N years ahead we only need to raise the matrix to the power of N

delim{[}{matrix{1}{2}{150 3000}}{]}  *delim{[}{matrix{2}{2}{0.9 0.1 0.03 0.97}}{]}^N

Why Swift?

Because that is what we are learning 😉 Also, Swift exposes some sought after features that graphics programmers missed from languages like C++, where most of the game engines are programmed in. Game engines of course use matrices heavily and so we come full circle to Swift.

Let’s do it!

A matrix is an object that has tabular data, so in terms of properties we have two main things: data, and dimensions, as in width and height. We are going to start by creating a new class that implements CustomStringConvertible. This is a public protocol that allows for an object to be

The array we are passing is one dimensional and we could I suppose have a 2d array which would include the rows and columns properties as part of its structure. While coding this however I found that it is easier to just pass a standard array and indicate the shape of the matrix separately. It is also the approach that well written libraries like numpy are currently using. Another initialiser will create a matrix full of 0.0 values.

Accessing Data

What is of vital importance is to be able to access the matrix data easily. Being essentially a 2D table we want to access the data by using 2 indices, x and y, or row and column if you prefer. For this we are going to use Swift’s subscript notation which essentially enables any class to behave like an array when accessing its data.

Holding it’s data in a 1D array means we need to calculate the index manually, but this is a small price to pay as we only need to do it once. After that we can access the data as

for the 2nd element of the 1rst row (0-indexed).

Rows and Columns

Using the code above we can write a way to access a row or a column and turn it into an array.

Printing

Now we definitely want to see the data printed out on a terminal at any given moment, and we also have the tools to do it!

He we implement description property of the CustomStringConvertible which is called every time an object is being printed:

Copying

One more utility function should be that of copying

 

Operations

Now we get to the meat of things! Since matrices are mathematical object we would like to use them inside expressions, like numbers. So we are going to overload standard operators like + and * to allow for this kind of manipulation.

Addition

As good developers we are also writing tests for our project. To test addition we write:

We can do the same for subtraction and multiplication with a scalar value. All we need to do is change += into -= and *=.

Equality

You might remember overriding the isEqual: function in objective-c. Here it gets much more intuitive as we can also use the == operator for custom types.

For 2 matrices to be equal, all elements must be equal one by one.

Transposition

A special operation we can perform on matrices is transposition. This will essentially flip the matrix so that its rows become columns and vica versa. To see where this might be useful, image the example above were we are presented with the initial populations as so:

delim{[}{matrix{2}{1}{150 3000}}{]}

This would yield the wrong results and we would need to transpose it

delim{[}{matrix{2}{1}{150 3000}}{]}^T = delim{[}{matrix{1}{2}{150 3000}}{]}

For this we will introduce an new operand. One that follows a matrix much like its mathematical notation does. Here I chose the caret ‘^’ character, but any one would do.

We test it with:

Multiplication

Now for the tricky one. Matrix multiplication. We saw how this works by the example of the 2 populations above.

To multiply to matrices, the rows of the first must equal the columns of the second. In the code above however we spare some cases on behalf of the user by transposing a matrix that has a single row or a single column. My rational is that many times I will use Matrices as arrays, for the reason that I might want them to interact with matrices later.

You will notice a new operator in use **. This is my version of the inner product of two vectors. Multiply all elements of an array (Vector) with another array of equal size and sum the results into a single value.

Accelerating Operations

In the code above, everything is done in Swift, which was the whole point of this tutorial. Matrix and Vector operations can often be the heavy lifters of your code and this is especially true in areas such as computer graphics and various forms of Artificial Intelligence, like Neural Networks for instance. This means that any speedup we can accomplish could be crucial for production ready code that is competing agains other equivalents and so we are going to look into one way of doing this.

The Accelerate Framework is a system library provided by Apple which includes C APIs for vector and matrix math as well as digital signal and image processing. It is highly optimised and well tested and so we are going to use it here to boost our hand crafted code.

vDSP_Length is a data type that the size of the vectors need to be cast into.

Same can go to the rest of operations like multiplication and transposition. The most important of which is multiplication so I will include it here.