// Non-conventional component-wise operators. use num::{Signed, Zero}; use std::ops::{Add, Mul}; use simba::scalar::{ClosedDiv, ClosedMul}; use simba::simd::SimdPartialOrd; use crate::base::allocator::{Allocator, SameShapeAllocator}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use crate::base::dimension::Dim; use crate::base::storage::{Storage, StorageMut}; use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar}; use crate::ClosedAdd; /// The type of the result of a matrix component-wise operation. pub type MatrixComponentOp = MatrixSum; impl> Matrix { /// Computes the component-wise absolute value. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let a = Matrix2::new(0.0, 1.0, /// -2.0, -3.0); /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0)) /// ``` #[inline] #[must_use = "This function does not mutate self. You should use the return value."] pub fn abs(&self) -> OMatrix where T: Signed, DefaultAllocator: Allocator, { let mut res = self.clone_owned(); for e in res.iter_mut() { *e = e.abs(); } res } // TODO: add other operators like component_ln, component_pow, etc. ? } macro_rules! component_binop_impl( ($($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);* $(;)*) => {$( #[doc = $desc] #[inline] #[must_use = "This function does not mutate self. You should use the return value."] pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp where T: $Trait, R2: Dim, C2: Dim, SB: Storage, DefaultAllocator: SameShapeAllocator, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); let mut res = self.clone_owned_sum(); for j in 0 .. res.ncols() { for i in 0 .. res.nrows() { unsafe { res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); } } } res } // componentwise binop plus Y. #[doc = $desc_cmpy] #[inline] pub fn $cmpy(&mut self, alpha: T, a: &Matrix, b: &Matrix, beta: T) where T: $Trait + Zero + Mul + Add, R2: Dim, C2: Dim, R3: Dim, C3: Dim, SA: StorageMut, SB: Storage, SC: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + SameNumberOfRows + SameNumberOfColumns { assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions."); assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions."); if beta.is_zero() { for j in 0 .. self.ncols() { for i in 0 .. self.nrows() { unsafe { let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); *self.get_unchecked_mut((i, j)) = res; } } } } else { for j in 0 .. self.ncols() { for i in 0 .. self.nrows() { unsafe { let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); *self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res; } } } } } #[doc = $desc_mut] #[inline] pub fn $binop_assign(&mut self, rhs: &Matrix) where T: $Trait, R2: Dim, C2: Dim, SA: StorageMut, SB: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); for j in 0 .. self.ncols() { for i in 0 .. self.nrows() { unsafe { self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); } } } } #[doc = $desc_mut] #[inline] #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")] pub fn $binop_mut(&mut self, rhs: &Matrix) where T: $Trait, R2: Dim, C2: Dim, SA: StorageMut, SB: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { self.$binop_assign(rhs) } )*} ); /// # Componentwise operations impl> Matrix { component_binop_impl!( component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign, r" Componentwise matrix or vector multiplication. # Example ``` # use nalgebra::Matrix2; let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); assert_eq!(a.component_mul(&b), expected); ``` ", r" Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`. # Example ``` # use nalgebra::Matrix2; let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = (a.component_mul(&b) * 5.0) + m * 10.0; m.cmpy(5.0, &a, &b, 10.0); assert_eq!(m, expected); ``` ", r" Inplace componentwise matrix or vector multiplication. # Example ``` # use nalgebra::Matrix2; let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); a.component_mul_assign(&b); assert_eq!(a, expected); ``` "; component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign, r" Componentwise matrix or vector division. # Example ``` # use nalgebra::Matrix2; let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); assert_eq!(a.component_div(&b), expected); ``` ", r" Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`. # Example ``` # use nalgebra::Matrix2; let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); let a = Matrix2::new(4.0, 5.0, 6.0, 7.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = (a.component_div(&b) * 5.0) + m * 10.0; m.cdpy(5.0, &a, &b, 10.0); assert_eq!(m, expected); ``` ", r" Inplace componentwise matrix or vector division. # Example ``` # use nalgebra::Matrix2; let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); a.component_div_assign(&b); assert_eq!(a, expected); ``` "; // TODO: add other operators like bitshift, etc. ? ); /// Computes the infimum (aka. componentwise min) of two matrices/vectors. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); /// let expected = Matrix2::new(2.0, 2.0, -2.0, -2.0); /// assert_eq!(u.inf(&v), expected) /// ``` #[inline] #[must_use = "This function does not mutate self. You should use the return value."] pub fn inf(&self, other: &Self) -> OMatrix where T: SimdPartialOrd, DefaultAllocator: Allocator, { self.zip_map(other, |a, b| a.simd_min(b)) } /// Computes the supremum (aka. componentwise max) of two matrices/vectors. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); /// let expected = Matrix2::new(4.0, 4.0, 1.0, 1.0); /// assert_eq!(u.sup(&v), expected) /// ``` #[inline] #[must_use = "This function does not mutate self. You should use the return value."] pub fn sup(&self, other: &Self) -> OMatrix where T: SimdPartialOrd, DefaultAllocator: Allocator, { self.zip_map(other, |a, b| a.simd_max(b)) } /// Computes the (infimum, supremum) of two matrices/vectors. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); /// let expected = (Matrix2::new(2.0, 2.0, -2.0, -2.0), Matrix2::new(4.0, 4.0, 1.0, 1.0)); /// assert_eq!(u.inf_sup(&v), expected) /// ``` #[inline] #[must_use = "This function does not mutate self. You should use the return value."] pub fn inf_sup(&self, other: &Self) -> (OMatrix, OMatrix) where T: SimdPartialOrd, DefaultAllocator: Allocator, { // TODO: can this be optimized? (self.inf(other), self.sup(other)) } /// Adds a scalar to `self`. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let u = Matrix2::new(1.0, 2.0, 3.0, 4.0); /// let s = 10.0; /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); /// assert_eq!(u.add_scalar(s), expected) /// ``` #[inline] #[must_use = "Did you mean to use add_scalar_mut()?"] pub fn add_scalar(&self, rhs: T) -> OMatrix where T: ClosedAdd, DefaultAllocator: Allocator, { let mut res = self.clone_owned(); res.add_scalar_mut(rhs); res } /// Adds a scalar to `self` in-place. /// /// # Example /// /// ``` /// # use nalgebra::Matrix2; /// let mut u = Matrix2::new(1.0, 2.0, 3.0, 4.0); /// let s = 10.0; /// u.add_scalar_mut(s); /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); /// assert_eq!(u, expected) /// ``` #[inline] pub fn add_scalar_mut(&mut self, rhs: T) where T: ClosedAdd, SA: StorageMut, { for e in self.iter_mut() { *e += rhs.inlined_clone() } } }