use rustc_hash::FxHashMap;
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct Token {
pub cost: f32,
pub aux: u32,
}
pub(crate) const NO_AUX: u32 = u32::MAX;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DecodeOptions {
pub beam: f32,
pub max_active: usize,
pub min_active: usize,
}
impl Default for DecodeOptions {
fn default() -> Self {
Self {
beam: 16.0,
max_active: 7000,
min_active: 200,
}
}
}
impl DecodeOptions {
pub fn exhaustive() -> Self {
Self {
beam: f32::INFINITY,
max_active: usize::MAX,
min_active: 0,
}
}
}
#[inline]
pub(crate) fn relax_cost<S: std::hash::Hash + Eq>(
frontier: &mut FxHashMap<S, Token>,
state: S,
cost: f32,
aux: u32,
) -> bool {
match frontier.get_mut(&state) {
Some(token) if token.cost <= cost => false,
Some(token) => {
*token = Token { cost, aux };
true
}
None => {
frontier.insert(state, Token { cost, aux });
true
}
}
}
pub(crate) fn prune<S: std::hash::Hash + Eq>(
frontier: &mut FxHashMap<S, Token>,
opts: &DecodeOptions,
costs: &mut Vec<f32>,
) -> f32 {
let best = frontier
.values()
.map(|token| token.cost)
.fold(f32::INFINITY, f32::min);
let mut cutoff = best + opts.beam;
let cap = opts.max_active.max(opts.min_active);
if frontier.len() > cap {
costs.clear();
costs.extend(frontier.values().map(|token| token.cost));
let rank = cap.min(costs.len() - 1);
let (_, &mut nth, _) = costs.select_nth_unstable_by(rank, |a, b| a.total_cmp(b));
cutoff = cutoff.min(nth);
}
if cutoff.is_finite() {
frontier.retain(|_, token| token.cost <= cutoff);
}
cutoff
}