1 // Non-conventional component-wise operators. 2 3 use num::{Signed, Zero}; 4 use std::ops::{Add, Mul}; 5 6 use alga::general::{ClosedDiv, ClosedMul}; 7 8 use crate::base::allocator::{Allocator, SameShapeAllocator}; 9 use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; 10 use crate::base::dimension::Dim; 11 use crate::base::storage::{Storage, StorageMut}; 12 use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar}; 13 14 /// The type of the result of a matrix component-wise operation. 15 pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>; 16 17 impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { 18 /// Computes the component-wise absolute value. 19 /// 20 /// # Example 21 /// 22 /// ``` 23 /// # use nalgebra::Matrix2; 24 /// let a = Matrix2::new(0.0, 1.0, 25 /// -2.0, -3.0); 26 /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0)) 27 /// ``` 28 #[inline] abs(&self) -> MatrixMN<N, R, C> where N: Signed, DefaultAllocator: Allocator<N, R, C>,29 pub fn abs(&self) -> MatrixMN<N, R, C> 30 where 31 N: Signed, 32 DefaultAllocator: Allocator<N, R, C>, 33 { 34 let mut res = self.clone_owned(); 35 36 for e in res.iter_mut() { 37 *e = e.abs(); 38 } 39 40 res 41 } 42 43 // FIXME: add other operators like component_ln, component_pow, etc. ? 44 } 45 46 macro_rules! component_binop_impl( 47 ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$( 48 impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> { 49 #[doc = $desc] 50 #[inline] 51 pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2> 52 where N: $Trait, 53 R2: Dim, C2: Dim, 54 SB: Storage<N, R2, C2>, 55 DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>, 56 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { 57 58 assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); 59 let mut res = self.clone_owned_sum(); 60 61 for j in 0 .. res.ncols() { 62 for i in 0 .. res.nrows() { 63 unsafe { 64 res.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j))); 65 } 66 } 67 } 68 69 res 70 } 71 } 72 73 impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> { 74 // componentwise binop plus Y. 75 #[doc = $desc_cmpy] 76 #[inline] 77 pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: N, a: &Matrix<N, R2, C2, SB>, b: &Matrix<N, R3, C3, SC>, beta: N) 78 where N: $Trait + Zero + Mul<N, Output = N> + Add<N, Output = N>, 79 R2: Dim, C2: Dim, 80 R3: Dim, C3: Dim, 81 SB: Storage<N, R2, C2>, 82 SC: Storage<N, R3, C3>, 83 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> + 84 SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> { 85 assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions."); 86 assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions."); 87 88 if beta.is_zero() { 89 for j in 0 .. self.ncols() { 90 for i in 0 .. self.nrows() { 91 unsafe { 92 let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j))); 93 *self.get_unchecked_mut((i, j)) = res; 94 } 95 } 96 } 97 } 98 else { 99 for j in 0 .. self.ncols() { 100 for i in 0 .. self.nrows() { 101 unsafe { 102 let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j))); 103 *self.get_unchecked_mut((i, j)) = beta * *self.get_unchecked((i, j)) + res; 104 } 105 } 106 } 107 } 108 } 109 110 #[doc = $desc_mut] 111 #[inline] 112 pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>) 113 where N: $Trait, 114 R2: Dim, 115 C2: Dim, 116 SB: Storage<N, R2, C2>, 117 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { 118 119 assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); 120 121 for j in 0 .. self.ncols() { 122 for i in 0 .. self.nrows() { 123 unsafe { 124 self.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j))); 125 } 126 } 127 } 128 } 129 130 #[doc = $desc_mut] 131 #[inline] 132 #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")] 133 pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>) 134 where N: $Trait, 135 R2: Dim, 136 C2: Dim, 137 SB: Storage<N, R2, C2>, 138 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { 139 self.$binop_assign(rhs) 140 } 141 } 142 )*} 143 ); 144 145 component_binop_impl!( 146 component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign, 147 r" 148 Componentwise matrix or vector multiplication. 149 150 # Example 151 152 ``` 153 # use nalgebra::Matrix2; 154 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); 155 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 156 let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); 157 158 assert_eq!(a.component_mul(&b), expected); 159 ``` 160 ", 161 r" 162 Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`. 163 164 # Example 165 ``` 166 # use nalgebra::Matrix2; 167 let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); 168 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); 169 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 170 let expected = (a.component_mul(&b) * 5.0) + m * 10.0; 171 172 m.cmpy(5.0, &a, &b, 10.0); 173 assert_eq!(m, expected); 174 ``` 175 ", 176 r" 177 Inplace componentwise matrix or vector multiplication. 178 179 # Example 180 ``` 181 # use nalgebra::Matrix2; 182 let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); 183 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 184 let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); 185 186 a.component_mul_assign(&b); 187 188 assert_eq!(a, expected); 189 ``` 190 "; 191 component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign, 192 r" 193 Componentwise matrix or vector division. 194 195 # Example 196 197 ``` 198 # use nalgebra::Matrix2; 199 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); 200 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 201 let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); 202 203 assert_eq!(a.component_div(&b), expected); 204 ``` 205 ", 206 r" 207 Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`. 208 209 # Example 210 ``` 211 # use nalgebra::Matrix2; 212 let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); 213 let a = Matrix2::new(4.0, 5.0, 6.0, 7.0); 214 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 215 let expected = (a.component_div(&b) * 5.0) + m * 10.0; 216 217 m.cdpy(5.0, &a, &b, 10.0); 218 assert_eq!(m, expected); 219 ``` 220 ", 221 r" 222 Inplace componentwise matrix or vector division. 223 224 # Example 225 ``` 226 # use nalgebra::Matrix2; 227 let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); 228 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); 229 let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); 230 231 a.component_div_assign(&b); 232 233 assert_eq!(a, expected); 234 ``` 235 "; 236 // FIXME: add other operators like bitshift, etc. ? 237 ); 238