pub const K: f32 = 1.2;
pub const B: f32 = 0.75;
pub const AVERAGE_LENGTH: f32 = 150.0;
pub fn saturation(count: u32, doc_len: u32) -> f32 {
let count = count as f32;
let doc_len = doc_len as f32;
count * (K + 1.0) / (count + K * (1.0 - B + B * doc_len / AVERAGE_LENGTH))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_single_occurrence_at_the_average_length_weighs_exactly_one() {
assert_eq!(saturation(1, 150), 1.0);
}
#[test]
fn repeated_occurrences_at_the_average_length_scale_by_the_bm25_ratio() {
let got = saturation(3, 150);
let want = 3.0 * 2.2 / 4.2;
assert!((got - want).abs() < 1e-6, "{got} vs {want}");
}
#[test]
fn a_shorter_than_average_document_weighs_a_single_occurrence_higher() {
let short = saturation(1, 1);
let at_average = saturation(1, 150);
assert!(short > at_average, "{short} vs {at_average}");
}
#[test]
fn matches_hand_arithmetic_at_a_short_row() {
let got = saturation(1, 5);
let want = 2.2 / 1.33;
assert!((got - want).abs() < 1e-5, "{got} vs {want}");
}
}