From 5cbbc25bb28109d85afe4929daba68bdcbd7bf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 14:49:37 +0100 Subject: [PATCH 1/8] Make vectors indexable the same way as slices. This includes range indexing. In addition, for unification, the methods `.as_slice` and `.as_mut_slice` of DVec have been renamed to `.as_ref` and `.as_mut`. --- benches/dmat.rs | 4 +-- src/structs/dvec_macros.rs | 52 +++++++++++++++++++------------------- src/structs/vec_macros.rs | 10 ++++---- tests/mat.rs | 22 ++++++++-------- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/benches/dmat.rs b/benches/dmat.rs index 40d62c15..b41c8d4d 100644 --- a/benches/dmat.rs +++ b/benches/dmat.rs @@ -13,7 +13,7 @@ macro_rules! bench_mul_dmat( let a: DMat = DMat::new_random($nrows, $ncols); let mut b: DMat = DMat::new_random($nrows, $ncols); - for _ in (0usize .. 1000) { + for _ in 0usize .. 1000 { // XXX: the clone here is highly undesirable! b = a.clone() * b; } @@ -55,7 +55,7 @@ macro_rules! bench_mul_dmat_dvec( let m : DMat = DMat::new_random($nrows, $ncols); let mut v : DVec = DVec::new_random($ncols); - for _ in (0usize .. 1000) { + for _ in 0usize .. 1000 { // XXX: the clone here is highly undesirable! v = m.clone() * v } diff --git a/src/structs/dvec_macros.rs b/src/structs/dvec_macros.rs index 43f3357e..d741a986 100644 --- a/src/structs/dvec_macros.rs +++ b/src/structs/dvec_macros.rs @@ -15,20 +15,20 @@ macro_rules! dvec_impl( /// Tests if all components of the vector are zeroes. #[inline] pub fn is_zero(&self) -> bool { - self.as_slice().iter().all(|e| e.is_zero()) + self.as_ref().iter().all(|e| e.is_zero()) } } impl $dvec { /// Slices this vector. #[inline] - pub fn as_slice<'a>(&'a self) -> &'a [N] { + pub fn as_ref<'a>(&'a self) -> &'a [N] { &self.at[.. self.len()] } /// Mutably slices this vector. #[inline] - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [N] { + pub fn as_mut<'a>(&'a mut self) -> &'a mut [N] { let len = self.len(); &mut self.at[.. len] } @@ -46,7 +46,7 @@ macro_rules! dvec_impl( fn swap(&mut self, i: usize, j: usize) { assert!(i < self.len()); assert!(j < self.len()); - self.as_mut_slice().swap(i, j); + self.as_mut().swap(i, j); } #[inline] @@ -61,17 +61,17 @@ macro_rules! dvec_impl( } - impl Index for $dvec { - type Output = N; + impl Index for $dvec where [N]: Index { + type Output = <[N] as Index>::Output; - fn index(&self, i: usize) -> &N { - &self.as_slice()[i] + fn index(&self, i: T) -> &<[N] as Index>::Output { + &self.as_ref()[i] } } - impl IndexMut for $dvec { - fn index_mut(&mut self, i: usize) -> &mut N { - &mut self.as_mut_slice()[i] + impl IndexMut for $dvec where [N]: IndexMut { + fn index_mut(&mut self, i: T) -> &mut <[N] as Index>::Output { + &mut self.as_mut()[i] } } @@ -97,14 +97,14 @@ macro_rules! dvec_impl( impl Iterable for $dvec { #[inline] fn iter<'l>(&'l self) -> Iter<'l, N> { - self.as_slice().iter() + self.as_ref().iter() } } impl IterableMut for $dvec { #[inline] fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { - self.as_mut_slice().iter_mut() + self.as_mut().iter_mut() } } @@ -185,7 +185,7 @@ macro_rules! dvec_impl( let mut res = self; - for (left, right) in res.as_mut_slice().iter_mut().zip(right.as_slice().iter()) { + for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) { *left = *left * *right } @@ -202,7 +202,7 @@ macro_rules! dvec_impl( let mut res = self; - for (left, right) in res.as_mut_slice().iter_mut().zip(right.as_slice().iter()) { + for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) { *left = *left / *right } @@ -219,7 +219,7 @@ macro_rules! dvec_impl( let mut res = self; - for (left, right) in res.as_mut_slice().iter_mut().zip(right.as_slice().iter()) { + for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) { *left = *left + *right } @@ -236,7 +236,7 @@ macro_rules! dvec_impl( let mut res = self; - for (left, right) in res.as_mut_slice().iter_mut().zip(right.as_slice().iter()) { + for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) { *left = *left - *right } @@ -249,7 +249,7 @@ macro_rules! dvec_impl( #[inline] fn neg(self) -> $dvec { - FromIterator::from_iter(self.as_slice().iter().map(|a| -*a)) + FromIterator::from_iter(self.as_ref().iter().map(|a| -*a)) } } @@ -282,7 +282,7 @@ macro_rules! dvec_impl( fn normalize_mut(&mut self) -> N { let l = Norm::norm(self); - for n in self.as_mut_slice().iter_mut() { + for n in self.as_mut().iter_mut() { *n = *n / l; } @@ -303,13 +303,13 @@ macro_rules! dvec_impl( #[inline] fn approx_eq_eps(&self, other: &$dvec, epsilon: &N) -> bool { - let mut zip = self.as_slice().iter().zip(other.as_slice().iter()); + let mut zip = self.as_ref().iter().zip(other.as_ref().iter()); zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) } #[inline] fn approx_eq_ulps(&self, other: &$dvec, ulps: u32) -> bool { - let mut zip = self.as_slice().iter().zip(other.as_slice().iter()); + let mut zip = self.as_ref().iter().zip(other.as_ref().iter()); zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) } } @@ -321,7 +321,7 @@ macro_rules! dvec_impl( fn mul(self, right: N) -> $dvec { let mut res = self; - for e in res.as_mut_slice().iter_mut() { + for e in res.as_mut().iter_mut() { *e = *e * right } @@ -336,7 +336,7 @@ macro_rules! dvec_impl( fn div(self, right: N) -> $dvec { let mut res = self; - for e in res.as_mut_slice().iter_mut() { + for e in res.as_mut().iter_mut() { *e = *e / right } @@ -351,7 +351,7 @@ macro_rules! dvec_impl( fn add(self, right: N) -> $dvec { let mut res = self; - for e in res.as_mut_slice().iter_mut() { + for e in res.as_mut().iter_mut() { *e = *e + right } @@ -366,7 +366,7 @@ macro_rules! dvec_impl( fn sub(self, right: N) -> $dvec { let mut res = self; - for e in res.as_mut_slice().iter_mut() { + for e in res.as_mut().iter_mut() { *e = *e - right } @@ -392,7 +392,7 @@ macro_rules! small_dvec_impl ( return false; // FIXME: fail instead? } - for (a, b) in self.as_slice().iter().zip(other.as_slice().iter()) { + for (a, b) in self.as_ref().iter().zip(other.as_ref().iter()) { if *a != *b { return false; } diff --git a/src/structs/vec_macros.rs b/src/structs/vec_macros.rs index c42cf227..152db309 100644 --- a/src/structs/vec_macros.rs +++ b/src/structs/vec_macros.rs @@ -208,16 +208,16 @@ macro_rules! indexable_impl( macro_rules! index_impl( ($t: ident) => ( - impl Index for $t { - type Output = N; + impl Index for $t where [N]: Index { + type Output = <[N] as Index>::Output; - fn index(&self, i: usize) -> &N { + fn index(&self, i: T) -> &<[N] as Index>::Output { &self.as_ref()[i] } } - impl IndexMut for $t { - fn index_mut(&mut self, i: usize) -> &mut N { + impl IndexMut for $t where [N]: IndexMut { + fn index_mut(&mut self, i: T) -> &mut <[N] as Index>::Output { &mut self.as_mut()[i] } } diff --git a/tests/mat.rs b/tests/mat.rs index afae18d8..b79c548d 100644 --- a/tests/mat.rs +++ b/tests/mat.rs @@ -7,7 +7,7 @@ use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot2, Rot3, Persp3, Per macro_rules! test_inv_mat_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); match na::inv(&randmat) { @@ -20,7 +20,7 @@ macro_rules! test_inv_mat_impl( macro_rules! test_transpose_mat_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); assert!(na::transpose(&na::transpose(&randmat)) == randmat); @@ -30,7 +30,7 @@ macro_rules! test_transpose_mat_impl( macro_rules! test_qr_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); let (q, r) = na::qr(&randmat); @@ -43,7 +43,7 @@ macro_rules! test_qr_impl( macro_rules! test_cholesky_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { // construct symmetric positive definite matrix let mut randmat : $t = random(); @@ -65,7 +65,7 @@ macro_rules! test_cholesky_impl( macro_rules! test_hessenberg_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); @@ -90,7 +90,7 @@ macro_rules! test_hessenberg_impl( macro_rules! test_eigen_qr_impl( ($t: ty) => { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); // Make it symetric so that we can recompose the matrix to test at the end. let randmat = na::transpose(&randmat) * randmat; @@ -105,7 +105,7 @@ macro_rules! test_eigen_qr_impl( assert!(na::approx_eq_eps(&randmat, &recomp, &1.0e-2)); } - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat : $t = random(); // Take only diagonal part let randmat: $t = Diag::from_diag(&randmat.diag()); @@ -184,7 +184,7 @@ fn test_inv_mat6() { #[test] fn test_rotation2() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat: na::Rot2 = na::one(); let ang = Vec1::new(na::abs(&random::()) % ::pi()); @@ -201,7 +201,7 @@ fn test_index_mat2() { #[test] fn test_inv_rotation3() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let randmat: Rot3 = na::one(); let dir: Vec3 = random(); let ang = na::normalize(&dir) * (na::abs(&random::()) % ::pi()); @@ -524,7 +524,7 @@ fn test_dmat_subtraction() { /* FIXME: review qr decomposition to make it work with DMat. #[test] fn test_qr() { - for _ in (0usize .. 10) { + for _ in 0usize .. 10 { let dim1: usize = random(); let dim2: usize = random(); let rows = min(40, max(dim1, dim2)); @@ -809,6 +809,6 @@ fn test_transpose_square_mat() { let mut mat = DMat::from_col_vec(num_rows, num_cols, col_major_mat); mat.transpose_mut(); for i in 0..num_rows { - assert_eq!(&[0, 1, 2, 3], mat.row_slice(i, 0, num_cols).as_slice()); + assert_eq!(&[0, 1, 2, 3], &mat.row_slice(i, 0, num_cols)[..]); } } 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 2/8] 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`. /// From 3cd4221bf7069e51730cd12366c50e0796be2257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 14:49:55 +0100 Subject: [PATCH 3/8] Implement `Row` and `Col` for `DMat`. Fix #153. --- src/structs/dmat.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++- tests/mat.rs | 50 ++++++++++++++++++++++++++++++++++ tests/quat.rs | 10 +++---- tests/vec.rs | 20 +++++++------- 4 files changed, 130 insertions(+), 16 deletions(-) diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index a8826850..9dec5a3b 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -10,7 +10,7 @@ use rand::{self, Rand}; use num::{Zero, One}; use structs::dvec::DVec; use traits::operations::{ApproxEq, Inv, Transpose, Mean, Cov}; -use traits::structure::{Cast, ColSlice, RowSlice, Diag, DiagMut, Eye, Indexable, Shape, BaseNum}; +use traits::structure::{Cast, Col, ColSlice, Row, RowSlice, Diag, DiagMut, Eye, Indexable, Shape, BaseNum}; #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -541,6 +541,38 @@ impl + Clone> Cov> for DMat { } } +impl Col> for DMat { + #[inline] + fn ncols(&self) -> usize { + self.ncols + } + + #[inline] + fn set_col(&mut self, col_id: usize, v: DVec) { + assert!(col_id < self.ncols); + assert!(self.nrows == v.len()); + + for (i, e) in v[..].iter().enumerate() { + unsafe { + self.unsafe_set((i, col_id), *e); + } + } + } + + #[inline] + fn col(&self, col_id: usize) -> DVec { + let mut res: DVec = unsafe { + DVec::new_uninitialized(self.nrows) + }; + + for (row_id, e) in res[..].iter_mut().enumerate() { + *e = unsafe { self.unsafe_at((row_id, col_id)) }; + } + + res + } +} + impl ColSlice> for DMat { fn col_slice(&self, col_id :usize, row_start: usize, row_end: usize) -> DVec { assert!(col_id < self.ncols); @@ -556,6 +588,38 @@ impl ColSlice> for DMat { } } +impl Row> for DMat { + #[inline] + fn nrows(&self) -> usize { + self.nrows + } + + #[inline] + fn set_row(&mut self, row_id: usize, v: DVec) { + assert!(row_id < self.nrows); + assert!(self.ncols == v.len()); + + for (i, e) in v[..].iter().enumerate() { + unsafe { + self.unsafe_set((row_id, i), *e); + } + } + } + + #[inline] + fn row(&self, row_id: usize) -> DVec { + let mut res: DVec = unsafe { + DVec::new_uninitialized(self.ncols) + }; + + for (col_id, e) in res[..].iter_mut().enumerate() { + *e = unsafe { self.unsafe_at((row_id, col_id)) }; + } + + res + } +} + impl RowSlice> for DMat { fn row_slice(&self, row_id :usize, col_start: usize, col_end: usize) -> DVec { assert!(row_id < self.nrows); diff --git a/tests/mat.rs b/tests/mat.rs index b79c548d..05725f69 100644 --- a/tests/mat.rs +++ b/tests/mat.rs @@ -315,6 +315,33 @@ fn test_transpose_dmat() { assert!(na::transpose(&na::transpose(&mat)) == mat); } +#[test] +fn test_row_dmat() { + let mat = DMat::from_row_vec( + 8, + 4, + &[ + 1u32,2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24, + 25, 26, 27, 28, + 29, 30, 31, 32 + ] + ); + + assert_eq!(&DVec::from_slice(4, &[1u32, 2, 3, 4]), &mat.row(0)); + assert_eq!(&DVec::from_slice(4, &[5u32, 6, 7, 8]), &mat.row(1)); + assert_eq!(&DVec::from_slice(4, &[9u32, 10, 11, 12]), &mat.row(2)); + assert_eq!(&DVec::from_slice(4, &[13u32, 14, 15, 16]), &mat.row(3)); + assert_eq!(&DVec::from_slice(4, &[17u32, 18, 19, 20]), &mat.row(4)); + assert_eq!(&DVec::from_slice(4, &[21u32, 22, 23, 24]), &mat.row(5)); + assert_eq!(&DVec::from_slice(4, &[25u32, 26, 27, 28]), &mat.row(6)); + assert_eq!(&DVec::from_slice(4, &[29u32, 30, 31, 32]), &mat.row(7)); +} + #[test] fn test_row_slice_dmat() { let mat = DMat::from_row_vec( @@ -335,6 +362,29 @@ fn test_row_slice_dmat() { assert_eq!(&DVec::from_slice(2, &[19u32, 20]), &mat.row_slice(4, 2, 4)); } +#[test] +fn test_col_dmat() { + let mat = DMat::from_row_vec( + 8, + 4, + &[ + 1u32,2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24, + 25, 26, 27, 28, + 29, 30, 31, 32 + ] + ); + + assert_eq!(&DVec::from_slice(8, &[1u32, 5, 9, 13, 17, 21, 25, 29]), &mat.col(0)); + assert_eq!(&DVec::from_slice(8, &[2u32, 6, 10, 14, 18, 22, 26, 30]), &mat.col(1)); + assert_eq!(&DVec::from_slice(8, &[3u32, 7, 11, 15, 19, 23, 27, 31]), &mat.col(2)); + assert_eq!(&DVec::from_slice(8, &[4u32, 8, 12, 16, 20, 24, 28, 32]), &mat.col(3)); +} + #[test] fn test_col_slice_dmat() { let mat = DMat::from_row_vec( diff --git a/tests/quat.rs b/tests/quat.rs index 279ea623..84864721 100644 --- a/tests/quat.rs +++ b/tests/quat.rs @@ -6,7 +6,7 @@ use rand::random; #[test] fn test_quat_as_mat() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let axis_angle: Vec3 = random(); assert!(na::approx_eq(&UnitQuat::new(axis_angle).to_rot(), &Rot3::new(axis_angle))) @@ -15,7 +15,7 @@ fn test_quat_as_mat() { #[test] fn test_quat_mul_vec_or_pnt_as_mat() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let axis_angle: Vec3 = random(); let vec: Vec3 = random(); let pnt: Pnt3 = random(); @@ -32,7 +32,7 @@ fn test_quat_mul_vec_or_pnt_as_mat() { #[test] fn test_quat_div_quat() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let axis_angle1: Vec3 = random(); let axis_angle2: Vec3 = random(); @@ -48,7 +48,7 @@ fn test_quat_div_quat() { #[test] fn test_quat_to_axis_angle() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let axis_angle: Vec3 = random(); let q = UnitQuat::new(axis_angle); @@ -60,7 +60,7 @@ fn test_quat_to_axis_angle() { #[test] fn test_quat_euler_angles() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let angles: Vec3 = random(); let q = UnitQuat::new_with_euler_angles(angles.x, angles.y, angles.z); diff --git a/tests/vec.rs b/tests/vec.rs index daceba03..40bf02c9 100644 --- a/tests/vec.rs +++ b/tests/vec.rs @@ -6,7 +6,7 @@ use na::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Mat3, Rot2, Rot3, Iterable, I macro_rules! test_iterator_impl( ($t: ty, $n: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v: $t = random(); let mut mv: $t = v.clone(); let n: $n = random(); @@ -24,7 +24,7 @@ macro_rules! test_iterator_impl( macro_rules! test_commut_dot_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v1 : $t = random(); let v2 : $t = random(); @@ -35,7 +35,7 @@ macro_rules! test_commut_dot_impl( macro_rules! test_scalar_op_impl( ($t: ty, $n: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v1 : $t = random(); let n : $n = random(); @@ -58,7 +58,7 @@ macro_rules! test_scalar_op_impl( macro_rules! test_basis_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { na::canonical_basis(|e1: $t| { na::canonical_basis(|e2: $t| { assert!(e1 == e2 || na::approx_eq(&na::dot(&e1, &e2), &na::zero())); @@ -76,7 +76,7 @@ macro_rules! test_basis_impl( macro_rules! test_subspace_basis_impl( ($t: ty) => ( - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v : $t = random(); let v1 = na::normalize(&v); @@ -100,7 +100,7 @@ macro_rules! test_subspace_basis_impl( #[test] fn test_cross_vec3() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v1 : Vec3 = random(); let v2 : Vec3 = random(); let v3 : Vec3 = na::cross(&v1, &v2); @@ -321,7 +321,7 @@ fn test_outer_vec3() { #[test] fn test_vec3_rotation_between() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v1: Vec3 = random(); let mut v2: Vec3 = random(); @@ -335,7 +335,7 @@ fn test_vec3_rotation_between() { #[test] fn test_vec3_angle_between() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let vec: Vec3 = random(); let other: Vec3 = random(); @@ -353,7 +353,7 @@ fn test_vec3_angle_between() { #[test] fn test_vec2_rotation_between() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let v1: Vec2 = random(); let mut v2: Vec2 = random(); @@ -367,7 +367,7 @@ fn test_vec2_rotation_between() { #[test] fn test_vec2_angle_between() { - for _ in (0usize .. 10000) { + for _ in 0usize .. 10000 { let axis_ang: Vec1 = random(); let ang = na::norm(&axis_ang); From 581251d5b4adf68782be1f8523caa5c796af8bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 14:50:02 +0100 Subject: [PATCH 4/8] Implement dynamic matrix with a maximum size. Those are named DMat1 to DMat6 and have the same relation with DMat as DVec1 to DVec6 are related to DVec. As a side effect, the method `to_vec` of DMat was renamed `into_vec` to be more in line with the std lib. Addresses the second point of #100. --- src/lib.rs | 2 +- src/structs/dmat.rs | 815 ++++----------------------------- src/structs/dmat_macros.rs | 896 +++++++++++++++++++++++++++++++++++++ src/structs/mod.rs | 3 +- 4 files changed, 976 insertions(+), 740 deletions(-) create mode 100644 src/structs/dmat_macros.rs diff --git a/src/lib.rs b/src/lib.rs index e28a4650..b20c3689 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,7 +135,7 @@ pub use traits::{ pub use structs::{ Identity, - DMat, + DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6, DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6, Iso2, Iso3, Iso4, Mat1, Mat2, Mat3, Mat4, diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index 9dec5a3b..090c7789 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -3,6 +3,7 @@ #![allow(missing_docs)] // we hide doc to not have to document the $trhs double dispatch trait. use std::cmp; +use std::mem; use std::iter::repeat; use std::ops::{Add, Sub, Mul, Div, Index, IndexMut}; use std::fmt::{Debug, Formatter, Result}; @@ -38,47 +39,6 @@ impl DMat { } } -impl DMat { - /// Builds a matrix filled with zeros. - /// - /// # Arguments - /// * `dim` - The dimension of the matrix. A `dim`-dimensional matrix contains `dim * dim` - /// components. - #[inline] - pub fn new_zeros(nrows: usize, ncols: usize) -> DMat { - DMat::from_elem(nrows, ncols, ::zero()) - } - - /// Tests if all components of the matrix are zeroes. - #[inline] - pub fn is_zero(&self) -> bool { - self.mij.iter().all(|e| e.is_zero()) - } - - #[inline] - pub fn reset(&mut self) { - for mij in self.mij.iter_mut() { - *mij = ::zero(); - } - } -} - -impl DMat { - /// Builds a matrix filled with random values. - #[inline] - pub fn new_random(nrows: usize, ncols: usize) -> DMat { - DMat::from_fn(nrows, ncols, |_, _| rand::random()) - } -} - -impl DMat { - /// Builds a matrix filled with a given constant. - #[inline] - pub fn new_ones(nrows: usize, ncols: usize) -> DMat { - DMat::from_elem(nrows, ncols, ::one()) - } -} - impl DMat { /// Builds a matrix filled with a given constant. #[inline] @@ -92,7 +52,7 @@ impl DMat { /// Builds a matrix filled with the components provided by a vector. /// The vector contains the matrix data in row-major order. - /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `DMat` stores its data + /// Note that `from_col_vec` is much faster than `from_row_vec` since a `DMat` stores its data /// in column-major order. /// /// The vector must have at least `nrows * ncols` elements. @@ -108,7 +68,7 @@ impl DMat { /// Builds a matrix filled with the components provided by a vector. /// The vector contains the matrix data in column-major order. - /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `DMat` stores its data + /// Note that `from_col_vec` is much faster than `from_row_vec` since a `DMat` stores its data /// in column-major order. /// /// The vector must have at least `nrows * ncols` elements. @@ -125,733 +85,112 @@ impl DMat { } impl DMat { - /// Builds a matrix filled with a given constant. + /// Builds a matrix using an initialization function. #[inline(always)] pub fn from_fn N>(nrows: usize, ncols: usize, mut f: F) -> DMat { DMat { nrows: nrows, ncols: ncols, - mij: (0..nrows * ncols).map(|i| { let m = i / nrows; f(i - m * nrows, m) }).collect() + mij: (0 .. nrows * ncols).map(|i| { let m = i / nrows; f(i - m * nrows, m) }).collect() } } - /// The number of row on the matrix. - #[inline] - pub fn nrows(&self) -> usize { - self.nrows - } - - /// The number of columns on the matrix. - #[inline] - pub fn ncols(&self) -> usize { - self.ncols - } - - /// Transforms this matrix isizeo an array. This consumes the matrix and is O(1). + /// Transforms this matrix into an array. This consumes the matrix and is O(1). /// The returned vector contains the matrix data in column-major order. #[inline] - pub fn to_vec(self) -> Vec { + pub fn into_vec(self) -> Vec { self.mij } - - /// Gets a reference to this matrix data. - /// The returned vector contains the matrix data in column-major order. - #[inline] - pub fn as_vec(&self) -> &[N] { - &self.mij - } - - /// Gets a mutable reference to this matrix data. - /// The returned vector contains the matrix data in column-major order. - #[inline] - pub fn as_mut_vec(&mut self) -> &mut [N] { - &mut self.mij[..] - } } -// FIXME: add a function to modify the dimension (to avoid useless allocations)? +dmat_impl!(DMat); -impl Eye for DMat { - /// Builds an identity matrix. - /// - /// # Arguments - /// * `dim` - The dimension of the matrix. A `dim`-dimensional matrix contains `dim * dim` - /// components. - #[inline] - fn new_identity(dim: usize) -> DMat { - let mut res = DMat::new_zeros(dim, dim); - for i in 0..dim { - let _1: N = ::one(); - res[(i, i)] = _1; - } - - res - } +pub struct DMat1 { + nrows: usize, + ncols: usize, + mij: [N; 1 * 1], } -impl DMat { - #[inline(always)] - fn offset(&self, i: usize, j: usize) -> usize { - i + j * self.nrows - } +small_dmat_impl!(DMat1, 1, 0); +small_dmat_from_impl!(DMat1, 1, ::zero()); + +pub struct DMat2 { + nrows: usize, + ncols: usize, + mij: [N; 2 * 2], } -impl Indexable<(usize, usize), N> for DMat { - /// Just like `set` without bounds checking. - #[inline] - unsafe fn unsafe_set(&mut self, rowcol: (usize, usize), val: N) { - let (row, col) = rowcol; - let offset = self.offset(row, col); - *self.mij[..].get_unchecked_mut(offset) = val - } +small_dmat_impl!(DMat2, 2, 0, 1, + 2, 3); +small_dmat_from_impl!(DMat2, 2, ::zero(), ::zero(), + ::zero(), ::zero()); - /// Just like `at` without bounds checking. - #[inline] - unsafe fn unsafe_at(&self, rowcol: (usize, usize)) -> N { - let (row, col) = rowcol; - - *self.mij.get_unchecked(self.offset(row, col)) - } - - #[inline] - fn swap(&mut self, rowcol1: (usize, usize), rowcol2: (usize, usize)) { - let (row1, col1) = rowcol1; - let (row2, col2) = rowcol2; - let offset1 = self.offset(row1, col1); - let offset2 = self.offset(row2, col2); - let count = self.mij.len(); - assert!(offset1 < count); - assert!(offset2 < count); - self.mij[..].swap(offset1, offset2); - } +pub struct DMat3 { + nrows: usize, + ncols: usize, + mij: [N; 3 * 3], } -impl Shape<(usize, usize)> for DMat { - #[inline] - fn shape(&self) -> (usize, usize) { - (self.nrows, self.ncols) - } +small_dmat_impl!(DMat3, 3, 0, 1, 2, + 3, 4, 5, + 6, 7, 8); +small_dmat_from_impl!(DMat3, 3, ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero()); + + +pub struct DMat4 { + nrows: usize, + ncols: usize, + mij: [N; 4 * 4], } -impl Index<(usize, usize)> for DMat { - type Output = N; +small_dmat_impl!(DMat4, 4, 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15); +small_dmat_from_impl!(DMat4, 4, ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero()); - fn index(&self, (i, j): (usize, usize)) -> &N { - assert!(i < self.nrows); - assert!(j < self.ncols); - unsafe { - self.mij.get_unchecked(self.offset(i, j)) - } - } +pub struct DMat5 { + nrows: usize, + ncols: usize, + mij: [N; 5 * 5], } -impl IndexMut<(usize, usize)> for DMat { - fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut N { - assert!(i < self.nrows); - assert!(j < self.ncols); +small_dmat_impl!(DMat5, 5, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24); +small_dmat_from_impl!(DMat5, 5, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero()); - let offset = self.offset(i, j); - unsafe { - self.mij[..].get_unchecked_mut(offset) - } - } +pub struct DMat6 { + nrows: usize, + ncols: usize, + mij: [N; 6 * 6], } -impl + Add + Zero> Mul> for DMat { - type Output = DMat; - - #[inline] - fn mul(self, right: DMat) -> DMat { - (&self) * (&right) - } -} - -impl<'a, N: Copy + Mul + Add + Zero> Mul<&'a DMat> for DMat { - type Output = DMat; - - #[inline] - fn mul(self, right: &'a DMat) -> DMat { - (&self) * right - } -} - -impl<'a, N: Copy + Mul + Add + Zero> Mul> for &'a DMat { - type Output = DMat; - - #[inline] - fn mul(self, right: DMat) -> DMat { - self * (&right) - } -} - -impl<'a, 'b, N: Copy + Mul + Add + Zero> Mul<&'b DMat> for &'a DMat { - type Output = DMat; - - #[inline] - fn mul(self, right: &DMat) -> DMat { - assert!(self.ncols == right.nrows); - - let mut res = unsafe { DMat::new_uninitialized(self.nrows, right.ncols) }; - - for i in 0..self.nrows { - for j in 0..right.ncols { - let mut acc: N = ::zero(); - - unsafe { - for k in 0..self.ncols { - acc = acc - + self.unsafe_at((i, k)) * right.unsafe_at((k, j)); - } - - res.unsafe_set((i, j), acc); - } - } - } - - res - } -} - -impl + Mul + Zero> Mul> for DMat { - type Output = DVec; - - fn mul(self, right: DVec) -> DVec { - assert!(self.ncols == right.at.len()); - - let mut res : DVec = unsafe { DVec::new_uninitialized(self.nrows) }; - - for i in 0..self.nrows { - let mut acc: N = ::zero(); - - for j in 0..self.ncols { - unsafe { - acc = acc + self.unsafe_at((i, j)) * right.unsafe_at(j); - } - } - - res.at[i] = acc; - } - - res - } -} - - -impl + Mul + Zero> Mul> for DVec { - type Output = DVec; - - fn mul(self, right: DMat) -> DVec { - assert!(right.nrows == self.at.len()); - - let mut res : DVec = unsafe { DVec::new_uninitialized(right.ncols) }; - - for i in 0..right.ncols { - let mut acc: N = ::zero(); - - for j in 0..right.nrows { - unsafe { - acc = acc + self.unsafe_at(j) * right.unsafe_at((j, i)); - } - } - - res.at[i] = acc; - } - - res - } -} - -impl Inv for DMat { - #[inline] - fn inv(&self) -> Option> { - let mut res: DMat = self.clone(); - if res.inv_mut() { - Some(res) - } - else { - None - } - } - - fn inv_mut(&mut self) -> bool { - assert!(self.nrows == self.ncols); - - let dim = self.nrows; - let mut res: DMat = Eye::new_identity(dim); - - // inversion using Gauss-Jordan elimination - for k in 0..dim { - // search a non-zero value on the k-th column - // FIXME: would it be worth it to spend some more time searching for the - // max instead? - - let mut n0 = k; // index of a non-zero entry - - while n0 != dim { - if unsafe { self.unsafe_at((n0, k)) } != ::zero() { - break; - } - - n0 = n0 + 1; - } - - if n0 == dim { - return false - } - - // swap pivot line - if n0 != k { - for j in 0..dim { - let off_n0_j = self.offset(n0, j); - let off_k_j = self.offset(k, j); - - self.mij[..].swap(off_n0_j, off_k_j); - res.mij[..].swap(off_n0_j, off_k_j); - } - } - - unsafe { - let pivot = self.unsafe_at((k, k)); - - for j in k..dim { - let selfval = self.unsafe_at((k, j)) / pivot; - self.unsafe_set((k, j), selfval); - } - - for j in 0..dim { - let resval = res.unsafe_at((k, j)) / pivot; - res.unsafe_set((k, j), resval); - } - - for l in 0..dim { - if l != k { - let normalizer = self.unsafe_at((l, k)); - - for j in k..dim { - let selfval = self.unsafe_at((l, j)) - self.unsafe_at((k, j)) * normalizer; - self.unsafe_set((l, j), selfval); - } - - for j in 0..dim { - let resval = res.unsafe_at((l, j)) - res.unsafe_at((k, j)) * normalizer; - res.unsafe_set((l, j), resval); - } - } - } - } - } - - *self = res; - - true - } -} - -impl Transpose for DMat { - #[inline] - fn transpose(&self) -> DMat { - if self.nrows == self.ncols { - let mut res = self.clone(); - - res.transpose_mut(); - - res - } - else { - let mut res = unsafe { DMat::new_uninitialized(self.ncols, self.nrows) }; - - for i in 0..self.nrows { - for j in 0..self.ncols { - unsafe { - res.unsafe_set((j, i), self.unsafe_at((i, j))) - } - } - } - - res - } - } - - #[inline] - fn transpose_mut(&mut self) { - if self.nrows == self.ncols { - let n = self.nrows; - for i in 0..n - 1 { - for j in i + 1..n { - let off_i_j = self.offset(i, j); - let off_j_i = self.offset(j, i); - - self.mij[..].swap(off_i_j, off_j_i); - } - } - } - else { - // FIXME: implement a better algorithm which does that in-place. - *self = Transpose::transpose(self); - } - } -} - -impl + Clone> Mean> for DMat { - fn mean(&self) -> DVec { - 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 { - unsafe { - let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer; - res.unsafe_set(j, acc); - } - } - } - - res - } -} - -impl + Clone> Cov> for DMat { - // FIXME: this could be heavily optimized, removing all temporaries by merging loops. - fn cov(&self) -> DMat { - assert!(self.nrows > 1); - - let mut centered = unsafe { DMat::new_uninitialized(self.nrows, self.ncols) }; - let mean = self.mean(); - - // FIXME: use the rows iterator when available - 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)); - } - } - } - - // 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 - } -} - -impl Col> for DMat { - #[inline] - fn ncols(&self) -> usize { - self.ncols - } - - #[inline] - fn set_col(&mut self, col_id: usize, v: DVec) { - assert!(col_id < self.ncols); - assert!(self.nrows == v.len()); - - for (i, e) in v[..].iter().enumerate() { - unsafe { - self.unsafe_set((i, col_id), *e); - } - } - } - - #[inline] - fn col(&self, col_id: usize) -> DVec { - let mut res: DVec = unsafe { - DVec::new_uninitialized(self.nrows) - }; - - for (row_id, e) in res[..].iter_mut().enumerate() { - *e = unsafe { self.unsafe_at((row_id, col_id)) }; - } - - res - } -} - -impl ColSlice> for DMat { - fn col_slice(&self, col_id :usize, row_start: usize, row_end: usize) -> DVec { - 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. - 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 - } -} - -impl Row> for DMat { - #[inline] - fn nrows(&self) -> usize { - self.nrows - } - - #[inline] - fn set_row(&mut self, row_id: usize, v: DVec) { - assert!(row_id < self.nrows); - assert!(self.ncols == v.len()); - - for (i, e) in v[..].iter().enumerate() { - unsafe { - self.unsafe_set((row_id, i), *e); - } - } - } - - #[inline] - fn row(&self, row_id: usize) -> DVec { - let mut res: DVec = unsafe { - DVec::new_uninitialized(self.ncols) - }; - - for (col_id, e) in res[..].iter_mut().enumerate() { - *e = unsafe { self.unsafe_at((row_id, col_id)) }; - } - - res - } -} - -impl RowSlice> for DMat { - fn row_slice(&self, row_id :usize, col_start: usize, col_end: usize) -> DVec { - 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) - }; - let mut slice_idx = 0; - for col_id in col_start..col_end { - unsafe { - slice.unsafe_set(slice_idx, self.unsafe_at((row_id, col_id))); - } - slice_idx += 1; - } - - slice - } -} - -impl Diag> for DMat { - #[inline] - fn from_diag(diag: &DVec) -> DMat { - let mut res = DMat::new_zeros(diag.len(), diag.len()); - - res.set_diag(diag); - - res - } - - #[inline] - fn diag(&self) -> DVec { - let smallest_dim = cmp::min(self.nrows, self.ncols); - - let mut diag: DVec = DVec::new_zeros(smallest_dim); - - for i in 0..smallest_dim { - unsafe { diag.unsafe_set(i, self.unsafe_at((i, i))) } - } - - diag - } -} - -impl DiagMut> for DMat { - #[inline] - fn set_diag(&mut self, diag: &DVec) { - let smallest_dim = cmp::min(self.nrows, self.ncols); - - assert!(diag.len() == smallest_dim); - - for i in 0..smallest_dim { - unsafe { self.unsafe_set((i, i), diag.unsafe_at(i)) } - } - } -} - -impl> ApproxEq for DMat { - #[inline] - fn approx_epsilon(_: Option>) -> N { - ApproxEq::approx_epsilon(None::) - } - - #[inline] - fn approx_ulps(_: Option>) -> u32 { - ApproxEq::approx_ulps(None::) - } - - #[inline] - fn approx_eq_eps(&self, other: &DMat, epsilon: &N) -> bool { - let mut zip = self.mij.iter().zip(other.mij.iter()); - zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) - } - - #[inline] - fn approx_eq_ulps(&self, other: &DMat, ulps: u32) -> bool { - let mut zip = self.mij.iter().zip(other.mij.iter()); - zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) - } -} - -impl Debug for DMat { - fn fmt(&self, form:&mut Formatter) -> Result { - for i in 0..self.nrows() { - for j in 0..self.ncols() { - let _ = write!(form, "{:?} ", self[(i, j)]); - } - let _ = write!(form, "\n"); - } - write!(form, "\n") - } -} - -impl> Mul for DMat { - type Output = DMat; - - #[inline] - fn mul(self, right: N) -> DMat { - let mut res = self; - - for mij in res.mij.iter_mut() { - *mij = *mij * right; - } - - res - } -} - -impl> Div for DMat { - type Output = DMat; - - #[inline] - fn div(self, right: N) -> DMat { - let mut res = self; - - for mij in res.mij.iter_mut() { - *mij = *mij / right; - } - - res - } -} - -impl> Add for DMat { - type Output = DMat; - - #[inline] - fn add(self, right: N) -> DMat { - let mut res = self; - - for mij in res.mij.iter_mut() { - *mij = *mij + right; - } - - res - } -} - -impl> Add> for DMat { - type Output = DMat; - - #[inline] - fn add(self, right: DMat) -> DMat { - self + (&right) - } -} - -impl<'a, N: Copy + Add> Add> for &'a DMat { - type Output = DMat; - - #[inline] - fn add(self, right: DMat) -> DMat { - right + self - } -} - -impl<'a, N: Copy + Add> Add<&'a DMat> for DMat { - type Output = DMat; - - #[inline] - fn add(self, right: &'a DMat) -> DMat { - assert!(self.nrows == right.nrows && self.ncols == right.ncols, - "Unable to add matrices with different dimensions."); - - let mut res = self; - - for (mij, right_ij) in res.mij.iter_mut().zip(right.mij.iter()) { - *mij = *mij + *right_ij; - } - - res - } -} - -impl> Sub for DMat { - type Output = DMat; - - #[inline] - fn sub(self, right: N) -> DMat { - let mut res = self; - - for mij in res.mij.iter_mut() { - *mij = *mij - right; - } - - res - } -} - -impl> Sub> for DMat { - type Output = DMat; - - #[inline] - fn sub(self, right: DMat) -> DMat { - self - (&right) - } -} - -impl<'a, N: Copy + Sub> Sub> for &'a DMat { - type Output = DMat; - - #[inline] - fn sub(self, right: DMat) -> DMat { - right - self - } -} - -impl<'a, N: Copy + Sub> Sub<&'a DMat> for DMat { - type Output = DMat; - - #[inline] - fn sub(self, right: &'a DMat) -> DMat { - assert!(self.nrows == right.nrows && self.ncols == right.ncols, - "Unable to subtract matrices with different dimensions."); - - let mut res = self; - - for (mij, right_ij) in res.mij.iter_mut().zip(right.mij.iter()) { - *mij = *mij - *right_ij; - } - - res - } -} - -#[cfg(feature="arbitrary")] -impl Arbitrary for DMat { - fn arbitrary(g: &mut G) -> DMat { - DMat::from_fn( - Arbitrary::arbitrary(g), Arbitrary::arbitrary(g), - |_, _| Arbitrary::arbitrary(g) - ) - } -} +small_dmat_impl!(DMat6, 6, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35); +small_dmat_from_impl!(DMat6, 6, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), + ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero()); diff --git a/src/structs/dmat_macros.rs b/src/structs/dmat_macros.rs new file mode 100644 index 00000000..efef4bf2 --- /dev/null +++ b/src/structs/dmat_macros.rs @@ -0,0 +1,896 @@ +#![macro_use] + +macro_rules! dmat_impl( + ($dmat: ident) => ( + impl $dmat { + /// Builds a matrix filled with zeros. + /// + /// # Arguments + /// * `dim` - The dimension of the matrix. A `dim`-dimensional matrix contains `dim * dim` + /// components. + #[inline] + pub fn new_zeros(nrows: usize, ncols: usize) -> $dmat { + $dmat::from_elem(nrows, ncols, ::zero()) + } + + /// Tests if all components of the matrix are zeroes. + #[inline] + pub fn is_zero(&self) -> bool { + self.mij.iter().all(|e| e.is_zero()) + } + + #[inline] + pub fn reset(&mut self) { + for mij in self.mij.iter_mut() { + *mij = ::zero(); + } + } + } + + impl $dmat { + /// Builds a matrix filled with random values. + #[inline] + pub fn new_random(nrows: usize, ncols: usize) -> $dmat { + $dmat::from_fn(nrows, ncols, |_, _| rand::random()) + } + } + + impl $dmat { + /// Builds a matrix filled with a given constant. + #[inline] + pub fn new_ones(nrows: usize, ncols: usize) -> $dmat { + $dmat::from_elem(nrows, ncols, ::one()) + } + } + + impl $dmat { + /// The number of row on the matrix. + #[inline] + pub fn nrows(&self) -> usize { + self.nrows + } + + /// The number of columns on the matrix. + #[inline] + pub fn ncols(&self) -> usize { + self.ncols + } + + /// Gets a reference to this matrix data. + /// The returned vector contains the matrix data in column-major order. + #[inline] + pub fn as_vec(&self) -> &[N] { + &self.mij + } + + /// Gets a mutable reference to this matrix data. + /// The returned vector contains the matrix data in column-major order. + #[inline] + pub fn as_mut_vec(&mut self) -> &mut [N] { + &mut self.mij[..] + } + } + + // FIXME: add a function to modify the dimension (to avoid useless allocations)? + + impl Eye for $dmat { + /// Builds an identity matrix. + /// + /// # Arguments + /// * `dim` - The dimension of the matrix. A `dim`-dimensional matrix contains `dim * dim` + /// components. + #[inline] + fn new_identity(dim: usize) -> $dmat { + let mut res = $dmat::new_zeros(dim, dim); + + for i in 0..dim { + let _1: N = ::one(); + res[(i, i)] = _1; + } + + res + } + } + + impl $dmat { + #[inline(always)] + fn offset(&self, i: usize, j: usize) -> usize { + i + j * self.nrows + } + + } + + impl Indexable<(usize, usize), N> for $dmat { + /// Just like `set` without bounds checking. + #[inline] + unsafe fn unsafe_set(&mut self, rowcol: (usize, usize), val: N) { + let (row, col) = rowcol; + let offset = self.offset(row, col); + *self.mij[..].get_unchecked_mut(offset) = val + } + + /// Just like `at` without bounds checking. + #[inline] + unsafe fn unsafe_at(&self, rowcol: (usize, usize)) -> N { + let (row, col) = rowcol; + + *self.mij.get_unchecked(self.offset(row, col)) + } + + #[inline] + fn swap(&mut self, rowcol1: (usize, usize), rowcol2: (usize, usize)) { + let (row1, col1) = rowcol1; + let (row2, col2) = rowcol2; + let offset1 = self.offset(row1, col1); + let offset2 = self.offset(row2, col2); + let count = self.mij.len(); + assert!(offset1 < count); + assert!(offset2 < count); + self.mij[..].swap(offset1, offset2); + } + + } + + impl Shape<(usize, usize)> for $dmat { + #[inline] + fn shape(&self) -> (usize, usize) { + (self.nrows, self.ncols) + } + } + + impl Index<(usize, usize)> for $dmat { + type Output = N; + + fn index(&self, (i, j): (usize, usize)) -> &N { + assert!(i < self.nrows); + assert!(j < self.ncols); + + unsafe { + self.mij.get_unchecked(self.offset(i, j)) + } + } + } + + impl IndexMut<(usize, usize)> for $dmat { + fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut N { + assert!(i < self.nrows); + assert!(j < self.ncols); + + let offset = self.offset(i, j); + + unsafe { + self.mij[..].get_unchecked_mut(offset) + } + } + } + + impl + Add + Zero> Mul<$dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn mul(self, right: $dmat) -> $dmat { + (&self) * (&right) + } + } + + impl<'a, N: Copy + Mul + Add + Zero> Mul<&'a $dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn mul(self, right: &'a $dmat) -> $dmat { + (&self) * right + } + } + + impl<'a, N: Copy + Mul + Add + Zero> Mul<$dmat> for &'a $dmat { + type Output = $dmat; + + #[inline] + fn mul(self, right: $dmat) -> $dmat { + self * (&right) + } + } + + impl<'a, 'b, N: Copy + Mul + Add + Zero> Mul<&'b $dmat> for &'a $dmat { + type Output = $dmat; + + #[inline] + fn mul(self, right: &$dmat) -> $dmat { + assert!(self.ncols == right.nrows); + + let mut res = unsafe { $dmat::new_uninitialized(self.nrows, right.ncols) }; + + for i in 0..self.nrows { + for j in 0..right.ncols { + let mut acc: N = ::zero(); + + unsafe { + for k in 0..self.ncols { + acc = acc + + self.unsafe_at((i, k)) * right.unsafe_at((k, j)); + } + + res.unsafe_set((i, j), acc); + } + } + } + + res + } + } + + impl + Mul + Zero> Mul> for $dmat { + type Output = DVec; + + fn mul(self, right: DVec) -> DVec { + assert!(self.ncols == right.at.len()); + + let mut res : DVec = unsafe { DVec::new_uninitialized(self.nrows) }; + + for i in 0..self.nrows { + let mut acc: N = ::zero(); + + for j in 0..self.ncols { + unsafe { + acc = acc + self.unsafe_at((i, j)) * right.unsafe_at(j); + } + } + + res.at[i] = acc; + } + + res + } + } + + + impl + Mul + Zero> Mul<$dmat> for DVec { + type Output = DVec; + + fn mul(self, right: $dmat) -> DVec { + assert!(right.nrows == self.at.len()); + + let mut res : DVec = unsafe { DVec::new_uninitialized(right.ncols) }; + + for i in 0..right.ncols { + let mut acc: N = ::zero(); + + for j in 0..right.nrows { + unsafe { + acc = acc + self.unsafe_at(j) * right.unsafe_at((j, i)); + } + } + + res.at[i] = acc; + } + + res + } + } + + impl Inv for $dmat { + #[inline] + fn inv(&self) -> Option<$dmat> { + let mut res: $dmat = self.clone(); + if res.inv_mut() { + Some(res) + } + else { + None + } + } + + fn inv_mut(&mut self) -> bool { + assert!(self.nrows == self.ncols); + + let dim = self.nrows; + let mut res: $dmat = Eye::new_identity(dim); + + // inversion using Gauss-Jordan elimination + for k in 0..dim { + // search a non-zero value on the k-th column + // FIXME: would it be worth it to spend some more time searching for the + // max instead? + + let mut n0 = k; // index of a non-zero entry + + while n0 != dim { + if unsafe { self.unsafe_at((n0, k)) } != ::zero() { + break; + } + + n0 = n0 + 1; + } + + if n0 == dim { + return false + } + + // swap pivot line + if n0 != k { + for j in 0..dim { + let off_n0_j = self.offset(n0, j); + let off_k_j = self.offset(k, j); + + self.mij[..].swap(off_n0_j, off_k_j); + res.mij[..].swap(off_n0_j, off_k_j); + } + } + + unsafe { + let pivot = self.unsafe_at((k, k)); + + for j in k..dim { + let selfval = self.unsafe_at((k, j)) / pivot; + self.unsafe_set((k, j), selfval); + } + + for j in 0..dim { + let resval = res.unsafe_at((k, j)) / pivot; + res.unsafe_set((k, j), resval); + } + + for l in 0..dim { + if l != k { + let normalizer = self.unsafe_at((l, k)); + + for j in k..dim { + let selfval = self.unsafe_at((l, j)) - self.unsafe_at((k, j)) * normalizer; + self.unsafe_set((l, j), selfval); + } + + for j in 0..dim { + let resval = res.unsafe_at((l, j)) - res.unsafe_at((k, j)) * normalizer; + res.unsafe_set((l, j), resval); + } + } + } + } + } + + *self = res; + + true + } + } + + impl Transpose for $dmat { + #[inline] + fn transpose(&self) -> $dmat { + if self.nrows == self.ncols { + let mut res = self.clone(); + + res.transpose_mut(); + + res + } + else { + let mut res = unsafe { $dmat::new_uninitialized(self.ncols, self.nrows) }; + + for i in 0..self.nrows { + for j in 0..self.ncols { + unsafe { + res.unsafe_set((j, i), self.unsafe_at((i, j))) + } + } + } + + res + } + } + + #[inline] + fn transpose_mut(&mut self) { + if self.nrows == self.ncols { + let n = self.nrows; + for i in 0..n - 1 { + for j in i + 1..n { + let off_i_j = self.offset(i, j); + let off_j_i = self.offset(j, i); + + self.mij[..].swap(off_i_j, off_j_i); + } + } + } + else { + // FIXME: implement a better algorithm which does that in-place. + *self = Transpose::transpose(self); + } + } + } + + impl + Clone> Mean> for $dmat { + fn mean(&self) -> DVec { + 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 { + unsafe { + let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer; + res.unsafe_set(j, acc); + } + } + } + + res + } + } + + impl + Clone> Cov<$dmat> for $dmat { + // FIXME: this could be heavily optimized, removing all temporaries by merging loops. + fn cov(&self) -> $dmat { + assert!(self.nrows > 1); + + let mut centered = unsafe { $dmat::new_uninitialized(self.nrows, self.ncols) }; + let mean = self.mean(); + + // FIXME: use the rows iterator when available + 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)); + } + } + } + + // 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 + } + } + + impl Col> for $dmat { + #[inline] + fn ncols(&self) -> usize { + self.ncols + } + + #[inline] + fn set_col(&mut self, col_id: usize, v: DVec) { + assert!(col_id < self.ncols); + assert!(self.nrows == v.len()); + + for (i, e) in v[..].iter().enumerate() { + unsafe { + self.unsafe_set((i, col_id), *e); + } + } + } + + #[inline] + fn col(&self, col_id: usize) -> DVec { + let mut res: DVec = unsafe { + DVec::new_uninitialized(self.nrows) + }; + + for (row_id, e) in res[..].iter_mut().enumerate() { + *e = unsafe { self.unsafe_at((row_id, col_id)) }; + } + + res + } + } + + impl ColSlice> for $dmat { + fn col_slice(&self, col_id :usize, row_start: usize, row_end: usize) -> DVec { + 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. + 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 + } + } + + impl Row> for $dmat { + #[inline] + fn nrows(&self) -> usize { + self.nrows + } + + #[inline] + fn set_row(&mut self, row_id: usize, v: DVec) { + assert!(row_id < self.nrows); + assert!(self.ncols == v.len()); + + for (i, e) in v[..].iter().enumerate() { + unsafe { + self.unsafe_set((row_id, i), *e); + } + } + } + + #[inline] + fn row(&self, row_id: usize) -> DVec { + let mut res: DVec = unsafe { + DVec::new_uninitialized(self.ncols) + }; + + for (col_id, e) in res[..].iter_mut().enumerate() { + *e = unsafe { self.unsafe_at((row_id, col_id)) }; + } + + res + } + } + + impl RowSlice> for $dmat { + fn row_slice(&self, row_id :usize, col_start: usize, col_end: usize) -> DVec { + 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) + }; + let mut slice_idx = 0; + for col_id in col_start..col_end { + unsafe { + slice.unsafe_set(slice_idx, self.unsafe_at((row_id, col_id))); + } + slice_idx += 1; + } + + slice + } + } + + impl Diag> for $dmat { + #[inline] + fn from_diag(diag: &DVec) -> $dmat { + let mut res = $dmat::new_zeros(diag.len(), diag.len()); + + res.set_diag(diag); + + res + } + + #[inline] + fn diag(&self) -> DVec { + let smallest_dim = cmp::min(self.nrows, self.ncols); + + let mut diag: DVec = DVec::new_zeros(smallest_dim); + + for i in 0..smallest_dim { + unsafe { diag.unsafe_set(i, self.unsafe_at((i, i))) } + } + + diag + } + } + + impl DiagMut> for $dmat { + #[inline] + fn set_diag(&mut self, diag: &DVec) { + let smallest_dim = cmp::min(self.nrows, self.ncols); + + assert!(diag.len() == smallest_dim); + + for i in 0..smallest_dim { + unsafe { self.unsafe_set((i, i), diag.unsafe_at(i)) } + } + } + } + + impl> ApproxEq for $dmat { + #[inline] + fn approx_epsilon(_: Option<$dmat>) -> N { + ApproxEq::approx_epsilon(None::) + } + + #[inline] + fn approx_ulps(_: Option<$dmat>) -> u32 { + ApproxEq::approx_ulps(None::) + } + + #[inline] + fn approx_eq_eps(&self, other: &$dmat, epsilon: &N) -> bool { + let mut zip = self.mij.iter().zip(other.mij.iter()); + zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) + } + + #[inline] + fn approx_eq_ulps(&self, other: &$dmat, ulps: u32) -> bool { + let mut zip = self.mij.iter().zip(other.mij.iter()); + zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) + } + } + + impl Debug for $dmat { + fn fmt(&self, form:&mut Formatter) -> Result { + for i in 0..self.nrows() { + for j in 0..self.ncols() { + let _ = write!(form, "{:?} ", self[(i, j)]); + } + let _ = write!(form, "\n"); + } + write!(form, "\n") + } + } + + impl> Mul for $dmat { + type Output = $dmat; + + #[inline] + fn mul(self, right: N) -> $dmat { + let mut res = self; + + for mij in res.mij.iter_mut() { + *mij = *mij * right; + } + + res + } + } + + impl> Div for $dmat { + type Output = $dmat; + + #[inline] + fn div(self, right: N) -> $dmat { + let mut res = self; + + for mij in res.mij.iter_mut() { + *mij = *mij / right; + } + + res + } + } + + impl> Add for $dmat { + type Output = $dmat; + + #[inline] + fn add(self, right: N) -> $dmat { + let mut res = self; + + for mij in res.mij.iter_mut() { + *mij = *mij + right; + } + + res + } + } + + impl> Add<$dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn add(self, right: $dmat) -> $dmat { + self + (&right) + } + } + + impl<'a, N: Copy + Add> Add<$dmat> for &'a $dmat { + type Output = $dmat; + + #[inline] + fn add(self, right: $dmat) -> $dmat { + right + self + } + } + + impl<'a, N: Copy + Add> Add<&'a $dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn add(self, right: &'a $dmat) -> $dmat { + assert!(self.nrows == right.nrows && self.ncols == right.ncols, + "Unable to add matrices with different dimensions."); + + let mut res = self; + + for (mij, right_ij) in res.mij.iter_mut().zip(right.mij.iter()) { + *mij = *mij + *right_ij; + } + + res + } + } + + impl> Sub for $dmat { + type Output = $dmat; + + #[inline] + fn sub(self, right: N) -> $dmat { + let mut res = self; + + for mij in res.mij.iter_mut() { + *mij = *mij - right; + } + + res + } + } + + impl> Sub<$dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn sub(self, right: $dmat) -> $dmat { + self - (&right) + } + } + + impl<'a, N: Copy + Sub> Sub<$dmat> for &'a $dmat { + type Output = $dmat; + + #[inline] + fn sub(self, right: $dmat) -> $dmat { + right - self + } + } + + impl<'a, N: Copy + Sub> Sub<&'a $dmat> for $dmat { + type Output = $dmat; + + #[inline] + fn sub(self, right: &'a $dmat) -> $dmat { + assert!(self.nrows == right.nrows && self.ncols == right.ncols, + "Unable to subtract matrices with different dimensions."); + + let mut res = self; + + for (mij, right_ij) in res.mij.iter_mut().zip(right.mij.iter()) { + *mij = *mij - *right_ij; + } + + res + } + } + + #[cfg(feature="arbitrary")] + impl Arbitrary for $dmat { + fn arbitrary(g: &mut G) -> $dmat { + $dmat::from_fn( + Arbitrary::arbitrary(g), Arbitrary::arbitrary(g), + |_, _| Arbitrary::arbitrary(g) + ) + } + } + ) +); + +macro_rules! small_dmat_impl ( + ($dmat: ident, $dim: expr, $($idx: expr),*) => ( + impl PartialEq for $dmat { + #[inline] + fn eq(&self, other: &$dmat) -> bool { + if self.nrows() != other.nrows() || self.ncols() != other.ncols() { + return false; // FIXME: fail instead? + } + + for (a, b) in self.mij[0 .. self.nrows() * self.ncols()].iter().zip( + other.mij[0 .. self.nrows() * self.ncols()].iter()) { + if *a != *b { + return false; + } + } + + true + } + } + + impl Clone for $dmat { + fn clone(&self) -> $dmat { + let mij: [N; $dim * $dim] = [ $( self.mij[$idx].clone(), )* ]; + + $dmat { + nrows: self.nrows, + ncols: self.ncols, + mij: mij, + } + } + } + + dmat_impl!($dmat); + ) +); + +macro_rules! small_dmat_from_impl( + ($dmat: ident, $dim: expr, $($zeros: expr),*) => ( + impl $dmat { + /// Builds a matrix filled with a given constant. + #[inline] + pub fn from_elem(nrows: usize, ncols: usize, elem: N) -> $dmat { + assert!(nrows <= $dim); + assert!(ncols <= $dim); + + let mut mij: [N; $dim * $dim] = [ $( $zeros, )* ]; + + for n in &mut mij[.. nrows * ncols] { + *n = elem; + } + + $dmat { + nrows: nrows, + ncols: ncols, + mij: mij + } + } + + /// Builds a matrix filled with the components provided by a vector. + /// The vector contains the matrix data in row-major order. + /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `$dmat` stores its data + /// in column-major order. + /// + /// The vector must have at least `nrows * ncols` elements. + #[inline] + pub fn from_row_vec(nrows: usize, ncols: usize, vec: &[N]) -> $dmat { + let mut res = $dmat::from_col_vec(ncols, nrows, vec); + + // we transpose because the buffer is row_major + res.transpose_mut(); + + res + } + + /// Builds a matrix filled with the components provided by a vector. + /// The vector contains the matrix data in column-major order. + /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `$dmat` stores its data + /// in column-major order. + /// + /// The vector must have at least `nrows * ncols` elements. + #[inline] + pub fn from_col_vec(nrows: usize, ncols: usize, vec: &[N]) -> $dmat { + assert!(nrows * ncols == vec.len()); + + let mut mij: [N; $dim * $dim] = [ $( $zeros, )* ]; + + for (n, val) in mij[.. nrows * ncols].iter_mut().zip(vec.iter()) { + *n = *val; + } + + $dmat { + nrows: nrows, + ncols: ncols, + mij: mij + } + } + + /// Builds a matrix using an initialization function. + #[inline(always)] + pub fn from_fn N>(nrows: usize, ncols: usize, mut f: F) -> $dmat { + assert!(nrows <= $dim); + assert!(ncols <= $dim); + + let mut mij: [N; $dim * $dim] = [ $( $zeros, )* ]; + + for i in 0 .. nrows { + for j in 0 .. ncols { + mij[i + j * nrows] = f(i, j) + } + } + + $dmat { + nrows: nrows, + ncols: ncols, + mij: mij + } + } + } + + impl $dmat { + #[inline] + pub unsafe fn new_uninitialized(nrows: usize, ncols: usize) -> $dmat { + assert!(nrows <= $dim); + assert!(ncols <= $dim); + + $dmat { + nrows: nrows, + ncols: ncols, + mij: mem::uninitialized() + } + } + } + ) +); diff --git a/src/structs/mod.rs b/src/structs/mod.rs index c9409a8f..a8ee812f 100644 --- a/src/structs/mod.rs +++ b/src/structs/mod.rs @@ -1,6 +1,6 @@ //! Data structures and implementations. -pub use self::dmat::DMat; +pub use self::dmat::{DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6}; pub use self::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6}; pub use self::vec::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; pub use self::pnt::{Pnt0, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6}; @@ -11,6 +11,7 @@ pub use self::persp::{Persp3, PerspMat3}; pub use self::ortho::{Ortho3, OrthoMat3}; pub use self::quat::{Quat, UnitQuat}; +mod dmat_macros; mod dmat; mod dvec_macros; mod dvec; From 1338e0c35867b9604718b73f3c6f591d5cca2568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 14:50:08 +0100 Subject: [PATCH 5/8] DMat: implement `from_row_iter` and `from_col_iter`. Those create a DMat by moving its argument into an interator and collecting it. Fix #167. --- src/structs/dmat.rs | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index 090c7789..efc359df 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -55,15 +55,10 @@ impl DMat { /// Note that `from_col_vec` is much faster than `from_row_vec` since a `DMat` stores its data /// in column-major order. /// - /// The vector must have at least `nrows * ncols` elements. + /// The vector must have exactly `nrows * ncols` elements. #[inline] pub fn from_row_vec(nrows: usize, ncols: usize, vec: &[N]) -> DMat { - let mut res = DMat::from_col_vec(ncols, nrows, vec); - - // we transpose because the buffer is row_major - res.transpose_mut(); - - res + DMat::from_row_iter(nrows, ncols, vec.to_vec()) } /// Builds a matrix filled with the components provided by a vector. @@ -71,15 +66,45 @@ impl DMat { /// Note that `from_col_vec` is much faster than `from_row_vec` since a `DMat` stores its data /// in column-major order. /// - /// The vector must have at least `nrows * ncols` elements. + /// The vector must have exactly `nrows * ncols` elements. #[inline] pub fn from_col_vec(nrows: usize, ncols: usize, vec: &[N]) -> DMat { - assert!(nrows * ncols == vec.len()); + DMat::from_col_iter(nrows, ncols, vec.to_vec()) + } + + /// Builds a matrix filled with the components provided by a source that may be moved into an iterator. + /// The source contains the matrix data in row-major order. + /// Note that `from_col_iter` is much faster than `from_row_iter` since a `DMat` stores its data + /// in column-major order. + /// + /// The source must have exactly `nrows * ncols` elements. + #[inline] + pub fn from_row_iter>(nrows: usize, ncols: usize, param: I) -> DMat { + let mut res = DMat::from_col_iter(ncols, nrows, param); + + // we transpose because the buffer is row_major + res.transpose_mut(); + + res + } + + + /// Builds a matrix filled with the components provided by a source that may be moved into an iterator. + /// The source contains the matrix data in column-major order. + /// Note that `from_col_iter` is much faster than `from_row_iter` since a `DMat` stores its data + /// in column-major order. + /// + /// The source must have exactly `nrows * ncols` elements. + #[inline] + pub fn from_col_iter>(nrows: usize, ncols: usize, param: I) -> DMat { + let mij: Vec = param.into_iter().collect(); + + assert!(nrows * ncols == mij.len(), "The ammount of data provided does not matches the matrix size."); DMat { nrows: nrows, ncols: ncols, - mij: vec.to_vec() + mij: mij } } } From 58de7f461ebe68c1af7d55c4916c788df23cf3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 15:23:18 +0100 Subject: [PATCH 6/8] DMat{1..6}: make the `Col` and `Row` implementation return a DVec{1..6} instead of a plain DVec. Also adds the `DVec{1..6}::new_uninitialized(dim)` function. --- src/structs/dmat.rs | 46 ++++++++++---------- src/structs/dmat_macros.rs | 88 ++++++++++++++++++++------------------ src/structs/dvec.rs | 1 + src/structs/dvec_macros.rs | 14 ++++++ 4 files changed, 84 insertions(+), 65 deletions(-) diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index efc359df..345c0742 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -9,7 +9,7 @@ use std::ops::{Add, Sub, Mul, Div, Index, IndexMut}; use std::fmt::{Debug, Formatter, Result}; use rand::{self, Rand}; use num::{Zero, One}; -use structs::dvec::DVec; +use structs::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6}; use traits::operations::{ApproxEq, Inv, Transpose, Mean, Cov}; use traits::structure::{Cast, Col, ColSlice, Row, RowSlice, Diag, DiagMut, Eye, Indexable, Shape, BaseNum}; #[cfg(feature="arbitrary")] @@ -128,7 +128,7 @@ impl DMat { } } -dmat_impl!(DMat); +dmat_impl!(DMat, DVec); pub struct DMat1 { @@ -137,7 +137,7 @@ pub struct DMat1 { mij: [N; 1 * 1], } -small_dmat_impl!(DMat1, 1, 0); +small_dmat_impl!(DMat1, DVec1, 1, 0); small_dmat_from_impl!(DMat1, 1, ::zero()); @@ -147,8 +147,8 @@ pub struct DMat2 { mij: [N; 2 * 2], } -small_dmat_impl!(DMat2, 2, 0, 1, - 2, 3); +small_dmat_impl!(DMat2, DVec2, 2, 0, 1, + 2, 3); small_dmat_from_impl!(DMat2, 2, ::zero(), ::zero(), ::zero(), ::zero()); @@ -159,9 +159,9 @@ pub struct DMat3 { mij: [N; 3 * 3], } -small_dmat_impl!(DMat3, 3, 0, 1, 2, - 3, 4, 5, - 6, 7, 8); +small_dmat_impl!(DMat3, DVec3, 3, 0, 1, 2, + 3, 4, 5, + 6, 7, 8); small_dmat_from_impl!(DMat3, 3, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero()); @@ -173,10 +173,10 @@ pub struct DMat4 { mij: [N; 4 * 4], } -small_dmat_impl!(DMat4, 4, 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15); +small_dmat_impl!(DMat4, DVec4, 4, 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15); small_dmat_from_impl!(DMat4, 4, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), @@ -189,11 +189,11 @@ pub struct DMat5 { mij: [N; 5 * 5], } -small_dmat_impl!(DMat5, 5, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24); +small_dmat_impl!(DMat5, DVec5, 5, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24); small_dmat_from_impl!(DMat5, 5, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), @@ -207,12 +207,12 @@ pub struct DMat6 { mij: [N; 6 * 6], } -small_dmat_impl!(DMat6, 6, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35); +small_dmat_impl!(DMat6, DVec6, 6, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35); small_dmat_from_impl!(DMat6, 6, ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), ::zero(), diff --git a/src/structs/dmat_macros.rs b/src/structs/dmat_macros.rs index efef4bf2..4492bff9 100644 --- a/src/structs/dmat_macros.rs +++ b/src/structs/dmat_macros.rs @@ -1,7 +1,7 @@ #![macro_use] macro_rules! dmat_impl( - ($dmat: ident) => ( + ($dmat: ident, $dvec: ident) => ( impl $dmat { /// Builds a matrix filled with zeros. /// @@ -219,13 +219,13 @@ macro_rules! dmat_impl( } } - impl + Mul + Zero> Mul> for $dmat { - type Output = DVec; + impl + Mul + Zero> Mul<$dvec> for $dmat { + type Output = $dvec; - fn mul(self, right: DVec) -> DVec { - assert!(self.ncols == right.at.len()); + fn mul(self, right: $dvec) -> $dvec { + assert!(self.ncols == right.len()); - let mut res : DVec = unsafe { DVec::new_uninitialized(self.nrows) }; + let mut res : $dvec = unsafe { $dvec::new_uninitialized(self.nrows) }; for i in 0..self.nrows { let mut acc: N = ::zero(); @@ -236,7 +236,9 @@ macro_rules! dmat_impl( } } - res.at[i] = acc; + unsafe { + res.unsafe_set(i, acc); + } } res @@ -244,13 +246,13 @@ macro_rules! dmat_impl( } - impl + Mul + Zero> Mul<$dmat> for DVec { - type Output = DVec; + impl + Mul + Zero> Mul<$dmat> for $dvec { + type Output = $dvec; - fn mul(self, right: $dmat) -> DVec { - assert!(right.nrows == self.at.len()); + fn mul(self, right: $dmat) -> $dvec { + assert!(right.nrows == self.len()); - let mut res : DVec = unsafe { DVec::new_uninitialized(right.ncols) }; + let mut res : $dvec = unsafe { $dvec::new_uninitialized(right.ncols) }; for i in 0..right.ncols { let mut acc: N = ::zero(); @@ -261,7 +263,9 @@ macro_rules! dmat_impl( } } - res.at[i] = acc; + unsafe { + res.unsafe_set(i, acc); + } } res @@ -399,10 +403,10 @@ macro_rules! dmat_impl( } } - impl + Clone> Mean> for $dmat { - fn mean(&self) -> DVec { - let mut res: DVec = DVec::new_zeros(self.ncols); - let normalizer: N = Cast::from(1.0f64 / self.nrows as f64); + impl + Clone> Mean<$dvec> for $dmat { + fn mean(&self) -> $dvec { + 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 { @@ -443,14 +447,14 @@ macro_rules! dmat_impl( } } - impl Col> for $dmat { + impl Col<$dvec> for $dmat { #[inline] fn ncols(&self) -> usize { self.ncols } #[inline] - fn set_col(&mut self, col_id: usize, v: DVec) { + fn set_col(&mut self, col_id: usize, v: $dvec) { assert!(col_id < self.ncols); assert!(self.nrows == v.len()); @@ -462,9 +466,9 @@ macro_rules! dmat_impl( } #[inline] - fn col(&self, col_id: usize) -> DVec { - let mut res: DVec = unsafe { - DVec::new_uninitialized(self.nrows) + fn col(&self, col_id: usize) -> $dvec { + let mut res: $dvec = unsafe { + $dvec::new_uninitialized(self.nrows) }; for (row_id, e) in res[..].iter_mut().enumerate() { @@ -475,8 +479,8 @@ macro_rules! dmat_impl( } } - impl ColSlice> for $dmat { - fn col_slice(&self, col_id :usize, row_start: usize, row_end: usize) -> DVec { + impl ColSlice<$dvec> for $dmat { + fn col_slice(&self, col_id :usize, row_start: usize, row_end: usize) -> $dvec { assert!(col_id < self.ncols); assert!(row_start < row_end); assert!(row_end <= self.nrows); @@ -484,20 +488,20 @@ macro_rules! dmat_impl( // 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]); + let slice = $dvec::from_slice(row_end - row_start, &self.mij[start .. stop]); slice } } - impl Row> for $dmat { + impl Row<$dvec> for $dmat { #[inline] fn nrows(&self) -> usize { self.nrows } #[inline] - fn set_row(&mut self, row_id: usize, v: DVec) { + fn set_row(&mut self, row_id: usize, v: $dvec) { assert!(row_id < self.nrows); assert!(self.ncols == v.len()); @@ -509,9 +513,9 @@ macro_rules! dmat_impl( } #[inline] - fn row(&self, row_id: usize) -> DVec { - let mut res: DVec = unsafe { - DVec::new_uninitialized(self.ncols) + fn row(&self, row_id: usize) -> $dvec { + let mut res: $dvec = unsafe { + $dvec::new_uninitialized(self.ncols) }; for (col_id, e) in res[..].iter_mut().enumerate() { @@ -522,14 +526,14 @@ macro_rules! dmat_impl( } } - impl RowSlice> for $dmat { - fn row_slice(&self, row_id :usize, col_start: usize, col_end: usize) -> DVec { + impl RowSlice<$dvec> for $dmat { + fn row_slice(&self, row_id :usize, col_start: usize, col_end: usize) -> $dvec { 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) + let mut slice : $dvec = unsafe { + $dvec::new_uninitialized(col_end - col_start) }; let mut slice_idx = 0; for col_id in col_start..col_end { @@ -543,9 +547,9 @@ macro_rules! dmat_impl( } } - impl Diag> for $dmat { + impl Diag<$dvec> for $dmat { #[inline] - fn from_diag(diag: &DVec) -> $dmat { + fn from_diag(diag: &$dvec) -> $dmat { let mut res = $dmat::new_zeros(diag.len(), diag.len()); res.set_diag(diag); @@ -554,10 +558,10 @@ macro_rules! dmat_impl( } #[inline] - fn diag(&self) -> DVec { + fn diag(&self) -> $dvec { let smallest_dim = cmp::min(self.nrows, self.ncols); - let mut diag: DVec = DVec::new_zeros(smallest_dim); + let mut diag: $dvec = $dvec::new_zeros(smallest_dim); for i in 0..smallest_dim { unsafe { diag.unsafe_set(i, self.unsafe_at((i, i))) } @@ -567,9 +571,9 @@ macro_rules! dmat_impl( } } - impl DiagMut> for $dmat { + impl DiagMut<$dvec> for $dmat { #[inline] - fn set_diag(&mut self, diag: &DVec) { + fn set_diag(&mut self, diag: &$dvec) { let smallest_dim = cmp::min(self.nrows, self.ncols); assert!(diag.len() == smallest_dim); @@ -761,7 +765,7 @@ macro_rules! dmat_impl( ); macro_rules! small_dmat_impl ( - ($dmat: ident, $dim: expr, $($idx: expr),*) => ( + ($dmat: ident, $dvec: ident, $dim: expr, $($idx: expr),*) => ( impl PartialEq for $dmat { #[inline] fn eq(&self, other: &$dmat) -> bool { @@ -792,7 +796,7 @@ macro_rules! small_dmat_impl ( } } - dmat_impl!($dmat); + dmat_impl!($dmat, $dvec); ) ); diff --git a/src/structs/dvec.rs b/src/structs/dvec.rs index 63e32aff..c9eb91ce 100644 --- a/src/structs/dvec.rs +++ b/src/structs/dvec.rs @@ -6,6 +6,7 @@ use std::slice::{Iter, IterMut}; use std::iter::{FromIterator, IntoIterator}; use std::iter::repeat; use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut}; +use std::mem; use rand::{self, Rand}; use num::{Zero, One}; use traits::operations::{ApproxEq, Axpy, Mean}; diff --git a/src/structs/dvec_macros.rs b/src/structs/dvec_macros.rs index b637827d..35d6c10f 100644 --- a/src/structs/dvec_macros.rs +++ b/src/structs/dvec_macros.rs @@ -387,10 +387,24 @@ macro_rules! dvec_impl( macro_rules! small_dvec_impl ( ($dvec: ident, $dim: expr, $($idx: expr),*) => ( impl $dvec { + /// The number of elements of this vector. #[inline] pub fn len(&self) -> usize { self.dim } + + /// Creates an uninitialized vec of dimension `dim`. + #[inline] + pub unsafe fn new_uninitialized(dim: usize) -> $dvec { + assert!(dim <= $dim, "The chosen dimension is too high for that type of \ + stack-allocated dynamic vector. Consider using the \ + heap-allocated vector: DVec."); + + $dvec { + at: mem::uninitialized(), + dim: dim + } + } } impl PartialEq for $dvec { From 5a058f0c76b4af5c8e372ff5774372de97053eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 15:24:36 +0100 Subject: [PATCH 7/8] Releave v0.5.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ba68bb95..0af85e33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.4.0" +version = "0.5.0" authors = [ "Sébastien Crozet " ] # FIXME: add the contributors. description = "Linear algebra library for computer physics, computer graphics and general low-dimensional linear algebra for Rust." From 91c4b58bbbbc6ee66997c81b4fa3261ed28e747e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 10 Jan 2016 15:39:54 +0100 Subject: [PATCH 8/8] Fix missing trait bounds when the "arbitrary" feature is enabled. --- src/structs/dmat_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structs/dmat_macros.rs b/src/structs/dmat_macros.rs index 4492bff9..23522b17 100644 --- a/src/structs/dmat_macros.rs +++ b/src/structs/dmat_macros.rs @@ -753,7 +753,7 @@ macro_rules! dmat_impl( } #[cfg(feature="arbitrary")] - impl Arbitrary for $dmat { + impl Arbitrary for $dmat { fn arbitrary(g: &mut G) -> $dmat { $dmat::from_fn( Arbitrary::arbitrary(g), Arbitrary::arbitrary(g),