iterstats 0.7.0

Statistics for rust iterators.
Documentation
//! Caculate the total sum of squares.

use crate::{welford_online::welford_online, Iterstats};

/// Calculate the total sum of squares of an iterator.
pub trait SumOfSquares<A = Self>: Sized {
    /// The type of the output.
    type Output;

    /// Calculate the total sum of squares.
    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);
}