pub struct ADCTable { /* private fields */ }Expand description
Asymmetric Distance Computation (ADC) lookup table for fast quantized search
Precomputes partial squared distances from a query vector to all possible quantized codes. This enables O(1) distance computation per dimension instead of O(dim) decompression + distance calculation.
§Performance
- Memory: For 4-bit: dim * 16 * 4 bytes (e.g., 1536D = 96KB per query)
- Speedup: 5-10x faster distance computation vs full decompression
- Use case: Scanning many candidate vectors during HNSW search
§Algorithm
Instead of:
for each candidate:
decompress(candidate) -> O(dim)
distance(query, decompressed) -> O(dim)With ADC:
precompute table[code] = (query_value - dequantize(code))^2 for all codes
for each candidate:
sum(table[candidate[i]]) -> O(1) per dimensionImplementations§
Source§impl ADCTable
impl ADCTable
Sourcepub fn new_trained(
query: &[f32],
trained: &TrainedParams,
params: &RaBitQParams,
) -> Self
pub fn new_trained( query: &[f32], trained: &TrainedParams, params: &RaBitQParams, ) -> Self
Build ADC lookup table using trained quantization parameters
This is the production method that computes correct distances. Uses per-dimension min/max ranges from training.
§Arguments
query- The uncompressed query vectortrained- Trained parameters with per-dimension min/maxparams- Quantization parameters (bits per dimension)
Sourcepub fn new(query: &[f32], scale: f32, params: &RaBitQParams) -> Self
pub fn new(query: &[f32], scale: f32, params: &RaBitQParams) -> Self
Build ADC lookup table for a query vector (DEPRECATED)
For each dimension and each possible quantized code, precomputes the squared distance contribution: (query[i] - dequantize(code, scale))^2
WARNING: This method uses a fixed scale which produces incorrect distances
when vectors were quantized with different scales. Use new_trained() instead.
§Arguments
query- The uncompressed query vectorscale- The scale factor used for quantization (from training or default)params- Quantization parameters (bits per dimension)
§Returns
An ADCTable that can compute distances via distance() method
§Note
Prefer ADCTable::new_trained() with TrainedParams for correct ADC distances.
This method uses per-vector scale which gives lower accuracy.
Sourcepub fn distance_squared(&self, data: &[u8]) -> f32
pub fn distance_squared(&self, data: &[u8]) -> f32
Compute approximate L2 squared distance using lookup table
This is the hot path for search! Instead of decompressing and computing distance, we just sum up precomputed values from the table.
§Performance
- 4-bit: ~5-10x faster than decompression + distance
- Cache-friendly: sequential access patterns
- SIMD-friendly: can vectorize the summation
§Arguments
data- Packed quantized bytes
§Returns
Approximate squared L2 distance (not square-rooted for efficiency)
Sourcepub fn distance(&self, data: &[u8]) -> f32
pub fn distance(&self, data: &[u8]) -> f32
Compute distance and return square root (actual L2 distance)
Uses SIMD-accelerated distance computation (AVX2 on x86_64, NEON on aarch64).
Sourcepub fn distance_squared_simd(&self, data: &[u8]) -> f32
pub fn distance_squared_simd(&self, data: &[u8]) -> f32
SIMD-accelerated distance computation for 4-bit quantization
Uses AVX2 on x86_64 or NEON on aarch64 to process multiple lookups in parallel.
Falls back to scalar implementation if SIMD not available.
Sourcepub fn dimensions(&self) -> usize
pub fn dimensions(&self) -> usize
Get number of dimensions
Sourcepub fn get(&self, dim: usize, code: usize) -> f32
pub fn get(&self, dim: usize, code: usize) -> f32
Get partial distance for a dimension and code
Returns 0.0 if indices are out of bounds.
Sourcepub fn memory_bytes(&self) -> usize
pub fn memory_bytes(&self) -> usize
Get memory usage in bytes
Trait Implementations§
Auto Trait Implementations§
impl Freeze for ADCTable
impl RefUnwindSafe for ADCTable
impl Send for ADCTable
impl Sync for ADCTable
impl Unpin for ADCTable
impl UnwindSafe for ADCTable
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more