extern crate aliasmethod; extern crate rand; #[cfg(test)] mod tests { use aliasmethod::AliasTable; use rand::thread_rng; use std::collections::HashMap; struct TestParam { weights: Vec, rates: Vec, } #[test] fn test_probability() { let params: [TestParam; 6] = [ TestParam { weights: vec![10.0, 15.0], rates: vec![40.0, 60.0], }, TestParam { weights: vec![20.0, 30.0], rates: vec![40.0, 60.0], }, TestParam { weights: vec![20.0, 5.0], rates: vec![80.0, 20.0], }, TestParam { weights: vec![25.0], rates: vec![100.0], }, TestParam { weights: vec![1.0, 99.0], rates: vec![1.0, 99.0], }, TestParam { weights: vec![1.0, 1.0, 8.0], rates: vec![10.0, 10.0, 80.0], }, ]; for ( param_no, &TestParam { ref weights, ref rates, }, ) in params.into_iter().enumerate() { match AliasTable::new(&weights) { Err(e) => { assert!(false, "error : {}", e); } Ok(alias_table) => { let sample: i64 = 100000; let mut results: HashMap = HashMap::new(); for _ in 0..sample { let n = alias_table.random(thread_rng()); let count = results.entry(n).or_insert(0); *count += 1; } let fs = sample as f64; for (n, rate) in rates.into_iter().enumerate() { match results.get(&n) { None => { assert!(false, "Not found '{}' in results", n); } Some(count) => { let p: f64 = rate / 100.0; let q: f64 = 1.0 - p; let expected = fs * p; // 3.89 = inverse of normal distribution function with alpha=0.9999 let delta = 3.89 * (fs * p * q).sqrt(); let count = *count as f64; let ok = expected - delta <= count && count <= expected + delta; assert!(ok, format!( "The probability is out of by interval estimation. param_no={} num={} weight={} actual={}, expected={}, delta={}", param_no, n, weights[n as usize], count, expected, delta)); } } } } } } } }