use bitpolar::{KvCacheCompressor, KvCacheConfig};
fn main() {
let config = KvCacheConfig {
head_dim: 64,
bits: 4,
projections: 32,
seed: 99,
};
let mut cache = KvCacheCompressor::new(&config).expect("failed to create KV cache");
println!(
"KvCacheCompressor: head_dim={} bits={} projections={}",
config.head_dim, config.bits, config.projections
);
let num_tokens = 100usize;
for t in 0..num_tokens {
let key: Vec<f32> =
(0..config.head_dim).map(|i| ((t * config.head_dim + i) as f32 * 0.01).sin()).collect();
let val: Vec<f32> =
(0..config.head_dim).map(|i| ((t * config.head_dim + i) as f32 * 0.01).cos()).collect();
cache.push(&key, &val).expect("push failed");
}
println!("Stored {} tokens.", cache.len());
println!("Compression ratio: {:.2}x", cache.compression_ratio());
let query: Vec<f32> = (0..config.head_dim).map(|i| (i as f32 * 0.02).sin()).collect();
let scores = cache.attention_scores(&query).expect("attention_scores failed");
assert_eq!(scores.len(), num_tokens);
let mut scored: Vec<(usize, f32)> = scores.iter().copied().enumerate().collect();
scored.sort_unstable_by(|(_, a), (_, b)| b.partial_cmp(a).unwrap());
println!("\nTop-5 attended positions:");
println!("{:<10} {}", "Position", "Score");
println!("{}", "-".repeat(22));
for (rank, (pos, score)) in scored.iter().take(5).enumerate() {
println!("#{:<9} t={:<6} score={:.4}", rank + 1, pos, score);
}
let (top_pos, top_score) = scored[0];
let values = cache.decode_values();
println!(
"\nDecoded value at top position (t={}, score={:.4}), first 4 dims: {:?}",
top_pos,
top_score,
&values[top_pos][..4]
);
}