use super::MIN_ACTIVITY_SCORE;
pub(crate) fn binomial_coefficient(n: i32, r: i32) -> i64 {
if r < 0 || r > n {
return 0;
}
let r = r.max(n - r);
let (mut t, mut i, mut j): (i64, i64, i64) = (1, n as i64, 1);
while i > r as i64 {
t = t * i / j;
i -= 1;
j += 1;
}
t
}
pub(crate) fn compute_activity_score(v_l: u8, n_r: u32, p: f64, lambda: f64) -> f64 {
let v_l = (v_l as u32).min(n_r);
let bc = binomial_coefficient(n_r as i32, v_l as i32).max(1) as f64;
let s = libm::log(bc) + (v_l as f64) * libm::log(p) + ((n_r - v_l) as f64) * libm::log(1.0 - p)
- libm::log(lambda)
+ lambda * (v_l as f64);
s.max(MIN_ACTIVITY_SCORE)
}
pub(crate) fn compute_bigs(littles: &[u8], bigs: &mut [u8], threshold: u8) -> bool {
let per = littles.len() / bigs.len();
let mut changed = false;
let mut l = 0usize;
for slot in bigs.iter_mut() {
let mut sum: u8 = 0;
let end = l + per;
while l < end {
if littles[l] > threshold {
sum += 1;
}
l += 1;
}
if *slot != sum {
*slot = sum;
changed = true;
}
}
changed
}
#[cfg(test)]
mod tests {
use super::super::N1;
use super::*;
#[test]
fn binomial_and_activity_score_sanity() {
assert_eq!(binomial_coefficient(20, 10), 184_756);
let s = compute_activity_score(0, N1, 0.5, 0.78);
assert!((s - MIN_ACTIVITY_SCORE).abs() < 1e-20, "got {s}");
}
#[test]
fn binomial_r_greater_than_n_is_zero() {
assert_eq!(binomial_coefficient(5, 10), 0);
assert_eq!(binomial_coefficient(0, 1), 0);
assert_eq!(binomial_coefficient(13, 14), 0);
}
#[test]
fn binomial_negative_r_is_zero() {
assert_eq!(binomial_coefficient(5, -1), 0);
}
#[test]
fn activity_score_v_l_greater_than_n_r_no_panic() {
let s = compute_activity_score(5, 1, 0.5, 24.0);
assert!(s.is_finite(), "score must be finite, got {s}");
assert!(s >= MIN_ACTIVITY_SCORE, "score must be >= MIN, got {s}");
}
#[test]
fn activity_score_v_l_equals_n_r_no_panic() {
let s = compute_activity_score(13, 13, 0.5, 0.78);
assert!(s.is_finite(), "got {s}");
}
#[test]
fn compute_bigs_counts_above_threshold() {
let littles = [0u8, 8, 9, 10, 0, 0, 0, 0, 0, 0];
let mut bigs = [0u8; 2];
assert!(compute_bigs(&littles, &mut bigs, 7));
assert_eq!(bigs, [3, 0]);
assert!(!compute_bigs(&littles, &mut bigs, 7));
}
}