<h1 align="center">
<img width="99" alt="Rust logo" src="https://raw.githubusercontent.com/jamesgober/rust-collection/72baabd71f00e14aa9184efcb16fa3deddda3a0a/assets/rust-logo.svg">
<br>
<b>iqdb-distance</b>
<br>
<sub><sup>iQDB DISTANCE FUNCTIONS</sup></sub>
</h1>
<div align="center">
<a href="https://crates.io/crates/iqdb-distance"><img alt="Crates.io" src="https://img.shields.io/crates/v/iqdb-distance"></a>
<a href="https://crates.io/crates/iqdb-distance"><img alt="Downloads" src="https://img.shields.io/crates/d/iqdb-distance?color=%230099ff"></a>
<a href="https://docs.rs/iqdb-distance"><img alt="docs.rs" src="https://img.shields.io/docsrs/iqdb-distance"></a>
<a href="https://github.com/jamesgober/iqdb-distance/actions"><img alt="CI" src="https://github.com/jamesgober/iqdb-distance/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://github.com/rust-lang/rfcs/blob/master/text/2495-min-rust-version.md"><img alt="MSRV" src="https://img.shields.io/badge/MSRV-1.87%2B-blue"></a>
</div>
<br>
<div align="left">
<p>
<strong>iqdb-distance</strong> is the innermost loop of the database: every search computes thousands of distances, so this crate is optimized aggressively while keeping a readable scalar reference.
</p>
<p>
It provides every metric vector search needs — cosine, dot product, Euclidean, Manhattan, and Hamming — with SIMD implementations that are property-tested to match the scalar ground truth within floating-point tolerance.
</p>
<br>
<hr>
<p>
<strong>MSRV is 1.87+</strong> (Rust 2024 edition). SIMD-accelerated. Scalar fallback. Property-tested equivalence.
</p>
<blockquote>
<strong>Status: stable (1.0).</strong> The public API is committed under SemVer for the 1.x series — no breaking changes until 2.0. See <a href="./CHANGELOG.md"><code>CHANGELOG.md</code></a>.
</blockquote>
</div>
<hr>
<br>
<h2>What it does</h2>
- **Every metric** — cosine, dot product, Euclidean (L2), Manhattan (L1), Hamming
- **SIMD + scalar** — AVX2 on x86_64, NEON on aarch64, with a readable scalar fallback
- **Runtime dispatch** — detect CPU features once; route each call to the fastest available kernel
- **Two entry points** — a type-level `Distance` trait when the metric is known at compile time, and `compute`/`compute_batch` over `DistanceMetric` when it is chosen at runtime
- **Normalized fast path** — `cosine_normalized` (and a `normalize` helper) skip the norm work for pre-normalized embeddings
- **Allocation-free** — every distance call borrows; batch evaluation writes into a caller-owned buffer
- **Never panics on bad input** — empty, mismatched, and non-finite inputs return a typed `IqdbError`
- **Standalone** — usable by anyone doing vector similarity in Rust, iQDB or not
<br>
## Installation
```toml
[dependencies]
iqdb-distance = "1.0"
```
<br>
## Quick start
Pick the metric at compile time through the `Distance` trait:
```rust
use iqdb_distance::{Cosine, Distance, Euclidean};
let a = [1.0_f32, 0.0, 0.0];
let b = [0.0_f32, 1.0, 0.0];
// Cosine distance of perpendicular unit vectors is 1.0.
let cos = Cosine::compute(&a, &b).expect("non-empty, same length");
assert!((cos - 1.0).abs() < 1e-6);
// Euclidean (L2): a 3-4-5 right triangle.
let l2 = Euclidean::compute(&[0.0, 0.0, 0.0], &[3.0, 4.0, 0.0]).expect("valid pair");
assert!((l2 - 5.0).abs() < 1e-6);
```
Or pick it at runtime with the `DistanceMetric` tag from `iqdb-types`:
```rust
use iqdb_distance::compute;
use iqdb_types::DistanceMetric;
let a = [1.0_f32, 2.0, 3.0];
let b = [4.0_f32, -5.0, 6.0];
// Dot-product similarity: 1*4 + 2*(-5) + 3*6 = 12.
let s = compute(DistanceMetric::DotProduct, &a, &b).expect("valid pair");
assert!((s - 12.0).abs() < 1e-6);
```
Score one query against many candidates into a caller-owned buffer (no allocation):
```rust
use iqdb_distance::compute_batch;
use iqdb_types::DistanceMetric;
let query = [0.0_f32, 0.0];
let candidates: [&[f32]; 3] = [&[1.0, 0.0], &[0.0, 2.0], &[3.0, 4.0]];
let mut out = [0.0_f32; 3];
compute_batch(DistanceMetric::Euclidean, &query, &candidates, &mut out)
.expect("output length matches candidate count");
assert_eq!(out, [1.0, 2.0, 5.0]);
```
When embeddings are already unit length, take the fast cosine path — it skips the norm, square root, and division:
```rust
use iqdb_distance::{cosine_normalized, normalize};
// Normalize once at ingest, then compare with the fast path.
let a = normalize(&[1.0_f32, 2.0, 3.0]).expect("non-zero magnitude");
let b = normalize(&[-2.0_f32, 0.5, 4.0]).expect("non-zero magnitude");
let d = cosine_normalized(&a, &b).expect("valid pair"); // 1 - dot(a, b)
assert!((0.0..=2.0).contains(&d));
```
Inspect the kernel the host will use:
```rust
let features = iqdb_distance::detect_features();
// On an AVX2 x86_64 host `features.avx2` is true; on aarch64 `features.neon` is.
let _ = (features.avx2, features.neon);
```
<br>
## Errors
Every fallible call returns `iqdb_types::Result`. Empty inputs surface as
`IqdbError::InvalidVector`; length mismatches as
`IqdbError::DimensionMismatch { expected, found }`; a batch whose output buffer
does not match the candidate count returns `IqdbError::InvalidConfig`. The
library never panics on hostile input.
<br>
## Status
<code>v1.0.0</code> — **stable.** All five metrics ship with a scalar reference path plus runtime-dispatched AVX2 and NEON kernels, each property-tested, differentially verified, **and fuzzed** against the scalar twin; the `cosine_normalized` fast path for pre-normalized embeddings; and allocation-free batch evaluation. The public API is committed under SemVer for the 1.x series (no breaking changes until 2.0; the frozen surface is recorded in the <a href="./dev/ROADMAP.md"><code>ROADMAP</code></a>), benchmarked (6.8–10.3× SIMD speedups on AVX2 at 768-dim), and verified on Windows + Linux across stable and the 1.87 MSRV. The full surface is documented in <a href="./docs/API.md"><code>docs/API.md</code></a>.
<hr>
<br>
## Where It Fits
`iqdb-distance` sits just above the types crate. It powers:
- `iqdb-types` — the `DistanceMetric` enum and vector types it operates on
- `iqdb-quantize` — quantized distance reuses this SIMD infrastructure
- `iqdb-flat` / `iqdb-hnsw` / `iqdb-ivf` — every index computes distances here
Its only first-party dependency is `iqdb-types`, so it is unblocked today.
<br>
## Standards
Built to the iQDB Rust standard. See <a href="./REPS.md"><code>REPS.md</code></a> (Rust Efficiency & Performance Standards) and <a href="./dev/DIRECTIVES.md"><code>dev/DIRECTIVES.md</code></a> for the engineering law and the definition of done. Before a PR: `cargo fmt --all`, `cargo clippy --all-targets --all-features -- -D warnings`, and `cargo test --all-features` must be clean.
<br>
<div id="license">
<h2>License</h2>
<p>Licensed under either of</p>
<ul>
<li><b>Apache License, Version 2.0</b> — <a href="./LICENSE-APACHE">LICENSE-APACHE</a></li>
<li><b>MIT License</b> — <a href="./LICENSE-MIT">LICENSE-MIT</a></li>
</ul>
<p>at your option.</p>
</div>
<div align="center">
<h2></h2>
<sup>COPYRIGHT <small>©</small> 2026 <strong>JAMES GOBER.</strong></sup>
</div>