A feature in some other languages you may have seen is something called matrix math. These are operations you can perform on matrices, which are 2-dimensional arrays. Xojo does not have any matrix math functions built in, but using the Extends command you can add your own.
I’ll show you how to add two of the simpler ones: add and multiply.
In case your linear algebra is a bit rusty, let me recap a little. A matrix is a 2-dimensional array. Adding one matrix to another involves adding the values in the corresponding cells of each matrix (which both must be the same size) together and putting that sum into a new matrix at the same position.
For example, consider these two matrices (taken from the Wikipedia page on Matrix Addition):
1 3 1 0 1 2 0 0 7 5 2 1
To add them
- 1st row: 1 + 0, 3 + 0
- 2nd row: 1 + 7, 0 + 5
- 3rd row: 1 + 2, 2 + 1
This results in a new matrix:
1 3 8 5 3 3
As you can see, addition is pretty straightforward. So how might this look in Xojo? Here is an extension method for Integer arrays that I created to do this:
Public Function Add(Extends m1(, ) As Integer, m2(, ) As Integer) As Integer(,)
// https://en.wikipedia.org/wiki/Matrix_addition
// Both arrays must have the same number of rows and columns.
If m1.LastIndex(1) <> m2.LastIndex(1) Or m1.LastIndex(2) <> m2.LastIndex(2) Then
Raise New UnsupportedOperationException("Array sizes must match.")
End If
// The values at each cell are added together and a new
// array is created with their sums.
Var newMatrix(-1, -1) As Integer
newMatrix.ResizeTo(m1.LastIndex(1), m1.LastIndex(2))
For c1 As Integer = 0 To m1.LastIndex(1)
For c2 As Integer = 0 To m1.LastIndex(2)
newMatrix(c1, c2) = m1(c1, c2) + m2(c1, c2)
Next
Next
Return newMatrix
End Function
To use it, you populate two matrices and call matrix1.add(matrix2). Here is some sample code to solve the example above:
// Matrix Addition
Var matrix1(2, 1) As Integer
matrix1(0, 0) = 1
matrix1(0, 1) = 3
matrix1(1, 0) = 1
matrix1(1, 1) = 0
matrix1(2, 0) = 1
matrix1(2, 1) = 2
Var matrix2(2, 1) As Integer
matrix2(0, 0) = 0
matrix2(0, 1) = 0
matrix2(1, 0) = 7
matrix2(1, 1) = 5
matrix2(2, 0) = 2
matrix2(2, 1) = 1
Var matrix3(-1, -1) As Integer
matrix3 = matrix1.Add(matrix2)
Multiplication gets more complex and is a bit tricky to explain. First, the sizes matter. The 2nd dimension of the 1st matrix must be the same as the 1st dimension of the 2nd matrix. That means that if you have matrix1(3,2) then matrix2(2,2) is valid, but matrix2(1,2) is not. The resulting matrix is matrix1’s 1st dimension by matrix2’s 2nd dimension.
To do the multiplication, for each cell in the new matrix you multiple each cell in the corresponding row of matrix1 with each cell of the corresponding column in matrix2.
A Xojo method to do that looks like this:
Public Function Multiply(Extends m1(, ) As Integer, m2(, ) As Integer) As Integer(,)
// https://en.wikipedia.org/wiki/Matrix_multiplication
// matrix1's 2nd dimension size must be the same as
// matrix2's 1st dimension size.
If m1.LastIndex(2) <> m2.LastIndex(1) Then
Raise New UnsupportedOperationException("m1 2nd dimension must match m2 1st dimension.")
End If
// The result matrix is matrix1's 1st dimension by matrix2's 2nd dimension
Var newMatrix(-1, -1) As Integer
newMatrix.ResizeTo(m1.LastIndex(1), m2.LastIndex(2))
For c1 As Integer = 0 To newMatrix.LastIndex(1)
For c2 As Integer = 0 To newMatrix.LastIndex(2)
Var prod As Integer
For p1 As Integer = 0 To m1.LastIndex(2)
prod = prod + m1(c1, p1) * m2(p1, c2)
Next
newMatrix(c1, c2) = prod
Next
Next
Return newMatrix
End Function
The Wikipedia example for matrix multiplication has these two matrices:
1 0 1 2 1 1 0 1 1 1 1 2 1 2 1 2 3 1 4 2 2
Multiplying them together results in this matrix:
5 4 3 8 9 5 6 5 3 11 9 6
This code sets up the above example and multiplies it using the method:
// Matrix Multiplication
Var matrix1(3, 2) As Integer
matrix1(0, 0) = 1
matrix1(0, 1) = 0
matrix1(0, 2) = 1
matrix1(1, 0) = 2
matrix1(1, 1) = 1
matrix1(1, 2) = 1
matrix1(2, 0) = 0
matrix1(2, 1) = 1
matrix1(2, 2) = 1
matrix1(3, 0) = 1
matrix1(3, 1) = 1
matrix1(3, 2) = 2
Var matrix2(2, 2) As Integer
matrix2(0, 0) = 1
matrix2(0, 1) = 2
matrix2(0, 2) = 1
matrix2(1, 0) = 2
matrix2(1, 1) = 3
matrix2(1, 2) = 1
matrix2(2, 0) = 4
matrix2(2, 1) = 2
matrix2(2, 2) = 2
Var matrix3(-1, -1) As Integer
matrix3 = matrix1.Multiply(matrix2)
I will point out that the two methods used here are very simple algorithms that won’t be nearly fast enough when working with large matrices. But hopefully they showed you that Extension Methods are a great way to extend the Xojo language for your specific needs and you found this example interesting, even if you have no use for linear algebra or matrix math.
Download the project: MatrixMath
As an alternative to using Extends, you could create your own Matrix class and then use Operator overloading (a subject for another blog post) so that you could write code like this:
Var m1 As New Matrix(1, 3, 1, 0, 1 2)
Var m2 As New Matrix(0, 0, 7, 5, 2, 1)
Var m3 As Matrix = m1 + m2
If you actually need full matrix support in Xojo, check out the free matrix-related Delaney or Einhugur plugins.
Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at Goto 10 and on Mastodon @lefebvre@hachyderm.io.