pub(crate) const K: f32 = 1.2;
pub(crate) const B: f32 = 0.75;
pub(crate) const AVERAGE_LENGTH: f32 = 256.0;
pub(crate) 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, 256), 1.0);
}
#[test]
fn matches_the_closed_form_on_the_short_fixture() {
let got = saturation(1, 6);
assert!((got - 1.665_286_8).abs() < 1e-5, "{got}");
}
#[test]
fn a_shorter_than_average_document_weighs_a_single_occurrence_higher() {
let short = saturation(1, 1);
let at_average = saturation(1, 256);
assert!(short > at_average, "{short} vs {at_average}");
}
#[test]
fn differs_from_minicoils_own_average_length_at_the_same_input() {
let bm25 = saturation(1, 200);
let minicoil = crate::models::sparse::minicoil::term_frequency::saturation(1, 200);
assert_ne!(bm25, minicoil);
}
}