Apple operating systems like iOS and macOS contain a performance optimized framework called Accelerate for fast matrix operations. This post presents examples for matrix addition, subtraction, multiplication, and division:
- Preparing Matrices
- Matrix Multiplication
a. Single Precision Matrix Multiplication
b. Double Precision Matrix Multiplication
c. Transpose, Row-Major, and Column-Major Matrix Multiplication Using CBLAS
d. Element-wise Matrix Multiplication - Element-wise Matrix Division
- Matrix Addition
- Matrix Subtraction
- Sum of All Values In A Matrix
Preparing Matrices
To prepare for matrix arithmetic using Accelerate matrices need to be transformed into a format Accelerate can accept. Two-dimensional matrices first need to be flattened (turned into one-dimensional vectors that represent two-dimension matrices).
The matrix multiplication examples in this post evaluate A * B = C
.
import Accelerate
// Define matrix row and column sizes
let M = Int32(3)
let N = Int32(1)
let K = Int32(2)
// Matrix A, a MxK sized matrix
let A: [Float] = [
[3, 6],
[1, 5],
[8, 0]
].flatMap { $0 }
// Matrix B, a KxN sized matrix
let B: [Float] = [
[2],
[6]
].flatMap { $0 }
// Matrix C, a MxN sized matrix
var C: [Float] = [
[0],
[0],
[0]
].flatMap { $0 }
Matrix Multiplication
The Accelerate framework contains multiple interfaces for single, double, and element-wise matrix multiplication in Swift.
Single Precision Matrix Multiplication
Use the vDSP_mmul
function to perform single precision matrix multiplication:
// Using A, B, C and M, N, K as defined
// The stride is the distance between elements to read.
// To use all consecutive elements, set the stride to 1.
let aStride = vDSP_Stride(1)
let bStride = vDSP_Stride(1)
let cStride = vDSP_Stride(1)
vDSP_mmul(
A, aStride,
B, bStride,
&C, cStride,
vDSP_Length(M),
vDSP_Length(N),
vDSP_Length(K)
)
// C will be [42.0, 32.0, 16.0]
Double Precision Matrix Multiplication
The process for double precision matrix multiplication using vDSP is the same as single precision except:
a. vDSP_mmulD
is used instead of vDSP_mmul
b. A
, B
, and C
must be of type [Double]
instead of [Float]
Transpose, Row-Major, and Column-Major Matrix Multiplication Using CBLAS
Accelerate includes another performance optimized interface for matrix multiplication supporting single precision (cblas_sgemm
) and double precision (cblas_dgemm
) multiplication.
The cblas_sgemm
and cblas_dgemm
functions include additional configuration options for row-major and column-major data formats, A
and/or B
matrix transposition, and scaling factors. The cblas functions enable the following matrix multiplication operation: αAB + βC = C
// Using A, B, C and M, N, K as defined
// Row-major indicates the row is contiguous in
// memory. The other option is column-major ordering
let Order = CblasRowMajor
// If matrix A should be transposed
let TransposeA = CblasNoTrans
// If matrix B should be transposed
let TransposeB = CblasNoTrans
// Scaling factor for A * B
let alpha = Float(1.0)
// Scaling factor for matrix C
let beta = Float(1.0)
// In row-major ordering, the number of items
// in a row of matrix A (K)
let lda = K
// In row-major ordering, the number of items
// in a row of matrix B (N)
let ldb = N
// In row-major ordering, the number of items
// in a row of matrix C (N)
let ldc = N
cblas_sgemm(
Order,
TransposeA, TransposeB,
M, N, K,
alpha,
A, lda,
B, ldb,
beta,
&C, ldc
)
// C will be [42.0, 32.0, 16.0]
The process for double precision matrix multiplication using CBLAS is the same as single precision except:
a. cblas_dgemm
is used instead of cblas_sgemm
b. alpha
and beta
must be of type Double
c. A
, B
, and C
must be of type [Double]
instead of [Float]
Element-wise Matrix Multiplication
To multiply each element in a matrix with a constant value, use vDSP.multiply
and pass a constant as the first argument:
let matrix: [Float] = [
[3, 6],
[1, 5]
].flatMap { $0 }
let result = vDSP.multiply(2, matrix)
Element-wise Matrix Division
To divide each element in a matrix with a constant value, use vDSP.divide
and pass a constant as the first argument:
let matrix: [Float] = [
[3, 6],
[1, 5]
].flatMap { $0 }
let result = vDSP.divide(2, matrix)
Matrix Addition
Use vDSP.add
to add two matrices:
let matrix: [Float] = [
[3, 6],
[1, 5]
].flatMap { $0 }
let result = vDSP.add(matrix, matrix)
Matrix Subtraction
Use vDSP.subtraact
to subtract two matrices:
let matrix: [Float] = [
[3, 6],
[1, 5]
].flatMap { $0 }
let result = vDSP.subtract(matrix, matrix)
Sum of All Values In A Matrix
Use vDSP.sum
to sum all the values in a matrix:
let matrix: [Float] = [
[3, 6],
[1, 5]
].flatMap { $0 }
let matrixSum = vDSP.sum(matrix)
Performance Optimized Matrix Operations In Swift
That’s it! By using Accelerate and vDSP you can multiply, divide, subtract, and add matrices in Swift in a performance optimized manner.