use crate::{welford_online::welford_online, Iterstats};
pub trait SumOfSquares<A = Self>: Sized {
type Output;
fn sum_of_squares<I: Iterator<Item = A>>(iter: I) -> Self::Output;
}
macro_rules! sst_impl {
($typ:ty) => {
impl SumOfSquares for $typ {
type Output = $typ;
fn sum_of_squares<I: Iterator<Item = Self>>(iter: I) -> Self::Output {
welford_online(iter).sum_of_squares
}
}
impl SumOfSquares for &$typ {
type Output = $typ;
fn sum_of_squares<I: Iterator<Item = Self>>(iter: I) -> Self::Output {
iter.map(|i| *i).sum_of_squares()
}
}
};
}
sst_impl!(f64);
sst_impl!(f32);
#[cfg(test)]
mod tests {
use super::*;
use paste::paste;
macro_rules! test_sst {
( $name:ident: $typ:ty as $iter:expr; iter => $expected:expr ; $tol:expr ) => {
paste! {
#[test]
fn [<$name _iter>]() {
let sst = <&$typ>::sum_of_squares($iter.iter());
assert!((sst - $expected).abs() < $tol);
}
}
};
( $name:ident: $typ:ty as $iter:expr; into_iter => $expected:expr ; $tol:expr ) => {
paste! {
#[test]
fn [<$name _into_iter >]() {
let sst = <$typ>::sum_of_squares($iter.into_iter());
assert!((sst - $expected).abs() < $tol);
}
}
};
( $name:ident: $typ:ty as $iter:expr => $expected:expr ; $tol:expr ) => {
test_sst!($name: $typ as $iter; iter => $expected; $tol);
test_sst!($name: $typ as $iter; into_iter => $expected; $tol);
};
}
test_sst!(f64: f64 as [0.3, 2.2, 3.5] => 5.18; 1e-12);
test_sst!(f32: f64 as [0.3, 2.2, 3.5] => 5.18; 1e-6);
}