avarok_core/kimi_k3/
greedy.rs1use super::cache::HybridCache;
6use super::cpu_forward::{forward_token, logits};
7use super::cpu_weights::{Ablation, K3CpuModel};
8use super::ops::argmax;
9
10pub fn greedy_decode(
12 model: &K3CpuModel,
13 prompt: &[u32],
14 max_new: usize,
15 ablation: Ablation,
16) -> Vec<u32> {
17 assert!(!prompt.is_empty(), "C1 greedy needs a non-empty prompt");
18 let mut cache = HybridCache::from_graph(&model.graph, &model.kda);
19 let mut tokens = prompt.to_vec();
20 let mut h = Vec::new();
21 for (pos, &tok) in prompt.iter().enumerate() {
22 h = forward_token(model, tok, pos, &mut cache, ablation);
23 }
24 for _ in 0..max_new {
25 let next = argmax(&logits(model, &h));
26 tokens.push(next);
27 let pos = tokens.len() - 1;
28 h = forward_token(model, next, pos, &mut cache, ablation);
29 }
30 tokens
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn greedy_emits_requested_new_tokens() {
39 let model = K3CpuModel::synthetic_tiny();
40 let out = greedy_decode(&model, &[1, 2], 4, Ablation::default());
41 assert_eq!(out.len(), 6);
42 assert_eq!(&out[..2], &[1, 2]);
43 assert!(out[2..].iter().all(|&t| (t as usize) < model.vocab));
44 }
45
46 #[test]
47 fn greedy_is_deterministic() {
48 let model = K3CpuModel::synthetic_tiny();
49 let a = greedy_decode(&model, &[3], 8, Ablation::default());
50 let b = greedy_decode(&model, &[3], 8, Ablation::default());
51 assert_eq!(a, b);
52 }
53}