use serde::Serialize;
use crate::attribution::alpha_beta;
use crate::stats::mean;
#[derive(Clone, Debug, Serialize)]
pub struct RoleContribution {
pub role: String,
pub beta_to_team: f64,
pub mean_return: f64,
}
pub fn attribute_roles(team: &[f64], roles: &[(String, Vec<f64>)]) -> Vec<RoleContribution> {
roles
.iter()
.map(|(name, r)| {
let (_, beta) = alpha_beta(team, r);
RoleContribution {
role: name.clone(),
beta_to_team: beta,
mean_return: mean(r),
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn load_bearing_role_dominates() {
let team: Vec<f64> = (0..40).map(|i| 0.001 * (i as f64 * 0.3).sin()).collect();
let roles = vec![
("driver".to_string(), team.clone()),
(
"noise".to_string(),
(0..40).map(|i| 0.001 * (i as f64 * 1.7).cos()).collect(),
),
];
let attr = attribute_roles(&team, &roles);
assert!(
(attr[0].beta_to_team - 1.0).abs() < 1e-6,
"driver={:?}",
attr[0]
);
assert!(
attr[0].beta_to_team.abs() > attr[1].beta_to_team.abs(),
"driver should out-load noise"
);
}
}