Expand description
Turbo4 encoder: rotated, standardized, 4-bit Lloyd-Max packed codes.
§Code blob layout (code_len = D/2 + 8 bytes)
[ D/2 packed nibbles | α: f32 LE | S: f32 LE ]- byte
iholds dimiin the low nibble and dimi + D/2in the high nibble — so SIMD unpacking yields two contiguous dimension runs (0..D/2andD/2..D) with no cross-lane shuffling; α = ‖v‖₂ / √D— the standardization factor (rotated coords are divided by α before table lookup, so they’re ~N(0,1));S = Σ level(cᵢ)²— precomputed for the L2 decomposition.
§Query blob layout (query_len = D + 8 bytes)
[ D int8 codes | qscale: f32 LE | ‖q‖²: f32 LE ]q_i8[i] = round(q_rot[i] / qscale), qscale = max|q_rot| / 127.
Blob lengths are structurally disjoint (D/2+8 vs D+8 for D ≥ 2), so a
scorer can tell the roles apart from slice lengths alone — this is what lets
hnsw_rs::Distance<u8>::eval run asymmetric scoring during traversal and
symmetric scoring during graph construction with one distance functor.
The original f32 vector is never stored — decoding reconstructs an approximation only, and only for tests/debugging.
Structs§
- Turbo4
Codec - The Turbo4 codec for a fixed (dimension, rotation-seed) pair.
- Turbo4
Query - A prepared query: the persisted-format blob plus the exact rotated f32 coordinates for final rescoring.
Constants§
- META_
BYTES - Bytes of per-blob constants (α + S, or qscale + ‖q‖²).
Functions§
- split_
code - Split a code blob into (packed nibbles, α, S).
blob.len()must equaldim/2 + META_BYTES. - split_
query - Split a query blob into (int8 codes, qscale, ‖q‖²).