1use num::{Signed, Zero};
4use std::ops::{Add, Mul};
5
6use simba::scalar::{ClosedDivAssign, ClosedMulAssign};
7use simba::simd::SimdPartialOrd;
8
9use crate::base::allocator::{Allocator, SameShapeAllocator};
10use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
11use crate::base::dimension::Dim;
12use crate::base::storage::{Storage, StorageMut};
13use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar};
14use crate::ClosedAddAssign;
15
16pub type MatrixComponentOp<T, R1, C1, R2, C2> = MatrixSum<T, R1, C1, R2, C2>;
18
19impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
20 #[inline]
31 #[must_use]
32 pub fn abs(&self) -> OMatrix<T, R, C>
33 where
34 T: Signed,
35 DefaultAllocator: Allocator<R, C>,
36 {
37 let mut res = self.clone_owned();
38
39 for e in res.iter_mut() {
40 *e = e.abs();
41 }
42
43 res
44 }
45
46 }
48
49macro_rules! component_binop_impl(
50 ($($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);* $(;)*) => {$(
51 #[doc = $desc]
52 #[inline]
53 #[must_use]
54 pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> MatrixComponentOp<T, R1, C1, R2, C2>
55 where T: $Trait,
56 R2: Dim, C2: Dim,
57 SB: Storage<T, R2, C2>,
58 DefaultAllocator: SameShapeAllocator<R1, C1, R2, C2>,
59 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
60
61 assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
62 let mut res = self.clone_owned_sum();
63
64 for j in 0 .. res.ncols() {
65 for i in 0 .. res.nrows() {
66 unsafe {
67 res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone());
68 }
69 }
70 }
71
72 res
73 }
74
75 #[doc = $desc_cmpy]
77 #[inline]
78 pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: T, a: &Matrix<T, R2, C2, SB>, b: &Matrix<T, R3, C3, SC>, beta: T)
79 where T: $Trait + Zero + Mul<T, Output = T> + Add<T, Output = T>,
80 R2: Dim, C2: Dim,
81 R3: Dim, C3: Dim,
82 SA: StorageMut<T, R1, C1>,
83 SB: Storage<T, R2, C2>,
84 SC: Storage<T, R3, C3>,
85 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
86 SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
87 assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
88 assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
89
90 if beta.is_zero() {
91 for j in 0 .. self.ncols() {
92 for i in 0 .. self.nrows() {
93 unsafe {
94 let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone());
95 *self.get_unchecked_mut((i, j)) = res;
96 }
97 }
98 }
99 }
100 else {
101 for j in 0 .. self.ncols() {
102 for i in 0 .. self.nrows() {
103 unsafe {
104 let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone());
105 *self.get_unchecked_mut((i, j)) = beta.clone() * self.get_unchecked((i, j)).clone() + res;
106 }
107 }
108 }
109 }
110 }
111
112 #[doc = $desc_mut]
113 #[inline]
114 pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
115 where T: $Trait,
116 R2: Dim,
117 C2: Dim,
118 SA: StorageMut<T, R1, C1>,
119 SB: Storage<T, R2, C2>,
120 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
121
122 assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
123
124 for j in 0 .. self.ncols() {
125 for i in 0 .. self.nrows() {
126 unsafe {
127 self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone());
128 }
129 }
130 }
131 }
132
133 #[doc = $desc_mut]
134 #[inline]
135 #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
136 pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
137 where T: $Trait,
138 R2: Dim,
139 C2: Dim,
140 SA: StorageMut<T, R1, C1>,
141 SB: Storage<T, R2, C2>,
142 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
143 self.$binop_assign(rhs)
144 }
145 )*}
146);
147
148impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA> {
150 component_binop_impl!(
151 component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMulAssign.mul.mul_assign,
152 r"
153 Componentwise matrix or vector multiplication.
154
155 # Example
156
157 ```
158 # use nalgebra::Matrix2;
159 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
160 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
161 let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);
162
163 assert_eq!(a.component_mul(&b), expected);
164 ```
165 ",
166 r"
167 Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.
168
169 # Example
170 ```
171 # use nalgebra::Matrix2;
172 let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
173 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
174 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
175 let expected = (a.component_mul(&b) * 5.0) + m * 10.0;
176
177 m.cmpy(5.0, &a, &b, 10.0);
178 assert_eq!(m, expected);
179 ```
180 ",
181 r"
182 Inplace componentwise matrix or vector multiplication.
183
184 # Example
185 ```
186 # use nalgebra::Matrix2;
187 let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
188 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
189 let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);
190
191 a.component_mul_assign(&b);
192
193 assert_eq!(a, expected);
194 ```
195 ";
196 component_div, component_div_mut, component_div_assign, cdpy, ClosedDivAssign.div.div_assign,
197 r"
198 Componentwise matrix or vector division.
199
200 # Example
201
202 ```
203 # use nalgebra::Matrix2;
204 let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
205 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
206 let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);
207
208 assert_eq!(a.component_div(&b), expected);
209 ```
210 ",
211 r"
212 Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.
213
214 # Example
215 ```
216 # use nalgebra::Matrix2;
217 let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
218 let a = Matrix2::new(4.0, 5.0, 6.0, 7.0);
219 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
220 let expected = (a.component_div(&b) * 5.0) + m * 10.0;
221
222 m.cdpy(5.0, &a, &b, 10.0);
223 assert_eq!(m, expected);
224 ```
225 ",
226 r"
227 Inplace componentwise matrix or vector division.
228
229 # Example
230 ```
231 # use nalgebra::Matrix2;
232 let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
233 let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
234 let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);
235
236 a.component_div_assign(&b);
237
238 assert_eq!(a, expected);
239 ```
240 ";
241 );
243
244 #[inline]
256 #[must_use]
257 pub fn inf(&self, other: &Self) -> OMatrix<T, R1, C1>
258 where
259 T: SimdPartialOrd,
260 DefaultAllocator: Allocator<R1, C1>,
261 {
262 self.zip_map(other, |a, b| a.simd_min(b))
263 }
264
265 #[inline]
277 #[must_use]
278 pub fn sup(&self, other: &Self) -> OMatrix<T, R1, C1>
279 where
280 T: SimdPartialOrd,
281 DefaultAllocator: Allocator<R1, C1>,
282 {
283 self.zip_map(other, |a, b| a.simd_max(b))
284 }
285
286 #[inline]
298 #[must_use]
299 pub fn inf_sup(&self, other: &Self) -> (OMatrix<T, R1, C1>, OMatrix<T, R1, C1>)
300 where
301 T: SimdPartialOrd,
302 DefaultAllocator: Allocator<R1, C1>,
303 {
304 (self.inf(other), self.sup(other))
306 }
307
308 #[inline]
320 #[must_use = "Did you mean to use add_scalar_mut()?"]
321 pub fn add_scalar(&self, rhs: T) -> OMatrix<T, R1, C1>
322 where
323 T: ClosedAddAssign,
324 DefaultAllocator: Allocator<R1, C1>,
325 {
326 let mut res = self.clone_owned();
327 res.add_scalar_mut(rhs);
328 res
329 }
330
331 #[inline]
344 pub fn add_scalar_mut(&mut self, rhs: T)
345 where
346 T: ClosedAddAssign,
347 SA: StorageMut<T, R1, C1>,
348 {
349 for e in self.iter_mut() {
350 *e += rhs.clone()
351 }
352 }
353}