use deep_causality_algebra::RealField;
use deep_causality_num::FromPrimitive;
pub(crate) fn subtract_mean_in_place<R>(v: &mut [R])
where
R: RealField + FromPrimitive,
{
if v.is_empty() {
return;
}
let n = <R as FromPrimitive>::from_usize(v.len())
.expect("v.len() is representable in every supported RealField");
let sum: R = v.iter().copied().fold(R::zero(), |a, b| a + b);
let mean = sum / n;
for entry in v.iter_mut() {
*entry -= mean;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subtract_mean_in_place_zeros_a_constant_vector() {
let mut v = vec![5.0_f64; 7];
subtract_mean_in_place(&mut v);
for &x in &v {
assert!(x.abs() < 1e-15);
}
}
#[test]
fn subtract_mean_in_place_preserves_zero_mean_input() {
let mut v = vec![-2.0_f64, -1.0, 0.0, 1.0, 2.0];
let original = v.clone();
subtract_mean_in_place(&mut v);
for (a, b) in v.iter().zip(original.iter()) {
assert!((a - b).abs() < 1e-15);
}
}
#[test]
fn subtract_mean_in_place_handles_empty_slice() {
let mut v: Vec<f64> = vec![];
subtract_mean_in_place(&mut v);
assert!(v.is_empty());
}
#[test]
fn subtract_mean_in_place_subtracts_correct_mean_from_arbitrary_input() {
let mut v = vec![1.0_f64, 2.0, 3.0, 4.0]; subtract_mean_in_place(&mut v);
let expected = [-1.5, -0.5, 0.5, 1.5];
for (a, e) in v.iter().zip(expected.iter()) {
assert!((a - e).abs() < 1e-15);
}
}
}