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

@ -535,6 +535,7 @@ impl<N: BaseNum + Cast<f64> + Clone> Cov<DMat<N>> for DMat<N> {
// FIXME: return a triangular matrix? // FIXME: return a triangular matrix?
let fnormalizer: f64 = Cast::from(self.nrows() - 1); let fnormalizer: f64 = Cast::from(self.nrows() - 1);
let normalizer: N = Cast::from(fnormalizer); let normalizer: N = Cast::from(fnormalizer);
// FIXME: this will do 2 allocations for temporaries! // FIXME: this will do 2 allocations for temporaries!
(Transpose::transpose(&centered) * centered) / normalizer (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!(col_id < self.ncols);
assert!(row_start < row_end); assert!(row_start < row_end);
assert!(row_end <= self.nrows); 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 start= self.offset(row_start, col_id);
let stop = self.offset(row_end, col_id); let stop = self.offset(row_end, col_id);
let slice = DVec::from_slice(row_end - row_start, &self.mij[start .. stop]); let slice = DVec::from_slice(row_end - row_start, &self.mij[start .. stop]);
slice slice
} }
} }
@ -558,6 +561,7 @@ impl<N: Copy> RowSlice<DVec<N>> for DMat<N> {
assert!(row_id < self.nrows); assert!(row_id < self.nrows);
assert!(col_start < col_end); assert!(col_start < col_end);
assert!(col_end <= self.ncols); assert!(col_end <= self.ncols);
let mut slice : DVec<N> = unsafe { let mut slice : DVec<N> = unsafe {
DVec::new_uninitialized(col_end - col_start) DVec::new_uninitialized(col_end - col_start)
}; };
@ -568,6 +572,7 @@ impl<N: Copy> RowSlice<DVec<N>> for DMat<N> {
} }
slice_idx += 1; slice_idx += 1;
} }
slice slice
} }
} }

View File

@ -8,9 +8,9 @@ use std::iter::repeat;
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut}; use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
use rand::{self, Rand}; use rand::{self, Rand};
use num::{Zero, One}; use num::{Zero, One};
use traits::operations::{ApproxEq, Axpy}; use traits::operations::{ApproxEq, Axpy, Mean};
use traits::geometry::{Dot, Norm}; 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")] #[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen}; 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> { impl<N: ApproxEq<N>> ApproxEq<N> for $dvec<N> {
#[inline] #[inline]
fn approx_epsilon(_: Option<$dvec<N>>) -> N { 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, use traits::structure::{Cast, Row, Col, Iterable, IterableMut, Dim, Indexable, Eye, ColSlice,
RowSlice, Diag, DiagMut, Shape, BaseFloat, BaseNum, Repeat}; 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 traits::geometry::{ToHomogeneous, FromHomogeneous, Orig};
use linalg; use linalg;
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
@ -81,6 +81,7 @@ outer_impl!(Vec1, Mat1);
eigen_qr_impl!(Mat1, Vec1); eigen_qr_impl!(Mat1, Vec1);
arbitrary_impl!(Mat1, m11); arbitrary_impl!(Mat1, m11);
rand_impl!(Mat1, m11); rand_impl!(Mat1, m11);
mean_impl!(Mat1, Vec1, 1);
/// Square matrix of dimension 2. /// Square matrix of dimension 2.
#[repr(C)] #[repr(C)]
@ -134,6 +135,7 @@ outer_impl!(Vec2, Mat2);
eigen_qr_impl!(Mat2, Vec2); eigen_qr_impl!(Mat2, Vec2);
arbitrary_impl!(Mat2, m11, m12, m21, m22); arbitrary_impl!(Mat2, m11, m12, m21, m22);
rand_impl!(Mat2, m11, m12, m21, m22); rand_impl!(Mat2, m11, m12, m21, m22);
mean_impl!(Mat2, Vec2, 2);
/// Square matrix of dimension 3. /// Square matrix of dimension 3.
#[repr(C)] #[repr(C)]
@ -230,6 +232,7 @@ rand_impl!(Mat3,
m21, m22, m23, m21, m22, m23,
m31, m32, m33 m31, m32, m33
); );
mean_impl!(Mat3, Vec3, 3);
/// Square matrix of dimension 4. /// Square matrix of dimension 4.
#[repr(C)] #[repr(C)]
@ -349,6 +352,7 @@ rand_impl!(Mat4,
m31, m32, m33, m34, m31, m32, m33, m34,
m41, m42, m43, m44 m41, m42, m43, m44
); );
mean_impl!(Mat4, Vec4, 4);
/// Square matrix of dimension 5. /// Square matrix of dimension 5.
#[repr(C)] #[repr(C)]
@ -485,6 +489,7 @@ rand_impl!(Mat5,
m41, m42, m43, m44, m45, m41, m42, m43, m44, m45,
m51, m52, m53, m54, m55 m51, m52, m53, m54, m55
); );
mean_impl!(Mat5, Vec5, 5);
/// Square matrix of dimension 6. /// Square matrix of dimension 6.
#[repr(C)] #[repr(C)]
@ -626,3 +631,4 @@ rand_impl!(Mat6,
m51, m52, m53, m54, m55, m56, m51, m52, m53, m54, m55, m56,
m61, m62, m63, m64, m65, m66 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 std::iter::{Iterator, FromIterator, IntoIterator};
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use num::{Zero, One}; 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, use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm,
Translation, Translate}; Translation, Translate};
use traits::structure::{Basis, Cast, Dim, Indexable, Iterable, IterableMut, Shape, NumVec, 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); absolute_vec_impl!(Vec1, x);
arbitrary_impl!(Vec1, x); arbitrary_impl!(Vec1, x);
rand_impl!(Vec1, x); rand_impl!(Vec1, x);
mean_impl!(Vec1);
/// Vector of dimension 2. /// Vector of dimension 2.
#[repr(C)] #[repr(C)]
@ -143,6 +144,7 @@ num_float_vec_impl!(Vec2);
absolute_vec_impl!(Vec2, x, y); absolute_vec_impl!(Vec2, x, y);
arbitrary_impl!(Vec2, x, y); arbitrary_impl!(Vec2, x, y);
rand_impl!(Vec2, x, y); rand_impl!(Vec2, x, y);
mean_impl!(Vec2);
/// Vector of dimension 3. /// Vector of dimension 3.
#[repr(C)] #[repr(C)]
@ -198,6 +200,7 @@ num_float_vec_impl!(Vec3);
absolute_vec_impl!(Vec3, x, y, z); absolute_vec_impl!(Vec3, x, y, z);
arbitrary_impl!(Vec3, x, y, z); arbitrary_impl!(Vec3, x, y, z);
rand_impl!(Vec3, x, y, z); rand_impl!(Vec3, x, y, z);
mean_impl!(Vec3);
/// Vector of dimension 4. /// Vector of dimension 4.
@ -256,6 +259,7 @@ num_float_vec_impl!(Vec4);
absolute_vec_impl!(Vec4, x, y, z, w); absolute_vec_impl!(Vec4, x, y, z, w);
arbitrary_impl!(Vec4, x, y, z, w); arbitrary_impl!(Vec4, x, y, z, w);
rand_impl!(Vec4, x, y, z, w); rand_impl!(Vec4, x, y, z, w);
mean_impl!(Vec4);
/// Vector of dimension 5. /// Vector of dimension 5.
#[repr(C)] #[repr(C)]
@ -315,6 +319,7 @@ num_float_vec_impl!(Vec5);
absolute_vec_impl!(Vec5, x, y, z, w, a); absolute_vec_impl!(Vec5, x, y, z, w, a);
arbitrary_impl!(Vec5, x, y, z, w, a); arbitrary_impl!(Vec5, x, y, z, w, a);
rand_impl!(Vec5, x, y, z, w, a); rand_impl!(Vec5, x, y, z, w, a);
mean_impl!(Vec5);
/// Vector of dimension 6. /// Vector of dimension 6.
#[repr(C)] #[repr(C)]
@ -374,3 +379,4 @@ num_float_vec_impl!(Vec6);
absolute_vec_impl!(Vec6, x, y, z, w, a, b); absolute_vec_impl!(Vec6, x, y, z, w, a, b);
arbitrary_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); 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> { pub trait Mean<N> {
/// Computes the mean of the observations stored by `v`. /// Computes the mean of the observations stored by `v`.
/// ///