pub use ferric_macros::make_model;
pub mod core;
pub mod distributions;
pub use self::core::FeOption;
pub use FeOption::{Known, Null, Unknown};
pub fn weighted_mean(values: &[f64], log_weights: &[f64]) -> f64 {
assert_eq!(
values.len(),
log_weights.len(),
"values and log_weights must have the same length"
);
let max_lw = log_weights
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
let weights: Vec<f64> = log_weights.iter().map(|&lw| (lw - max_lw).exp()).collect();
let total: f64 = weights.iter().sum();
values
.iter()
.zip(weights.iter())
.map(|(&v, &w)| v * w)
.sum::<f64>()
/ total
}
pub fn weighted_std(values: &[f64], log_weights: &[f64]) -> f64 {
assert_eq!(
values.len(),
log_weights.len(),
"values and log_weights must have the same length"
);
let mean = weighted_mean(values, log_weights);
let max_lw = log_weights
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
let weights: Vec<f64> = log_weights.iter().map(|&lw| (lw - max_lw).exp()).collect();
let total: f64 = weights.iter().sum();
let variance = values
.iter()
.zip(weights.iter())
.map(|(&v, &w)| w * (v - mean).powi(2))
.sum::<f64>()
/ total;
variance.sqrt()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn weighted_mean_uniform() {
let values = vec![1.0, 2.0, 3.0];
let log_weights = vec![0.0, 0.0, 0.0];
let mean = weighted_mean(&values, &log_weights);
assert!((mean - 2.0).abs() < 1e-10);
}
#[test]
fn weighted_std_uniform() {
let values = vec![1.0, 2.0, 3.0];
let log_weights = vec![0.0, 0.0, 0.0];
let std = weighted_std(&values, &log_weights);
assert!((std - (2.0f64 / 3.0).sqrt()).abs() < 1e-10);
}
#[test]
fn weighted_mean_concentrated() {
let values = vec![1.0, 2.0, 10.0];
let log_weights = vec![-100.0, -100.0, 0.0];
let mean = weighted_mean(&values, &log_weights);
assert!((mean - 10.0).abs() < 0.01);
}
}