From 11b49f50c944f2b5bd26a5ba5935f6e7e62cd694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 14:49:48 +0100 Subject: [PATCH] Implement `Mean` for `DVec`, `DVecN`, `VecN` and `MatN`. Fix #166. --- src/structs/dmat.rs | 17 +++++++++++------ src/structs/dvec.rs | 4 ++-- src/structs/dvec_macros.rs | 8 ++++++++ src/structs/mat.rs | 8 +++++++- src/structs/mat_macros.rs | 23 +++++++++++++++++++++++ src/structs/vec.rs | 8 +++++++- src/structs/vec_macros.rs | 12 ++++++++++++ src/traits/operations.rs | 2 +- 8 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index 7cf5ab7f..a8826850 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -502,8 +502,8 @@ impl + Clone> Mean> for DMat { let mut res: DVec = 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 + Clone> Cov> for DMat { 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 + Clone> Cov> for DMat { // 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(¢ered) * centered) / normalizer } @@ -545,10 +546,12 @@ impl ColSlice> for DMat { 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 RowSlice> for DMat { assert!(row_id < self.nrows); assert!(col_start < col_end); assert!(col_end <= self.ncols); + let mut slice : DVec = unsafe { DVec::new_uninitialized(col_end - col_start) }; @@ -568,11 +572,12 @@ impl RowSlice> for DMat { } slice_idx += 1; } + slice } } -impl Diag> for DMat { +impl Diag> for DMat { #[inline] fn from_diag(diag: &DVec) -> DMat { let mut res = DMat::new_zeros(diag.len(), diag.len()); diff --git a/src/structs/dvec.rs b/src/structs/dvec.rs index 520a1ede..63e32aff 100644 --- a/src/structs/dvec.rs +++ b/src/structs/dvec.rs @@ -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}; diff --git a/src/structs/dvec_macros.rs b/src/structs/dvec_macros.rs index d741a986..b637827d 100644 --- a/src/structs/dvec_macros.rs +++ b/src/structs/dvec_macros.rs @@ -290,6 +290,14 @@ macro_rules! dvec_impl( } } + impl> Mean for $dvec { + #[inline] + fn mean(&self) -> N { + let normalizer = ::cast(1.0f64 / self.len() as f64); + self.iter().fold(::zero(), |acc, x| acc + *x * normalizer) + } + } + impl> ApproxEq for $dvec { #[inline] fn approx_epsilon(_: Option<$dvec>) -> N { diff --git a/src/structs/mat.rs b/src/structs/mat.rs index 3cee999a..6ca710fc 100644 --- a/src/structs/mat.rs +++ b/src/structs/mat.rs @@ -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); diff --git a/src/structs/mat_macros.rs b/src/structs/mat_macros.rs index d128b998..53f919bd 100644 --- a/src/structs/mat_macros.rs +++ b/src/structs/mat_macros.rs @@ -726,3 +726,26 @@ macro_rules! eigen_qr_impl( } ) ); + + +macro_rules! mean_impl( + ($t: ident, $v: ident, $dim: expr) => ( + impl + Clone> Mean<$v> for $t { + fn mean(&self) -> $v { + let mut res: $v = ::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 + } + } + ) +); diff --git a/src/structs/vec.rs b/src/structs/vec.rs index cbe4621c..cf0f7c20 100644 --- a/src/structs/vec.rs +++ b/src/structs/vec.rs @@ -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); diff --git a/src/structs/vec_macros.rs b/src/structs/vec_macros.rs index 152db309..64bae53a 100644 --- a/src/structs/vec_macros.rs +++ b/src/structs/vec_macros.rs @@ -805,3 +805,15 @@ macro_rules! rand_impl( } ) ); + +macro_rules! mean_impl( + ($t: ident) => ( + impl> Mean for $t { + #[inline] + fn mean(&self) -> N { + let normalizer = ::cast(1.0f64 / self.len() as f64); + self.iter().fold(::zero(), |acc, x| acc + *x * normalizer) + } + } + ) +); diff --git a/src/traits/operations.rs b/src/traits/operations.rs index 80c899ce..38f17b0b 100644 --- a/src/traits/operations.rs +++ b/src/traits/operations.rs @@ -325,7 +325,7 @@ pub trait Cov { } } -/// Trait for computing the covariance of a set of data. +/// Trait for computing the mean of a set of data. pub trait Mean { /// Computes the mean of the observations stored by `v`. ///