Files
wifi-densepose/crates/cognitum-gate-kernel/tests_disabled/evidence_tests.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

251 lines
6.8 KiB
Rust

//! Comprehensive tests for E-value accumulator
//!
//! Tests cover:
//! - E-value bounds (E[e] <= 1 under null)
//! - Overflow/underflow protection
//! - Update rules (Product, Average, ExponentialMoving, Maximum)
//! - Stopping rules
use cognitum_gate_kernel::evidence::{
EValueAccumulator, EValueError, StoppingDecision, StoppingRule, UpdateRule,
E_VALUE_MAX, E_VALUE_MIN,
};
#[cfg(test)]
mod basic_operations {
use super::*;
#[test]
fn test_accumulator_creation() {
let acc = EValueAccumulator::new();
assert_eq!(acc.current_value(), 1.0);
assert_eq!(acc.observation_count(), 0);
}
#[test]
fn test_observe_updates_count() {
let mut acc = EValueAccumulator::new();
acc.observe(0.5);
assert_eq!(acc.observation_count(), 1);
acc.observe(0.7);
assert_eq!(acc.observation_count(), 2);
}
#[test]
fn test_reset() {
let mut acc = EValueAccumulator::new();
acc.observe(0.5);
acc.reset();
assert_eq!(acc.current_value(), 1.0);
assert_eq!(acc.observation_count(), 0);
}
}
#[cfg(test)]
mod update_rules {
use super::*;
#[test]
fn test_product_rule() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
acc.observe_evalue(2.0);
assert!((acc.current_value() - 2.0).abs() < 0.001);
acc.observe_evalue(3.0);
assert!((acc.current_value() - 6.0).abs() < 0.001);
}
#[test]
fn test_average_rule() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Average);
acc.observe_evalue(2.0);
acc.observe_evalue(4.0);
assert!((acc.current_value() - 3.0).abs() < 0.001);
}
#[test]
fn test_exponential_moving() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::ExponentialMoving { lambda: 0.5 });
acc.observe_evalue(2.0);
acc.observe_evalue(4.0);
assert!((acc.current_value() - 3.0).abs() < 0.001);
}
#[test]
fn test_maximum_rule() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Maximum);
acc.observe_evalue(2.0);
acc.observe_evalue(5.0);
acc.observe_evalue(3.0);
assert_eq!(acc.current_value(), 5.0);
}
}
#[cfg(test)]
mod bounds_and_overflow {
use super::*;
#[test]
fn test_e_value_clamping_high() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
acc.observe_evalue(1e20);
assert!(acc.current_value() <= E_VALUE_MAX);
}
#[test]
fn test_e_value_clamping_low() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
acc.observe_evalue(1e-20);
assert!(acc.current_value() >= E_VALUE_MIN);
}
#[test]
fn test_product_overflow_protection() {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
for _ in 0..100 {
acc.observe_evalue(100.0);
}
assert!(acc.current_value() <= E_VALUE_MAX);
assert!(acc.current_value().is_finite());
}
}
#[cfg(test)]
mod likelihood_ratio {
use super::*;
#[test]
fn test_valid_likelihood_ratio() {
let result = EValueAccumulator::from_likelihood_ratio(0.9, 0.1);
assert!(result.is_ok());
assert!((result.unwrap() - 9.0).abs() < 0.001);
}
#[test]
fn test_zero_denominator() {
let result = EValueAccumulator::from_likelihood_ratio(0.5, 0.0);
assert_eq!(result, Err(EValueError::DivisionByZero));
}
#[test]
fn test_nan_input() {
let result = EValueAccumulator::from_likelihood_ratio(f64::NAN, 0.5);
assert_eq!(result, Err(EValueError::InvalidInput));
}
}
#[cfg(test)]
mod mixture_evalue {
use super::*;
#[test]
fn test_uniform_mixture() {
let components = [2.0, 4.0, 6.0];
let weights = [1.0, 1.0, 1.0];
let result = EValueAccumulator::mixture(&components, &weights);
assert!(result.is_ok());
assert!((result.unwrap() - 4.0).abs() < 0.001);
}
#[test]
fn test_empty_mixture() {
let result = EValueAccumulator::mixture(&[], &[]);
assert_eq!(result, Err(EValueError::InvalidInput));
}
}
#[cfg(test)]
mod stopping_rules {
use super::*;
#[test]
fn test_continue_decision() {
let rule = StoppingRule::new(100.0);
let acc = EValueAccumulator::new();
assert_eq!(rule.check(&acc), StoppingDecision::Continue);
}
#[test]
fn test_accept_decision() {
let rule = StoppingRule::new(100.0);
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
for _ in 0..10 {
acc.observe_evalue(2.0);
}
assert!(acc.current_value() > 100.0);
assert_eq!(rule.check(&acc), StoppingDecision::Accept);
}
#[test]
fn test_reject_decision() {
let rule = StoppingRule::with_accept(100.0, 0.01);
let mut acc = EValueAccumulator::with_rule(UpdateRule::Product);
for _ in 0..10 {
acc.observe_evalue(0.1);
}
assert!(acc.current_value() < 0.01);
assert_eq!(rule.check(&acc), StoppingDecision::Reject);
}
#[test]
fn test_confidence_calculation() {
let rule = StoppingRule::default();
let mut acc = EValueAccumulator::new();
assert_eq!(rule.confidence(&acc), 0.0);
acc.observe_evalue(2.0);
assert!((rule.confidence(&acc) - 0.5).abs() < 0.001);
}
}
#[cfg(test)]
mod combine_evalues {
use super::*;
#[test]
fn test_combine_basic() {
let combined = EValueAccumulator::combine(2.0, 3.0);
assert_eq!(combined, 6.0);
}
#[test]
fn test_combine_overflow_clamped() {
let combined = EValueAccumulator::combine(1e10, 1e10);
assert!(combined <= E_VALUE_MAX);
}
}
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_e_value_always_positive(score in 0.0f64..1.0) {
let acc = EValueAccumulator::new();
let e = acc.compute_e_value(score);
assert!(e > 0.0);
}
#[test]
fn prop_e_value_bounded(score in 0.0f64..1.0) {
let acc = EValueAccumulator::new();
let e = acc.compute_e_value(score);
assert!(e >= E_VALUE_MIN);
assert!(e <= E_VALUE_MAX);
}
#[test]
fn prop_maximum_never_decreases(observations in proptest::collection::vec(0.1f64..10.0, 1..20)) {
let mut acc = EValueAccumulator::with_rule(UpdateRule::Maximum);
let mut max_seen = 0.0f64;
for o in observations {
acc.observe_evalue(o);
let current = acc.current_value();
assert!(current >= max_seen);
max_seen = current;
}
}
}
}