The dual-phase quantization codec trait. `Quantized` is the on-disk / in-memory packed form (one per vector). `Query` is the prepared query — may be raw FP32, may be rotated, may hold a precomputed ADC LUT, depending on the codec. # Extensibility audit — future algorithms The following six algorithms can each be added as a new `impl VectorCodec` without changing the trait surface: TurboQuant**
| 99 | /// `packed_bits` (the codec controls that region's layout entirely). No trait |
| 100 | /// change needed. |
| 101 | pub trait VectorCodec: Send + Sync { |
| 102 | /// The packed quantized form. Must be convertible to a `UnifiedQuantizedVector` |
| 103 | /// reference via `AsRef`. |
| 104 | type Quantized: AsRef<UnifiedQuantizedVector>; |
| 105 | |
| 106 | /// The prepared query form (codec-specific). |
| 107 | type Query; |
| 108 | |
| 109 | /// Encode a single FP32 vector into the codec's packed form. |
| 110 | fn encode(&self, v: &[f32]) -> Self::Quantized; |
| 111 | |
| 112 | /// Prepare a query for distance computations against this codec. |
| 113 | /// May rotate, normalize, build a LUT, etc. |
| 114 | fn prepare_query(&self, q: &[f32]) -> Self::Query; |
| 115 | |
| 116 | /// Optional: precompute ADC lookup table for codecs that use one |
| 117 | /// (PQ, IVF-PQ, TurboQuant). Returns `None` for codecs that don't |
| 118 | /// (RaBitQ, BBQ, ternary, binary). |
| 119 | fn adc_lut(&self, _q: &Self::Query) -> Option<AdcLut> { |
| 120 | None |
| 121 | } |
| 122 | |
| 123 | /// Optional: fit the codec's learned parameters on a set of training vectors. |
| 124 | /// |
| 125 | /// Called once before encoding begins, typically at index-build time. Codecs |
| 126 | /// with no learnable parameters (binary sign-bit, ternary) can use the |
| 127 | /// default no-op. Codecs with an SVD- or k-means-based fitting phase |
| 128 | /// (ITQ3_S, OPQ, PQ, TurboQuant) override this to update their internal |
| 129 | /// rotation matrices or codebooks. |
| 130 | /// |
| 131 | /// Returns `Ok(())` on success. The error type is `CodecError` so callers |
| 132 | /// that drive training through a generic bound can propagate failures without |
| 133 | /// knowing the concrete codec. |
| 134 | /// |
| 135 | /// The default implementation is a no-op and always returns `Ok(())`. |
| 136 | #[allow(unused_variables)] |
| 137 | fn train(&mut self, samples: &[&[f32]]) -> Result<(), crate::error::CodecError> { |
| 138 | Ok(()) |
| 139 | } |
| 140 | |
| 141 | /// Fast symmetric distance — bitwise / heuristic. Used during HNSW |
| 142 | /// upper-layer routing. Both arguments are quantized; no scalar |
| 143 | /// correction; no outlier resolution. Hot path; must be inline-friendly. |
| 144 | fn fast_symmetric_distance(&self, q: &Self::Quantized, v: &Self::Quantized) -> f32; |
| 145 | |
| 146 | /// Exact asymmetric distance — full ADC with scalar correction and |
| 147 | /// sparse outlier resolution. Used at base-layer rerank only. Slower |
| 148 | /// but high-fidelity. |
| 149 | fn exact_asymmetric_distance(&self, q: &Self::Query, v: &Self::Quantized) -> f32; |
| 150 | } |
| 151 | |
| 152 | #[cfg(test)] |
| 153 | mod tests { |
nothing calls this directly
no outgoing calls
no test coverage detected