Skip to main content

Performance

Matft uses Apple's Accelerate framework, so MfArray operations keep high performance. The tables below compare Matft with Numpy on the same inputs, prepared as follows.

let a = Matft.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let ad = a.astype(.Double)
let aneg = Matft.arange(start: 0, to: -10*10*10*10*10*10, by: -1, shape: [10,10,10,10,10,10])
let aT = a.T
let b = a.transpose(axes: [0,3,4,2,1,5])
let c = a.transpose(axes: [1,2,3,4,5,0])
let posb = a > 0
let idx = MfArray([1, 3, 5, 7, 9])
let values = a[posb]
let signal = Matft.arange(start: 0, to: 1024*1024, by: 1, shape: [1024, 1024], mftype: .Float)
let v = Matft.arange(start: 0, to: 10000, by: 1)
let nested: [[Float]] = (0..<1000).map{ i in (0..<100).map{ Float(i*100 + $0) } }
let m = MfArray((0..<256).map{ (i: Int) -> [Double] in (0..<256).map{ (j: Int) -> Double in i == j ? 256 : Double((i*256 + j) % 7) } })
import numpy as np

a = np.arange(10**6).reshape((10,10,10,10,10,10))
ad = a.astype(np.float64)
aneg = np.arange(0, -10**6, -1).reshape((10,10,10,10,10,10))
aT = a.T
b = a.transpose((0,3,4,2,1,5))
c = a.transpose((1,2,3,4,5,0))
posb = a > 0
idx = np.array([1, 3, 5, 7, 9])
values = a[posb]
signal = np.arange(1024*1024, dtype=np.float32).reshape((1024,1024))
v = np.arange(10000)
nested = np.arange(100000, dtype=np.float32).reshape(1000, 100).tolist()
m = np.fromfunction(lambda i, j: np.where(i == j, 256, (i*256 + j) % 7), (256, 256))
  • Arithmetic
MatfttimeNumpytimeMatft / Numpy
let _ = a+aneg52.1μsa+aneg197μs0.26x
let _ = b+aT689μsb+aT959μs0.72x
let _ = c+aT864μsc+aT735μs1.18x
let _ = a + Float(0.5)30.3μsa + np.float32(0.5)319μs0.10x
  • Math
MatfttimeNumpytimeMatft / Numpy
let _ = Matft.math.sin(a)290μsnp.sin(a)2.80ms0.10x
let _ = Matft.math.sin(b)289μsnp.sin(b)2.81ms0.10x
let _ = Matft.math.sign(a)265μsnp.sign(a)128μs2.08x
let _ = Matft.math.sign(b)266μsnp.sign(b)128μs2.09x
let _ = Matft.math.power(bases: ad, exponents: 2)125μsnp.power(ad, 2)4.06ms0.03x
let _ = Matft.math.arctan2(x1: ad, x2: ad)1.93msnp.arctan2(ad, ad)1.09ms1.76x
  • Stats
MatfttimeNumpytimeMatft / Numpy
let _ = a.mean()34.0μsa.mean()347μs0.10x
let _ = Matft.stats.cumsum(a, axis: 0)31.3μsnp.cumsum(a, axis=0)645μs0.05x
let _ = Matft.stats.cumsum(a, axis: 5)371μsnp.cumsum(a, axis=5)686μs0.54x
let _ = Matft.stats.cumsum(v)16.1μsnp.cumsum(v)15.0μs1.07x
let _ = a.argmax(axis: 5)961μsnp.argmax(a, axis=5)211μs4.56x
let _ = a.argmax(axis: 0)916μsnp.argmax(a, axis=0)562μs1.63x
  • Conversion
MatfttimeNumpytimeMatft / Numpy
let _ = aneg.argsort(axis: -1)7.02msnp.argsort(aneg, axis=-1)2.41ms2.91x
let _ = a.astype(.Double)122μsa.astype(np.float64)236μs0.52x
let _ = Matft.deepcopy(a)49.2μsa.copy()128μs0.38x
let _ = a.reshape([1000, 1000])49.4μsa.reshape((1000, 1000)).copy()132μs0.37x
  • Creation
MatfttimeNumpytimeMatft / Numpy
let _ = MfArray(nested)3.95msnp.array(nested, dtype=np.float32)1.19ms3.31x
let _ = Matft.nums(Float(1), shape: [1000, 1000])47.7μsnp.full((1000, 1000), 1, dtype=np.float32)48.6μs0.98x
  • LinAlg
MatfttimeNumpytimeMatft / Numpy
let _ = try! Matft.linalg.inv(m)490μsnp.linalg.inv(m)506μs0.97x
  • Bool
MatfttimeNumpytimeMatft / Numpy
let _ = a > 0122μsa > 075.9μs1.60x
let _ = ad > 0248μsad > 0156μs1.59x
let _ = a > b474μsa > b394μs1.20x
let _ = a === 0184μsa == 075.6μs2.43x
let _ = a === b551μsa == b407μs1.36x
let _ = a === 5232μsa == 576.6μs3.03x
let _ = a !== 0187μsa != 087.6μs2.13x
let _ = Matft.logical_not(posb)28.7μsnp.logical_not(posb)17.8μs1.62x
let _ = a == a114μsnp.array_equal(a, a)110μs1.03x
  • FFT
MatfttimeNumpytimeMatft / Numpy
let _ = Matft.fft.rfft(signal)1.98msnp.fft.rfft(signal)1.43ms1.39x
let _ = Matft.fft.rfft(signal, vDSP: true)629μsnp.fft.rfft(signal)1.45ms0.43x
  • Indexing
MatfttimeNumpytimeMatft / Numpy
let _ = a[posb]319μsa[posb]391μs0.82x
let _ = a[a > 0]443μsa[a > 0]448μs0.99x
let _ = aT[aT > 0]3.47msaT[aT > 0]1.55ms2.24x
let _ = a[idx]11.3μsa[idx]50.0μs0.23x
let x = Matft.deepcopy(a); x[x > 0] = MfArray([0])360μsx = a.copy(); x[x > 0] = 0556μs0.65x
let x = Matft.deepcopy(a); x[posb] = values667μsx = a.copy(); x[posb] = values529μs1.26x
let x = Matft.deepcopy(a).T; x[x > 0] = MfArray([0])3.88msx = a.copy().T; x[x > 0] = 01.73ms2.24x

Measured on Apple M5, macOS 26.5.1, Swift version 6.2.3, Python 3.9.6, numpy 2.0.2 (Matft 1.0.0, 2026-09-27).

Matft: median of XCTest measure {} in release build (swift test -c release), after a warm-up and with several calls per sample (like timeit). Numpy: median of timeit. Ratios > 1 (Matft slower) are shown in bold.

Regenerate with python3 scripts/benchmark.py --update-docs.

Performance improvements are always welcome (Issue #18)!!