nalgebra/src/base/componentwise.rs

298 lines
9.8 KiB
Rust
Raw Normal View History

2018-10-21 04:26:44 +08:00
// Non-conventional component-wise operators.
2018-02-02 19:26:35 +08:00
use num::{Signed, Zero};
use std::ops::{Add, Mul};
2020-03-21 19:16:46 +08:00
use simba::scalar::{ClosedDiv, ClosedMul};
2020-03-25 02:05:47 +08:00
use simba::simd::SimdPartialOrd;
2019-03-23 21:29:07 +08:00
use crate::base::allocator::{Allocator, SameShapeAllocator};
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::Dim;
use crate::base::storage::{Storage, StorageMut};
2021-04-11 17:00:38 +08:00
use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar};
2020-11-15 23:57:49 +08:00
use crate::ClosedAdd;
/// The type of the result of a matrix component-wise operation.
2021-04-11 17:00:38 +08:00
pub type MatrixComponentOp<T, R1, C1, R2, C2> = MatrixSum<T, R1, C1, R2, C2>;
2021-04-11 17:00:38 +08:00
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// 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]
2021-04-11 17:00:38 +08:00
pub fn abs(&self) -> OMatrix<T, R, C>
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T: Signed,
DefaultAllocator: Allocator<T, R, C>,
2018-02-02 19:26:35 +08:00
{
let mut res = self.clone_owned();
for e in res.iter_mut() {
*e = e.abs();
}
res
}
2020-11-15 23:57:49 +08:00
// TODO: add other operators like component_ln, component_pow, etc. ?
}
macro_rules! component_binop_impl(
2018-02-02 19:26:40 +08:00
($($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);* $(;)*) => {$(
2020-11-15 23:57:49 +08:00
#[doc = $desc]
#[inline]
2021-04-11 17:00:38 +08:00
pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> MatrixComponentOp<T, R1, C1, R2, C2>
where T: $Trait,
2020-11-15 23:57:49 +08:00
R2: Dim, C2: Dim,
2021-04-11 17:00:38 +08:00
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
2020-11-15 23:57:49 +08:00
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
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());
}
}
}
2020-11-15 23:57:49 +08:00
res
}
2020-11-15 23:57:49 +08:00
// componentwise binop plus Y.
#[doc = $desc_cmpy]
#[inline]
2021-04-11 17:00:38 +08:00
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)
where T: $Trait + Zero + Mul<T, Output = T> + Add<T, Output = T>,
2020-11-15 23:57:49 +08:00
R2: Dim, C2: Dim,
R3: Dim, C3: Dim,
2021-04-11 17:00:38 +08:00
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
SC: Storage<T, R3, C3>,
2020-11-15 23:57:49 +08:00
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
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;
2018-02-02 19:26:27 +08:00
}
}
}
}
2020-11-15 23:57:49 +08:00
else {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
2020-11-15 23:57:49 +08:00
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;
}
}
}
}
2020-11-15 23:57:49 +08:00
}
2020-11-15 23:57:49 +08:00
#[doc = $desc_mut]
#[inline]
2021-04-11 17:00:38 +08:00
pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
where T: $Trait,
2020-11-15 23:57:49 +08:00
R2: Dim,
C2: Dim,
2021-04-11 17:00:38 +08:00
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
2020-11-15 23:57:49 +08:00
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
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());
}
}
}
}
2020-11-15 23:57:49 +08:00
#[doc = $desc_mut]
#[inline]
#[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
2021-04-11 17:00:38 +08:00
pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
where T: $Trait,
2020-11-15 23:57:49 +08:00
R2: Dim,
C2: Dim,
2021-04-11 17:00:38 +08:00
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
2020-11-15 23:57:49 +08:00
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
self.$binop_assign(rhs)
}
)*}
);
2020-11-15 23:57:49 +08:00
/// # Componentwise operations
2021-04-11 17:00:38 +08:00
impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA> {
2020-11-15 23:57:49 +08:00
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. ?
);
2020-03-25 02:05:47 +08:00
/// Computes the infimum (aka. componentwise min) of two matrices/vectors.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn inf(&self, other: &Self) -> OMatrix<T, R1, C1>
2020-11-15 23:57:49 +08:00
where
2021-04-11 17:00:38 +08:00
T: SimdPartialOrd,
DefaultAllocator: Allocator<T, R1, C1>,
2020-11-15 23:57:49 +08:00
{
2020-03-25 02:05:47 +08:00
self.zip_map(other, |a, b| a.simd_min(b))
}
/// Computes the supremum (aka. componentwise max) of two matrices/vectors.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn sup(&self, other: &Self) -> OMatrix<T, R1, C1>
2020-11-15 23:57:49 +08:00
where
2021-04-11 17:00:38 +08:00
T: SimdPartialOrd,
DefaultAllocator: Allocator<T, R1, C1>,
2020-11-15 23:57:49 +08:00
{
2020-03-25 02:05:47 +08:00
self.zip_map(other, |a, b| a.simd_max(b))
}
/// Computes the (infimum, supremum) of two matrices/vectors.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn inf_sup(&self, other: &Self) -> (OMatrix<T, R1, C1>, OMatrix<T, R1, C1>)
2020-11-15 23:57:49 +08:00
where
2021-04-11 17:00:38 +08:00
T: SimdPartialOrd,
DefaultAllocator: Allocator<T, R1, C1>,
2020-11-15 23:57:49 +08:00
{
// TODO: can this be optimized?
2020-03-25 02:05:47 +08:00
(self.inf(other), self.sup(other))
}
2020-11-15 23:57:49 +08:00
/// Adds a scalar to `self`.
#[inline]
#[must_use = "Did you mean to use add_scalar_mut()?"]
2021-04-11 17:00:38 +08:00
pub fn add_scalar(&self, rhs: T) -> OMatrix<T, R1, C1>
2020-11-15 23:57:49 +08:00
where
2021-04-11 17:00:38 +08:00
T: ClosedAdd,
DefaultAllocator: Allocator<T, R1, C1>,
2020-11-15 23:57:49 +08:00
{
let mut res = self.clone_owned();
res.add_scalar_mut(rhs);
res
}
/// Adds a scalar to `self` in-place.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn add_scalar_mut(&mut self, rhs: T)
2020-11-15 23:57:49 +08:00
where
2021-04-11 17:00:38 +08:00
T: ClosedAdd,
SA: StorageMut<T, R1, C1>,
2020-11-15 23:57:49 +08:00
{
for e in self.iter_mut() {
*e += rhs.inlined_clone()
}
}
2020-03-25 02:05:47 +08:00
}