Skip to main content

Module codec

Module codec 

Source
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 i holds dim i in the low nibble and dim i + D/2 in the high nibble — so SIMD unpacking yields two contiguous dimension runs (0..D/2 and D/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§

Turbo4Codec
The Turbo4 codec for a fixed (dimension, rotation-seed) pair.
Turbo4Query
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 equal dim/2 + META_BYTES.
split_query
Split a query blob into (int8 codes, qscale, ‖q‖²).