dclelland/Plinth
Hardware-accelerated matrix/numeric programming library for Swift
Installation
Swift Package Manager
Simply add Plinth to your Package.swift file:
let package = Package(
name: "Example",
dependencies: [
.package(url: "https://github.com/dclelland/Plinth.git", from: "2.0.0"),
],
targets: [
.target(name: "Example", dependencies: ["Plinth"])
]
)Then import Plinth into your Swift files:
import PlinthOr for full ComplexMatrix support you should also import swift-numerics, as that's where the Complex type lives.
import Plinth
import NumericsLinks
Dependencies
References/prior art
- https://github.com/apple/swift-numerics/issues/6 (discussion on adding a
ShapedArraytype toswift-numerics) - Jounce/Surge
- hollance/Matrix
- stsievert/swix
- cgarciae/NDArray
Todo
- [ ] ~~Add Cocoapods support~~ Can't do this,
swift-numericsonly supports SPM. I'd have to make my ownComplextype. - [x] Implement Equality/Comparisons extension
- [x] Implement both
.zerosand.onesinitializers - [x] Implement exception handling for LAPACK calls
- [x] Revisit
Eigendecomposition.sorted, is sorting the eigenvalues by real component or the magnitude preferable? - [x] Implement wrapper for
vDSP.ramp - [x] Implement wrapper for
vDSP.convolve - [ ] Implement wrappers for
vDSP.fill,vDSP.clear,vDSP.window,vDSP.stereoRamp - [ ] Implement API for specifying seeds for LAPACK random number generator calls.
- Note the LAPACK specifications: "ISEED is INTEGER array, dimension (4). On entry, the seed of the random number generator; the array elements must be between 0 and 4095, and ISEED(4) must be odd."
- [ ] Write code examples
Philosophy
Plinth's philosophy is to do "the simplest thing that works". For example, many of the arithmetic/numeric functions are implemented twice – for both Matrix<Float> and Matrix<Double> – instead of managing this through a morass of protocols and protocol implementations, we just implement the given function twice using copy and paste. Plinth is not DRY.
Documentation
Types
Shape
Defines the shape of a matrix using rows and columns properties.
public struct Shape {
public let rows: Int
public let columns: Int
}This includes a number of convenience properties like count, length and breadth; as well as convenience initializers .row(length:), .column(length:) and .square(length:).
Matrix
Generic matrix struct with Scalar type argument and shape and elements properties. Elements are stored as a single array in row-major format.
public struct Matrix<Scalar> {
public let shape: Shape
public var elements: [Scalar]
}This also includes a large number of convenience initializers and implementations of typical typeclasses such as Codable and ExpressibleByArrayLiteral.
The elements property is directly mutable but this is ideally to be avoided; matrix regularity is not enforced, except during encoding to or decoding from a serialization format.
There is a computed property state which can be used to check if the matrix is considered to be malformed:
let malformed = Matrix<Double>(
shape: .init(rows: 2, columns: 2),
elements: [1.0, 2.0, 3.0, 4.0, 5.0]
)
print(malformed.state)> Malformed: Mismatched shape and elements; 2×2 != 5ComplexMatrix
Generic complex matrix struct encapsulating two separate matrices for the real and imaginary parts.
public struct ComplexMatrix<Scalar> where Scalar: Real {
public var real: Matrix<Scalar>
public var imaginary: Matrix<Scalar>
}This also includes a large number of convenience initializers and implementations of typical typeclasses such as Codable and ExpressibleByArrayLiteral.
The real and imaginary properties are also directly mutable; ComplexMatrix has its own state property which can be used to check if the parts are mismatched or malformed.
Core
Arithmetic
+ and - prefix operators and +, -, *, / infix operators.
Implements fast pointwise arithmetic for combinations of Scalar, Complex<Scalar>, Matrix<Scalar> and ComplexMatrix<Scalar>, where Scalar is Float or Double.
Conversions
Fast type conversions between the integer types UInt8, UInt16, UInt32, Int8, Int16, Int32 and the floating point types Float and Double.
Functors
Higher-order functions for shape-preserving operations on a matrix's elements.
Includes support for complex matrix operations on DSPSplitComplex/DSPDoubleSplitComplex.
Disclaimer: These are not true functors, Swift lacks higher-kinded types...
Submatrix
Fast submatrix read/write access using a Swift subscript interface.
Uses Accelerate's
vDSP_mmov/vDSP_mmovD.
Wrappers
Wrappers over most of the basic vDSP and vForce functions in Accelerate.
Transformations
Center
Find the center point of a matrix, given a rounding rule.
Concatenate
Concatentate multiple matrices together, row-wise or column-wise.
Crop
Crop a matrix towards the center, given a rounding rule.
Pad
Zero-pad a matrix away from the center, given a rounding rule.
Repeat
Repeat the elements in a matrix as rows or columns.
Reshape
Apply a new shape to a matrix, or reshape it as a single row or column.
This also supports both .rowMajor and .columnMajor orderings.
Reverse
Reverse a matrix's elements, rows, or columns.
Shift
Apply a circular shift to a matrix.
Mathematics
Comparisons
<, <=, >, >=, ==, !== infix operators.
Pointwise comparison or equality checks, returning 0.0 for false and 1.0 for true.
Interpolation
Linear interpolate values from a given range to/from 0.0...1.0.
This is similar to C++'s
std::lerp.
Powers
** infix operator.
Implements fast pointwise power operations for Scalar and Matrix.
Includes special functions for taking integer powers of matrices, for use when recursive application of vDSP.multiply will be faster than vForce.pow (which is quite an expensive operation).
This also supports negative integers by applying vForce.reciprocal to the result.
Ramps
Generate matrices which ramp from the start to end of a range of values, along cartesian or polar coordinates.
Statistics
Random
Generate matrices populated with random noise using the Swift random number generators or LAPACK functions for faster generation within set distributions.
Uses LAPACK's
slarnv_/dlarnv_for real matrices andclarnv_/zlarnv_for complex matrices.
Gaussian
Generate matrices populated with Gaussian noise using the Swift random number generators.
This is derived from an answer on the comp.lang.c FAQ.
Moments
Calculate central and standardized moments; convenience methods for variance, standardDeviation, skewness, and kurtosis.
Normalization
Normalize a matrix to 0.0...1.0 using its minimum() and maximum() values; or shift it so that its mean() is centered on zero.
Linear Algebra
Zeros
Generate matrices populated by zeros.
Ones
Generate matrices populated by ones.
Identity
Generate identity matrices.
Diagonal
Generate diagonal matrices.
Circulant
Generate circulant matrices.
Transposition
Transpose a matrix.
Uses Accelerate's
vDSP_mtrans/vDSP_mtransD.
Inversion
Calculate the inverse of a matrix.
Uses LAPACK's
sgetri_/dgetri_for real matrices andcgetri_/zgetri_for complex matrices.
Multiplication
<*> infix operator.
Implements matrix multiplication.
Uses Accelerate's
vDSP_mmul/vDSP_mmulDfor real matrices andvDSP_zmmul/vDSP_zmmulDfor complex matrices.
Division
/> and </ infix operators.
Implements left and right matrix division (multiplying by the inverse of a matrix).
Square Root
Complex square roots.
Formula taken from MATLAB's
sqrtfunction.
Exponentiation
Complex exponentials.
Formula taken from MATLAB's
expfunction.
Products
Inner and outer products.
Eigendecomposition
Calculate the eigendecomposition of a matrix. Includes support for only calculating the necessary components. Also includes support for sorting the eigenvectors by properties of the eigenvalues.
Uses LAPACK's
sgeev_/dgeev_. Swift implementation cribbed from Surge.
Roots
Calculate the roots of a polynomial by taking the eigenvalues of a companion matrix.
Signal Processing
FFT
Includes support for creating, reusing, and destroying your own FFTSetup/FFTSetupD structure.
FFT1D
Forward and inverse one-dimensional fourier transforms.
Some of the inverse fourier transform methods implement energy conservation by dividing by the size of the matrix.
Uses Accelerate's
vDSP_fft_zip/vDSP_fft_zipD.
FFT2D
Forward and inverse two-dimensional fourier transforms.
Some of the inverse fourier transform methods implement energy conservation by dividing by the size of the matrix.
Uses Accelerate's
vDSP_fft2d_zip/vDSP_fft2d_zipD.
FFTShift
Apply a circular rotation to a frequency-domain matrix so that the DC/DC signal is at the top left of the lower right quadrant.
FFTRamp
Generate centered ramps and ramps aligned to the FFT layout, for use when masking FFT signals.
Autocorrelation
Calculate the autocorrelation of a matrix by taking the product of the spectrum with its complex conjugate or magnitudes.
Autoconvolution
Calculate the autoconvolution of a matrix by taking the square of the spectrum or its magnitudes.
Convolution1D
Calculate convolutions using one-dimensional kernels.
Convolution2D
Calculate convolutions using two-dimensional kernels.
Resampling
Upsample and downsample signals, with an optional anti-aliasing filter.
Package Metadata
Repository: dclelland/Plinth
Stars: 12
Forks: 0
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
README: README.md