I created a matrix type for working with 2D numerical data. As shown in the example below, the underlying data is stored as a flat array of generic values. Those values could be Float
, Double
, or a complex type such as DSPComplex
. I'm using functions from Accelerate to conduct various scalar-matrix, matrix-matrix, vector-matrix operations. The example demonstrates overloading *
to perform matrix-matrix multiplication using the cblas_dgemm
function.
import Accelerate
struct Matrix<T> {
let rows: Int
let columns: Int
var values: [T]
init(rows: Int, columns: Int, values: [T]) {
self.rows = rows
self.columns = columns
self.values = values
}
init(_ content: [[T]]) {
self.rows = content.count
self.columns = content[0].count
self.values = content.flatMap { $0 }
}
subscript(row: Int, column: Int) -> T {
get { return values[(row * columns) + column] }
set { values[(row * columns) + column] = newValue }
}
}
extension Matrix {
static func * (lhs: Matrix, rhs: Matrix) -> Matrix where T == Double {
precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix")
var a = lhs.values
var b = rhs.values
var c = [Double](repeating: 0.0, count: lhs.rows * rhs.columns)
let m = lhs.rows // rows in matrices A and C
let n = rhs.columns // columns in matrices B and C
let k = lhs.columns // columns in matrix A and rows in matrix B
let alpha = 1.0
let beta = 0.0
// matrix multiplication where C ← αAB + βC
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, &a, k, &b, n, beta, &c, n)
let mat = Matrix(rows: lhs.rows, columns: rhs.columns, values: c)
return mat
}
}
Here's how I would use this matrix type:
let a = Matrix([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
let b = Matrix([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0]])
let c = a * b
for i in 0..<c.rows {
for j in 0..<c.columns {
print(c[i, j], terminator: " ")
}
print()
}
Which prints the following:
30.0 36.0 42.0
66.0 81.0 96.0
My question is about using a Swift Array
as the underlying data storage for the Matrix
. Should I use an Array
or some other approach to store the numerical data? Arrays in Swift can handle a bunch of types (Int
, String
, Float
, Bool
, etc.) but I'm only interested in numerical data. As such, I would think that having a numerical array type that is a fixed size would be more performant and efficient than the standard Array
type. I see that Swift has a ContiguousArray
type but it seems to be for class objects and working with Objective-C objects like NSArray
. There's also UnsafeMutablePointer
but it would require memory management. Anyway, I'm just curious if there is a better way to store a collection numerical data in Swift for matrix and vector operations.