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