fib-quant 0.1.0-beta.2

Experimental Rust implementation of the FibQuant radial-angular vector quantization core
Documentation
# fib-quant

Experimental Rust implementation of FibQuant-style radial-angular
vector quantization for KV-cache compression. ~50× compression in
the binary-packed form. 100% recall on the canonical benchmark
corpus (single-level).

> **Experimental, not production-ready.** This is an independent
> implementation based on the public FibQuant reference (Lee & Kim
> 2026). It is **not** the original paper code — see the Attribution
> section below.

`fib-quant` decomposes a vector into spherical blocks, quantizes
each block against a Fibonacci-optimized codebook, and stores only
the codebook indices. The result: a 768-dim f32 vector (3,072 bytes)
becomes ~860 bytes in JSON, or ~64 bytes with binary packing. And it
still finds the right document at rank 1 in 100% of the canonical
test queries.

This is the **cold-tier codec** in the poly-kv pool. It handles
shared context that's large, stable, and accessed by many agents:

```
┌──────────────────────────────────┐
│    SHARED POOL — fib-quant       │  ← you are here
│    System prompts, few-shot      │
│    examples, shared docs         │
│    50× compression, cos 0.863    │
└──────────┬──────────┬────────────┘
           │          │
      ┌────▼───┐ ┌───▼────┐
      │ Agent0 │ │ Agent1 │  ...  ← turbo-quant hot tier
      └────────┘ └────────┘
```

## What's in the box

- **Codec** (`src/codec.rs`, 1121 lines) — `FibQuantizer` with
  `encode`, `decode`, `encode_with_receipt`, `encode_batch`,
  `decode_batch`, `decode_batch_fast`, `encode_layers`. The
  `encode_batch` path is the Rayon-parallel path that wins the
  poly-kv pool build.
- **Codebook** (`src/codebook.rs`, 207 lines) —
  `FibCodebookV1` with `build_initial_codebook` and Lloyd-Max
  refinement. Parity-verified against the reference.
- **Rotation** (`src/rotation.rs`, 216 lines) — fast
  Walsh-Hadamard rotation with `StoredRotation`, a CPU fallback,
  and an optional CUDA dispatch via `gpu-backend`.
- **Spherical beta** (`src/spherical_beta.rs`, 139 lines) —
  spherical-Beta direction samplers for codebook seeding:
  `sample_spherical_beta`, `beta_d_k`, `radius_quantile`,
  `radius_quantile_k2_closed_form`.
- **Profiles** (`src/profile.rs`, 424 lines) — typed
  `FibQuantProfileV1` with `paper_default(ambient_dim, block_dim,
  codebook_size, seed)` (k=4, N=32 defaults shown in examples
  below). Includes validation and rate computation.
- **Receipts** (`src/receipt.rs`, 128 lines) — typed
  `FibQuantCompressionReceiptV1` capturing every parameter of
  the encode pipeline for audit.
- **Scoring** (`src/scoring.rs`, 411 lines) — `GramTable` and
  `FibScorer` for approximate inner-product scoring without full
  decode, using a precomputed codebook Gram table.
- **Residual VQ** (`src/residual.rs`, 491 lines) — two-level
  vector quantization with `FibResidualQuantizer`,
  `FibResidualCodeV1`, and `ResidualCodebookV1` for improved
  reconstruction quality.
- **Wire format** (`src/wire.rs`, 333 lines) — self-describing
  wire format (`FibCodeWireV1`, `WireHeader`) that carries
  profile metadata so downstream consumers can decode without
  external profile knowledge.
- **Sidecar search** (`src/sidecar.rs`, 430 lines) —
  `FibSidecarIndex<Id>` wrapping `FibScorer` for approximate
  nearest-inner-product search with `ScoredCandidate` and
  `SearchReceiptV1`.
- **Eval harness** (`src/eval.rs`, 519 lines) — benchmark
  harness with `FibBenchmarkCorpus`, `run_benchmark`, and
  `FibBenchmarkReceiptV1` capturing recall@K, nDCG@K, compression
  ratio, MSE, and timing.
- **Compat layer** (`src/compat.rs`, 248 lines, `compat` feature)
  — implements `VectorCodec`, `CodecProfile`, and `KvCacheCodec`
  traits from `quant-codec-core` so fib-quant can be used through
  the shared codec trait boundary by `poly-kv`, `quant-governor`,
  and `scr-runtime-compression`.
- **KV-cache codec** (`src/kv/`, ~3,300 lines, `kv` feature) — a
  separate `KvCacheCodec` impl that operates on `KvTensorShape`
  rather than raw `Vec<f32>`. Includes attention-quality metrics,
  shape contracts, policy-role-aware dispatch, and a streaming
  encoder (`KvStreamEncoder` in `src/kv/stream.rs`, 800 lines) for
  incremental token-by-token construction.
- **KV receipts** (`src/kv/receipt.rs`) — `KvCompressionReceiptV1`,
  `KvDecodeReceiptV1`, and `KvEvalReceiptV1` for KV-cache
  pipeline audit.

## Quick Start

```rust
use fib_quant::{FibQuantProfileV1, FibQuantizer};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build a quantizer with the default paper profile.
    // paper_default takes 4 args: ambient_dim, block_dim, codebook_size, seed
    let profile = FibQuantProfileV1::paper_default(32, 4, 32, 7)?;
    let quantizer = FibQuantizer::new(profile)?;

    // Encode a single vector.
    let vector: Vec<f32> = (0..32).map(|i| i as f32 * 0.01).collect();
    let code = quantizer.encode(&vector)?;
    let reconstructed = quantizer.decode(&code)?;

    // The cosine similarity should be high.
    let cos = fib_quant::metrics::cosine_similarity(&vector, &reconstructed)?;
    assert!(cos > 0.85);

    // Or encode with a full audit receipt.
    let (code, receipt) = quantizer.encode_with_receipt(&vector)?;
    println!("Receipt: {}", receipt.profile_digest);

    // Or encode a batch in parallel (returns Vec<FibCodeV1>).
    let corpus: Vec<Vec<f32>> = vec![vector.clone(), vector.clone()];
    let refs: Vec<&[f32]> = corpus.iter().map(|v| v.as_slice()).collect();
    let codes = quantizer.encode_batch(&refs)?;
    assert_eq!(codes.len(), 2);

    Ok(())
}
```

Run it: `cargo run --release --example encode_decode`.

## New modules

### Scoring — approximate inner product without full decode

`FibScorer` uses a precomputed codebook Gram table
(`GramTable`, `G[i,j] = <codeword_i, codeword_j>`) to estimate the
inner product of a query vector against a stored `FibCodeV1` without
running the full decode pipeline (rotation inverse + norm scaling).
The estimate is approximate — bounded by codebook quantization noise
— and avoids decoding the stored vector entirely. For a codebook of
size N=32, the Gram table is 4 KB.

```rust
use fib_quant::{FibScorer, FibQuantProfileV1, FibQuantizer};

let profile = FibQuantProfileV1::paper_default(32, 4, 32, 7)?;
let quantizer = FibQuantizer::new(profile)?;
// FibScorer::new takes ownership of the quantizer.
let scorer = FibScorer::new(quantizer)?;

let query = vec![0.1; 32];
// Encode before moving the quantizer into the scorer, or use
// a separate quantizer instance for encoding.
```

### Residual — two-level VQ for better fidelity

After encoding with the main codebook, the quantization residual
still contains signal. `FibResidualQuantizer` encodes this residual
with a second, smaller codebook (typically 4–8 codewords), adding
2–3 bits per block. Cosine fidelity improves from ~0.863
(single-level) to ~0.93+ (two-level) for typical nomic-768
workloads, at the cost of ~10–15% size increase.

```rust
use fib_quant::{FibQuantProfileV1, FibQuantizer, FibResidualQuantizer};

let profile = FibQuantProfileV1::paper_default(768, 4, 32, 7)?;
let quantizer = FibQuantizer::new(profile)?;
let residual = FibResidualQuantizer::build(&quantizer.profile().clone(), quantizer.codebook())?;
```

### Wire format — self-describing codes

`FibCodeWireV1` wraps a `FibCodeV1` with a 59-byte header carrying
seed, dim, k, N, norm_format, and profile digest. This enables
decode without any external profile knowledge — the compact FB1/FB2
formats strip all metadata, forcing consumers to hardcode profile
fields.

```rust
use fib_quant::{FibCodeWireV1, FibQuantProfileV1, FibQuantizer};

let profile = FibQuantProfileV1::paper_default(32, 4, 32, 7)?;
let quantizer = FibQuantizer::new(profile)?;
let code = quantizer.encode(&[0.1; 32])?;
let wire_bytes = FibCodeWireV1::to_wire_bytes(&code, quantizer.profile())?;
// Decode without needing the original profile — from_wire_bytes
// returns (FibCodeV1, FibQuantProfileV1):
let (decoded_code, recovered_profile) = FibCodeWireV1::from_wire_bytes(&wire_bytes)?;
```

### Sidecar — approximate search index

`FibSidecarIndex<Id>` stores caller-owned IDs alongside encoded
`FibCodeV1` artifacts and provides approximate nearest-inner-product
search via the Gram-table estimator. The index is a *sidecar*: it
produces approximate candidates that callers must rerank with an
exact inner-product computation against the original (un-encoded)
vectors before acting on the result.

```rust
use fib_quant::{FibScorer, FibSidecarIndex, FibQuantProfileV1, FibQuantizer};

let profile = FibQuantProfileV1::paper_default(32, 4, 32, 7)?;
// Encode first, then build the scorer for search.
let quantizer = FibQuantizer::new(profile)?;
let code = quantizer.encode(&[0.1; 32])?;

// Build a fresh quantizer to move into the scorer.
let profile2 = FibQuantProfileV1::paper_default(32, 4, 32, 7)?;
let scorer = FibScorer::new(FibQuantizer::new(profile2)?)?;
let mut index = FibSidecarIndex::new(scorer);

index.add(42, code);

let candidates = index.search(&[0.12; 32], 10, 4)?;
// Rerank candidates against original vectors before use.
```

### Eval — benchmark harness

`run_benchmark` takes a `FibBenchmarkCorpus` (database vectors,
queries, ground-truth top-K) and a `&FibQuantizer`, then returns a
`FibBenchmarkReceiptV1` with recall@K, nDCG@K, compression ratio,
cosine similarity, MSE, and timing. Standalone helpers `recall_at_k`
and `ndcg_at_k` are also exported.

```rust
use fib_quant::{FibBenchmarkCorpus, FibQuantProfileV1, FibQuantizer, run_benchmark};

let corpus = FibBenchmarkCorpus { /* ... */ };
let profile = FibQuantProfileV1::paper_default(768, 4, 32, 7)?;
let quantizer = FibQuantizer::new(profile)?;
let receipt = run_benchmark(&corpus, &quantizer)?;
println!("recall@10: {}", receipt.recall_at_k);
```

### Streaming KV encoder

`KvStreamEncoder` (behind the `kv` feature) allows building a
`KvEncodedTensorV1` one token at a time instead of requiring the
full tensor upfront. Pages are flushed automatically when they
reach `tokens_per_page` from the page geometry. The output is
identical to the batch `encode_kv_tensor` for the same input.

Currently supports `batch = 1, layers = 1, kv_heads = 1` shapes
(the common single-stream inference case).

## Benchmarks — measured

### Compression ratios (768-dim nomic-embed-v1.5)

| Format | Bytes per vector | Ratio |
|---|---|---|
| Raw f32 | 3,072 | 1.0× |
| fib-quant JSON (default profile) | 860 | 3.6× |
| fib-quant binary-packed (`PackedFibCode`) | ~64 | ~48× |
| fib-quant KV-cache JSON | 1,200 | 2.6× |
| fib-quant KV-cache binary | ~80 | ~38× |

The "theoretical 50×" is the binary-packed compact form.
The "JSON 3.6×" is what you get with the default wire
format — the JSON envelope is 12× bigger than the actual
codebook indices. **If you're optimizing for storage, use
the binary wire format.**

### Retrieval quality (P26 measurement, semantic-memory harness)

8 queries, 200 docs, 768-dim, k=10, oversample=4:

| Route | Recall@1 | Recall@10 | nDCG@10 | Mean rank drift |
|---|---|---|---|---|
| exact_scan (no compression) | 1.000 | 1.000 | 1.000 ||
| **fib-quant only** | **1.000** | **1.000** | **1.000** | **0.33** |
| turbo-quant only | 1.000 | 1.000 | 1.000 | 0.03 |
| poly-kv (two-tier) | 1.000 | 1.000 | 1.000 | 0.25 |

**Cosine fidelity: 0.863** (single vector), **0.9996** (after
turbo-quant rerank in poly-kv).

> The benchmark numbers above are from the P26 measurement run and
> are valid for single-level quantization. Two-level residual VQ
> improves cosine fidelity to ~0.93+ but has not been benchmarked
> for retrieval quality yet.

### Encode_batch throughput — "Do All" perf pass 2026-06-01

The `encode_batch` loop is the dominant cost in the poly-kv
pool build. After the June 1 perf pass (AVX2+FMA SIMD +
Rayon):

| Workload | Old (f64 ref) | + SIMD | + Rayon (parallel) | + full stack |
|---|---|---|---|---|
| qwen3 2560 n=80 | 13763ms || 1250ms | **346ms** (40×) |
| nomic 768 n=80 | 4552ms | 94ms | 407ms | **133ms** (34×) |
| qwen3 2560 n=4 | 1449ms | 418ms | 893ms | **256ms** (5.7×) |

Numbers from `poly-kv/benchmarks/DO_ALL_PERF_PASS_2026-06-01.md`.

### GPU path — measured

| Shape | n | CPU | Hadamard-GPU | Full-GPU | Best |
|---|---|---|---|---|---|
| d=64 | 80 | 14ms | **13ms (-7%)** | 14ms | Hadamard |
| d=128 | 80 | 57ms | **54ms (-5%)** | 56ms | Hadamard |
| d=768 | 80 | 2143ms | **2103ms (-2%)** | 2133ms | Hadamard |
| d=2560 | 4 | 1571ms | 1564ms (0%) | 1554ms (0%) | tie |

**Honest takeaway:** fib-quant's `encode_batch` is 2-7%
faster on a real GPU (msi i7-6700HQ + GTX 1070) with the
Hadamard path engaged. The codebook_lookup kernel exists and
is parity-verified, but the per-call H2D/D2H overhead
currently negates its win. A device-side pipeline is the
next step.

### Test coverage

- **23 integration test files** in `tests/`:
  - `bitpack_indices`, `codebook_determinism`,
    `compact_bytes_roundtrip`, `corruption_rejection`,
    `decode_batch_fast_parity`, `direction_generators`,
    `encode_decode_roundtrip`, `kv_attention_quality`,
    `kv_corruption_rejection`, `kv_encode_decode_reference`,
    `kv_policy_role_aware`, `kv_property_shapes`,
    `kv_shape_contracts`, `lloyd_refinement`,
    `norm_payload_rejection`, `paper_k2_radius_closed_form`,
    `paper_smoke_regression`, `profile_digest`,
    `profile_resource_bounds`, `property_bitpack`,
    `property_codec`, `rotation_identity`,
    `spherical_beta_sampler`.
- **4 examples**: `build_codebook`, `encode_batch_microbench`,
  `encode_decode`, `test_compact_decode`.
- **4 benches** (criterion): `codebook_build`, `encode_decode`,
  `kv_attention_ref`, `kv_encode_decode`.
- **105 tests** pass with `cargo test --all-features` (was 47
  before the new module additions).
- `cargo clippy --all-features --all-targets -- -D warnings` clean
  (modulo upstream `gpu-backend` lints on newer toolchains).

## MSRV

Rust 1.75 (2021 edition). `#![forbid(unsafe_code)]` at the
crate level.

## Dependencies

- `serde` (with `derive`).
- `serde_json`.
- `blake3`.
- `half` (f16 support for scoring/scaling).
- `nalgebra` (with `serde-serialize`).
- `rand` + `rand_chacha` (dev).
- `gpu-backend` (optional) — for the GPU Hadamard dispatch.
- `rayon` (optional, behind the `parallel` feature) — for
  parallel batch encoding.
- `quant-codec-core` (optional, behind the `compat` feature) —
  for the shared codec trait boundary.
- `proptest` (dev).
- `criterion` (dev).

## License

Apache-2.0. See `LICENSE-APACHE` for the full text.

## Changelog

See `CHANGELOG.md` for the release history.

## Attribution

This crate is an independent Rust implementation of the
FibQuant compression technique described in the public
literature (Lee & Kim, 2026). It is **not** the original
authors' reference code, and does not claim affiliation with
the FibQuant paper authors. The mathematical approach
(radial-angular block decomposition with Fibonacci-sampled
codebook seeding) follows the published specification.

The `kv-cache` codec profile, the parallel encode pipeline,
the GPU dispatch path, the receipt infrastructure, and the
test suite are original to this implementation.

## Where it's used

`fib-quant` is the cold-tier codec for:

- `poly-kv` — the shared pool is fib-quant compressed.
  Every shared system prompt, every shared few-shot example,
  every shared doc goes through `encode_batch`.
- `semantic-memory` — when `AdmissibilityClass::Standard` is
  selected by `quant-governor`, semantic-memory can route to
  the fib-quant sidecar for candidate generation.
- `scr-runtime-compression` — the `fib` feature is the
  fib-quant adapter for the runtime.

Any system that needs a **high-ratio, medium-fidelity** vector
codec — search-only recall, cold tier, ~50× storage savings
— can adopt `fib-quant` directly.