use crate::generate::GeneratedChoice;
pub(crate) fn score(choice: &GeneratedChoice) -> f64 {
choice
.logprobs
.iter()
.map(|(id, probs)| {
let p = probs.get(*id).copied().unwrap_or(0.0) as f64;
p.ln()
})
.sum()
}
pub(crate) fn take_best(mut choices: Vec<GeneratedChoice>, n: usize) -> Vec<GeneratedChoice> {
choices.sort_by(|a, b| score(b).total_cmp(&score(a)));
choices.truncate(n);
choices
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate::FinishReason;
fn choice(text: &str, probs: &[f32]) -> GeneratedChoice {
let logprobs = probs.iter().map(|p| (0usize, vec![*p, 1.0 - *p])).collect();
GeneratedChoice {
finish: FinishReason::Stop,
text: text.to_string(),
logprobs,
}
}
#[test]
fn the_score_is_the_sum_of_the_log_probabilities() {
let c = choice("x", &[0.5, 0.25]);
let want = 0.5f64.ln() + 0.25f64.ln();
assert!((score(&c) - want).abs() < 1e-9, "{}", score(&c));
}
#[test]
fn the_rule_is_the_sum_which_a_mean_would_rank_differently() {
let short_and_unsure = choice("one", &[0.5]);
let long_and_confident = choice("ten of them", &[0.9; 10]);
let sum_short = 0.5f64.ln();
let sum_long = 10.0 * 0.9f64.ln();
assert!(sum_short > sum_long, "the premise: the sum picks short");
assert!(sum_short < 0.9f64.ln(), "the premise: the mean picks long");
let best = take_best(vec![long_and_confident, short_and_unsure], 1);
assert_eq!(
best[0].text, "one",
"ranked by something other than the summed logprob"
);
}
#[test]
fn take_best_returns_n_in_descending_score() {
let best = take_best(
vec![
choice("worst", &[0.1]),
choice("best", &[0.9]),
choice("middle", &[0.5]),
],
2,
);
assert_eq!(
best.iter().map(|c| c.text.as_str()).collect::<Vec<_>>(),
vec!["best", "middle"]
);
}
#[test]
fn ties_keep_generation_order() {
let best = take_best(
vec![
choice("first", &[0.5]),
choice("second", &[0.5]),
choice("third", &[0.5]),
],
2,
);
assert_eq!(
best.iter().map(|c| c.text.as_str()).collect::<Vec<_>>(),
vec!["first", "second"]
);
}
#[test]
fn asking_for_more_than_exist_returns_them_all() {
let best = take_best(vec![choice("only", &[0.5])], 4);
assert_eq!(best.len(), 1);
}
}