#![macro_use] macro_rules! mat_impl( ($t: ident, $($compN: ident),+) => ( impl $t { #[inline] pub fn new($($compN: N ),+) -> $t { $t { $($compN: $compN ),+ } } } ) ); macro_rules! as_array_impl( ($t: ident, $dim: expr) => ( impl $t { /// View this matrix as a column-major array of arrays. #[inline] pub fn as_array(&self) -> &[[N; $dim]; $dim] { unsafe { mem::transmute(self) } } /// View this matrix as a column-major mutable array of arrays. #[inline] pub fn as_array_mut<'a>(&'a mut self) -> &'a mut [[N; $dim]; $dim] { unsafe { mem::transmute(self) } } // FIXME: because of https://github.com/rust-lang/rust/issues/16418 we cannot do the // array-to-mat conversion by-value: // // pub fn from_array(array: [N; $dim]) -> $t /// View a column-major array of array as a vector. #[inline] pub fn from_array_ref(array: &[[N; $dim]; $dim]) -> &$t { unsafe { mem::transmute(array) } } /// View a column-major array of array as a mutable vector. #[inline] pub fn from_array_mut(array: &mut [[N; $dim]; $dim]) -> &mut $t { unsafe { mem::transmute(array) } } } ) ); macro_rules! at_fast_impl( ($t: ident, $dim: expr) => ( impl $t { #[inline] pub unsafe fn at_fast(&self, (i, j): (usize, usize)) -> N { (*mem::transmute::<&$t, &[N; $dim * $dim]>(self) .get_unchecked(i + j * $dim)) } #[inline] pub unsafe fn set_fast(&mut self, (i, j): (usize, usize), val: N) { (*mem::transmute::<&mut $t, &mut [N; $dim * $dim]>(self) .get_unchecked_mut(i + j * $dim)) = val } } ) ); macro_rules! mat_cast_impl( ($t: ident, $($compN: ident),+) => ( impl> Cast<$t> for $t { #[inline] fn from(v: $t) -> $t { $t::new($(Cast::from(v.$compN)),+) } } ) ); macro_rules! add_impl( ($t: ident, $($compN: ident),+) => ( impl> Add<$t> for $t { type Output = $t; #[inline] fn add(self, right: $t) -> $t { $t::new($(self.$compN + right.$compN),+) } } ) ); macro_rules! sub_impl( ($t: ident, $($compN: ident),+) => ( impl> Sub<$t> for $t { type Output = $t; #[inline] fn sub(self, right: $t) -> $t { $t::new($(self.$compN - right.$compN),+) } } ) ); macro_rules! mat_mul_scalar_impl( ($t: ident, $($compN: ident),+) => ( impl> Mul for N { type Output = $t; #[inline] fn mul(self, right: N) -> $t { $t::new($(self.$compN * *right),+) } } ) ); macro_rules! mat_div_scalar_impl( ($t: ident, $($compN: ident),+) => ( impl> Div for $t { type Output = $t; #[inline] fn div(self, right: N) -> $t { $t::new($(self.$compN / *right),+) } } ) ); macro_rules! mat_add_scalar_impl( ($t: ident, $($compN: ident),+) => ( impl> Add for $t { type Output = $t; #[inline] fn add(self, right: N) -> $t { $t::new($(self.$compN + *right),+) } } ) ); macro_rules! eye_impl( ($t: ident, $dim: expr, $($comp_diagN: ident),+) => ( impl Eye for $t { fn new_identity(dim: usize) -> $t { assert!(dim == $dim); let mut eye: $t = ::zero(); $(eye.$comp_diagN = ::one();)+ eye } } ) ); macro_rules! mat_sub_scalar_impl( ($t: ident, $($compN: ident),+) => ( impl Sub for $t { type Output = $t; #[inline] fn sub(self, right: &N) -> $t { $t::new($(self.$compN - *right),+) } } ) ); macro_rules! absolute_impl( ($t: ident, $($compN: ident),+) => ( impl> Absolute<$t> for $t { #[inline] fn abs(m: &$t) -> $t { $t::new($(::abs(&m.$compN) ),+) } } ) ); macro_rules! iterable_impl( ($t: ident, $dim: expr) => ( impl Iterable for $t { #[inline] fn iter<'l>(&'l self) -> Iter<'l, N> { unsafe { mem::transmute::<&'l $t, &'l [N; $dim * $dim]>(self).iter() } } } ) ); macro_rules! iterable_mut_impl( ($t: ident, $dim: expr) => ( impl IterableMut for $t { #[inline] fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { unsafe { mem::transmute::<&'l mut $t, &'l mut [N; $dim * $dim]>(self).iter_mut() } } } ) ); macro_rules! one_impl( ($t: ident, $($valueN: expr),+ ) => ( impl One for $t { #[inline] fn one() -> $t { $t::new($($valueN() ),+) } } ) ); macro_rules! zero_impl( ($t: ident, $($compN: ident),+ ) => ( impl Zero for $t { #[inline] fn zero() -> $t { $t { $($compN: ::zero() ),+ } } #[inline] fn is_zero(&self) -> bool { $(::is_zero(&self.$compN) )&&+ } } ) ); macro_rules! dim_impl( ($t: ident, $dim: expr) => ( impl Dim for $t { #[inline] fn dim(_: Option<$t>) -> usize { $dim } } ) ); macro_rules! indexable_impl( ($t: ident, $dim: expr) => ( impl Shape<(usize, usize)> for $t { #[inline] fn shape(&self) -> (usize, usize) { ($dim, $dim) } } impl Indexable<(usize, usize), N> for $t { #[inline] fn at(&self, (i, j): (usize, usize)) -> N { unsafe { mem::transmute::<&$t, &[N; $dim * $dim]>(self)[i + j * $dim] } } #[inline] fn set(&mut self, (i, j): (usize, usize), val: N) { unsafe { mem::transmute::<&mut $t, &mut [N; $dim * $dim]>(self)[i + j * $dim] = val } } #[inline] fn swap(&mut self, (i1, j1): (usize, usize), (i2, j2): (usize, usize)) { unsafe { mem::transmute::<&mut $t, &mut [N; $dim * $dim]>(self) .swap(i1 + j1 * $dim, i2 + j2 * $dim) } } #[inline] unsafe fn unsafe_at(&self, (i, j): (usize, usize)) -> N { (*mem::transmute::<&$t, &[N; $dim * $dim]>(self).get_unchecked(i + j * $dim)) } #[inline] unsafe fn unsafe_set(&mut self, (i, j): (usize, usize), val: N) { (*mem::transmute::<&mut $t, &mut [N; $dim * $dim]>(self).get_unchecked_mut(i + j * $dim)) = val } } ) ); macro_rules! index_impl( ($t: ident, $dim: expr) => ( impl Index<(usize, usize)> for $t { type Output = N; fn index(&self, &(i, j): &(usize, usize)) -> &N { unsafe { &mem::transmute::<&$t, &mut [N; $dim * $dim]>(self)[i + j * $dim] } } } impl IndexMut<(usize, usize)> for $t { fn index_mut(&mut self, &(i, j): &(usize, usize)) -> &mut N { unsafe { &mut mem::transmute::<&mut $t, &mut [N; $dim * $dim]>(self)[i + j * $dim] } } } ) ); macro_rules! col_slice_impl( ($t: ident, $tv: ident, $slice: ident, $dim: expr) => ( impl ColSlice<$slice> for $t { fn col_slice(&self, cid: usize, rstart: usize, rend: usize) -> $slice { let col = self.col(cid); $slice::from_slice(rend - rstart, col.as_array().slice(rstart, rend)) } } ) ); macro_rules! row_impl( ($t: ident, $tv: ident, $dim: expr) => ( impl Row<$tv> for $t { #[inline] fn nrows(&self) -> usize { Dim::dim(None::<$t>) } #[inline] fn set_row(&mut self, row: usize, v: $tv) { for (i, e) in v.iter().enumerate() { self.set((row, i), *e); } } #[inline] fn row(&self, row: usize) -> $tv { let mut res: $tv = ::zero(); for (i, e) in res.iter_mut().enumerate() { *e = self.at((row, i)); } res } } ) ); macro_rules! row_slice_impl( ($t: ident, $tv: ident, $slice: ident, $dim: expr) => ( impl RowSlice<$slice> for $t { fn row_slice(&self, rid: usize, cstart: usize, cend: usize) -> $slice { let row = self.row(rid); $slice::from_slice(cend - cstart, row.as_array().slice(cstart, cend)) } } ) ); macro_rules! col_impl( ($t: ident, $tv: ident, $dim: expr) => ( impl Col<$tv> for $t { #[inline] fn ncols(&self) -> usize { Dim::dim(None::<$t>) } #[inline] fn set_col(&mut self, col: usize, v: $tv) { for (i, e) in v.iter().enumerate() { self.set((i, col), *e); } } #[inline] fn col(&self, col: usize) -> $tv { let mut res: $tv = ::zero(); for (i, e) in res.iter_mut().enumerate() { *e = self.at((i, col)); } res } } ) ); macro_rules! diag_impl( ($t: ident, $tv: ident, $dim: expr) => ( impl Diag<$tv> for $t { #[inline] fn from_diag(diag: &$tv) -> $t { let mut res: $t = ::zero(); res.set_diag(diag); res } #[inline] fn set_diag(&mut self, diag: &$tv) { for i in (0us .. $dim) { unsafe { self.unsafe_set((i, i), diag.unsafe_at(i)) } } } #[inline] fn diag(&self) -> $tv { let mut diag: $tv = ::zero(); for i in (0us .. $dim) { unsafe { diag.unsafe_set(i, self.unsafe_at((i, i))) } } diag } } ) ); macro_rules! mat_mul_mat_impl( ($t: ident, $dim: expr) => ( impl Mul<$t> for $t { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { // careful! we need to comute other * self here (self is the rhs). let mut res: $t = ::zero(); for i in (0us .. $dim) { for j in (0us .. $dim) { let mut acc: N = ::zero(); unsafe { for k in (0us .. $dim) { acc = acc + self.at_fast((i, k)) * right.at_fast((k, j)); } res.set_fast((i, j), acc); } } } res } } ) ); macro_rules! vec_mul_mat_impl( ($t: ident, $v: ident, $dim: expr, $zero: expr) => ( impl Mul<$t> for $v { type Output = $v; #[inline] fn mul(self, right: $t) -> $v { let mut res : $v = $zero(); for i in (0us .. $dim) { for j in (0us .. $dim) { unsafe { let val = res.at_fast(i) + self.at_fast(j) * right.at_fast((j, i)); res.set_fast(i, val) } } } res } } ) ); macro_rules! mat_mul_vec_impl( ($t: ident, $v: ident, $dim: expr, $zero: expr) => ( impl Mul<$v> for $t { type Output = $v; #[inline] fn mul(self, right: $v) -> $v { let mut res : $v = $zero(); for i in (0us .. $dim) { for j in (0us .. $dim) { unsafe { let val = res.at_fast(i) + self.at_fast((i, j)) * right.at_fast(j); res.set_fast(i, val) } } } res } } ) ); macro_rules! pnt_mul_mat_impl( ($t: ident, $v: ident, $dim: expr, $zero: expr) => ( vec_mul_mat_impl!($t, $v, $dim, $zero); ) ); macro_rules! mat_mul_pnt_impl( ($t: ident, $v: ident, $dim: expr, $zero: expr) => ( mat_mul_vec_impl!($t, $v, $dim, $zero); ) ); macro_rules! inv_impl( ($t: ident, $dim: expr) => ( impl Inv for $t { #[inline] fn inv(&self) -> Option<$t> { let mut res : $t = *self; if res.inv_mut() { Some(res) } else { None } } fn inv_mut(&mut self) -> bool { let mut res: $t = ::one(); // inversion using Gauss-Jordan elimination for k in (0us .. $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 self.at((n0, k)) != ::zero() { break; } n0 = n0 + 1; } if n0 == $dim { return false } // swap pivot line if n0 != k { for j in (0us .. $dim) { self.swap((n0, j), (k, j)); res.swap((n0, j), (k, j)); } } let pivot = self.at((k, k)); for j in (k .. $dim) { let selfval = self.at((k, j)) / pivot; self.set((k, j), selfval); } for j in (0us .. $dim) { let resval = res.at((k, j)) / pivot; res.set((k, j), resval); } for l in (0us .. $dim) { if l != k { let normalizer = self.at((l, k)); for j in (k .. $dim) { let selfval = self.at((l, j)) - self.at((k, j)) * normalizer; self.set((l, j), selfval); } for j in (0us .. $dim) { let resval = res.at((l, j)) - res.at((k, j)) * normalizer; res.set((l, j), resval); } } } } *self = res; true } } ) ); macro_rules! transpose_impl( ($t: ident, $dim: expr) => ( impl Transpose for $t { #[inline] fn transpose(&self) -> $t { let mut res = *self; res.transpose_mut(); res } #[inline] fn transpose_mut(&mut self) { for i in (1us .. $dim) { for j in (0us .. i) { self.swap((i, j), (j, i)) } } } } ) ); macro_rules! approx_eq_impl( ($t: ident) => ( impl> ApproxEq for $t { #[inline] fn approx_epsilon(_: Option<$t>) -> N { ApproxEq::approx_epsilon(None::) } #[inline] fn approx_ulps(_: Option<$t>) -> u32 { ApproxEq::approx_ulps(None::) } #[inline] fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { let zip = self.iter().zip(other.iter()); zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) } #[inline] fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { let zip = self.iter().zip(other.iter()); zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) } } ) ); macro_rules! to_homogeneous_impl( ($t: ident, $t2: ident, $dim: expr, $dim2: expr) => ( impl ToHomogeneous<$t2> for $t { #[inline] fn to_homogeneous(&self) -> $t2 { let mut res: $t2 = ::one(); for i in (0us .. $dim) { for j in (0us .. $dim) { res.set((i, j), self.at((i, j))) } } res } } ) ); macro_rules! from_homogeneous_impl( ($t: ident, $t2: ident, $dim: expr, $dim2: expr) => ( impl FromHomogeneous<$t2> for $t { #[inline] fn from(m: &$t2) -> $t { let mut res: $t = ::one(); for i in (0us .. $dim2) { for j in (0us .. $dim2) { res.set((i, j), m.at((i, j))) } } // FIXME: do we have to deal the lost components // (like if the 1 is not a 1… do we have to divide?) res } } ) ); macro_rules! outer_impl( ($t: ident, $m: ident) => ( impl + Zero> Outer<$m> for $t { #[inline] fn outer(&self, other: &$t) -> $m { let mut res: $m = ::zero(); for i in (0us .. Dim::dim(None::<$t>)) { for j in (0us .. Dim::dim(None::<$t>)) { res.set((i, j), self.at(i) * other.at(j)) } } res } } ) ); macro_rules! eigen_qr_impl( ($t: ident, $v: ident) => ( impl EigenQR> for $t where N: BaseFloat + ApproxEq + Clone { fn eigen_qr(&self, eps: &N, niter: usize) -> ($t, $v) { linalg::eigen_qr(self, eps, niter) } } ) );