pub struct ProductQuantizer { /* private fields */ }Expand description
Product quantizer: M subvectors × K centroids per subvector.
Build one with ProductQuantizer::new for the standard
M = 8, K = 256 shape, or ProductQuantizer::with_config to
pick M, K, and the training seed explicitly. Train it once
with a representative sample, then quantize and compare. The
trained quantizer is callable from multiple threads — it owns its
calibration by value and exposes no interior mutability.
§Examples
use iqdb_quantize::{ProductQuantizer, Quantizer};
use iqdb_types::DistanceMetric;
let mut pq = ProductQuantizer::with_config(2, 4, 7);
let training: Vec<Vec<f32>> = (0..16)
.map(|i| {
let f = i as f32;
vec![f, f + 1.0, f + 2.0, f + 3.0]
})
.collect();
let refs: Vec<&[f32]> = training.iter().map(Vec::as_slice).collect();
pq.train(&refs).expect("training succeeds");
let code = pq.quantize(&[1.0_f32, 2.0, 3.0, 4.0]).expect("quantize");
let d = pq
.distance(&[1.0_f32, 2.0, 3.0, 4.0], &code, DistanceMetric::Euclidean)
.expect("supported metric");
assert!(d.is_finite());Implementations§
Source§impl ProductQuantizer
impl ProductQuantizer
Sourcepub fn new() -> Self
pub fn new() -> Self
Build an untrained PQ with the standard shape (M = 8,
K = 256, seed = 0).
Every hot method returns IqdbError::InvalidConfig until
Quantizer::train succeeds. The trained dimension must be a
multiple of M, so new()’s M = 8 works for the common
embedding dimensions (128, 256, 384, 512, 768, 1024, …) but
not for, say, dim 50; use ProductQuantizer::with_config
when that matters.
§Examples
use iqdb_quantize::ProductQuantizer;
let pq = ProductQuantizer::new();
assert_eq!(pq.n_subvectors(), 8);
assert_eq!(pq.n_centroids(), 256);Sourcepub fn with_config(n_subvectors: usize, n_centroids: usize, seed: u64) -> Self
pub fn with_config(n_subvectors: usize, n_centroids: usize, seed: u64) -> Self
Build an untrained PQ with the given shape and training seed.
All three parameters take effect at Quantizer::train time;
invalid combinations (e.g. n_centroids == 0, n_centroids > 256, training dim not divisible by n_subvectors) surface as
IqdbError::InvalidConfig from train. The constructor
itself is infallible — it just stores the configuration.
§Examples
use iqdb_quantize::ProductQuantizer;
let pq = ProductQuantizer::with_config(16, 256, 42);
assert_eq!(pq.n_subvectors(), 16);
assert_eq!(pq.n_centroids(), 256);
assert_eq!(pq.seed(), 42);Sourcepub fn dim(&self) -> Option<usize>
pub fn dim(&self) -> Option<usize>
The trained dimension, if any.
§Examples
use iqdb_quantize::{ProductQuantizer, Quantizer};
let mut pq = ProductQuantizer::with_config(2, 4, 7);
assert_eq!(pq.dim(), None);
let data: Vec<Vec<f32>> = (0..8).map(|i| vec![i as f32; 4]).collect();
let refs: Vec<&[f32]> = data.iter().map(Vec::as_slice).collect();
pq.train(&refs).expect("ok");
assert_eq!(pq.dim(), Some(4));Sourcepub fn n_subvectors(&self) -> usize
pub fn n_subvectors(&self) -> usize
The configured number of subvectors M.
§Examples
use iqdb_quantize::ProductQuantizer;
assert_eq!(ProductQuantizer::with_config(4, 16, 1).n_subvectors(), 4);Sourcepub fn n_centroids(&self) -> usize
pub fn n_centroids(&self) -> usize
The configured number of centroids per subvector codebook K.
§Examples
use iqdb_quantize::ProductQuantizer;
assert_eq!(ProductQuantizer::with_config(4, 16, 1).n_centroids(), 16);Source§impl ProductQuantizer
impl ProductQuantizer
Sourcepub fn build_query_tables(
&self,
query: &[f32],
metric: DistanceMetric,
) -> Result<PqAdcTables>
pub fn build_query_tables( &self, query: &[f32], metric: DistanceMetric, ) -> Result<PqAdcTables>
Build the ADC lookup tables for (query, metric) once so the
caller can score many PqCodes against the same query
without rebuilding the M × K table per call.
This is the primitive that
Quantizer::distance is built
on; callers scoring a single code can keep using distance
directly. Use this method when scoring a batch — e.g.
IVF-PQ’s intra-cluster scan, which builds the table once per
query and then scores every code in every probed cluster.
§Errors
Returns IqdbError::InvalidConfig if the quantizer is
untrained, IqdbError::InvalidVector if query is empty or
non-finite, IqdbError::DimensionMismatch if query.len()
doesn’t match the trained dim, or IqdbError::InvalidMetric
for DistanceMetric::Cosine / DistanceMetric::Hamming.
§Examples
use iqdb_quantize::{ProductQuantizer, Quantizer};
use iqdb_types::DistanceMetric;
let mut pq = ProductQuantizer::with_config(2, 4, 7);
let training: Vec<Vec<f32>> = (0..16)
.map(|i| {
let f = i as f32;
vec![f, f + 1.0, f + 2.0, f + 3.0]
})
.collect();
let refs: Vec<&[f32]> = training.iter().map(Vec::as_slice).collect();
pq.train(&refs).expect("training succeeds");
let code_a = pq.quantize(&[1.0_f32, 2.0, 3.0, 4.0]).expect("quantize");
let code_b = pq.quantize(&[5.0_f32, 6.0, 7.0, 8.0]).expect("quantize");
// Build the table ONCE for this (query, metric), then score many codes.
let query = [1.0_f32, 2.0, 3.0, 4.0];
let tables = pq
.build_query_tables(&query, DistanceMetric::Euclidean)
.expect("supported metric");
let d_a = tables.distance(&code_a).expect("matching code shape");
let d_b = tables.distance(&code_b).expect("matching code shape");
assert!(d_a.is_finite() && d_b.is_finite());Trait Implementations§
Source§impl Clone for ProductQuantizer
impl Clone for ProductQuantizer
Source§fn clone(&self) -> ProductQuantizer
fn clone(&self) -> ProductQuantizer
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ProductQuantizer
impl Debug for ProductQuantizer
Source§impl Default for ProductQuantizer
impl Default for ProductQuantizer
Source§impl PartialEq for ProductQuantizer
impl PartialEq for ProductQuantizer
Source§impl Quantizer for ProductQuantizer
impl Quantizer for ProductQuantizer
Source§type Quantized = PqCode
type Quantized = PqCode
Quantizer::quantize.Source§fn train(&mut self, vectors: &[&[f32]]) -> Result<()>
fn train(&mut self, vectors: &[&[f32]]) -> Result<()>
Source§fn quantize(&self, vector: &[f32]) -> Result<Self::Quantized>
fn quantize(&self, vector: &[f32]) -> Result<Self::Quantized>
vector as a compact code. Read more