Sitemap

Introducing Quiver: Vector Mathematics and Machine Learning, Now in Swift

9 min readMar 30, 2026
Press enter or click to view image in full size

Today I’m pleased to announce Quiver — a Swift package for vector mathematics, numerical computing, and machine learning. Yes, in Swift.

If you write Swift, that sentence probably needs no further explanation. If you don’t — welcome. This is a story about a ten-year relationship with a programming language, a detour through Coursera, and eventually building something I wanted to exist.

Where This Started

My relationship with Swift began in 2014 when Apple announced the language at WWDC. I’ve been working in it ever since — and writing about it. The fifth edition of my Swift Algorithms & Data Structures book arrives alongside Quiver, with its final chapters covering the vectors, matrices, and machine learning concepts this framework is built on.

During my time in software there’s been a gap worth closing — and the TIOBE index quietly tells that story. Python sits at number one programming language with over 21% market share. Swift, the primary language for the world’s most profitable device ecosystem, currently hovers around 20th. The reason isn’t the language. It’s that Swift is largely perceived as a tool for building apps, not for the kind of work — data science, machine learning, numerical computing — that drives the most excitement in software today. Expanding that perception, through education and accessible tooling, has been a personal goal for a long time.

Press enter or click to view image in full size

A few years ago I decided to properly understand machine learning — not just the surface concepts, but the actual mathematics underneath. I enrolled in courses on Coursera and quickly noticed something: every single data science course, machine learning tutorial and assignment is in Python.

This isn’t surprising. Python dominates this space for good reason — NumPy, pandas, scikit-learn, PyTorch — the ecosystem is extraordinary and continues to grow. Understanding the world’s most popular programming language has always been a career goal of mine, so it was genuinely exciting to step in and discover how it all works.

However, after a few months I considered how would this work in Swift?

From Linear Algebra to Machine Learning

Before diving into code, it’s worth defining terms.

A vector is simply an ordered list of numbers. Vectors can describe a point or direction in space — but they can also represent relationships. A user’s rating across five movie categories is a vector. So is their purchase history, their listening habits, or their engagement patterns. The numbers don’t have to mean “up” or “left.” They just have to mean something, consistently. Once they do, you can measure how far apart two vectors are, how similar they are, and which direction they point relative to each other — and those three questions are the foundation of machine learning.

How It Works

Quiver adds numerical computing capabilities directly to Swift’s standard Array type using a language feature called extensions. Rather than introducing custom container types, Quiver works with standard Swift Array. The result is that a plain [Double] gains mathematical operations without becoming a different type.

import Quiver

// This is a standard Swift Array<Double> — nothing special
let position = [3.0, 4.0]

// Quiver adds .magnitude directly to the array
position.magnitude // 5.0

Swift’s type system also encodes dimensionality. The compiler distinguishes between [Double] (a vector) and [[Double]] (a matrix) at compile time — there is no need to query how many dimensions an array has at runtime. The type signature already tells you.

The Quiver Model

One of Quiver’s core goals is that the mathematics and the models live in the same place. A student working through linear algebra uses the same framework they’ll use to train their first ML model. The concepts form a continuous thread.

Here’s what that thread looks like.

Magnitude is the length of a vector — how far a point sits from the origin. It’s the Pythagorean theorem applied to as many dimensions as the array has. For [3, 4], that’s √(3² + 4²) = 5. Simple enough for a classroom, and the same calculation K-Nearest Neighbors runs every time it finds the closest training example.

import Quiver

let velocity = [3.0, 4.0]
velocity.magnitude // √(3² + 4²) = 5.0

We can represent velocity as well as its length in vector space with the following visualization:

Press enter or click to view image in full size

Normalization takes a vector and scales it so its length becomes exactly 1, preserving direction while removing magnitude. This is how you compare two things based purely on what they represent rather than how large they are. And for educators — asFractions() converts the result into its rational form, making the underlying math visible rather than hidden behind decimals.

import Quiver

let v = [3.0, 4.0]

// Magnitude: the length of the vector
v.magnitude // 5.0

// Direction: a unit vector (length of 1) pointing the same way
v.normalized // [0.6, 0.8]

// See the rational form
v.normalized.asFractions() // [3/5, 4/5]

Calculating Distance — Quiver provides both a magnitude property — how far a point sits from the origin — and a distance(to:) method for measuring the gap between any two points directly. Distance is one of the key concepts that connects abstract mathematics to machine learning.

import Quiver

let pointA = [4.0, 7.0]
let pointB = [1.0, 3.0]

pointA.distance(to: pointB) // 5.0 - straight-line distance between the two points
pointA.magnitude // 8.06 - distance from the origin to pointA

// Proof: magnitude is just a special case of distance(to:)
// where the starting point is always the origin
let origin = [0.0, 0.0]

origin.distance(to: pointA) // 8.06 - identical to pointA.magnitude

This one is a bit tricky to conceptualize so another illustration helps:

Press enter or click to view image in full size

The dot product reveals the angular relationship between two vectors. Multiply corresponding elements and sum them. Positive means similar direction, zero means perpendicular, negative means opposing — the building block for cosine similarity, and an operation that runs inside every Quiver model.

import Quiver

let v1 = [1.0, 0.0] // points right
let v2 = [0.0, 1.0] // points up

v1.dot(v2) // 0.0 - perpendicular, no shared direction

Cosine similarity normalizes the dot product by both vectors’ magnitudes, stripping away scale and isolating direction. Two vectors that point the same way score 1.0 regardless of length. This is the engine behind recommendation systems, semantic search, and duplicate detection.

import Quiver

let userA = [5.0, 2.0, 4.0] // movie ratings: action, drama, comedy
let userB = [4.0, 1.0, 5.0]

userA.cosineOfAngle(with: userB) // ~0.97 - very similar taste

Determinants tell you whether a matrix is invertible. Linear regression finds its coefficients by inverting a feature matrix, so a non-zero determinant is the mathematical prerequisite before any model can fit.

import Quiver


let features = [[1.0, 2.0],
[3.0, 4.0]]

features.determinant // -2.0 - columns are independent, safe to fit

Each of these is a concept from linear algebra. Each one also forms the foundation of a machine learning model.

Being Swifty in Vector Mathematics

Swift developers will notice several things that make Quiver feel at home. Every result type conforms to both Sequence and Equatable. And Equatable runs deeper than just the models — it covers the entire pipeline, from preprocessing through training to evaluation.

import Quiver                                                                                                                                                             

let data: [[Double]] = [
[1.0, 2.0], [1.5, 1.8], [5.0, 8.0],
[6.0, 9.0], [1.2, 2.1], [5.5, 7.5]
]

// Train two models with the same seed
let run1 = KMeans.fit(data: data, k: 2, seed: 42)
let run2 = KMeans.fit(data: data, k: 2, seed: 42)

run1 == run2 // true — Equatable conformance

// Iterate clusters directly — Sequence conformance
for cluster in run1.clusters(from: data) {
print("Center: \(cluster.centroid), size: \(cluster.count)")
for point in cluster {
print(" \(point)")
}
}

In Quiver, fit() returns a fully trained, immutable value — a Swift struct. You cannot refit it, mutate its coefficients, or call predict on something that hasn’t been trained. The compiler makes that class of mistake impossible rather than something you discover at runtime.

This example applies the popular K-Means algorithm to associate similar feature vectors into clusters. The k in K-means establishes the number of clusters and is set by the developer. The math determines how to group each vector:

Press enter or click to view image in full size

At high level we can see the formation of two clusters but it’s hard to see the exact positioning of each cluster’s centroid. A centroid is simply the average position of a group of points. The algorithm uses centroids to represent the “center” of each cluster.

Let’s zoom to one of the clusters for a closer look:

Press enter or click to view image in full size

We can even go a step further and see how the centroid was calculated :

Press enter or click to view image in full size

The Four Models

Quiver ships with four machine learning models at 1.0.0. Every model follows the same two-step API — fit, then predict. Once trained, a model is immutable. The same seed always produces the same result.

  • Linear Regression — predicts continuous values. Give it house features; it learns to predict prices, with directly interpretable coefficients.
  • Gaussian Naive Bayes — fast classification that trains in a single pass. A reliable baseline for almost any problem.
  • K-Nearest Neighbors — classifies by proximity, using the Euclidean distance from the section above.
  • K-Means Clustering — finds natural structure in unlabeled data. The algorithm behind customer segmentation and anomaly detection.
import Quiver


let features: [[Double]] = [
[85.0, 30.0], [90.0, 25.0], [78.0, 40.0], [82.0, 35.0], [88.0, 28.0],
[65.0, 85.0], [60.0, 90.0], [68.0, 80.0], [62.0, 88.0], [64.0, 82.0]
]

let labels = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] // 0 = no rain, 1 = rain

// Split data - training and test sets stay separate
let (trainX, testX) = features.trainTestSplit(testRatio: 0.2, seed: 42)
let (trainY, testY) = labels.trainTestSplit(testRatio: 0.2, seed: 42)

// Scale features so both columns contribute equally
let scaler = FeatureScaler.fit(features: trainX)

let scaledTrain = scaler.transform(trainX)
let scaledTest = scaler.transform(testX)

// Train, predict, evaluate
let model = GaussianNaiveBayes.fit(features: scaledTrain, labels: trainY)
let predictions = model.predict(scaledTest)

print(predictions.classificationReport(actual: testY))

Honest About Scope

People will ask if this is a NumPy replacement. It isn’t. NumPy has been in development since 2006, built on C foundations, and is the engine underneath one of the most extensive data science ecosystems ever assembled. That breadth is a genuine achievement — the Python community has spent decades building something remarkable. GPU acceleration, automatic differentiation, and distributed training are outside Quiver’s scope, and deliberately so. Every decision not to add a dependency is a decision to keep the framework running everywhere Swift runs — macOS, iPhone, Apple Watch, and server-side Swift on Linux — without conditions.

However, that being said the hope is to grow the Quiver ecosystem — adding new models and mathematics to help power student curriculum or even your next app.

Get Started

Open a project in Xcode and navigate to File → Add Package Dependencies. In the search field, enter the repository URL: https://github.com/waynewbishop/quiver. Set the dependency rule to Up to Next Major Version starting from 1.0.0, then click Add Package. Xcode resolves and downloads the package automatically.

For Swift packages, add Quiver as a dependency in Package.swift:

dependencies: [
.package(url: "https://github.com/waynewbishop/quiver", from: "1.0.0")
]

Quiver runs everywhere Swift runs — iPhone, iPad, Mac, Apple Watch, Apple Vision Pro, and server-side Swift on Linux with Vapor.

The Quiver Cookbook has 30+ interactive recipes that walk through essential machine learning concepts step by step — from vectors and dot products to training classifiers and clustering data. Each recipe runs as a#Playground macro in Xcode 26+, so the results appear as you type.

The Quiver documentation covers every API with conceptual guides, code examples, and three primers on linear algebra, determinants, and machine learning fundamentals. Whether exploring a new concept or looking up a specific method, the docs are designed to teach the math alongside the code.

What makes Quiver fun is that it all lives in one place. Learn the mathematics in Xcode, build and train models in Xcode, then take those models directly into an app — also in Xcode. No context switching, no separate environment, no files to download, no translation layer between learning and shipping.

This project started as personal education — a Swift developer wanting to understand machine learning. Getting to 1.0.0 took longer and went in more interesting directions than I expected.

I hope Quiver sparks interest, curiosity and imagination.

Welcome to Quiver.

--

--

Wayne Bishop
Wayne Bishop

Written by Wayne Bishop

I write about Swift Development & Computer Science. Let's connect on LinkedIn at - www.linkedin.com/in/waynebishop.