tinyquant_core/corpus/compression_policy.rs
1//! Compression policy enum and storage tag for the [`Corpus`](super::Corpus) aggregate.
2//!
3//! Three mutually exclusive policies control how a [`Corpus`] stores embedding
4//! vectors:
5//!
6//! | Policy | Transform | `StorageTag` | Typical compression ratio |
7//! |---|---|---|---|
8//! | `Compress` | Full codec pipeline (rotate → quantize → optional residual) | `U8` | 4–8× |
9//! | `Passthrough` | Raw f32 bytes, no transformation | `F32` | 1× |
10//! | `Fp16` | Each f32 cast to f16 little-endian | `F16` | 2× |
11//!
12//! The policy is set at corpus construction time and is **immutable** after
13//! the first `insert` call. Attempting to change it raises
14//! [`CorpusError::PolicyImmutable`](crate::errors::CorpusError::PolicyImmutable).
15
16/// Determines how vectors are stored in a [`Corpus`](super::Corpus).
17///
18/// The policy is set at construction and cannot be changed after the first
19/// [`insert`](super::Corpus::insert) call.
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21pub enum CompressionPolicy {
22 /// Full codec pipeline: rotate → scalar quantize → optional FP16 residual.
23 ///
24 /// Requires a trained [`Codebook`](crate::codec::Codebook) and a
25 /// [`CodecConfig`](crate::codec::CodecConfig). Produces `StorageTag::U8`
26 /// output.
27 Compress,
28
29 /// Store raw f32 bytes with no transformation (1× compression ratio).
30 ///
31 /// The four bytes of each `f32` are stored in little-endian order inside
32 /// the `indices` field of a [`CompressedVector`](crate::codec::CompressedVector).
33 /// Produces `StorageTag::F32` output.
34 Passthrough,
35
36 /// Cast each `f32` to a 16-bit float and store 2 bytes per dimension
37 /// in little-endian order (2× compression ratio).
38 ///
39 /// Precision loss is bounded by the f16 range; `max |error|` is
40 /// typically below `1e-2` for normalised embedding values.
41 /// Produces `StorageTag::F16` output.
42 Fp16,
43}
44
45impl CompressionPolicy {
46 /// Returns `true` for policies that run the full codec pipeline.
47 ///
48 /// Only [`CompressionPolicy::Compress`] requires a trained codebook;
49 /// the other policies bypass the codec entirely.
50 #[must_use]
51 pub const fn requires_codec(&self) -> bool {
52 matches!(self, Self::Compress)
53 }
54
55 /// Returns the [`StorageTag`] that describes the byte layout used by this policy.
56 #[must_use]
57 pub const fn storage_tag(&self) -> StorageTag {
58 match self {
59 Self::Compress => StorageTag::U8,
60 Self::Passthrough => StorageTag::F32,
61 Self::Fp16 => StorageTag::F16,
62 }
63 }
64}
65
66/// Describes the physical byte layout of stored vector data.
67///
68/// Returned by [`CompressionPolicy::storage_tag`]. Used by decompression
69/// routines to select the correct byte-interpretation strategy without
70/// inspecting the policy directly.
71#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
72pub enum StorageTag {
73 /// One byte per dimension (codec quantisation index, 2/4/8-bit packed in 1 byte).
74 U8,
75 /// Four bytes per dimension, raw `f32` little-endian.
76 F32,
77 /// Two bytes per dimension, `f16` little-endian.
78 F16,
79}