extern crate num;
use math::{Dimension, Normalization, Mean, MeanVec};
use vectors::zero;
use matrix::Matrix;
use ops::{VectorVectorOps, VectorScalarOps};
use ops_inplace::VectorVectorOpsInPlace;
pub trait Var<T> {
fn var(&self, dim: Dimension, nrm: Normalization) -> T;
}
macro_rules! var_impl {
($($t:ty)*) => ($(
impl Var<$t> for Vec<$t> {
fn var(&self, dim: Dimension, nrm: Normalization) -> $t {
(&self[..]).var(dim, nrm)
}
}
impl Var<$t> for [$t] {
fn var(&self, dim: Dimension, nrm: Normalization) -> $t {
if self.len() == 0 {
return 0 as $t;
}
match dim {
Dimension::Row => {
let m = self.mean();
let n = self.len();
let d = match nrm {
Normalization::N => n as $t,
Normalization::MinusOne => if n > 1 { (n - 1) as $t } else { n as $t }
};
self.iter()
.map(|&x| (x - m) * (x - m))
.fold(0 as $t, |acc, x| acc + x) / d
}
_ => 0 as $t
}
}
}
impl Var<Vec<$t>> for Matrix<$t> {
fn var(&self, dim: Dimension, nrm: Normalization) -> Vec<$t> {
match dim {
Dimension::Row => {
self.row_iter().map(|row| row.var(Dimension::Row, nrm)).collect()
}
Dimension::Column => {
let mean_vec = self.mean(Dimension::Column);
let mut v = zero::<$t>(self.cols());
for row in self.row_iter() {
let x = row.sub(&mean_vec).mutate(|x| x * x);
v.iadd(&x);
}
let n = self.rows();
let d = match nrm {
Normalization::N => n as $t,
Normalization::MinusOne => if n > 1 { (n - 1) as $t } else { n as $t }
};
v.div_scalar(d)
}
}
}
}
)*)
}
var_impl!{ f32 f64 }
#[cfg(test)]
mod tests {
extern crate num;
use super::*;
use math::{Dimension, Normalization};
use matrix::Matrix;
fn vec_equal(a: &Vec<f32>, b: &Vec<f32>) -> bool {
a.iter().zip(b.iter()).all(|(&x, &y)| num::abs(x - y) < 0.01)
}
#[test]
fn test_var_vec_f32() {
let x: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0];
assert_eq!(x.var(Dimension::Row, Normalization::N), 1.25);
let y: Vec<f32> = vec![10.0, 5.0, 3.0, 11.0, 2.0, 15.0, 13.0, 5.0, 3.0];
assert!(y.var(Dimension::Row, Normalization::N) - 20.914 < 0.001);
let a: Vec<f32> = Vec::new();
assert_eq!(a.var(Dimension::Row, Normalization::N), 0.0);
assert_eq!(a.var(Dimension::Column, Normalization::N), 0.0);
assert_eq!(x.var(Dimension::Column, Normalization::N), 0.0);
}
#[test]
fn test_var_minus_vec_f32() {
let x: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0];
assert!(x.var(Dimension::Row, Normalization::MinusOne) - 1.6667 < 0.0001);
let y: Vec<f32> = vec![10.0, 5.0, 3.0, 11.0, 2.0, 15.0, 13.0, 5.0, 3.0];
assert!(y.var(Dimension::Row, Normalization::MinusOne) - 23.528 < 0.001);
let a: Vec<f32> = Vec::new();
assert_eq!(a.var(Dimension::Row, Normalization::MinusOne), 0.0);
assert_eq!(a.var(Dimension::Column, Normalization::MinusOne), 0.0);
assert_eq!(x.var(Dimension::Column, Normalization::MinusOne), 0.0);
}
#[test]
fn test_var_matrix() {
let m = mat![
1.0f32, 5.0, 3.0, 6.0, 2.0;
2.0, 2.5, 2.2, 1.8, 2.1;
4.0, 9.0, 2.7, 13.0, 1.9
];
let mut x = m.var(Dimension::Row, Normalization::N);
assert_eq!(x.len(), 3);
assert!(vec_equal(&x, &vec![3.44, 0.0536, 17.926]));
let mut y = m.var(Dimension::Row, Normalization::MinusOne);
assert_eq!(y.len(), 3);
assert!(vec_equal(&y, &vec![4.3, 0.067, 22.407]));
x = m.var(Dimension::Column, Normalization::N);
assert_eq!(x.len(), 5);
assert!(vec_equal(&x, &vec![1.5556, 7.1667, 0.10889, 21.342, 0.0066667]));
y = m.var(Dimension::Column, Normalization::MinusOne);
assert_eq!(y.len(), 5);
assert!(vec_equal(&y, &vec![2.3333, 10.750, 0.16333, 32.013, 0.01]));
}
}