metrale_storage/
projection.rs1use half::bf16;
11use rand::SeedableRng;
12use rand::distr::Distribution;
13use rand_chacha::ChaCha8Rng;
14use rand_distr::StandardNormal;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct PredictorShape {
18 pub head_dim: usize,
19 pub r: usize,
20}
21
22impl PredictorShape {
23 pub fn new(head_dim: usize, r: usize) -> Self {
24 assert!(head_dim > 0 && r > 0, "head_dim/r must be positive");
25 assert!(head_dim <= 256, "MAX_HEAD_DIM=256 in kv_lowrank_project.cu");
26 assert!(r <= 128, "predictor_score block dim caps r at 128");
27 Self { head_dim, r }
28 }
29}
30
31pub fn build_projection(shape: PredictorShape, seed: u64) -> Vec<bf16> {
35 let mut rng = ChaCha8Rng::seed_from_u64(seed);
36 let inv_sqrt_d = 1.0_f32 / (shape.head_dim as f32).sqrt();
37 let dist = StandardNormal;
38 let n = shape.head_dim * shape.r;
39 let mut out = Vec::with_capacity(n);
40 for _ in 0..n {
41 let v: f32 = dist.sample(&mut rng);
42 out.push(bf16::from_f32(v * inv_sqrt_d));
43 }
44 out
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn determinism() {
53 let s = PredictorShape::new(128, 32);
54 let a = build_projection(s, 0xCAFE_F00D);
55 let b = build_projection(s, 0xCAFE_F00D);
56 assert_eq!(a, b);
57 let c = build_projection(s, 0xDEAD_BEEF);
58 assert_ne!(a, c);
59 }
60
61 #[test]
62 fn shape() {
63 let s = PredictorShape::new(128, 32);
64 let p = build_projection(s, 1);
65 assert_eq!(p.len(), 128 * 32);
66 }
67
68 #[test]
73 fn the_default_seed_gives_the_pinned_projection() {
74 let p = build_projection(PredictorShape::new(128, 32), 0xCAFE_F00D);
75 let bits: Vec<u16> = p.iter().map(|x| x.to_bits()).collect();
76 assert_eq!(
77 bits[..8],
78 [48010, 48438, 15723, 15775, 48398, 48642, 48035, 48715]
79 );
80 let fnv = bits.iter().fold(0xcbf2_9ce4_8422_2325_u64, |h, b| {
81 (h ^ u64::from(*b)).wrapping_mul(0x0100_0000_01b3)
82 });
83 assert_eq!(fnv, 0x5498_6948_5a9b_0c37);
84 }
85}