research(nightly): residual-vq — RVQ with ADC search (ADR-194)#465
Draft
ruvnet wants to merge 2 commits into
Draft
research(nightly): residual-vq — RVQ with ADC search (ADR-194)#465ruvnet wants to merge 2 commits into
ruvnet wants to merge 2 commits into
Conversation
Implements Residual Vector Quantization as crates/ruvector-residual-vq, ruvector's first multi-codebook full-dimensional cascade quantizer. Three AnnIndex variants behind a shared trait: - RvqGreedyIndex: greedy (beam=1) encoding + O(M) ADC table scoring - RvqBeamIndex: beam-4 encoding + same ADC scoring path - RvqRerankIndex: greedy + ADC coarse + exact L2 rerank Key properties: - 64× compression: D=128 f32 (512 B) → 8 bytes with M=8, K=64 - ADC scoring exact wrt reconstruction: ||q−x̂||² = ||q||²−2·ΣIP+||x̂||² - k-means++ seeding with f64 accumulation to avoid centroid drift - Max-heap top-k O(n log k) scan, heap stores (dist_bits, id) Benchmark (N=1k, D=128, M=8, K=64, 4-core x86_64 release): Greedy: 14 602 QPS, 74.5% recall@10, 64× compression Beam-4: 14 027 QPS, 74.5% recall@10, 64× compression Rerank×5: 11 590 QPS, 100% recall@10, 64× compression (N=1k) All 7 unit tests pass; cargo build --release -p ruvector-residual-vq green. Closes: docs/research/nightly/2026-05-16-residual-vq/README.md ADR: docs/adr/ADR-194-residual-vq.md
…search doc Full-run numbers (100 queries, D=128, M=8, K=64, 4-core x86_64): N=1k: Greedy 71.2% recall, 13 872 QPS | Rerank×5 99.8%, 11 574 QPS N=10k: Greedy 31.4% recall, 7 561 QPS | Rerank×5 76.7%, 5 665 QPS N=50k: Greedy 14.0% recall, 2 300 QPS | Rerank×5 40.4%, 2 185 QPS All at 64× compression (512B → 8B). Confirms the recall cliff at large N motivating K=256 and IVFRVQ in the roadmap.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nightly Research — Residual Vector Quantization (RVQ)
See
docs/research/nightly/2026-05-16-residual-vq/README.mdanddocs/adr/ADR-194-residual-vq.md.Gist overview: https://gist.github.com/ruvnet/cadf124e2e8220682452c268210b09a0
What this adds
crates/ruvector-residual-vq— ruvector's first multi-codebook full-dimensional residual quantizer, complementing the existing RaBitQ (1-bit) and PQ (dimension-splitting) implementations.RVQ quantises the full-D-dimensional residual at each of M stages rather than splitting dimensions (PQ), yielding 15–25% better recall at equal bit budgets — the improvement that convinced LanceDB to ship RVQ as their default in 2024.
Three backends behind a shared
AnnIndextraitRvqGreedyIndexRvqBeamIndexRvqRerankIndexAll at 64× compression (D=128 f32 = 512 bytes → 8 bytes, M=8, K=64).
Full benchmark results (D=128, M=8, K=64, 4-core x86_64, 100 queries)
Reproduce:
cargo run --release -p ruvector-residual-vq --bin rvq-demoChecklist
cargo build --release -p ruvector-residual-vqgreencargo test -p ruvector-residual-vq— 7/7 tests pass (+ 1 doctest)docs/research/nightly/2026-05-16-residual-vq/README.mddocs/adr/ADR-194-residual-vq.mdcargo run --release(no mocked results)