Matrix Multiplication, Division, Addition, and Subtraction in Swift

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:

  1. Preparing Matrices
  2. 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
  3. Element-wise Matrix Division
  4. Matrix Addition
  5. Matrix Subtraction
  6. 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.