(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:

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.

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

So for N years ahead we only need to raise the matrix to the power of 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.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Matrix { internal var data:Array<Double> var rows: Int var columns: Int init(_ data:Array<Double>, rows:Int, columns:Int) { self.data = data self.rows = rows self.columns = columns } init(rows:Int, columns:Int) { self.data = [Double](repeating: 0.0, count: rows*columns) self.rows = rows self.columns = columns } } |

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.

1 2 3 4 5 6 7 8 |
subscript(row: Int, col: Int) -> Double { get { return data[(row * columns) + col] } set { self.data[(row * columns) + col] = newValue } } |

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

1 2 |
let m = Matrix([0.5, 3.0], rows:1, columns:2) // create let v = m[0,1] // v should be 0.3 |

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.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
func row(index:Int) -> [Double] { var r = [Double]() for col in 0..<columns { r.append(self[index,col]) } return r } func col(index:Int) -> [Double] { var c = [Double]() for row in 0..<rows { c.append(self[row,index]) } return c } |

#### 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! We are going to implement *CustomStringConvertible*, the public protocol that allows for an object to be printed on the stdout using the print(…) method.

1 2 3 4 5 6 7 8 9 10 11 12 13 |
extension Matrix: CustomStringConvertible { var description: String { var dsc = "" for row in 0..<rows { for col in 0..<columns { let s = String(self[row,col]) dsc += s + " " } dsc += "\n" } return dsc } } |

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

1 2 |
let m = Matrix([0.5, 3.0], rows:1, columns:2) // create print("My Matrix is: \(m)") |

#### Copying

One more utility function should be that of copying

1 2 3 4 |
func copy(with zone: NSZone? = nil) -> Matrix { let cp = Matrix(self.data, rows:self.rows, columns:self.columns) return cp } |

#### 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

1 2 3 4 5 6 7 8 9 10 11 |
func +(left: Matrix, right: Matrix) -> Matrix { precondition(left.rows == right.rows && left.columns == right.columns) let m = Matrix(left.data, rows: left.rows, columns: left.columns) for row in 0..<left.rows { for col in 0..<left.columns { m[row,col] += right[row,col] } } return m } |

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

1 2 3 4 |
func testAddition() { let sum = Matrix([2, 2], rows:1, columns:2) + Matrix([1, 1], rows:1, columns:2) XCTAssert(sum == Matrix([3, 3], rows:1, columns:2), "1x1 Matrix wrong") } |

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.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func ==(left:Matrix, right:Matrix) -> Bool { if left.rows != right.rows { return false } if left.columns != right.columns { return false } for i in 0..<left.rows { for j in 0..<left.columns { if left[i,j] != right[i,j] { return false } } } return true } |

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:

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

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.

1 2 3 4 5 6 7 8 9 10 |
postfix operator ^ postfix func ^(m:Matrix) -> Matrix { let t = Matrix(rows:m.columns, columns:m.rows) for row in 0..<m.rows { for col in 0..<m.columns { t[col,row] = m[row,col] } } return t } |

We test it with:

1 2 3 4 |
func testTransposition() { var trans = Matrix([1, 2, 3, 4, 5, 6], rows:3, columns:2) XCTAssert(trans^ == Matrix([1, 3, 5, 2, 4, 6], rows:2, columns:3), "Matrix did not transpose correctly") } |

###### Multiplication

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
func *(left:Matrix, right:Matrix) -> Matrix { var lcp = left.copy() var rcp = right.copy() if (lcp.rows == 1 && rcp.rows == 1) && (lcp.columns == rcp.columns) { // exception for single row matrices (inspired by numpy) rcp = rcp^ } else if (lcp.columns == 1 && rcp.columns == 1) && (lcp.rows == rcp.rows) { // exception for single row matrices (inspired by numpy) lcp = lcp^ } precondition(lcp.columns == rcp.rows, "Matrices cannot be multipied") let dot = Matrix(rows:lcp.rows, columns:rcp.columns) for i in 0..<lcp.rows { for j in 0..<rcp.columns { let a = lcp.row(index: i) ** rcp.col(index: j) dot[i,j] = a } } return dot } |

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.

1 2 3 4 5 6 7 8 9 10 |
typealias Vector = [Double] infix operator ** func **(left:Vector, right:Vector) -> Double { precondition(left.count == right.count) var d : Double = 0 for i in 0..<left.count { d += left[i] * right[i] } return d } |

#### 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.

1 2 3 4 5 6 7 8 |
import Accelerate // definitions (as above) func **(left:Vector, right:Vector) -> Double { precondition(left.count == right.count) var d: Double = 0.0 vDSP_dotprD(left, 1, right, 1, &d, vDSP_Length(left.count)) return d } |

**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.

1 2 3 4 5 6 7 8 9 |
func *(left:Matrix, right:Matrix) -> Matrix { var lcp = left.copy() var rcp = right.copy() // can include the same transpose code as above var r = [Double](repeating: 1, count: lcp.rows * rcp.columns) vDSP_mmulD(lcp.data, 1, right.data, 1, &r, 1, vDSP_Length(lcp.rows), vDSP_Length(rcp.columns), vDSP_Length(rcp.rows)) let dot = Matrix(r, rows:lcp.rows, columns:rcp.columns) return dot } |