First MLX implementation of TurboQuant KV cache compression for Apple Silicon
Python
30
0 commits
updated Jun 2, 2026
First MLX Implementation of TurboQuant KV Cache Compression
TurboQuant achieves 4.6x KV cache compression with ~0% accuracy loss on Apple Silicon.
What this actually means: KV cache compression helps the decode phase (token generation), not prefill. Peak VRAM during prefill is still determined by prompt length. What you gain is: faster decode bandwidth, longer effective KV cache during generation, and more concurrent decode sessions. It does not let you run larger models than your VRAM can fit.
This enables running longer generation contexts and more concurrent sessions on M-series Macs — including multi-node distributed inference via exo.
39 passed, 2 skipped in 1.79s
TestWHT 7/7 ✅ Walsh-Hadamard orthogonality, norm preservation, invertibility
TestPolarQuant 5/5 ✅ Quantize/dequantize roundtrip, compression ratio, shapes
TestQJL 4/4 ✅ Sketch accuracy, inner product estimation
TestKVCache 6/6 ✅ Attention sinks, chunk buffering, memory tracking
TestAsymmetric 4/4 ✅ Keys=TurboQuant, Values=PolarQuant (asymmetric)
TestOllama 5/5 ✅ Client instantiation, stats tracking, env patching
TestHFIntegration 5/5 ✅ DynamicCache compat, from_legacy_cache, update()
TestLazyImports 3/3 ✅ Lazy import safety for all optional backends
Replaced O(n²) Gram-Schmidt orthogonalization with O(n log n) fast Walsh-Hadamard Transform (WHT). Same rotation Gaussianization quality, ~4x faster. Implemented in pure MLX.
# turboquant_mlx/wht.py — SRHT: D @ H @ D
from turboquant_mlx.wht import WalshHadamardRotation
rotation = WalshHadamardRotation(head_dim=128, seed=42)
x_rotated = rotation.rotate(x) # O(n log n)
x_back = rotation.rotate_inverse(x_rotated)
Keys use full TurboQuant (PolarQuant + QJL). Values use PolarQuant only — QJL corrects inner product bias for the Q·K dot product, making it mathematically redundant for V. Lower MSE on value reconstruction.
First 128 tokens kept in float16. Prevents instruction-following degradation at extreme compression ratios (3-bit). Zero noticeable memory overhead.
Tokens accumulated in 64-token chunks before compression fires. Reduces per-token overhead during autoregressive decode.
TurboQuant-MLX is designed around MLX's unified memory model on Apple Silicon. Key notes:
For ANE-native inference, use Core ML conversion after quantization (future roadmap).
Drop-in patch for any mlx-lm model — including distributed multi-node inference via the Star Platinum cluster:
# Monkey-patch mlx-lm to use TurboQuant
from turboquant_mlx.mlx_kvcache import TurboQuantKVCache
import mlx_lm.models.cache as cache_module
def turboquant_make_prompt_cache(model, max_kv_size=None):
num_layers = len(model.layers)
return [TurboQuantKVCache(r_bits=4, theta_bits=4) for _ in range(num_layers)]
cache_module.make_prompt_cache = turboquant_make_prompt_cache
# All subsequent mlx-lm inference uses TurboQuant KV compression
Or use the included patch script:
python3 patch_exo.py # patches the exo distributed inference cluster
from turboquant_mlx.hf_patch import load_and_patch
model, tokenizer = load_and_patch("Qwen/Qwen2.5-7B-Instruct")
# model.generate() now uses asymmetric TurboQuant KV compression automatically
inputs = tokenizer("Hello, world!", return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=100)
Or apply manually:
from turboquant_mlx.hf_patch import TurboQuantHFCache, patch_transformers
patch_transformers() # monkey-patches AutoModelForCausalLM.generate globally
Note: HuggingFace integration requires
transformersandtorch. TurboQuant uses lazy imports — if these aren't installed, importingturboquant_mlxstill works, the HF backend is simply unavailable.
Note: Ollama manages its own internal KV cache (via llama.cpp). The
TurboQuantOllamaClientis a monitoring/stats wrapper and consistent API layer — it does not inject compression into Ollama's internal cache. True KV compression with Ollama requires the llama.cpp backend.
from turboquant_mlx.ollama_patch import TurboQuantOllamaClient, patch_ollama_env
# Optimize Ollama environment settings
patch_ollama_env()
# Wrap the Ollama API with stats tracking
client = TurboQuantOllamaClient(base_url="http://localhost:11434/v1")
response = client.chat(
model="qwen2.5:7b",
messages=[{"role": "user", "content": "What is distributed inference?"}]
)
print(response)
print(client.stats()) # estimated memory savings
client.reset_stats()
A C port with Metal GPU kernels is on the roadmap. Once available:
./llama-server -m model.gguf --cache-type-k turbo3 --cache-type-v turbo3
TurboQuant-MLX ships as a first-class OpenClaw skill. Install it to bring TurboQuant compression awareness into your AI agent:
openclaw skills install turboquant-mlx
The skill enables your agent to:
Input KV vector x ∈ R^d
│
├── Walsh-Hadamard Rotation (SRHT: D @ H @ D) — O(n log n)
│ Gaussianizes distribution: kurtosis 900 → ~3.0
│
├── PolarQuant (Keys + Values)
│ x' → (radius, angle) → quantize independently
│ 4-bit r + 4-bit θ = 8 bits total per dimension pair
│ No per-block normalization constants
│
├── QJL Residual Correction (Keys only — asymmetric)
│ sign(S · residual) → 1-bit inner product correction
│ Mathematically redundant for Values (no Q·V dot product)
│
└── CompressedKV: 4.6x smaller, fp16 sinks preserved
| Component | Detail |
|---|---|
| Rotation | Randomized SRHT (D@H@D) — pure MLX, O(n log n) |
| Keys | PolarQuant + QJL (full TurboQuant) |
| Values | PolarQuant only (asymmetric — mathematically correct) |
| Attention sinks | First 128 tokens in fp16 — preserves instruction following |
| Chunk buffer | 64 tokens staged before compression — reduces decode overhead |
| Group size | 128 vectors per quantization group |
git clone https://github.com/DeadByDawn101/turboquant-mlx.git
cd turboquant-mlx
pip install mlx numpy
pip install -e .
# Optional backends
pip install transformers torch accelerate # HuggingFace
pip install openai # Ollama wrapper
import mlx.core as mx
from turboquant_mlx import TurboQuantKVCache
# Create cache (drop-in for mlx-lm KVCache)
cache = TurboQuantKVCache(
r_bits=4, # radius quantization bits
theta_bits=4, # angle quantization bits
fp16_sink_size=128, # protect first N tokens
chunk_size=64, # buffer before compressing
)
# Use exactly like mlx-lm KVCache
keys = mx.random.normal(shape=(1, 8, 32, 64))
values = mx.random.normal(shape=(1, 8, 32, 64))
k_out, v_out = cache.update_and_fetch(keys, values)
print(f"Cache offset: {cache.offset}")
print(f"Memory: {cache.memory_size / 1024:.1f} KB")
pip install pytest
python3 -m pytest tests/ -v
# 39 passed, 2 skipped
| Config | Compression | Cosine Sim | MSE |
|---|---|---|---|
| TurboQuant 2-bit | 7.1× | 0.79 | 0.0047 |
| TurboQuant 3-bit | 4.9× | 0.91 | 0.0018 |
| TurboQuant 4-bit (default) | 3.8× | 0.96 | 0.0007 |
Default 4-bit config gives 3.8x compression with 0.96 cosine similarity — effectively lossless for most tasks.
Process a codebase or long document once. Resume instantly next session.
from turboquant_mlx.persistence import TurboQuantCache
cache = TurboQuantCache(bits=4) # 4x compression
# After processing (once):
cache.save(kv_states, "my-project", metadata={"tokens": 4096, "model": "Qwen3.5-35B"})
# Saved: 26.6 MB → 6.7 MB (4x), 0.002s
# Next session (instant):
kv_states, meta = cache.load("my-project")
# Loaded in 0.0003s vs 1.01s reprocessing
# Cross-device sync via Cloudflare R2:
cache.push("my-project") # upload (free tier: 10GB)
cache.pull("my-project") # download on other Mac
What 0.0003s load time means in practice:
Process documents larger than GPU memory:
from turboquant_mlx.persistence import PagedKVCache
paged = PagedKVCache(max_gpu_chunks=4, chunk_size=512)
# Process in chunks — GPU holds recent 4, rest on SSD
for chunk_id, kv_chunk in enumerate(kv_chunks):
paged.add_chunk(kv_chunk, chunk_id)
print(paged.stats)
# {"gpu_chunks": 4, "ssd_chunks": 12, "gpu_hits": 89, "ssd_reads": 11}
from turboquant_mlx.tiered_cache import TieredKVCacheManager
manager = TieredKVCacheManager(
max_gpu_mb=2000, # 2GB in GPU
max_ssd_mb=50000, # 50GB on SSD
r2_config={...}, # Cloudflare R2 for cold storage
)
# Store KV state — auto-tiers based on size/recency
manager.put("my-project", kv_states, metadata={"tokens": 4096})
# Retrieve — auto-promotes from lower tiers
states, tier = manager.get("my-project")
print(f"Retrieved from {tier}") # "gpu" | "ssd" | "r2"
# Check tier utilization
print(manager.stats())
# {"gpu_mb": 1.2, "ssd_mb": 15.3, "gpu_hits": 42, "ssd_hits": 8, "r2_hits": 1}
Tier access times:
Inspired by Apple's "LLM in a Flash" research + mac-code.
On March 26, 2026, the authors of the RaBitQ line of work (SIGMOD 2024, SIGMOD 2025) posted a public comment on OpenReview raising three specific concerns about the TurboQuant ICLR 2026 paper:
Method misrepresentation — TurboQuant describes random rotation as its key innovation while characterizing RaBitQ as a simple grid-based PQ method, omitting that RaBitQ also applies a Johnson-Lindenstrauss (random rotation) transform. Multiple reviewers flagged this; the authors responded by moving the RaBitQ description to the appendix rather than acknowledging the structural similarity.
Unsupported theoretical claim — TurboQuant calls RaBitQ's guarantees "suboptimal due to loose analysis." The RaBitQ SIGMOD 2025 paper (posted Sept 2024, before TurboQuant submission) already proves asymptotic optimality, matching the Alon-Klartag lower bound — the theoretical ceiling. This correction was communicated privately in May 2025 and not incorporated.
Undisclosed benchmark conditions — The paper's runtime/efficiency comparisons run the RaBitQ baseline on a single CPU with multiprocessing disabled while running TurboQuant on an A100 GPU. This was never disclosed. The RaBitQ authors note that TurboQuant's second author (Majid Daliri) contacted them in January 2025 to debug his own Python translation of their implementation.
What this means for this implementation:
The core algorithm in this repository is still mathematically sound — random rotation + scalar quantization + residual correction is a valid and effective approach. However:
qjl.py implements the two-stage residual approach from TurboQuant. As an alternative, we also provide rabitq_correction() — the simpler RaBitQ-style (π/2) scaling bias correction, which is theoretically equivalent for bias removal but trades variance increase for implementation simplicity. See RaBitQ vs QJL correction below.We recommend reading both the TurboQuant paper and the RaBitQ SIGMOD 2025 paper for a complete picture.
The inner product bias from 1-bit sign quantization (factor of 2/π) can be corrected two ways:
from turboquant_mlx.qjl import rabitq_correction, QJLSketch
# Option A: RaBitQ-style — multiply by π/2 (simple, ~6% more variance)
corrected = rabitq_correction(signs, scale_x, scale_y, sketch_dim)
# Option B: TurboQuant-style — QJL residual on the remainder (lower variance, more memory)
sketch = QJLSketch(head_dim, sketch_dim)
signs, scale = sketch.sketch(keys)
Both are unbiased estimators. TurboQuant's residual approach has lower variance (better MSE) at the cost of extra computation. RaBitQ's scaling is simpler and zero overhead — ideal if memory is the binding constraint.
--cache-type-k turbo3)Built with 🖤 by RavenX AI
This repository is a research and experimentation layer, not a production-faithful implementation of the TurboQuant paper. Known gaps:
| Component | Status | Notes |
|---|---|---|
mlx_kvcache.py | Partial | PolarQuant applied ✅, QJL residual NOT applied in live path ❌ |
hf_patch.py | Simulation | Perturbs HF KV tensors, doesn't change attention kernel ❌ |
| Compressed-domain attention | Not implemented | Requires custom Metal kernel — the key missing piece |
QJL correction in qjl.py | Math correct ✅ | But used in testing only, not wired into live cache path |
What works today:
π/2 scaling correction (rabitq_correction()) as documented alternative ✅What's needed for paper fidelity:
score ≈ (π/2) × scale_q × scale_k × sign_agreement directlyPRs welcome. See issue #2 for full technical discussion.
Python
100.0%
First MLX implementation of TurboQuant KV cache compression for Apple Silicon
Python
30
0 commits
updated Jun 2, 2026
First MLX Implementation of TurboQuant KV Cache Compression
TurboQuant achieves 4.6x KV cache compression with ~0% accuracy loss on Apple Silicon.
What this actually means: KV cache compression helps the decode phase (token generation), not prefill. Peak VRAM during prefill is still determined by prompt length. What you gain is: faster decode bandwidth, longer effective KV cache during generation, and more concurrent decode sessions. It does not let you run larger models than your VRAM can fit.
This enables running longer generation contexts and more concurrent sessions on M-series Macs — including multi-node distributed inference via exo.
39 passed, 2 skipped in 1.79s
TestWHT 7/7 ✅ Walsh-Hadamard orthogonality, norm preservation, invertibility
TestPolarQuant 5/5 ✅ Quantize/dequantize roundtrip, compression ratio, shapes
TestQJL 4/4 ✅ Sketch accuracy, inner product estimation
TestKVCache 6/6 ✅ Attention sinks, chunk buffering, memory tracking
TestAsymmetric 4/4 ✅ Keys=TurboQuant, Values=PolarQuant (asymmetric)
TestOllama 5/5 ✅ Client instantiation, stats tracking, env patching
TestHFIntegration 5/5 ✅ DynamicCache compat, from_legacy_cache, update()
TestLazyImports 3/3 ✅ Lazy import safety for all optional backends
Replaced O(n²) Gram-Schmidt orthogonalization with O(n log n) fast Walsh-Hadamard Transform (WHT). Same rotation Gaussianization quality, ~4x faster. Implemented in pure MLX.
# turboquant_mlx/wht.py — SRHT: D @ H @ D
from turboquant_mlx.wht import WalshHadamardRotation
rotation = WalshHadamardRotation(head_dim=128, seed=42)
x_rotated = rotation.rotate(x) # O(n log n)
x_back = rotation.rotate_inverse(x_rotated)
Keys use full TurboQuant (PolarQuant + QJL). Values use PolarQuant only — QJL corrects inner product bias for the Q·K dot product, making it mathematically redundant for V. Lower MSE on value reconstruction.
First 128 tokens kept in float16. Prevents instruction-following degradation at extreme compression ratios (3-bit). Zero noticeable memory overhead.
Tokens accumulated in 64-token chunks before compression fires. Reduces per-token overhead during autoregressive decode.
TurboQuant-MLX is designed around MLX's unified memory model on Apple Silicon. Key notes:
For ANE-native inference, use Core ML conversion after quantization (future roadmap).
Drop-in patch for any mlx-lm model — including distributed multi-node inference via the Star Platinum cluster:
# Monkey-patch mlx-lm to use TurboQuant
from turboquant_mlx.mlx_kvcache import TurboQuantKVCache
import mlx_lm.models.cache as cache_module
def turboquant_make_prompt_cache(model, max_kv_size=None):
num_layers = len(model.layers)
return [TurboQuantKVCache(r_bits=4, theta_bits=4) for _ in range(num_layers)]
cache_module.make_prompt_cache = turboquant_make_prompt_cache
# All subsequent mlx-lm inference uses TurboQuant KV compression
Or use the included patch script:
python3 patch_exo.py # patches the exo distributed inference cluster
from turboquant_mlx.hf_patch import load_and_patch
model, tokenizer = load_and_patch("Qwen/Qwen2.5-7B-Instruct")
# model.generate() now uses asymmetric TurboQuant KV compression automatically
inputs = tokenizer("Hello, world!", return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=100)
Or apply manually:
from turboquant_mlx.hf_patch import TurboQuantHFCache, patch_transformers
patch_transformers() # monkey-patches AutoModelForCausalLM.generate globally
Note: HuggingFace integration requires
transformersandtorch. TurboQuant uses lazy imports — if these aren't installed, importingturboquant_mlxstill works, the HF backend is simply unavailable.
Note: Ollama manages its own internal KV cache (via llama.cpp). The
TurboQuantOllamaClientis a monitoring/stats wrapper and consistent API layer — it does not inject compression into Ollama's internal cache. True KV compression with Ollama requires the llama.cpp backend.
from turboquant_mlx.ollama_patch import TurboQuantOllamaClient, patch_ollama_env
# Optimize Ollama environment settings
patch_ollama_env()
# Wrap the Ollama API with stats tracking
client = TurboQuantOllamaClient(base_url="http://localhost:11434/v1")
response = client.chat(
model="qwen2.5:7b",
messages=[{"role": "user", "content": "What is distributed inference?"}]
)
print(response)
print(client.stats()) # estimated memory savings
client.reset_stats()
A C port with Metal GPU kernels is on the roadmap. Once available:
./llama-server -m model.gguf --cache-type-k turbo3 --cache-type-v turbo3
TurboQuant-MLX ships as a first-class OpenClaw skill. Install it to bring TurboQuant compression awareness into your AI agent:
openclaw skills install turboquant-mlx
The skill enables your agent to:
Input KV vector x ∈ R^d
│
├── Walsh-Hadamard Rotation (SRHT: D @ H @ D) — O(n log n)
│ Gaussianizes distribution: kurtosis 900 → ~3.0
│
├── PolarQuant (Keys + Values)
│ x' → (radius, angle) → quantize independently
│ 4-bit r + 4-bit θ = 8 bits total per dimension pair
│ No per-block normalization constants
│
├── QJL Residual Correction (Keys only — asymmetric)
│ sign(S · residual) → 1-bit inner product correction
│ Mathematically redundant for Values (no Q·V dot product)
│
└── CompressedKV: 4.6x smaller, fp16 sinks preserved
| Component | Detail |
|---|---|
| Rotation | Randomized SRHT (D@H@D) — pure MLX, O(n log n) |
| Keys | PolarQuant + QJL (full TurboQuant) |
| Values | PolarQuant only (asymmetric — mathematically correct) |
| Attention sinks | First 128 tokens in fp16 — preserves instruction following |
| Chunk buffer | 64 tokens staged before compression — reduces decode overhead |
| Group size | 128 vectors per quantization group |
git clone https://github.com/DeadByDawn101/turboquant-mlx.git
cd turboquant-mlx
pip install mlx numpy
pip install -e .
# Optional backends
pip install transformers torch accelerate # HuggingFace
pip install openai # Ollama wrapper
import mlx.core as mx
from turboquant_mlx import TurboQuantKVCache
# Create cache (drop-in for mlx-lm KVCache)
cache = TurboQuantKVCache(
r_bits=4, # radius quantization bits
theta_bits=4, # angle quantization bits
fp16_sink_size=128, # protect first N tokens
chunk_size=64, # buffer before compressing
)
# Use exactly like mlx-lm KVCache
keys = mx.random.normal(shape=(1, 8, 32, 64))
values = mx.random.normal(shape=(1, 8, 32, 64))
k_out, v_out = cache.update_and_fetch(keys, values)
print(f"Cache offset: {cache.offset}")
print(f"Memory: {cache.memory_size / 1024:.1f} KB")
pip install pytest
python3 -m pytest tests/ -v
# 39 passed, 2 skipped
| Config | Compression | Cosine Sim | MSE |
|---|---|---|---|
| TurboQuant 2-bit | 7.1× | 0.79 | 0.0047 |
| TurboQuant 3-bit | 4.9× | 0.91 | 0.0018 |
| TurboQuant 4-bit (default) | 3.8× | 0.96 | 0.0007 |
Default 4-bit config gives 3.8x compression with 0.96 cosine similarity — effectively lossless for most tasks.
Process a codebase or long document once. Resume instantly next session.
from turboquant_mlx.persistence import TurboQuantCache
cache = TurboQuantCache(bits=4) # 4x compression
# After processing (once):
cache.save(kv_states, "my-project", metadata={"tokens": 4096, "model": "Qwen3.5-35B"})
# Saved: 26.6 MB → 6.7 MB (4x), 0.002s
# Next session (instant):
kv_states, meta = cache.load("my-project")
# Loaded in 0.0003s vs 1.01s reprocessing
# Cross-device sync via Cloudflare R2:
cache.push("my-project") # upload (free tier: 10GB)
cache.pull("my-project") # download on other Mac
What 0.0003s load time means in practice:
Process documents larger than GPU memory:
from turboquant_mlx.persistence import PagedKVCache
paged = PagedKVCache(max_gpu_chunks=4, chunk_size=512)
# Process in chunks — GPU holds recent 4, rest on SSD
for chunk_id, kv_chunk in enumerate(kv_chunks):
paged.add_chunk(kv_chunk, chunk_id)
print(paged.stats)
# {"gpu_chunks": 4, "ssd_chunks": 12, "gpu_hits": 89, "ssd_reads": 11}
from turboquant_mlx.tiered_cache import TieredKVCacheManager
manager = TieredKVCacheManager(
max_gpu_mb=2000, # 2GB in GPU
max_ssd_mb=50000, # 50GB on SSD
r2_config={...}, # Cloudflare R2 for cold storage
)
# Store KV state — auto-tiers based on size/recency
manager.put("my-project", kv_states, metadata={"tokens": 4096})
# Retrieve — auto-promotes from lower tiers
states, tier = manager.get("my-project")
print(f"Retrieved from {tier}") # "gpu" | "ssd" | "r2"
# Check tier utilization
print(manager.stats())
# {"gpu_mb": 1.2, "ssd_mb": 15.3, "gpu_hits": 42, "ssd_hits": 8, "r2_hits": 1}
Tier access times:
Inspired by Apple's "LLM in a Flash" research + mac-code.
On March 26, 2026, the authors of the RaBitQ line of work (SIGMOD 2024, SIGMOD 2025) posted a public comment on OpenReview raising three specific concerns about the TurboQuant ICLR 2026 paper:
Method misrepresentation — TurboQuant describes random rotation as its key innovation while characterizing RaBitQ as a simple grid-based PQ method, omitting that RaBitQ also applies a Johnson-Lindenstrauss (random rotation) transform. Multiple reviewers flagged this; the authors responded by moving the RaBitQ description to the appendix rather than acknowledging the structural similarity.
Unsupported theoretical claim — TurboQuant calls RaBitQ's guarantees "suboptimal due to loose analysis." The RaBitQ SIGMOD 2025 paper (posted Sept 2024, before TurboQuant submission) already proves asymptotic optimality, matching the Alon-Klartag lower bound — the theoretical ceiling. This correction was communicated privately in May 2025 and not incorporated.
Undisclosed benchmark conditions — The paper's runtime/efficiency comparisons run the RaBitQ baseline on a single CPU with multiprocessing disabled while running TurboQuant on an A100 GPU. This was never disclosed. The RaBitQ authors note that TurboQuant's second author (Majid Daliri) contacted them in January 2025 to debug his own Python translation of their implementation.
What this means for this implementation:
The core algorithm in this repository is still mathematically sound — random rotation + scalar quantization + residual correction is a valid and effective approach. However:
qjl.py implements the two-stage residual approach from TurboQuant. As an alternative, we also provide rabitq_correction() — the simpler RaBitQ-style (π/2) scaling bias correction, which is theoretically equivalent for bias removal but trades variance increase for implementation simplicity. See RaBitQ vs QJL correction below.We recommend reading both the TurboQuant paper and the RaBitQ SIGMOD 2025 paper for a complete picture.
The inner product bias from 1-bit sign quantization (factor of 2/π) can be corrected two ways:
from turboquant_mlx.qjl import rabitq_correction, QJLSketch
# Option A: RaBitQ-style — multiply by π/2 (simple, ~6% more variance)
corrected = rabitq_correction(signs, scale_x, scale_y, sketch_dim)
# Option B: TurboQuant-style — QJL residual on the remainder (lower variance, more memory)
sketch = QJLSketch(head_dim, sketch_dim)
signs, scale = sketch.sketch(keys)
Both are unbiased estimators. TurboQuant's residual approach has lower variance (better MSE) at the cost of extra computation. RaBitQ's scaling is simpler and zero overhead — ideal if memory is the binding constraint.
--cache-type-k turbo3)Built with 🖤 by RavenX AI
This repository is a research and experimentation layer, not a production-faithful implementation of the TurboQuant paper. Known gaps:
| Component | Status | Notes |
|---|---|---|
mlx_kvcache.py | Partial | PolarQuant applied ✅, QJL residual NOT applied in live path ❌ |
hf_patch.py | Simulation | Perturbs HF KV tensors, doesn't change attention kernel ❌ |
| Compressed-domain attention | Not implemented | Requires custom Metal kernel — the key missing piece |
QJL correction in qjl.py | Math correct ✅ | But used in testing only, not wired into live cache path |
What works today:
π/2 scaling correction (rabitq_correction()) as documented alternative ✅What's needed for paper fidelity:
score ≈ (π/2) × scale_q × scale_k × sign_agreement directlyPRs welcome. See issue #2 for full technical discussion.
Python
100.0%