Implement `Mean` for `DVec`, `DVecN`, `VecN` and `MatN`.

Fix #166.
This commit is contained in:
Sébastien Crozet 2016-01-10 14:49:48 +01:00
parent 5cbbc25bb2
commit 11b49f50c9
8 changed files with 71 additions and 11 deletions

View File

@ -502,8 +502,8 @@ impl<N: BaseNum + Cast<f64> + Clone> Mean<DVec<N>> for DMat<N> {
let mut res: DVec<N> = DVec::new_zeros(self.ncols);
let normalizer: N = Cast::from(1.0f64 / self.nrows as f64);
for i in 0..self.nrows {
for j in 0..self.ncols {
for i in 0 .. self.nrows {
for j in 0 .. self.ncols {
unsafe {
let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer;
res.unsafe_set(j, acc);
@ -524,8 +524,8 @@ impl<N: BaseNum + Cast<f64> + Clone> Cov<DMat<N>> for DMat<N> {
let mean = self.mean();
// FIXME: use the rows iterator when available
for i in 0..self.nrows {
for j in 0..self.ncols {
for i in 0 .. self.nrows {
for j in 0 .. self.ncols {
unsafe {
centered.unsafe_set((i, j), self.unsafe_at((i, j)) - mean.unsafe_at(j));
}
@ -535,6 +535,7 @@ impl<N: BaseNum + Cast<f64> + Clone> Cov<DMat<N>> for DMat<N> {
// FIXME: return a triangular matrix?
let fnormalizer: f64 = Cast::from(self.nrows() - 1);
let normalizer: N = Cast::from(fnormalizer);
// FIXME: this will do 2 allocations for temporaries!
(Transpose::transpose(&centered) * centered) / normalizer
}
@ -545,10 +546,12 @@ impl<N: Copy + Clone> ColSlice<DVec<N>> for DMat<N> {
assert!(col_id < self.ncols);
assert!(row_start < row_end);
assert!(row_end <= self.nrows);
// we can init from slice thanks to the matrix being column major
// We can init from slice thanks to the matrix being column-major.
let start= self.offset(row_start, col_id);
let stop = self.offset(row_end, col_id);
let slice = DVec::from_slice(row_end - row_start, &self.mij[start .. stop]);
slice
}
}
@ -558,6 +561,7 @@ impl<N: Copy> RowSlice<DVec<N>> for DMat<N> {
assert!(row_id < self.nrows);
assert!(col_start < col_end);
assert!(col_end <= self.ncols);
let mut slice : DVec<N> = unsafe {
DVec::new_uninitialized(col_end - col_start)
};
@ -568,11 +572,12 @@ impl<N: Copy> RowSlice<DVec<N>> for DMat<N> {
}
slice_idx += 1;
}
slice
}
}
impl<N: Copy + Clone + Zero> Diag<DVec<N>> for DMat<N> {
impl<N: Copy + Clone + Zero> Diag<DVec<N>> for DMat<N> {
#[inline]
fn from_diag(diag: &DVec<N>) -> DMat<N> {
let mut res = DMat::new_zeros(diag.len(), diag.len());

View File

@ -8,9 +8,9 @@ use std::iter::repeat;
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
use rand::{self, Rand};
use num::{Zero, One};
use traits::operations::{ApproxEq, Axpy};
use traits::operations::{ApproxEq, Axpy, Mean};
use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut, Indexable, Shape, BaseFloat, BaseNum};
use traits::structure::{Iterable, IterableMut, Indexable, Shape, BaseFloat, BaseNum, Cast};
#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};

View File

@ -290,6 +290,14 @@ macro_rules! dvec_impl(
}
}
impl<N: BaseFloat + Cast<f64>> Mean<N> for $dvec<N> {
#[inline]
fn mean(&self) -> N {
let normalizer = ::cast(1.0f64 / self.len() as f64);
self.iter().fold(::zero(), |acc, x| acc + *x * normalizer)
}
}
impl<N: ApproxEq<N>> ApproxEq<N> for $dvec<N> {
#[inline]
fn approx_epsilon(_: Option<$dvec<N>>) -> N {

View File

@ -14,7 +14,7 @@ use structs::dvec::{DVec1, DVec2, DVec3, DVec4, DVec5, DVec6};
use traits::structure::{Cast, Row, Col, Iterable, IterableMut, Dim, Indexable, Eye, ColSlice,
RowSlice, Diag, DiagMut, Shape, BaseFloat, BaseNum, Repeat};
use traits::operations::{Absolute, Transpose, Inv, Outer, EigenQR};
use traits::operations::{Absolute, Transpose, Inv, Outer, EigenQR, Mean};
use traits::geometry::{ToHomogeneous, FromHomogeneous, Orig};
use linalg;
#[cfg(feature="arbitrary")]
@ -81,6 +81,7 @@ outer_impl!(Vec1, Mat1);
eigen_qr_impl!(Mat1, Vec1);
arbitrary_impl!(Mat1, m11);
rand_impl!(Mat1, m11);
mean_impl!(Mat1, Vec1, 1);
/// Square matrix of dimension 2.
#[repr(C)]
@ -134,6 +135,7 @@ outer_impl!(Vec2, Mat2);
eigen_qr_impl!(Mat2, Vec2);
arbitrary_impl!(Mat2, m11, m12, m21, m22);
rand_impl!(Mat2, m11, m12, m21, m22);
mean_impl!(Mat2, Vec2, 2);
/// Square matrix of dimension 3.
#[repr(C)]
@ -230,6 +232,7 @@ rand_impl!(Mat3,
m21, m22, m23,
m31, m32, m33
);
mean_impl!(Mat3, Vec3, 3);
/// Square matrix of dimension 4.
#[repr(C)]
@ -349,6 +352,7 @@ rand_impl!(Mat4,
m31, m32, m33, m34,
m41, m42, m43, m44
);
mean_impl!(Mat4, Vec4, 4);
/// Square matrix of dimension 5.
#[repr(C)]
@ -485,6 +489,7 @@ rand_impl!(Mat5,
m41, m42, m43, m44, m45,
m51, m52, m53, m54, m55
);
mean_impl!(Mat5, Vec5, 5);
/// Square matrix of dimension 6.
#[repr(C)]
@ -626,3 +631,4 @@ rand_impl!(Mat6,
m51, m52, m53, m54, m55, m56,
m61, m62, m63, m64, m65, m66
);
mean_impl!(Mat6, Vec6, 6);

View File

@ -726,3 +726,26 @@ macro_rules! eigen_qr_impl(
}
)
);
macro_rules! mean_impl(
($t: ident, $v: ident, $dim: expr) => (
impl<N: BaseNum + Cast<f64> + Clone> Mean<$v<N>> for $t<N> {
fn mean(&self) -> $v<N> {
let mut res: $v<N> = ::zero();
let normalizer: N = Cast::from(1.0f64 / $dim as f64);
for i in 0 .. $dim {
for j in 0 .. $dim {
unsafe {
let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer;
res.unsafe_set(j, acc);
}
}
}
res
}
}
)
);

View File

@ -9,7 +9,7 @@ use std::slice::{Iter, IterMut};
use std::iter::{Iterator, FromIterator, IntoIterator};
use rand::{Rand, Rng};
use num::{Zero, One};
use traits::operations::{ApproxEq, POrd, POrdering, Axpy, Absolute};
use traits::operations::{ApproxEq, POrd, POrdering, Axpy, Absolute, Mean};
use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm,
Translation, Translate};
use traits::structure::{Basis, Cast, Dim, Indexable, Iterable, IterableMut, Shape, NumVec,
@ -90,6 +90,7 @@ num_float_vec_impl!(Vec1);
absolute_vec_impl!(Vec1, x);
arbitrary_impl!(Vec1, x);
rand_impl!(Vec1, x);
mean_impl!(Vec1);
/// Vector of dimension 2.
#[repr(C)]
@ -143,6 +144,7 @@ num_float_vec_impl!(Vec2);
absolute_vec_impl!(Vec2, x, y);
arbitrary_impl!(Vec2, x, y);
rand_impl!(Vec2, x, y);
mean_impl!(Vec2);
/// Vector of dimension 3.
#[repr(C)]
@ -198,6 +200,7 @@ num_float_vec_impl!(Vec3);
absolute_vec_impl!(Vec3, x, y, z);
arbitrary_impl!(Vec3, x, y, z);
rand_impl!(Vec3, x, y, z);
mean_impl!(Vec3);
/// Vector of dimension 4.
@ -256,6 +259,7 @@ num_float_vec_impl!(Vec4);
absolute_vec_impl!(Vec4, x, y, z, w);
arbitrary_impl!(Vec4, x, y, z, w);
rand_impl!(Vec4, x, y, z, w);
mean_impl!(Vec4);
/// Vector of dimension 5.
#[repr(C)]
@ -315,6 +319,7 @@ num_float_vec_impl!(Vec5);
absolute_vec_impl!(Vec5, x, y, z, w, a);
arbitrary_impl!(Vec5, x, y, z, w, a);
rand_impl!(Vec5, x, y, z, w, a);
mean_impl!(Vec5);
/// Vector of dimension 6.
#[repr(C)]
@ -374,3 +379,4 @@ num_float_vec_impl!(Vec6);
absolute_vec_impl!(Vec6, x, y, z, w, a, b);
arbitrary_impl!(Vec6, x, y, z, w, a, b);
rand_impl!(Vec6, x, y, z, w, a, b);
mean_impl!(Vec6);

View File

@ -805,3 +805,15 @@ macro_rules! rand_impl(
}
)
);
macro_rules! mean_impl(
($t: ident) => (
impl<N: BaseFloat + Cast<f64>> Mean<N> for $t<N> {
#[inline]
fn mean(&self) -> N {
let normalizer = ::cast(1.0f64 / self.len() as f64);
self.iter().fold(::zero(), |acc, x| acc + *x * normalizer)
}
}
)
);

View File

@ -325,7 +325,7 @@ pub trait Cov<M> {
}
}
/// Trait for computing the covariance of a set of data.
/// Trait for computing the mean of a set of data.
pub trait Mean<N> {
/// Computes the mean of the observations stored by `v`.
///