Matrix.swift is a lightweight, easy-to-use Matrix data structure in pure Swift. The backend is based on Accelerate.framework to run compute intensive operations in parallel. The API is inspired by NumPy.
This is not a fully fledged linear algebra library. If you are looking for one, check out Surge.
Processing a batch of MNIST-like images (on a 2016 15" MacBook Pro):
let totalSeconds = (0..<100).reduce(0.0) { _,_ in
let x = Matrix(randomIn: 0...1, rows: 100, columns: 784)
let w = Matrix(randomIn: 0...1, rows: 784, columns: 10)
let start = CFAbsoluteTimeGetCurrent()
_ = x • w
let end = CFAbsoluteTimeGetCurrent()
return Double(end - start)
}
print("\(totalSeconds / 100) seconds")
Tool | Processing 100 MNIST-like images | Supported Platforms | Size |
---|---|---|---|
Native implementation | 4628.63 µs¹ | all | - |
Matrix.swift | 1.41 µs¹ | macOS, iOS, tvOS, watchOS | 16 kB |
Swift for TensorFlow | 1.04 µs¹ | macOS, Ubuntu | ~2.4GB |
NumPy | 69.3 µs¹ | macOS, Ubuntu, Windows | 88.2MB |
¹ On a 2016 15" MacBook Pro, no eGPU
Keep in mind that these tools are designed for different usecases. Which one is the best depends on the project.
Simply copy the Matrix.swift
file into your project.
From an array
Matrix([1, 2, 3, 4])
Matrix([
[1, 2],
[3, 4]
])
Copy another matrix
Matrix(copy: anotherMatrix)
Repeating a number (similar to this). This is an alternative to NumPy zeros
or ones
.
Matrix(repeating: .pi, rows: 2, columns: 2)
Random
Matrix(randomIn: 0...1, columns: 5, rows: 5)
Matrix.swift
has powerful slicing support with Range
. Slicing also supports in place assignment.
var m = Matrix([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
])
m[1...3, 1...2] *= 2
Matrix([
[1.0, 4.0, 6.0],
[4.0, 10.0, 12.0],
[7.0, 16.0, 18.0],
[10.0, 11.0, 12.0],
])
You can assign integers to matrices:
m[...1, 1...] &= 0 // Is equal to: Matrix(repeating: 0, rows: a[...1, 1...].rows, columns: a[...1, 1...].columns)
Matrix([
[1.0, 0.0, 0.0],
[4.0, 0.0, 0.0],
[7.0, 8.0, 9.0],
[10.0, 11.0, 12.0],
])
Every usual arithmatic operators +
, -
, *
and /
is supported for Matrix-Scalar and Matrix-Matrix computations. Note that these are elementwise if both operands are matrices. +=
, -=
, *=
, •=
can be used for in place operations.
•
is used for matrix multiplication (hint: alt+8
).
Number of elements:
m.size
Sum:
m.sum
m.sum(.rows)
m.sum(.columns)
Max:
m.max(.rows)
m.max(.columns)
Min:
m.min(.rows)
m.min(.columns)
Argmax:
m.argmax(.rows)
m.argmax(.columns)
Argmin:
m.argmin(.rows)
m.argmin(.columns)
Transposition:
m.transposed()
Diagonal:
m.diagonal()
Reversed:
m.reversed()
Count zero / nonzero:
m.countNonzeros()
m.countZeros()
Flipping:
m.flipped(.rows)
m.flipped(.columns)
Flatten:
m.flatten()
Sorting:
m.sorted(.rows, sortOrder: .ascending)
m.sorted(.columns, sortOrder: .descending)
Searching:
m.firstIndex(where: {$0 == 9}) // -> (row: Optional(2), column: Optional(2))
Matrix.swift is available under the MIT License. See LICENSE
for details.
©2020 Rick Wierenga