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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
extern crate num; use matrix::Matrix; use vectors::zero; use ops_inplace::VectorVectorOpsInPlace; use math::Dimension; pub trait SumVec<T> { fn sum(&self) -> T; } macro_rules! vec_sum_impl { ($($t:ty)*) => ($( impl SumVec<$t> for Vec<$t> { // TODO in the future there might be a default value fn sum(&self) -> $t { (&self[..]).sum() } } impl SumVec<$t> for [$t] { // TODO in the future there might be a default value fn sum(&self) -> $t { // TODO is there a more efficient method to sum up all values? self.iter().fold(0 as $t, |init, &val| init + val) } } )*) } vec_sum_impl!{ usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Trait to compute the sum of values. pub trait Sum<T> { /// Computes the sum over all elements of the specified dimension. /// /// When computing the sum of a vector or a slice both /// are interpreted as a row vector. Thus, /// the only valid dimension for vectors or slices /// is `Dimension::Row`. For other dimensions the function /// will always return zero. /// /// # Examples /// /// Compute the sum of all elements of a vector. /// /// ``` /// use rustml::*; /// /// let v = vec![1.0, 5.0, 9.0]; /// assert_eq!(v.sum(), 15.0); /// ``` /// /// To compute the sum of all elements in each column or each row of a /// matrix you have to specify the correct dimension. /// /// ``` /// # #[macro_use] extern crate rustml; /// use rustml::*; /// /// # fn main() { /// let m = mat![ /// 1.0, 2.0; /// 5.0, 10.0 /// ]; /// /// assert_eq!(m.sum(Dimension::Row), vec![3.0, 15.0]); /// assert_eq!(m.sum(Dimension::Column), vec![6.0, 12.0]); /// # } /// ``` /// /// # Implementation details /// /// Currently, the following code is used to compute the sum of a row: /// /// ```ignore /// self.iter().fold(T::zero(), |init, &val| init + val) /// ``` /// /// In the future this may be replaced by a more efficient implementation. fn sum(&self, dim: Dimension) -> T; } /* macro_rules! sum_vec_impl { ($($t:ty)*) => ($( impl Sum<$t> for Vec<$t> { // TODO in the future there might be a default value fn sum(&self, dim: Dimension) -> $t { (&self[..]).sum(dim) } } impl Sum<$t> for [$t] { // TODO in the future there might be a default value fn sum(&self, dim: Dimension) -> $t { match dim { // TODO is there a more efficient method to sum up all values? Dimension::Row => { self.iter().fold(0 as $t, |init, &val| init + val) } _ => 0 as $t } } } )*) } sum_vec_impl!{ usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } */ macro_rules! sum_impl { ($($t:ty)*) => ($( impl Sum<Vec<$t>> for Matrix<$t> { fn sum(&self, dim: Dimension) -> Vec<$t> { match dim { Dimension:: Column => { let mut v = zero::<$t>(self.cols()); for row in self.row_iter() { v.iadd(row); } v } Dimension::Row => { self.row_iter().map(|row| row.sum()).collect() } } } } )*) } sum_impl!{ f32 f64 } // ------------------------------------------------------------------------------ #[cfg(test)] mod tests { use super::*; use matrix::*; use math::Dimension; #[test] fn test_sum_matrix_f32() { let m = mat![ 1.0f32, 2.0; 5.0, 10.0 ]; assert_eq!(m.sum(Dimension::Column), vec![6.0, 12.0]); assert_eq!(m.sum(Dimension::Row), vec![3.0, 15.0]); let a = Matrix::<f32>::new(); assert_eq!(a.sum(Dimension::Column), vec![]); assert_eq!(a.sum(Dimension::Row), vec![]); } #[test] fn test_sum_vec_f32() { let x: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0]; assert_eq!(x.sum(), 10.0); let a: Vec<f32> = Vec::new(); assert_eq!(a.sum(), 0.0); } }