Skip to main content

token_sampling/
samplers.rs

1use core::cmp::Ordering;
2
3use crate::candidates::{candidate_order, Candidates, Error};
4use crate::rng::{unit, Rng};
5
6/// Randomness and token history supplied to one sampling stage.
7pub struct SamplerCtx<'a> {
8    /// Random source for stages that draw.
9    pub rng: &'a mut dyn Rng,
10    /// Token history in chronological order.
11    pub history: &'a [u32],
12}
13
14impl core::fmt::Debug for SamplerCtx<'_> {
15    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16        formatter
17            .debug_struct("SamplerCtx")
18            .field("rng", &"dyn Rng")
19            .field("history", &self.history)
20            .finish()
21    }
22}
23
24/// One object-safe stage in a sampling chain.
25pub trait Sampler: Send {
26    /// Applies the stage to the current candidates.
27    fn apply(&mut self, candidates: &mut Candidates, ctx: &mut SamplerCtx<'_>)
28        -> Result<(), Error>;
29
30    /// Restores per-sequence state.
31    fn reset(&mut self) {}
32}
33
34/// Divides logits by a fixed temperature, with greedy masking at zero.
35#[derive(Clone, Copy, Debug, PartialEq)]
36pub struct Temperature {
37    /// Temperature value.
38    pub t: f32,
39}
40
41impl Default for Temperature {
42    fn default() -> Self {
43        Self { t: 0.8 }
44    }
45}
46
47impl Sampler for Temperature {
48    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
49        apply_temperature(candidates, self.t);
50        Ok(())
51    }
52}
53
54/// Maps distribution entropy to a temperature range.
55#[derive(Clone, Copy, Debug, PartialEq)]
56pub struct DynTemperature {
57    /// Center temperature.
58    pub t: f32,
59    /// Half-width of the temperature range.
60    pub delta: f32,
61    /// Exponent applied to normalized entropy.
62    pub exponent: f32,
63}
64
65impl Default for DynTemperature {
66    fn default() -> Self {
67        Self {
68            t: 0.8,
69            delta: 0.0,
70            exponent: 1.0,
71        }
72    }
73}
74
75impl Sampler for DynTemperature {
76    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
77        if !self.delta.is_finite() || self.delta <= 0.0 {
78            apply_temperature(candidates, self.t);
79            return Ok(());
80        }
81        if candidates.buf.len() <= 1 {
82            return Ok(());
83        }
84
85        let min_t = (self.t as f64 - self.delta as f64).max(0.0);
86        let max_t = self.t as f64 + self.delta as f64;
87        candidates.softmax(true)?;
88        let entropy = candidates
89            .buf
90            .iter()
91            .filter(|candidate| candidate.p > 0.0)
92            .map(|candidate| {
93                let p = candidate.p as f64;
94                -p * p.ln()
95            })
96            .sum::<f64>();
97        let max_entropy = (candidates.buf.len() as f64).ln();
98        let exponent = if self.exponent.is_finite() {
99            self.exponent as f64
100        } else {
101            1.0
102        };
103        let normalized = (entropy / max_entropy).powf(exponent);
104        let dynamic = min_t + (max_t - min_t) * normalized;
105        let dynamic = if dynamic.is_nan() {
106            self.t
107        } else {
108            finite_f32(dynamic)
109        };
110        apply_temperature(candidates, dynamic);
111        candidates.softmax(false)
112    }
113}
114
115/// Keeps the `k` candidates with the largest logits.
116#[derive(Clone, Copy, Debug, PartialEq, Eq)]
117pub struct TopK {
118    /// Maximum survivor count. Non-positive values disable the stage.
119    pub k: i32,
120}
121
122impl Default for TopK {
123    fn default() -> Self {
124        Self { k: 40 }
125    }
126}
127
128impl Sampler for TopK {
129    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
130        apply_top_k(candidates, self.k);
131        Ok(())
132    }
133}
134
135/// Keeps the smallest descending prefix that reaches a probability mass.
136#[derive(Clone, Copy, Debug, PartialEq)]
137pub struct TopP {
138    /// Target cumulative probability.
139    pub p: f32,
140    /// Minimum survivor count.
141    pub min_keep: usize,
142}
143
144impl Default for TopP {
145    fn default() -> Self {
146        Self {
147            p: 0.95,
148            min_keep: 0,
149        }
150    }
151}
152
153impl Sampler for TopP {
154    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
155        if self.p.is_nan() || self.p >= 1.0 {
156            return Ok(());
157        }
158        candidates.softmax(false)?;
159        if candidates.sorted {
160            truncate_top_p(candidates, self.p, self.min_keep);
161            return Ok(());
162        }
163
164        let len = candidates.buf.len();
165        let minimum = self.min_keep.max(1).min(len);
166        let mut prefix = minimum.max(32).min(len);
167        loop {
168            if prefix < len {
169                candidates
170                    .buf
171                    .select_nth_unstable_by(prefix, candidate_order);
172                candidates.buf[..prefix].sort_unstable_by(candidate_order);
173            } else {
174                candidates.buf.sort_unstable_by(candidate_order);
175            }
176
177            let mut cumulative = 0.0_f64;
178            for (index, candidate) in candidates.buf[..prefix].iter().enumerate() {
179                cumulative += candidate.p as f64;
180                if cumulative >= self.p as f64 && index + 1 >= minimum {
181                    candidates.buf.truncate(index + 1);
182                    candidates.sorted = true;
183                    return Ok(());
184                }
185            }
186            if prefix == len {
187                candidates.sorted = true;
188                return Ok(());
189            }
190
191            let estimated = if cumulative > 0.0 && self.p > 0.0 {
192                ((prefix as f64 * self.p as f64 / cumulative).ceil() as usize).min(len)
193            } else {
194                prefix.saturating_mul(2).min(len)
195            };
196            prefix = estimated.max(prefix + 1).max(minimum).min(len);
197        }
198    }
199}
200
201/// Keeps logits above a fraction of the maximum token probability.
202#[derive(Clone, Copy, Debug, PartialEq)]
203pub struct MinP {
204    /// Fraction of the maximum token probability.
205    pub p: f32,
206    /// Minimum survivor count.
207    pub min_keep: usize,
208}
209
210impl Default for MinP {
211    fn default() -> Self {
212        Self {
213            p: 0.05,
214            min_keep: 0,
215        }
216    }
217}
218
219impl Sampler for MinP {
220    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
221        if self.p.is_nan() || self.p <= 0.0 || candidates.buf.is_empty() {
222            return Ok(());
223        }
224
225        if !candidates.sorted {
226            let max_logit = candidates
227                .buf
228                .iter()
229                .map(|candidate| candidate.logit)
230                .fold(f32::NEG_INFINITY, f32::max);
231            let min_logit = max_logit + self.p.ln();
232            let matching = candidates
233                .buf
234                .iter()
235                .filter(|candidate| candidate.logit >= min_logit)
236                .count();
237            if matching > 0 && matching >= self.min_keep {
238                candidates
239                    .buf
240                    .retain(|candidate| candidate.logit >= min_logit);
241                return Ok(());
242            }
243            candidates.sort_desc();
244        }
245
246        let min_logit = candidates.buf[0].logit + self.p.ln();
247        let mut keep = 1;
248        while keep < candidates.buf.len()
249            && (candidates.buf[keep].logit >= min_logit || keep < self.min_keep)
250        {
251            keep += 1;
252        }
253        candidates.buf.truncate(keep);
254        Ok(())
255    }
256}
257
258/// Keeps candidates closest to the distribution's information content.
259#[derive(Clone, Copy, Debug, PartialEq)]
260pub struct Typical {
261    /// Target cumulative probability.
262    pub p: f32,
263    /// Minimum survivor count.
264    pub min_keep: usize,
265}
266
267impl Default for Typical {
268    fn default() -> Self {
269        Self {
270            p: 1.0,
271            min_keep: 0,
272        }
273    }
274}
275
276impl Sampler for Typical {
277    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
278        if self.p.is_nan() || self.p >= 1.0 {
279            return Ok(());
280        }
281        candidates.softmax(true)?;
282        let entropy = candidates
283            .buf
284            .iter()
285            .filter(|candidate| candidate.p > 0.0)
286            .map(|candidate| {
287                let p = candidate.p as f64;
288                -p * p.ln()
289            })
290            .sum::<f64>();
291        candidates.buf.sort_unstable_by(|left, right| {
292            typical_score(left.p, entropy)
293                .total_cmp(&typical_score(right.p, entropy))
294                .then_with(|| left.id.cmp(&right.id))
295        });
296        let mut cumulative = 0.0_f64;
297        let mut keep = candidates.buf.len();
298        for (index, candidate) in candidates.buf.iter().enumerate() {
299            cumulative += candidate.p as f64;
300            if cumulative > self.p as f64 && (self.min_keep == 0 || index >= self.min_keep - 1) {
301                keep = index + 1;
302                break;
303            }
304        }
305        candidates.buf.truncate(keep);
306        candidates.sorted = false;
307        Ok(())
308    }
309}
310
311/// Removes the low-probability tail using normalized second differences.
312#[derive(Clone, Copy, Debug, PartialEq)]
313pub struct TailFree {
314    /// Cumulative normalized second-difference threshold.
315    pub z: f32,
316    /// Minimum index before truncation is allowed.
317    pub min_keep: usize,
318}
319
320impl Default for TailFree {
321    fn default() -> Self {
322        Self {
323            z: 1.0,
324            min_keep: 0,
325        }
326    }
327}
328
329impl Sampler for TailFree {
330    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
331        if self.z.is_nan() || self.z >= 1.0 || candidates.buf.len() <= 2 {
332            return Ok(());
333        }
334        candidates.softmax(true)?;
335        let second_difference = |index: usize| {
336            let first = candidates.buf[index].p - candidates.buf[index + 1].p;
337            let next = candidates.buf[index + 1].p - candidates.buf[index + 2].p;
338            (first - next).abs() as f64
339        };
340        let count = candidates.buf.len() - 2;
341        let sum = (0..count).map(second_difference).sum::<f64>();
342        let mut cumulative = 0.0;
343        let mut keep = candidates.buf.len();
344        for index in 0..count {
345            let value = if sum > 1e-6 {
346                second_difference(index) / sum
347            } else {
348                1.0 / count as f64
349            };
350            cumulative += value;
351            if cumulative > self.z as f64 && index >= self.min_keep {
352                keep = index.max(1);
353                break;
354            }
355        }
356        candidates.buf.truncate(keep);
357        Ok(())
358    }
359}
360
361/// Excludes leading candidates whose probabilities exceed a threshold.
362#[derive(Clone, Copy, Debug, PartialEq)]
363pub struct Xtc {
364    /// Chance that the exclusion stage runs.
365    pub probability: f32,
366    /// Candidate probability threshold.
367    pub threshold: f32,
368    /// Minimum survivor count.
369    pub min_keep: usize,
370}
371
372impl Default for Xtc {
373    fn default() -> Self {
374        Self {
375            probability: 0.0,
376            threshold: 0.1,
377            min_keep: 0,
378        }
379    }
380}
381
382impl Sampler for Xtc {
383    fn apply(
384        &mut self,
385        candidates: &mut Candidates,
386        ctx: &mut SamplerCtx<'_>,
387    ) -> Result<(), Error> {
388        if self.probability.is_nan()
389            || self.threshold.is_nan()
390            || self.probability <= 0.0
391            || self.threshold > 0.5
392            || candidates.buf.len() < 2
393        {
394            return Ok(());
395        }
396        if unit(ctx.rng) > self.probability as f64 {
397            return Ok(());
398        }
399        candidates.softmax(true)?;
400        let mut pos_last = 0;
401        for (index, candidate) in candidates.buf.iter().enumerate() {
402            if candidate.p > 0.0 && candidate.p >= self.threshold {
403                pos_last = index;
404            } else {
405                break;
406            }
407        }
408        if pos_last > 0 && candidates.buf.len() - pos_last >= self.min_keep {
409            candidates.buf.drain(..pos_last);
410        }
411        Ok(())
412    }
413}
414
415/// Applies repetition, frequency, and presence penalties over recent history.
416#[derive(Clone, Copy, Debug, PartialEq)]
417pub struct Penalties {
418    /// Number of recent tokens to count. Non-positive values disable history.
419    pub last_n: i32,
420    /// Sign-aware repetition multiplier.
421    pub repeat: f32,
422    /// Penalty multiplied by token frequency.
423    pub freq: f32,
424    /// Penalty applied once to each present token.
425    pub presence: f32,
426}
427
428impl Default for Penalties {
429    fn default() -> Self {
430        Self {
431            last_n: 64,
432            repeat: 1.0,
433            freq: 0.0,
434            presence: 0.0,
435        }
436    }
437}
438
439impl Sampler for Penalties {
440    fn apply(
441        &mut self,
442        candidates: &mut Candidates,
443        ctx: &mut SamplerCtx<'_>,
444    ) -> Result<(), Error> {
445        if self.last_n <= 0 || (self.repeat == 1.0 && self.freq == 0.0 && self.presence == 0.0) {
446            return Ok(());
447        }
448        let window_len = ctx.history.len().min(self.last_n as usize);
449        if candidates.counts.capacity() < window_len {
450            candidates
451                .counts
452                .reserve_exact(window_len - candidates.counts.capacity());
453        }
454        candidates.counts.clear();
455        candidates.counts.extend(
456            ctx.history[ctx.history.len() - window_len..]
457                .iter()
458                .map(|&token| (token, 1)),
459        );
460        candidates.counts.sort_unstable_by_key(|entry| entry.0);
461        coalesce_counts(&mut candidates.counts);
462
463        let repeat = if self.repeat.is_finite() && self.repeat > 0.0 {
464            self.repeat
465        } else {
466            1.0
467        };
468        let frequency = if self.freq.is_finite() {
469            self.freq
470        } else {
471            0.0
472        };
473        let presence = if self.presence.is_finite() {
474            self.presence
475        } else {
476            0.0
477        };
478        for candidate in &mut candidates.buf {
479            let index = match candidates
480                .counts
481                .binary_search_by_key(&candidate.id, |entry| entry.0)
482            {
483                Ok(index) => index,
484                Err(_) => continue,
485            };
486            let count = candidates.counts[index].1 as f32;
487            if candidate.logit == f32::NEG_INFINITY {
488                continue;
489            }
490            let repeated = if candidate.logit <= 0.0 {
491                candidate.logit as f64 * repeat as f64
492            } else {
493                candidate.logit as f64 / repeat as f64
494            };
495            candidate.logit =
496                finite_f32(repeated - count as f64 * frequency as f64 - presence as f64);
497        }
498        candidates.sorted = false;
499        Ok(())
500    }
501}
502
503/// Applies sequence-extension penalties using recent token repetitions.
504#[derive(Clone, Debug, PartialEq)]
505pub struct Dry {
506    /// Penalty multiplier.
507    pub multiplier: f32,
508    /// Exponential penalty base.
509    pub base: f32,
510    /// Repetition length allowed before penalties begin.
511    pub allowed_length: i32,
512    /// Number of recent history tokens to inspect.
513    pub last_n: i32,
514    /// Token sequences that reset repetition matching.
515    pub breakers: Vec<Vec<u32>>,
516}
517
518impl Default for Dry {
519    fn default() -> Self {
520        Self {
521            multiplier: 0.0,
522            base: 1.75,
523            allowed_length: 2,
524            last_n: 64,
525            breakers: Vec::new(),
526        }
527    }
528}
529
530impl Sampler for Dry {
531    fn apply(
532        &mut self,
533        candidates: &mut Candidates,
534        ctx: &mut SamplerCtx<'_>,
535    ) -> Result<(), Error> {
536        if !self.multiplier.is_finite()
537            || !self.base.is_finite()
538            || self.multiplier == 0.0
539            || self.base < 1.0
540            || self.last_n <= 0
541        {
542            return Ok(());
543        }
544        let allowed = self.allowed_length.max(0) as usize;
545        let n = ctx.history.len().min(self.last_n as usize);
546        if n <= allowed {
547            return Ok(());
548        }
549        let history = &ctx.history[ctx.history.len() - n..];
550        if candidates.breaker_indices.capacity() < self.breakers.len() {
551            candidates
552                .breaker_indices
553                .reserve_exact(self.breakers.len() - candidates.breaker_indices.capacity());
554        }
555        candidates.breaker_indices.clear();
556        candidates.breaker_indices.extend(
557            self.breakers
558                .iter()
559                .enumerate()
560                .filter_map(|(index, sequence)| (!sequence.is_empty()).then_some(index)),
561        );
562        candidates
563            .breaker_indices
564            .sort_unstable_by(|&left, &right| {
565                breaker_order(&self.breakers[left], &self.breakers[right])
566            });
567
568        let recent = |offset: usize| history[n - 1 - offset];
569        let mut repeat_limit = n;
570        for index in 0..n {
571            let token = recent(index);
572            let range = breaker_range(&self.breakers, &candidates.breaker_indices, token);
573            let mut longest = None;
574            for &breaker_index in &candidates.breaker_indices[range] {
575                let sequence = &self.breakers[breaker_index];
576                let tail = &sequence[1..];
577                if tail.len() <= index
578                    && longest.map_or(true, |length| tail.len() > length)
579                    && tail
580                        .iter()
581                        .enumerate()
582                        .all(|(offset, &expected)| expected == recent(index - offset - 1))
583                {
584                    longest = Some(tail.len());
585                }
586            }
587            if let Some(length) = longest {
588                repeat_limit = index - length;
589                break;
590            }
591        }
592        if repeat_limit < allowed {
593            return Ok(());
594        }
595
596        if candidates.repeat_count.capacity() < n {
597            candidates
598                .repeat_count
599                .reserve_exact(n - candidates.repeat_count.capacity());
600        }
601        if candidates.max_repeats.capacity() < n {
602            candidates
603                .max_repeats
604                .reserve_exact(n - candidates.max_repeats.capacity());
605        }
606        candidates.repeat_count.clear();
607        candidates.repeat_count.resize(n, 0);
608        let last_index = n - 1;
609        let (mut left, mut right) = (0, 0);
610        for k in 1..n {
611            if k > right {
612                let mut matched = 0;
613                while matched + k < n && recent(matched) == recent(matched + k) {
614                    matched += 1;
615                }
616                candidates.repeat_count[last_index - k] = matched.min(repeat_limit);
617                if matched > 0 {
618                    left = k;
619                    right = k + matched - 1;
620                }
621            } else {
622                let previous = k - left;
623                let available = right - k + 1;
624                if candidates.repeat_count[last_index - previous] < available {
625                    candidates.repeat_count[last_index - k] =
626                        candidates.repeat_count[last_index - previous].min(repeat_limit);
627                } else {
628                    let mut index = right + 1;
629                    while index < n && recent(index) == recent(index - k) {
630                        index += 1;
631                    }
632                    candidates.repeat_count[last_index - k] = (index - k).min(repeat_limit);
633                    left = k;
634                    right = index - 1;
635                }
636            }
637        }
638
639        candidates.max_repeats.clear();
640        for index in 0..n - 1 {
641            let length = candidates.repeat_count[index];
642            if length < allowed {
643                continue;
644            }
645            let token = recent(n - 2 - index);
646            candidates.max_repeats.push((token, length));
647        }
648        candidates.max_repeats.sort_unstable_by_key(|entry| entry.0);
649        coalesce_max_repeats(&mut candidates.max_repeats);
650
651        let max_exponent = if self.base > 1.000_001 {
652            (88.722_84_f32 / self.base.ln()) as usize
653        } else {
654            0
655        };
656        for candidate in &mut candidates.buf {
657            let position = match candidates
658                .max_repeats
659                .binary_search_by_key(&candidate.id, |entry| entry.0)
660            {
661                Ok(position) => position,
662                Err(_) => continue,
663            };
664            let range = breaker_range(&self.breakers, &candidates.breaker_indices, candidate.id);
665            if candidates.breaker_indices[range]
666                .iter()
667                .any(|&index| self.breakers[index].len() == 1)
668            {
669                continue;
670            }
671            let mut exponent = candidates.max_repeats[position].1.saturating_sub(allowed);
672            if max_exponent > 0 {
673                exponent = exponent.min(max_exponent);
674            }
675            if candidate.logit != f32::NEG_INFINITY {
676                let penalty = self.multiplier as f64 * (self.base as f64).powi(exponent as i32);
677                candidate.logit = finite_f32(candidate.logit as f64 - penalty);
678            }
679        }
680        candidates.sorted = false;
681        Ok(())
682    }
683}
684
685/// Stateful Mirostat version 1 sampling.
686#[derive(Clone, Debug, PartialEq)]
687pub struct MirostatV1 {
688    /// Vocabulary size used by the Mirostat estimate.
689    pub n_vocab: u32,
690    /// Target surprise.
691    pub tau: f32,
692    /// Learning rate.
693    pub eta: f32,
694    /// Number of leading probabilities used for the estimate.
695    pub m: usize,
696    mu: f32,
697    last_k: usize,
698}
699
700impl MirostatV1 {
701    /// Creates a sampler with default Mirostat parameters and a required vocabulary size.
702    pub fn new(n_vocab: u32) -> Self {
703        Self {
704            n_vocab: n_vocab.max(1),
705            tau: 5.0,
706            eta: 0.1,
707            m: 100,
708            mu: 10.0,
709            last_k: 0,
710        }
711    }
712
713    /// Returns the current adaptive target.
714    pub fn mu(&self) -> f32 {
715        self.mu
716    }
717
718    #[cfg(test)]
719    pub(crate) fn last_k(&self) -> usize {
720        self.last_k
721    }
722}
723
724impl Sampler for MirostatV1 {
725    fn apply(
726        &mut self,
727        candidates: &mut Candidates,
728        ctx: &mut SamplerCtx<'_>,
729    ) -> Result<(), Error> {
730        candidates.softmax(true)?;
731        let pair_count = self
732            .m
733            .saturating_sub(1)
734            .min(candidates.buf.len().saturating_sub(1));
735        let (mut sum_tb, mut sum_tt) = (0.0_f64, 0.0_f64);
736        for index in 0..pair_count {
737            let t = (((index + 2) as f64) / ((index + 1) as f64)).ln();
738            let b = ((candidates.buf[index].p as f64) / (candidates.buf[index + 1].p as f64)).ln();
739            sum_tb += t * b;
740            sum_tt += t * t;
741        }
742        let slope = sum_tb / sum_tt;
743        let epsilon = slope - 1.0;
744        let numerator = epsilon * 2.0_f64.powf(self.mu as f64);
745        let denominator = 1.0 - (self.n_vocab as f64).powf(-epsilon);
746        let estimate = (numerator / denominator).powf(1.0 / slope);
747        let k = if estimate.is_finite() && estimate >= 1.0 {
748            estimate.min(i32::MAX as f64) as i32
749        } else {
750            1
751        };
752        self.last_k = k as usize;
753        apply_top_k(candidates, k);
754        candidates.softmax(true)?;
755        apply_dist(candidates, ctx.rng)?;
756        let selected = candidates.selected.ok_or(Error::AllMasked)?;
757        let surprise = -(candidates.buf[selected].p as f64).log2();
758        self.mu -= self.eta * (surprise as f32 - self.tau);
759        Ok(())
760    }
761
762    fn reset(&mut self) {
763        self.mu = 2.0 * self.tau;
764        self.last_k = 0;
765    }
766}
767
768/// Stateful Mirostat version 2 sampling.
769#[derive(Clone, Debug, PartialEq)]
770pub struct MirostatV2 {
771    /// Target surprise.
772    pub tau: f32,
773    /// Learning rate.
774    pub eta: f32,
775    mu: f32,
776}
777
778impl MirostatV2 {
779    /// Creates a sampler from a target surprise and learning rate.
780    pub fn new(tau: f32, eta: f32) -> Self {
781        Self {
782            tau,
783            eta,
784            mu: 2.0 * tau,
785        }
786    }
787
788    /// Returns the current adaptive target.
789    pub fn mu(&self) -> f32 {
790        self.mu
791    }
792}
793
794impl Default for MirostatV2 {
795    fn default() -> Self {
796        Self::new(5.0, 0.1)
797    }
798}
799
800impl Sampler for MirostatV2 {
801    fn apply(
802        &mut self,
803        candidates: &mut Candidates,
804        ctx: &mut SamplerCtx<'_>,
805    ) -> Result<(), Error> {
806        candidates.softmax(true)?;
807        let mut keep = candidates.buf.len();
808        for (index, candidate) in candidates.buf.iter().enumerate() {
809            if -(candidate.p as f64).log2() > self.mu as f64 {
810                keep = index.max(1);
811                break;
812            }
813        }
814        candidates.buf.truncate(keep);
815        candidates.softmax(true)?;
816        apply_dist(candidates, ctx.rng)?;
817        let selected = candidates.selected.ok_or(Error::AllMasked)?;
818        let surprise = -(candidates.buf[selected].p as f64).log2();
819        self.mu -= self.eta * (surprise as f32 - self.tau);
820        Ok(())
821    }
822
823    fn reset(&mut self) {
824        self.mu = 2.0 * self.tau;
825    }
826}
827
828/// Selects the first maximum logit in candidate order.
829#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
830pub struct Greedy;
831
832impl Sampler for Greedy {
833    fn apply(&mut self, candidates: &mut Candidates, _: &mut SamplerCtx<'_>) -> Result<(), Error> {
834        if candidates.buf.is_empty() {
835            return Err(Error::AllMasked);
836        }
837        let mut selected: Option<usize> = None;
838        for (index, candidate) in candidates.buf.iter().enumerate() {
839            if !candidate.logit.is_finite() {
840                continue;
841            }
842            let is_larger = match selected {
843                Some(current) => {
844                    candidate.logit.total_cmp(&candidates.buf[current].logit) == Ordering::Greater
845                }
846                None => true,
847            };
848            if is_larger {
849                selected = Some(index);
850            }
851        }
852        candidates.selected = selected;
853        selected.ok_or(Error::AllMasked).map(|_| ())
854    }
855}
856
857/// Runs softmax and selects one candidate by cumulative probability.
858#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
859pub struct Dist;
860
861impl Sampler for Dist {
862    fn apply(
863        &mut self,
864        candidates: &mut Candidates,
865        ctx: &mut SamplerCtx<'_>,
866    ) -> Result<(), Error> {
867        apply_dist(candidates, ctx.rng)
868    }
869}
870
871fn apply_temperature(candidates: &mut Candidates, temperature: f32) {
872    if candidates.buf.is_empty() {
873        return;
874    }
875    if temperature.partial_cmp(&0.0) != Some(Ordering::Greater) {
876        let maximum = candidates
877            .buf
878            .iter()
879            .enumerate()
880            .filter(|(_, candidate)| candidate.logit.is_finite())
881            .max_by(|(left_index, left), (right_index, right)| {
882                left.logit
883                    .total_cmp(&right.logit)
884                    .then_with(|| right_index.cmp(left_index))
885            })
886            .map(|(index, _)| index);
887        for (index, candidate) in candidates.buf.iter_mut().enumerate() {
888            if Some(index) != maximum {
889                candidate.logit = f32::NEG_INFINITY;
890            }
891        }
892        return;
893    }
894
895    let would_overflow = temperature.is_finite()
896        && candidates.buf.iter().any(|candidate| {
897            candidate.logit.is_finite()
898                && (candidate.logit as f64 / temperature as f64).abs() > f32::MAX as f64
899        });
900    let offset = if would_overflow {
901        candidates
902            .buf
903            .iter()
904            .filter(|candidate| candidate.logit.is_finite())
905            .map(|candidate| candidate.logit)
906            .max_by(f32::total_cmp)
907            .unwrap_or(0.0)
908    } else {
909        0.0
910    };
911    for candidate in &mut candidates.buf {
912        if candidate.logit == f32::NEG_INFINITY {
913            continue;
914        }
915        candidate.logit = finite_f32((candidate.logit as f64 - offset as f64) / temperature as f64);
916    }
917}
918
919fn apply_top_k(candidates: &mut Candidates, k: i32) {
920    if k <= 0 || candidates.buf.is_empty() {
921        return;
922    }
923    let keep = (k as usize).min(candidates.buf.len());
924    if !candidates.sorted {
925        if keep < candidates.buf.len() {
926            candidates.buf.select_nth_unstable_by(keep, candidate_order);
927            candidates.buf[..keep].sort_unstable_by(candidate_order);
928        } else {
929            candidates.buf.sort_unstable_by(candidate_order);
930        }
931        candidates.sorted = true;
932    }
933    candidates.buf.truncate(keep);
934}
935
936fn apply_dist(candidates: &mut Candidates, rng: &mut dyn Rng) -> Result<(), Error> {
937    if candidates.buf.is_empty() {
938        return Err(Error::AllMasked);
939    }
940    if !candidates.sanitize_logits() {
941        return Err(Error::AllMasked);
942    }
943    let draw = unit(rng);
944    if candidates.buf.len() == 1 {
945        candidates.buf[0].p = 1.0;
946        candidates.selected = Some(0);
947        return Ok(());
948    }
949
950    let max_logit = candidates
951        .buf
952        .iter()
953        .map(|candidate| candidate.logit)
954        .fold(f32::NEG_INFINITY, f32::max);
955    let total = candidates
956        .buf
957        .iter()
958        .map(|candidate| ((candidate.logit - max_logit) as f64).exp())
959        .sum::<f64>();
960    if !total.is_finite() || total <= 0.0 {
961        return Err(Error::AllMasked);
962    }
963    let target = draw * total;
964    let mut running = 0.0;
965    let mut selected = None;
966    for (index, candidate) in candidates.buf.iter_mut().enumerate() {
967        let weight = ((candidate.logit - max_logit) as f64).exp();
968        candidate.p = (weight / total) as f32;
969        running += weight;
970        if selected.is_none() && weight > 0.0 && running >= target {
971            selected = Some(index);
972        }
973    }
974    candidates.selected = selected.or_else(|| {
975        candidates
976            .buf
977            .iter()
978            .enumerate()
979            .rev()
980            .find(|(_, candidate)| candidate.p > 0.0)
981            .map(|(index, _)| index)
982    });
983    candidates.selected.ok_or(Error::AllMasked).map(|_| ())
984}
985
986fn typical_score(probability: f32, entropy: f64) -> f64 {
987    if probability > 0.0 {
988        (-(probability as f64).ln() - entropy).abs()
989    } else {
990        f64::INFINITY
991    }
992}
993
994fn truncate_top_p(candidates: &mut Candidates, probability: f32, min_keep: usize) {
995    let minimum = min_keep.max(1).min(candidates.buf.len());
996    let mut cumulative = 0.0_f64;
997    let mut keep = candidates.buf.len();
998    for (index, candidate) in candidates.buf.iter().enumerate() {
999        cumulative += candidate.p as f64;
1000        if cumulative >= probability as f64 && index + 1 >= minimum {
1001            keep = index + 1;
1002            break;
1003        }
1004    }
1005    candidates.buf.truncate(keep);
1006}
1007
1008fn coalesce_counts(counts: &mut Vec<(u32, u32)>) {
1009    let mut write = 0;
1010    for read in 0..counts.len() {
1011        if write > 0 && counts[write - 1].0 == counts[read].0 {
1012            counts[write - 1].1 += counts[read].1;
1013        } else {
1014            counts[write] = counts[read];
1015            write += 1;
1016        }
1017    }
1018    counts.truncate(write);
1019}
1020
1021fn coalesce_max_repeats(repeats: &mut Vec<(u32, usize)>) {
1022    let mut write = 0;
1023    for read in 0..repeats.len() {
1024        if write > 0 && repeats[write - 1].0 == repeats[read].0 {
1025            repeats[write - 1].1 = repeats[write - 1].1.max(repeats[read].1);
1026        } else {
1027            repeats[write] = repeats[read];
1028            write += 1;
1029        }
1030    }
1031    repeats.truncate(write);
1032}
1033
1034fn finite_f32(value: f64) -> f32 {
1035    if value.is_nan() {
1036        f32::NEG_INFINITY
1037    } else if value > f32::MAX as f64 {
1038        f32::MAX
1039    } else if value < -(f32::MAX as f64) {
1040        -f32::MAX
1041    } else {
1042        value as f32
1043    }
1044}
1045
1046fn breaker_order(left: &[u32], right: &[u32]) -> Ordering {
1047    left.first()
1048        .cmp(&right.first())
1049        .then_with(|| right.len().cmp(&left.len()))
1050        .then_with(|| left.cmp(right))
1051}
1052
1053fn breaker_range(breakers: &[Vec<u32>], indices: &[usize], token: u32) -> core::ops::Range<usize> {
1054    let start = indices.partition_point(|&index| breakers[index].first().copied().unwrap() < token);
1055    let end = indices.partition_point(|&index| breakers[index].first().copied().unwrap() <= token);
1056    start..end
1057}