- Scalar quantization (SQ8) — f32 →
u8per dimension, ~4× compression; asymmetric distance under every metric - Product quantization (PQ) — subvector k-means codebooks, up to ~192× compression, with batch-ADC scoring for IVF-PQ
- Binary quantization (BQ) — one bit per dimension, 32× compression, Hamming distance on packed
u64words - One trait —
train→quantize→distance, every method fallible and returning a typed error - Asymmetric distance — compress the database, keep the query in f32 for better recall
- Deterministic — same seed + same data ⇒ byte-identical PQ codebooks on every platform
- Never panics on bad input — empty, non-finite, mismatched, untrained, and unsupported-metric inputs return a typed
IqdbError
Installation
[]
= "1.0"
Quick start
Train on a representative sample, then quantize and score. Scalar (SQ8) supports every metric:
use ;
use DistanceMetric;
let training: = vec!;
let refs: = training.iter.map.collect;
let mut sq = new;
sq.train.unwrap;
let code = sq.quantize.unwrap; // 3 bytes
let d = sq.distance.unwrap;
assert!;
Product (PQ) trades a little recall for big compression, and precomputes a query table for batch scoring:
use ;
use DistanceMetric;
let mut pq = with_config; // M = 2 subvectors, K = 4, seed = 7
let training: =
.map
.collect;
let refs: = training.iter.map.collect;
pq.train.unwrap;
// Build the ADC table once per query, then score many codes against it.
let query = ;
let tables = pq.build_query_tables.unwrap;
let code = pq.quantize.unwrap; // 2 bytes
let d = tables.distance.unwrap;
assert!;
Binary (BQ) is the highest-compression scheme, scored with Hamming distance:
use ;
use DistanceMetric;
let mut bq = new;
bq.train.unwrap;
let code = bq.quantize.unwrap; // packed u64 words
let d = bq.distance.unwrap;
assert_eq!; // self-distance is zero
Two rules to use quantization well: train on representative data, and search quantized but rerank with full f32. Skipping the rerank is the most common cause of "quantization broke recall" reports.
How to use it
Every method of the Quantizer trait is fallible and returns iqdb_types::Result. The library never panics on bad input.
ScalarQuantizer(SQ8) — per-dimension affine calibration; codes areu8. Supports everyDistanceMetricvia asymmetric distance throughiqdb-distance.ProductQuantizer(PQ) —M-byte codes via deterministic k-means codebooks.PqAdcTablesprecomputes per-query lookup tables for batch scoring. SupportsEuclidean,DotProduct,Manhattan;Cosine(no global norm — L2-normalize and useDotProduct) andHamming(wrong code space) returnIqdbError::InvalidMetric.BinaryQuantizer(BQ) — one bit per dimension, packed intoVec<u64>. SupportsDistanceMetric::Hammingonly; other metrics returnIqdbError::InvalidMetric.
The full per-item reference, including the metric-support matrix and the error variants, is in docs/API.md.
Status
v1.0.0 — stable. SQ8, PQ, and BQ all ship behind a single Quantizer trait, with the PqAdcTables batch-ADC primitive, deterministic seeded k-means, property tests for round-trip and distance invariants, recall integration tests against full-f32 baselines, a consumer-simulation soak that builds a mini IVF-PQ on the public surface, tracing instrumentation, a criterion bench harness, and five runnable examples. 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 ROADMAP), has zero unsafe, and is verified on Windows and Linux across stable and the 1.87 MSRV. The full surface is documented in docs/API.md.
Where It Fits
iqdb-quantize is a Phase-2 crate, independent of the index layer. It builds on:
iqdb-types— theDistanceMetric,IqdbError, andResultvocabularyiqdb-distance— the f32 distance kernels SQ8 and PQ delegate to
and is consumed by:
iqdb-ivf— IVF-PQ scores in-cluster codes throughPqAdcTables
It is an optimization, not a requirement: iQDB runs without it.
Standards
Built to the iQDB Rust standard. See REPS.md (Rust Efficiency & Performance Standards) and dev/DIRECTIVES.md 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.