token_sampling/
candidates.rs1use core::cmp::Ordering;
2use core::fmt;
3
4#[derive(Clone, Copy, Debug, PartialEq)]
6pub struct Candidate {
7 pub id: u32,
9 pub logit: f32,
11 pub p: f32,
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub enum Error {
18 EmptyLogits,
20 InvalidLogit {
22 index: usize,
24 },
25 AllMasked,
27 NoSelection,
29}
30
31impl fmt::Display for Error {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::EmptyLogits => f.write_str("logits are empty"),
35 Self::InvalidLogit { index } => write!(f, "logit at index {index} is invalid"),
36 Self::AllMasked => f.write_str("all logits are masked"),
37 Self::NoSelection => f.write_str("no sampling stage selected a token"),
38 }
39 }
40}
41
42impl std::error::Error for Error {}
43
44#[derive(Clone, Debug)]
46pub struct Candidates {
47 pub(crate) buf: Vec<Candidate>,
48 pub(crate) counts: Vec<(u32, u32)>,
49 pub(crate) repeat_count: Vec<usize>,
50 pub(crate) max_repeats: Vec<(u32, usize)>,
51 pub(crate) breaker_indices: Vec<usize>,
52 pub(crate) sorted: bool,
53 pub(crate) selected: Option<usize>,
54}
55
56impl Candidates {
57 pub const fn new() -> Self {
59 Self {
60 buf: Vec::new(),
61 counts: Vec::new(),
62 repeat_count: Vec::new(),
63 max_repeats: Vec::new(),
64 breaker_indices: Vec::new(),
65 sorted: false,
66 selected: None,
67 }
68 }
69
70 pub fn with_capacity(n_vocab: usize) -> Self {
72 Self {
73 buf: Vec::with_capacity(n_vocab),
74 counts: Vec::new(),
75 repeat_count: Vec::new(),
76 max_repeats: Vec::new(),
77 breaker_indices: Vec::new(),
78 sorted: false,
79 selected: None,
80 }
81 }
82
83 pub fn load(&mut self, logits: &[f32]) -> Result<(), Error> {
85 if logits.is_empty() {
86 return Err(Error::EmptyLogits);
87 }
88 let mut any_unmasked = false;
89 for (index, &logit) in logits.iter().enumerate() {
90 if logit.is_nan() || logit == f32::INFINITY {
91 return Err(Error::InvalidLogit { index });
92 }
93 any_unmasked |= logit != f32::NEG_INFINITY;
94 }
95 if !any_unmasked {
96 return Err(Error::AllMasked);
97 }
98
99 reserve_to(&mut self.buf, logits.len());
100 self.buf.clear();
101 self.buf
102 .extend(logits.iter().enumerate().map(|(id, &logit)| Candidate {
103 id: id as u32,
104 logit,
105 p: 0.0,
106 }));
107 self.counts.clear();
108 self.repeat_count.clear();
109 self.max_repeats.clear();
110 self.breaker_indices.clear();
111 self.sorted = false;
112 self.selected = None;
113 Ok(())
114 }
115
116 pub fn as_slice(&self) -> &[Candidate] {
118 &self.buf
119 }
120
121 pub fn selected(&self) -> Option<u32> {
123 self.selected
124 .and_then(|position| self.buf.get(position))
125 .map(|candidate| candidate.id)
126 }
127
128 pub(crate) fn sort_desc(&mut self) {
129 if !self.sorted {
130 self.buf.sort_unstable_by(candidate_order);
131 self.sorted = true;
132 }
133 }
134
135 pub(crate) fn softmax(&mut self, sort: bool) -> Result<(), Error> {
136 if self.buf.is_empty() {
137 return Err(Error::AllMasked);
138 }
139 if !self.sanitize_logits() {
140 return Err(Error::AllMasked);
141 }
142 if sort {
143 self.sort_desc();
144 }
145 let max_logit = self
146 .buf
147 .iter()
148 .map(|candidate| candidate.logit)
149 .fold(f32::NEG_INFINITY, f32::max);
150 let sum = self
151 .buf
152 .iter()
153 .map(|candidate| ((candidate.logit - max_logit) as f64).exp())
154 .sum::<f64>();
155 if !sum.is_finite() || sum <= 0.0 {
156 return Err(Error::AllMasked);
157 }
158 for candidate in &mut self.buf {
159 candidate.p = (((candidate.logit - max_logit) as f64).exp() / sum) as f32;
160 }
161 Ok(())
162 }
163
164 pub(crate) fn sanitize_logits(&mut self) -> bool {
165 let mut any_unmasked = false;
166 let mut changed = false;
167 for candidate in &mut self.buf {
168 if candidate.logit.is_nan() {
169 candidate.logit = f32::NEG_INFINITY;
170 changed = true;
171 } else if candidate.logit == f32::INFINITY {
172 candidate.logit = f32::MAX;
173 changed = true;
174 }
175 any_unmasked |= candidate.logit.is_finite();
176 }
177 if changed {
178 self.sorted = false;
179 }
180 any_unmasked
181 }
182}
183
184impl Default for Candidates {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190pub(crate) fn candidate_order(left: &Candidate, right: &Candidate) -> Ordering {
191 right
192 .logit
193 .total_cmp(&left.logit)
194 .then_with(|| left.id.cmp(&right.id))
195}
196
197fn reserve_to<T>(values: &mut Vec<T>, capacity: usize) {
198 if values.capacity() < capacity {
199 values.reserve_exact(capacity - values.capacity());
200 }
201}