2018-10-27 21:16:03 +08:00
|
|
|
|
use num::{One, Zero};
|
2018-07-20 21:25:55 +08:00
|
|
|
|
#[cfg(feature = "abomonation-serialize")]
|
|
|
|
|
use std::io::{Result as IOResult, Write};
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-05-19 21:41:58 +08:00
|
|
|
|
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
|
|
|
|
use std::any::TypeId;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
use std::fmt;
|
2018-12-28 01:05:25 +08:00
|
|
|
|
use std::hash::{Hash, Hasher};
|
2018-05-19 21:41:58 +08:00
|
|
|
|
use std::marker::PhantomData;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
use std::mem;
|
|
|
|
|
|
2017-05-04 10:02:30 +08:00
|
|
|
|
#[cfg(feature = "serde-serialize")]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
2017-05-04 10:02:30 +08:00
|
|
|
|
|
2017-08-14 18:07:06 +08:00
|
|
|
|
#[cfg(feature = "abomonation-serialize")]
|
|
|
|
|
use abomonation::Abomonation;
|
|
|
|
|
|
2020-03-21 19:16:46 +08:00
|
|
|
|
use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, RealField};
|
|
|
|
|
use simba::simd::SimdPartialOrd;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-03-23 21:29:07 +08:00
|
|
|
|
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
|
|
|
|
use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
|
|
|
|
use crate::base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
|
2020-03-18 00:58:36 +08:00
|
|
|
|
use crate::base::iter::{
|
|
|
|
|
ColumnIter, ColumnIterMut, MatrixIter, MatrixIterMut, RowIter, RowIterMut,
|
|
|
|
|
};
|
2019-03-23 21:29:07 +08:00
|
|
|
|
use crate::base::storage::{
|
2018-05-19 21:41:58 +08:00
|
|
|
|
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
|
|
|
|
|
};
|
2019-03-23 21:29:07 +08:00
|
|
|
|
use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN};
|
2020-03-21 19:16:46 +08:00
|
|
|
|
use crate::SimdComplexField;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
/// A square matrix.
|
|
|
|
|
pub type SquareMatrix<N, D, S> = Matrix<N, D, D, S>;
|
|
|
|
|
|
|
|
|
|
/// A matrix with one column and `D` rows.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub type Vector<N, D, S> = Matrix<N, D, U1, S>;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// A matrix with one row and `D` columns .
|
2017-05-18 04:37:18 +08:00
|
|
|
|
pub type RowVector<N, D, S> = Matrix<N, U1, D, S>;
|
|
|
|
|
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// The type of the result of a matrix sum.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub type MatrixSum<N, R1, C1, R2, C2> =
|
|
|
|
|
Matrix<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>, SameShapeStorage<N, R1, C1, R2, C2>>;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
/// The type of the result of a matrix sum.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub type VectorSum<N, R1, R2> =
|
|
|
|
|
Matrix<N, SameShapeR<R1, R2>, U1, SameShapeStorage<N, R1, U1, R2, U1>>;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
/// The type of the result of a matrix cross product.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub type MatrixCross<N, R1, C1, R2, C2> =
|
|
|
|
|
Matrix<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>, SameShapeStorage<N, R1, C1, R2, C2>>;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// The most generic column-major matrix (and vector) type.
|
|
|
|
|
///
|
|
|
|
|
/// It combines four type parameters:
|
|
|
|
|
/// - `N`: for the matrix components scalar type.
|
|
|
|
|
/// - `R`: for the matrix number of rows.
|
|
|
|
|
/// - `C`: for the matrix number of columns.
|
|
|
|
|
/// - `S`: for the matrix data storage, i.e., the buffer that actually contains the matrix
|
|
|
|
|
/// components.
|
|
|
|
|
///
|
|
|
|
|
/// The matrix dimensions parameters `R` and `C` can either be:
|
2018-09-24 12:48:42 +08:00
|
|
|
|
/// - type-level unsigned integer constants (e.g. `U1`, `U124`) from the `nalgebra::` root module.
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// All numbers from 0 to 127 are defined that way.
|
|
|
|
|
/// - type-level unsigned integer constants (e.g. `U1024`, `U10000`) from the `typenum::` crate.
|
|
|
|
|
/// Using those, you will not get error messages as nice as for numbers smaller than 128 defined on
|
|
|
|
|
/// the `nalgebra::` module.
|
|
|
|
|
/// - the special value `Dynamic` from the `nalgebra::` root module. This indicates that the
|
|
|
|
|
/// specified dimension is not known at compile-time. Note that this will generally imply that the
|
|
|
|
|
/// matrix data storage `S` performs a dynamic allocation and contains extra metadata for the
|
|
|
|
|
/// matrix shape.
|
|
|
|
|
///
|
|
|
|
|
/// Note that mixing `Dynamic` with type-level unsigned integers is allowed. Actually, a
|
|
|
|
|
/// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given
|
|
|
|
|
/// some concrete types for `N` and a compatible data storage type `S`).
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[repr(C)]
|
2018-12-28 01:05:25 +08:00
|
|
|
|
#[derive(Clone, Copy)]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// The data storage that contains all the matrix components and informations about its number
|
|
|
|
|
/// of rows and column (if needed).
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub data: S,
|
2017-02-13 01:17:09 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
_phantoms: PhantomData<(N, R, C)>,
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: fmt::Debug> fmt::Debug for Matrix<N, R, C, S> {
|
2018-01-18 00:35:01 +08:00
|
|
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2018-05-19 21:41:58 +08:00
|
|
|
|
formatter
|
|
|
|
|
.debug_struct("Matrix")
|
2018-01-18 00:35:01 +08:00
|
|
|
|
.field("data", &self.data)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 16:11:27 +08:00
|
|
|
|
impl<N, R, C, S> Default for Matrix<N, R, C, S>
|
|
|
|
|
where
|
|
|
|
|
N: Scalar,
|
|
|
|
|
R: Dim,
|
|
|
|
|
C: Dim,
|
|
|
|
|
S: Default,
|
|
|
|
|
{
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Matrix {
|
|
|
|
|
data: Default::default(),
|
|
|
|
|
_phantoms: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-04 10:02:30 +08:00
|
|
|
|
#[cfg(feature = "serde-serialize")]
|
|
|
|
|
impl<N, R, C, S> Serialize for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
R: Dim,
|
|
|
|
|
C: Dim,
|
|
|
|
|
S: Serialize,
|
|
|
|
|
{
|
2017-05-04 10:02:30 +08:00
|
|
|
|
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
T: Serializer,
|
|
|
|
|
{
|
2017-05-04 10:02:30 +08:00
|
|
|
|
self.data.serialize(serializer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "serde-serialize")]
|
|
|
|
|
impl<'de, N, R, C, S> Deserialize<'de> for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
R: Dim,
|
|
|
|
|
C: Dim,
|
|
|
|
|
S: Deserialize<'de>,
|
|
|
|
|
{
|
2017-05-04 10:02:30 +08:00
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
|
{
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S::deserialize(deserializer).map(|x| Matrix {
|
|
|
|
|
data: x,
|
|
|
|
|
_phantoms: PhantomData,
|
|
|
|
|
})
|
2017-05-04 10:02:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-14 18:07:06 +08:00
|
|
|
|
#[cfg(feature = "abomonation-serialize")]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: Abomonation> Abomonation for Matrix<N, R, C, S> {
|
2018-07-20 21:25:55 +08:00
|
|
|
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
2017-08-14 18:07:06 +08:00
|
|
|
|
self.data.entomb(writer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
|
|
|
|
|
self.data.exhume(bytes)
|
|
|
|
|
}
|
2018-07-20 21:25:55 +08:00
|
|
|
|
|
|
|
|
|
fn extent(&self) -> usize {
|
|
|
|
|
self.data.extent()
|
|
|
|
|
}
|
2017-08-14 18:07:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-12 00:26:12 +08:00
|
|
|
|
#[cfg(feature = "compare")]
|
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>>
|
|
|
|
|
matrixcompare_core::Matrix<N> for Matrix<N, R, C, S> {
|
|
|
|
|
fn rows(&self) -> usize {
|
|
|
|
|
self.nrows()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn cols(&self) -> usize {
|
|
|
|
|
self.ncols()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn access(&self) -> matrixcompare_core::Access<N> {
|
|
|
|
|
matrixcompare_core::Access::Dense(self)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "compare")]
|
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>>
|
|
|
|
|
matrixcompare_core::DenseAccess<N> for Matrix<N, R, C, S> {
|
|
|
|
|
fn fetch_single(&self, row: usize, col: usize) -> N {
|
|
|
|
|
self.index((row, col)).clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S> Matrix<N, R, C, S> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Creates a new matrix with the given data without statically checking that the matrix
|
|
|
|
|
/// dimension matches the storage dimension.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn from_data_statically_unchecked(data: S) -> Matrix<N, R, C, S> {
|
|
|
|
|
Matrix {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
data: data,
|
|
|
|
|
_phantoms: PhantomData,
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Creates a new matrix with the given data.
|
|
|
|
|
#[inline]
|
2019-02-17 05:29:41 +08:00
|
|
|
|
pub fn from_data(data: S) -> Self {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
unsafe { Self::from_data_statically_unchecked(data) }
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The total number of elements of this matrix.
|
2018-10-16 04:44:01 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix3x4;
|
|
|
|
|
/// let mat = Matrix3x4::<f32>::zeros();
|
|
|
|
|
/// assert_eq!(mat.len(), 12);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
nrows * ncols
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// The shape of this matrix returned as the tuple (number of rows, number of columns).
|
2018-10-16 04:44:01 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix3x4;
|
|
|
|
|
/// let mat = Matrix3x4::<f32>::zeros();
|
|
|
|
|
/// assert_eq!(mat.shape(), (3, 4));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn shape(&self) -> (usize, usize) {
|
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
(nrows.value(), ncols.value())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The number of rows of this matrix.
|
2018-10-16 04:44:01 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix3x4;
|
|
|
|
|
/// let mat = Matrix3x4::<f32>::zeros();
|
|
|
|
|
/// assert_eq!(mat.nrows(), 3);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn nrows(&self) -> usize {
|
|
|
|
|
self.shape().0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The number of columns of this matrix.
|
2018-10-16 04:44:01 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix3x4;
|
|
|
|
|
/// let mat = Matrix3x4::<f32>::zeros();
|
|
|
|
|
/// assert_eq!(mat.ncols(), 4);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn ncols(&self) -> usize {
|
|
|
|
|
self.shape().1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The strides (row stride, column stride) of this matrix.
|
2018-10-16 04:44:01 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::DMatrix;
|
|
|
|
|
/// let mat = DMatrix::<f32>::zeros(10, 10);
|
|
|
|
|
/// let slice = mat.slice_with_steps((0, 0), (5, 3), (1, 2));
|
|
|
|
|
/// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension.
|
|
|
|
|
/// assert_eq!(mat.strides(), (1, 10));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn strides(&self) -> (usize, usize) {
|
|
|
|
|
let (srows, scols) = self.data.strides();
|
|
|
|
|
(srows.value(), scols.value())
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-16 04:44:01 +08:00
|
|
|
|
/// Iterates through this matrix coordinates in column-major order.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2x3;
|
|
|
|
|
/// let mat = Matrix2x3::new(11, 12, 13,
|
|
|
|
|
/// 21, 22, 23);
|
|
|
|
|
/// let mut it = mat.iter();
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 11);
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 21);
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 12);
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 22);
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 13);
|
|
|
|
|
/// assert_eq!(*it.next().unwrap(), 23);
|
|
|
|
|
/// assert!(it.next().is_none());
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn iter(&self) -> MatrixIter<N, R, C, S> {
|
|
|
|
|
MatrixIter::new(&self.data)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 15:33:07 +08:00
|
|
|
|
/// Iterate through the rows of this matrix.
|
2019-02-03 18:17:09 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2x3;
|
|
|
|
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
|
|
|
|
/// 4, 5, 6);
|
|
|
|
|
/// for (i, row) in a.row_iter().enumerate() {
|
|
|
|
|
/// assert_eq!(row, a.row(i))
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
2018-12-09 22:21:05 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn row_iter(&self) -> RowIter<N, R, C, S> {
|
|
|
|
|
RowIter::new(self)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-03 15:33:07 +08:00
|
|
|
|
/// Iterate through the columns of this matrix.
|
2019-02-03 18:17:09 +08:00
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2x3;
|
|
|
|
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
|
|
|
|
/// 4, 5, 6);
|
|
|
|
|
/// for (i, column) in a.column_iter().enumerate() {
|
|
|
|
|
/// assert_eq!(column, a.column(i))
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
2018-12-09 22:21:05 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn column_iter(&self) -> ColumnIter<N, R, C, S> {
|
|
|
|
|
ColumnIter::new(self)
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Computes the row and column coordinates of the i-th element of this matrix seen as a
|
|
|
|
|
/// vector.
|
2020-04-03 17:39:49 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2;
|
|
|
|
|
/// let m = Matrix2::new(1, 2,
|
|
|
|
|
/// 3, 4);
|
|
|
|
|
/// let i = m.vector_to_matrix_index(3);
|
|
|
|
|
/// assert_eq!(i, (1, 1));
|
|
|
|
|
/// assert_eq!(m[i], m[3]);
|
|
|
|
|
/// ```
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn vector_to_matrix_index(&self, i: usize) -> (usize, usize) {
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
|
|
|
|
|
// Two most common uses that should be optimized by the compiler for statically-sized
|
|
|
|
|
// matrices.
|
|
|
|
|
if nrows == 1 {
|
|
|
|
|
(0, i)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else if ncols == 1 {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
(i, 0)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
(i % nrows, i / nrows)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-20 05:51:01 +08:00
|
|
|
|
/// Returns a pointer to the start of the matrix.
|
|
|
|
|
///
|
|
|
|
|
/// If the matrix is not empty, this pointer is guaranteed to be aligned
|
|
|
|
|
/// and non-null.
|
2020-04-03 17:56:08 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2;
|
|
|
|
|
/// let m = Matrix2::new(1, 2,
|
|
|
|
|
/// 3, 4);
|
|
|
|
|
/// let ptr = m.as_ptr();
|
|
|
|
|
/// assert_eq!(unsafe { *ptr }, m[0]);
|
|
|
|
|
/// ```
|
2018-11-20 05:51:01 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_ptr(&self) -> *const N {
|
|
|
|
|
self.data.ptr()
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Tests whether `self` and `rhs` are equal up to a given epsilon.
|
|
|
|
|
///
|
2018-05-19 21:41:58 +08:00
|
|
|
|
/// See `relative_eq` from the `RelativeEq` trait for more details.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
pub fn relative_eq<R2, C2, SB>(
|
|
|
|
|
&self,
|
|
|
|
|
other: &Matrix<N, R2, C2, SB>,
|
|
|
|
|
eps: N::Epsilon,
|
|
|
|
|
max_relative: N::Epsilon,
|
|
|
|
|
) -> bool
|
|
|
|
|
where
|
2018-05-19 21:41:58 +08:00
|
|
|
|
N: RelativeEq,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
|
|
|
|
assert!(self.shape() == other.shape());
|
|
|
|
|
self.iter()
|
|
|
|
|
.zip(other.iter())
|
|
|
|
|
.all(|(a, b)| a.relative_eq(b, eps, max_relative))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
|
|
|
|
|
/// Tests whether `self` and `rhs` are exactly equal.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn eq<R2, C2, SB>(&self, other: &Matrix<N, R2, C2, SB>) -> bool
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
N: PartialEq,
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
|
|
|
|
assert!(self.shape() == other.shape());
|
|
|
|
|
self.iter().zip(other.iter()).all(|(a, b)| *a == *b)
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Moves this matrix into one that owns its data.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn into_owned(self) -> MatrixMN<N, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, R, C>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Matrix::from_data(self.data.into_owned())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: this could probably benefit from specialization.
|
|
|
|
|
// XXX: bad name.
|
|
|
|
|
/// Moves this matrix into one that owns its data. The actual type of the result depends on
|
|
|
|
|
/// matrix storage combination rules for addition.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn into_owned_sum<R2, C2>(self) -> MatrixSum<N, R, C, R2, C2>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
DefaultAllocator: SameShapeAllocator<N, R, C, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
if TypeId::of::<SameShapeStorage<N, R, C, R2, C2>>() == TypeId::of::<Owned<N, R, C>>() {
|
|
|
|
|
// We can just return `self.into_owned()`.
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
// FIXME: check that those copies are optimized away by the compiler.
|
|
|
|
|
let owned = self.into_owned();
|
|
|
|
|
let res = mem::transmute_copy(&owned);
|
|
|
|
|
mem::forget(owned);
|
|
|
|
|
res
|
|
|
|
|
}
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
self.clone_owned_sum()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-14 01:53:02 +08:00
|
|
|
|
/// Clones this matrix to one that owns its data.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn clone_owned(&self) -> MatrixMN<N, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, R, C>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Matrix::from_data(self.data.clone_owned())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Clones this matrix into one that owns its data. The actual type of the result depends on
|
|
|
|
|
/// matrix storage combination rules for addition.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn clone_owned_sum<R2, C2>(&self) -> MatrixSum<N, R, C, R2, C2>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
DefaultAllocator: SameShapeAllocator<N, R, C, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
let nrows: SameShapeR<R, R2> = Dim::from_usize(nrows);
|
|
|
|
|
let ncols: SameShapeC<C, C2> = Dim::from_usize(ncols);
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
let mut res: MatrixSum<N, R, C, R2, C2> =
|
|
|
|
|
unsafe { Matrix::new_uninitialized_generic(nrows, ncols) };
|
2017-08-03 01:37:44 +08:00
|
|
|
|
|
|
|
|
|
// FIXME: use copy_from
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..res.ncols() {
|
|
|
|
|
for i in 0..res.nrows() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*res.get_unchecked_mut((i, j)) = self.get_unchecked((i, j)).inlined_clone();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a matrix containing the result of `f` applied to each of its entries.
|
|
|
|
|
#[inline]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
pub fn map<N2: Scalar, F: FnMut(N) -> N2>(&self, mut f: F) -> MatrixMN<N2, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N2, R, C>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) };
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
*res.data.get_unchecked_mut(i, j) = f(a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
/// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure.
|
|
|
|
|
///
|
|
|
|
|
/// The initialization closure is given the first component of this matrix:
|
|
|
|
|
/// - If the matrix has no component (0 rows or 0 columns) then `init_f` is called with `None`
|
|
|
|
|
/// and its return value is the value returned by this method.
|
|
|
|
|
/// - If the matrix has has least one component, then `init_f` is called with the first component
|
|
|
|
|
/// to compute the initial value. Folding then continues on all the remaining components of the matrix.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn fold_with<N2>(
|
|
|
|
|
&self,
|
|
|
|
|
init_f: impl FnOnce(Option<&N>) -> N2,
|
|
|
|
|
f: impl FnMut(N2, &N) -> N2,
|
2020-04-06 00:49:48 +08:00
|
|
|
|
) -> N2 {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
let mut it = self.iter();
|
|
|
|
|
let init = init_f(it.next());
|
|
|
|
|
it.fold(init, f)
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-26 03:27:27 +08:00
|
|
|
|
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
|
2019-01-30 09:31:10 +08:00
|
|
|
|
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
|
2018-09-26 03:27:27 +08:00
|
|
|
|
#[inline]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
|
2018-10-16 04:44:01 +08:00
|
|
|
|
&self,
|
|
|
|
|
mut f: F,
|
|
|
|
|
) -> MatrixMN<N2, R, C>
|
2018-09-26 03:27:27 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N2, R, C>,
|
|
|
|
|
{
|
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) };
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
2018-09-26 03:27:27 +08:00
|
|
|
|
*res.data.get_unchecked_mut(i, j) = f(i, j, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Returns a matrix containing the result of `f` applied to each entries of `self` and
|
|
|
|
|
/// `rhs`.
|
|
|
|
|
#[inline]
|
2017-08-14 01:52:55 +08:00
|
|
|
|
pub fn zip_map<N2, N3, S2, F>(&self, rhs: &Matrix<N2, R, C, S2>, mut f: F) -> MatrixMN<N3, R, C>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N2: Scalar,
|
|
|
|
|
N3: Scalar,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S2: Storage<N2, R, C>,
|
|
|
|
|
F: FnMut(N, N2) -> N3,
|
|
|
|
|
DefaultAllocator: Allocator<N3, R, C>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) };
|
|
|
|
|
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows.value(), ncols.value()),
|
|
|
|
|
rhs.shape(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
2017-08-03 01:37:44 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
|
|
|
|
let b = rhs.data.get_unchecked(i, j).inlined_clone();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
*res.data.get_unchecked_mut(i, j) = f(a, b)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 21:38:33 +08:00
|
|
|
|
/// Returns a matrix containing the result of `f` applied to each entries of `self` and
|
|
|
|
|
/// `b`, and `c`.
|
|
|
|
|
#[inline]
|
2018-10-16 04:44:01 +08:00
|
|
|
|
pub fn zip_zip_map<N2, N3, N4, S2, S3, F>(
|
|
|
|
|
&self,
|
|
|
|
|
b: &Matrix<N2, R, C, S2>,
|
|
|
|
|
c: &Matrix<N3, R, C, S3>,
|
|
|
|
|
mut f: F,
|
|
|
|
|
) -> MatrixMN<N4, R, C>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N2: Scalar,
|
|
|
|
|
N3: Scalar,
|
|
|
|
|
N4: Scalar,
|
2018-10-16 04:44:01 +08:00
|
|
|
|
S2: Storage<N2, R, C>,
|
|
|
|
|
S3: Storage<N3, R, C>,
|
|
|
|
|
F: FnMut(N, N2, N3) -> N4,
|
|
|
|
|
DefaultAllocator: Allocator<N4, R, C>,
|
2018-09-22 21:38:33 +08:00
|
|
|
|
{
|
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) };
|
|
|
|
|
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows.value(), ncols.value()),
|
|
|
|
|
b.shape(),
|
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows.value(), ncols.value()),
|
|
|
|
|
c.shape(),
|
2018-09-22 21:38:33 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
|
|
|
|
let b = b.data.get_unchecked(i, j).inlined_clone();
|
|
|
|
|
let c = c.data.get_unchecked(i, j).inlined_clone();
|
2018-09-22 21:38:33 +08:00
|
|
|
|
*res.data.get_unchecked_mut(i, j) = f(a, b, c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-09 18:21:24 +08:00
|
|
|
|
/// Folds a function `f` on each entry of `self`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, N) -> Acc) -> Acc {
|
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = init;
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
2018-12-09 18:21:24 +08:00
|
|
|
|
res = f(res, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
|
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn zip_fold<N2, R2, C2, S2, Acc>(
|
|
|
|
|
&self,
|
|
|
|
|
rhs: &Matrix<N2, R2, C2, S2>,
|
|
|
|
|
init: Acc,
|
|
|
|
|
mut f: impl FnMut(Acc, N, N2) -> Acc,
|
|
|
|
|
) -> Acc
|
|
|
|
|
where
|
|
|
|
|
N2: Scalar,
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
S2: Storage<N2, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
2018-12-09 18:21:24 +08:00
|
|
|
|
{
|
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
let mut res = init;
|
|
|
|
|
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows.value(), ncols.value()),
|
|
|
|
|
rhs.shape(),
|
2018-12-09 18:21:24 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols.value() {
|
|
|
|
|
for i in 0..nrows.value() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let a = self.data.get_unchecked(i, j).inlined_clone();
|
|
|
|
|
let b = rhs.data.get_unchecked(i, j).inlined_clone();
|
2018-12-09 18:21:24 +08:00
|
|
|
|
res = f(res, a, b)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Transposes `self` and store the result into `out`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: StorageMut<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, C2> + SameNumberOfColumns<C, R2>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
(ncols, nrows) == out.shape(),
|
|
|
|
|
"Incompatible shape for transpose-copy."
|
|
|
|
|
);
|
2017-08-03 01:37:44 +08:00
|
|
|
|
|
|
|
|
|
// FIXME: optimize that.
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
for j in 0..ncols {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).inlined_clone();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transposes `self`.
|
|
|
|
|
#[inline]
|
2019-06-06 05:04:04 +08:00
|
|
|
|
#[must_use = "Did you mean to use transpose_mut()?"]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn transpose(&self) -> MatrixMN<N, C, R>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, C, R>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
let mut res = Matrix::new_uninitialized_generic(ncols, nrows);
|
|
|
|
|
self.transpose_to(&mut res);
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Mutably iterates through this matrix coordinates.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn iter_mut(&mut self) -> MatrixIterMut<N, R, C, S> {
|
|
|
|
|
MatrixIterMut::new(&mut self.data)
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-20 05:51:01 +08:00
|
|
|
|
/// Returns a mutable pointer to the start of the matrix.
|
|
|
|
|
///
|
|
|
|
|
/// If the matrix is not empty, this pointer is guaranteed to be aligned
|
|
|
|
|
/// and non-null.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_mut_ptr(&mut self) -> *mut N {
|
|
|
|
|
self.data.ptr_mut()
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-09 22:21:05 +08:00
|
|
|
|
/// Mutably iterates through this matrix rows.
|
2019-02-03 18:17:09 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2x3;
|
|
|
|
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
|
|
|
|
/// 4, 5, 6);
|
|
|
|
|
/// for (i, mut row) in a.row_iter_mut().enumerate() {
|
|
|
|
|
/// row *= (i + 1) * 10;
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// let expected = Matrix2x3::new(10, 20, 30,
|
|
|
|
|
/// 80, 100, 120);
|
|
|
|
|
/// assert_eq!(a, expected);
|
|
|
|
|
/// ```
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2018-12-09 22:21:05 +08:00
|
|
|
|
pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
|
|
|
|
|
RowIterMut::new(self)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Mutably iterates through this matrix columns.
|
2019-02-03 18:17:09 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Matrix2x3;
|
|
|
|
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
|
|
|
|
/// 4, 5, 6);
|
|
|
|
|
/// for (i, mut col) in a.column_iter_mut().enumerate() {
|
|
|
|
|
/// col *= (i + 1) * 10;
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// let expected = Matrix2x3::new(10, 40, 90,
|
|
|
|
|
/// 40, 100, 180);
|
|
|
|
|
/// assert_eq!(a, expected);
|
|
|
|
|
/// ```
|
2018-12-09 22:21:05 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn column_iter_mut(&mut self) -> ColumnIterMut<N, R, C, S> {
|
|
|
|
|
ColumnIterMut::new(self)
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Swaps two entries without bound-checking.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
debug_assert!(row_cols1.0 < self.nrows() && row_cols1.1 < self.ncols());
|
|
|
|
|
debug_assert!(row_cols2.0 < self.nrows() && row_cols2.1 < self.ncols());
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.data.swap_unchecked(row_cols1, row_cols2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Swaps two entries.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn swap(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) {
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
row_cols1.0 < nrows && row_cols1.1 < ncols,
|
|
|
|
|
"Matrix elements swap index out of bounds."
|
|
|
|
|
);
|
|
|
|
|
assert!(
|
|
|
|
|
row_cols2.0 < nrows && row_cols2.1 < ncols,
|
|
|
|
|
"Matrix elements swap index out of bounds."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
unsafe { self.swap_unchecked(row_cols1, row_cols2) }
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-13 11:38:57 +08:00
|
|
|
|
/// Fills this matrix with the content of a slice. Both must hold the same number of elements.
|
|
|
|
|
///
|
|
|
|
|
/// The components of the slice are assumed to be ordered in column-major order.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn copy_from_slice(&mut self, slice: &[N]) {
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
|
nrows * ncols == slice.len(),
|
|
|
|
|
"The slice must contain the same number of elements as the matrix."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
unsafe {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
*self.get_unchecked_mut((i, j)) =
|
|
|
|
|
slice.get_unchecked(i + j * nrows).inlined_clone();
|
2018-09-13 11:38:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Fills this matrix with the content of another one. Both must have the same shape.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn copy_from<R2, C2, SB>(&mut self, other: &Matrix<N, R2, C2, SB>)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
|
|
|
|
assert!(
|
|
|
|
|
self.shape() == other.shape(),
|
|
|
|
|
"Unable to copy from a matrix with a different shape."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..self.ncols() {
|
|
|
|
|
for i in 0..self.nrows() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*self.get_unchecked_mut((i, j)) = other.get_unchecked((i, j)).inlined_clone();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Fills this matrix with the content of the transpose another one.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn tr_copy_from<R2, C2, SB>(&mut self, other: &Matrix<N, R2, C2, SB>)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: DimEq<R, C2> + SameNumberOfColumns<C, R2>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
(ncols, nrows) == other.shape(),
|
|
|
|
|
"Unable to copy from a matrix with incompatible shape."
|
|
|
|
|
);
|
2017-08-03 01:37:44 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*self.get_unchecked_mut((i, j)) = other.get_unchecked((j, i)).inlined_clone();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-18 04:37:18 +08:00
|
|
|
|
|
2019-03-19 19:00:10 +08:00
|
|
|
|
// FIXME: rename `apply` to `apply_mut` and `apply_into` to `apply`?
|
|
|
|
|
/// Returns `self` with each of its components replaced by the result of a closure `f` applied on it.
|
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn apply_into<F: FnMut(N) -> N>(mut self, f: F) -> Self {
|
2019-03-19 19:00:10 +08:00
|
|
|
|
self.apply(f);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-14 01:52:53 +08:00
|
|
|
|
/// Replaces each component of `self` by the result of a closure `f` applied on it.
|
2017-05-18 04:37:18 +08:00
|
|
|
|
#[inline]
|
2018-12-09 23:56:09 +08:00
|
|
|
|
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
|
2017-08-14 01:52:53 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
2017-08-14 01:52:53 +08:00
|
|
|
|
unsafe {
|
|
|
|
|
let e = self.data.get_unchecked_mut(i, j);
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*e = f(e.inlined_clone())
|
2017-08-14 01:52:53 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-18 04:37:18 +08:00
|
|
|
|
}
|
2018-12-09 23:56:09 +08:00
|
|
|
|
|
|
|
|
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
|
|
|
|
/// joined with the components from `rhs`.
|
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn zip_apply<N2, R2, C2, S2>(
|
|
|
|
|
&mut self,
|
|
|
|
|
rhs: &Matrix<N2, R2, C2, S2>,
|
|
|
|
|
mut f: impl FnMut(N, N2) -> N,
|
|
|
|
|
) where
|
|
|
|
|
N2: Scalar,
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
S2: Storage<N2, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
2018-12-09 23:56:09 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows, ncols),
|
|
|
|
|
rhs.shape(),
|
2018-12-09 23:56:09 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
unsafe {
|
|
|
|
|
let e = self.data.get_unchecked_mut(i, j);
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let rhs = rhs.get_unchecked((i, j)).inlined_clone();
|
|
|
|
|
*e = f(e.inlined_clone(), rhs)
|
2018-12-09 23:56:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
|
|
|
|
/// joined with the components from `b` and `c`.
|
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(
|
|
|
|
|
&mut self,
|
|
|
|
|
b: &Matrix<N2, R2, C2, S2>,
|
|
|
|
|
c: &Matrix<N3, R3, C3, S3>,
|
|
|
|
|
mut f: impl FnMut(N, N2, N3) -> N,
|
|
|
|
|
) where
|
|
|
|
|
N2: Scalar,
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
S2: Storage<N2, R2, C2>,
|
|
|
|
|
N3: Scalar,
|
|
|
|
|
R3: Dim,
|
|
|
|
|
C3: Dim,
|
|
|
|
|
S3: Storage<N3, R3, C3>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
2018-12-09 23:56:09 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows, ncols),
|
|
|
|
|
b.shape(),
|
2018-12-09 23:56:09 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(nrows, ncols),
|
|
|
|
|
c.shape(),
|
2018-12-09 23:56:09 +08:00
|
|
|
|
"Matrix simultaneous traversal error: dimension mismatch."
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
unsafe {
|
|
|
|
|
let e = self.data.get_unchecked_mut(i, j);
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let b = b.get_unchecked((i, j)).inlined_clone();
|
|
|
|
|
let c = c.get_unchecked((i, j)).inlined_clone();
|
|
|
|
|
*e = f(e.inlined_clone(), b, c)
|
2018-12-09 23:56:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2017-05-18 04:37:18 +08:00
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Gets a reference to the i-th element of this column vector without bound checking.
|
2017-05-18 04:37:18 +08:00
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub unsafe fn vget_unchecked(&self, i: usize) -> &N {
|
|
|
|
|
debug_assert!(i < self.nrows(), "Vector index out of bounds.");
|
|
|
|
|
let i = i * self.strides().0;
|
|
|
|
|
self.data.get_unchecked_linear(i)
|
2017-05-18 04:37:18 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, D: Dim, S: StorageMut<N, D>> Vector<N, D, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Gets a mutable reference to the i-th element of this column vector without bound checking.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut N {
|
|
|
|
|
debug_assert!(i < self.nrows(), "Vector index out of bounds.");
|
|
|
|
|
let i = i * self.strides().0;
|
|
|
|
|
self.data.get_unchecked_linear_mut(i)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: ContiguousStorage<N, R, C>> Matrix<N, R, C, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Extracts a slice containing the entire matrix entries ordered column-by-columns.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_slice(&self) -> &[N] {
|
|
|
|
|
self.data.as_slice()
|
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, R: Dim, C: Dim, S: ContiguousStorageMut<N, R, C>> Matrix<N, R, C, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Extracts a mutable slice containing the entire matrix entries ordered column-by-columns.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn as_mut_slice(&mut self) -> &mut [N] {
|
|
|
|
|
self.data.as_mut_slice()
|
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// Transposes the square matrix `self` in-place.
|
|
|
|
|
pub fn transpose_mut(&mut self) {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Unable to transpose a non-square matrix in-place."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let dim = self.shape().0;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for i in 1..dim {
|
|
|
|
|
for j in 0..i {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe { self.swap_unchecked((i, j), (j, i)) }
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
2019-03-23 18:48:12 +08:00
|
|
|
|
/// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2019-03-23 18:48:12 +08:00
|
|
|
|
pub fn adjoint_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
2019-02-23 18:24:07 +08:00
|
|
|
|
SB: StorageMut<N, R2, C2>,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, C2> + SameNumberOfColumns<C, R2>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let (nrows, ncols) = self.shape();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
(ncols, nrows) == out.shape(),
|
|
|
|
|
"Incompatible shape for transpose-copy."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
// FIXME: optimize that.
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
for j in 0..ncols {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).simd_conjugate();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 18:48:12 +08:00
|
|
|
|
/// The adjoint (aka. conjugate-transpose) of `self`.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2019-06-06 05:04:04 +08:00
|
|
|
|
#[must_use = "Did you mean to use adjoint_mut()?"]
|
2019-03-23 18:48:12 +08:00
|
|
|
|
pub fn adjoint(&self) -> MatrixMN<N, C, R>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, C, R>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let mut res: MatrixMN<_, C, R> = Matrix::new_uninitialized_generic(ncols, nrows);
|
2019-03-23 18:48:12 +08:00
|
|
|
|
self.adjoint_to(&mut res);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-03 02:33:49 +08:00
|
|
|
|
|
2019-03-23 18:48:12 +08:00
|
|
|
|
/// Takes the conjugate and transposes `self` and store the result into `out`.
|
|
|
|
|
#[deprecated(note = "Renamed `self.adjoint_to(out)`.")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn conjugate_transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
2020-03-18 00:58:36 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: StorageMut<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, C2> + SameNumberOfColumns<C, R2>,
|
2019-03-23 18:48:12 +08:00
|
|
|
|
{
|
|
|
|
|
self.adjoint_to(out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The conjugate transposition of `self`.
|
|
|
|
|
#[deprecated(note = "Renamed `self.adjoint()`.")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn conjugate_transpose(&self) -> MatrixMN<N, C, R>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, C, R>,
|
|
|
|
|
{
|
2019-03-23 18:48:12 +08:00
|
|
|
|
self.adjoint()
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-03 02:33:49 +08:00
|
|
|
|
/// The conjugate of `self`.
|
|
|
|
|
#[inline]
|
2019-06-06 05:04:04 +08:00
|
|
|
|
#[must_use = "Did you mean to use conjugate_mut()?"]
|
2019-03-03 02:33:49 +08:00
|
|
|
|
pub fn conjugate(&self) -> MatrixMN<N, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, R, C>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
self.map(|e| e.simd_conjugate())
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// Divides each component of the complex matrix `self` by the given real.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
2019-06-06 05:04:04 +08:00
|
|
|
|
#[must_use = "Did you mean to use unscale_mut()?"]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn unscale(&self, real: N::SimdRealField) -> MatrixMN<N, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, R, C>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
self.map(|e| e.simd_unscale(real))
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// Multiplies each component of the complex matrix `self` by the given real.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
2019-06-06 05:04:04 +08:00
|
|
|
|
#[must_use = "Did you mean to use scale_mut()?"]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn scale(&self, real: N::SimdRealField) -> MatrixMN<N, R, C>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, R, C>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
self.map(|e| e.simd_scale(real))
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// The conjugate of the complex matrix `self` computed in-place.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn conjugate_mut(&mut self) {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
self.apply(|e| e.simd_conjugate())
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// Divides each component of the complex matrix `self` by the given real.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn unscale_mut(&mut self, real: N::SimdRealField) {
|
|
|
|
|
self.apply(|e| e.simd_unscale(real))
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// Multiplies each component of the complex matrix `self` by the given real.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn scale_mut(&mut self, real: N::SimdRealField) {
|
|
|
|
|
self.apply(|e| e.simd_scale(real))
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: SimdComplexField, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
2019-03-23 21:13:00 +08:00
|
|
|
|
/// Sets `self` to its adjoint.
|
|
|
|
|
#[deprecated(note = "Renamed to `self.adjoint_mut()`.")]
|
|
|
|
|
pub fn conjugate_transform_mut(&mut self) {
|
|
|
|
|
self.adjoint_mut()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets `self` to its adjoint (aka. conjugate-transpose).
|
|
|
|
|
pub fn adjoint_mut(&mut self) {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Unable to transpose a non-square matrix in-place."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
let dim = self.shape().0;
|
|
|
|
|
|
2019-03-12 20:15:02 +08:00
|
|
|
|
for i in 0..dim {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for j in 0..i {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
unsafe {
|
2019-02-23 18:24:07 +08:00
|
|
|
|
let ref_ij = self.get_unchecked_mut((i, j)) as *mut N;
|
|
|
|
|
let ref_ji = self.get_unchecked_mut((j, i)) as *mut N;
|
2020-03-18 00:58:36 +08:00
|
|
|
|
let conj_ij = (*ref_ij).simd_conjugate();
|
|
|
|
|
let conj_ji = (*ref_ji).simd_conjugate();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
*ref_ij = conj_ji;
|
|
|
|
|
*ref_ji = conj_ij;
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2019-03-23 21:13:00 +08:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let diag = unsafe { self.get_unchecked_mut((i, i)) };
|
2020-03-18 00:58:36 +08:00
|
|
|
|
*diag = diag.simd_conjugate();
|
2019-03-23 21:13:00 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
2019-03-19 21:22:59 +08:00
|
|
|
|
/// The diagonal of this matrix.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn diagonal(&self) -> VectorN<N, D>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, D>,
|
|
|
|
|
{
|
2019-03-19 21:22:59 +08:00
|
|
|
|
self.map_diagonal(|e| e)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Apply the given function to this matrix's diagonal and returns it.
|
|
|
|
|
///
|
|
|
|
|
/// This is a more efficient version of `self.diagonal().map(f)` since this
|
|
|
|
|
/// allocates only once.
|
2019-12-17 07:09:14 +08:00
|
|
|
|
pub fn map_diagonal<N2: Scalar>(&self, mut f: impl FnMut(N) -> N2) -> VectorN<N2, D>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N2, D>,
|
|
|
|
|
{
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Unable to get the diagonal of a non-square matrix."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
let dim = self.data.shape().0;
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let mut res = unsafe { VectorN::new_uninitialized_generic(dim, U1) };
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for i in 0..dim.value() {
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
*res.vget_unchecked_mut(i) = f(self.get_unchecked((i, i)).inlined_clone());
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
2017-03-20 05:33:01 +08:00
|
|
|
|
|
|
|
|
|
/// Computes a trace of a square matrix, i.e., the sum of its diagonal elements.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn trace(&self) -> N
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
N: Scalar + Zero + ClosedAdd,
|
|
|
|
|
{
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Cannot compute the trace of non-square matrix."
|
|
|
|
|
);
|
2017-03-20 05:33:01 +08:00
|
|
|
|
|
|
|
|
|
let dim = self.data.shape().0;
|
|
|
|
|
let mut res = N::zero();
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
for i in 0..dim.value() {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
res += unsafe { self.get_unchecked((i, i)).inlined_clone() };
|
2017-03-20 05:33:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: SimdComplexField, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
2019-03-03 02:33:49 +08:00
|
|
|
|
/// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn symmetric_part(&self) -> MatrixMN<N, D, D>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, D, D>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Cannot compute the symmetric part of a non-square matrix."
|
|
|
|
|
);
|
2019-03-03 02:33:49 +08:00
|
|
|
|
let mut tr = self.transpose();
|
|
|
|
|
tr += self;
|
2019-03-23 21:29:07 +08:00
|
|
|
|
tr *= crate::convert::<_, N>(0.5);
|
2019-03-03 02:33:49 +08:00
|
|
|
|
tr
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 18:48:12 +08:00
|
|
|
|
/// The hermitian part of `self`, i.e., `0.5 * (self + self.adjoint())`.
|
2019-03-03 02:33:49 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn hermitian_part(&self) -> MatrixMN<N, D, D>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, D, D>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Cannot compute the hermitian part of a non-square matrix."
|
|
|
|
|
);
|
2019-03-03 02:33:49 +08:00
|
|
|
|
|
2019-03-23 18:48:12 +08:00
|
|
|
|
let mut tr = self.adjoint();
|
2019-03-23 18:46:56 +08:00
|
|
|
|
tr += self;
|
2019-03-23 21:29:07 +08:00
|
|
|
|
tr *= crate::convert::<_, N>(0.5);
|
2019-03-23 18:46:56 +08:00
|
|
|
|
tr
|
2019-03-03 02:33:49 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: Scalar + Zero + One, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>>
|
|
|
|
|
Matrix<N, D, D, S>
|
|
|
|
|
{
|
2018-11-18 23:51:40 +08:00
|
|
|
|
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
|
|
|
|
|
/// and setting the diagonal element to `1`.
|
|
|
|
|
#[inline]
|
2018-11-20 04:21:25 +08:00
|
|
|
|
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>>,
|
|
|
|
|
{
|
2020-03-18 00:58:36 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.is_square(),
|
|
|
|
|
"Only square matrices can currently be transformed to homogeneous coordinates."
|
|
|
|
|
);
|
2018-11-20 04:21:25 +08:00
|
|
|
|
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
|
2020-01-25 19:56:17 +08:00
|
|
|
|
let mut res = MatrixN::identity_generic(dim, dim);
|
2020-03-18 00:58:36 +08:00
|
|
|
|
res.generic_slice_mut::<D, D>((0, 0), self.data.shape())
|
|
|
|
|
.copy_from(&self);
|
2018-11-18 23:51:40 +08:00
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
|
|
|
|
|
/// coordinates.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, DimSum<D, U1>>,
|
|
|
|
|
{
|
2019-01-10 10:48:03 +08:00
|
|
|
|
self.push(N::zero())
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2017-02-13 01:17:09 +08:00
|
|
|
|
|
|
|
|
|
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
|
|
|
|
|
/// `self`. Returns `None` if this last component is not zero.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn from_homogeneous<SB>(v: Vector<N, DimSum<D, U1>, SB>) -> Option<VectorN<N, D>>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, DimSum<D, U1>>,
|
|
|
|
|
DefaultAllocator: Allocator<N, D>,
|
|
|
|
|
{
|
2017-02-13 01:17:09 +08:00
|
|
|
|
if v[v.len() - 1].is_zero() {
|
|
|
|
|
let nrows = D::from_usize(v.len() - 1);
|
|
|
|
|
Some(v.generic_slice((0, 0), (nrows, U1)).into_owned())
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2017-02-13 01:17:09 +08:00
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
2019-01-10 10:38:58 +08:00
|
|
|
|
/// Constructs a new vector of higher dimension by appending `element` to the end of `self`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn push(&self, element: N) -> VectorN<N, DimSum<D, U1>>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, DimSum<D, U1>>,
|
|
|
|
|
{
|
2019-01-10 10:38:58 +08:00
|
|
|
|
let len = self.len();
|
|
|
|
|
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
|
|
|
|
|
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
|
|
|
|
|
res.generic_slice_mut((0, 0), self.data.shape())
|
|
|
|
|
.copy_from(self);
|
|
|
|
|
res[(len, 0)] = element;
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-19 21:41:58 +08:00
|
|
|
|
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + AbsDiffEq,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
type Epsilon = N::Epsilon;
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn default_epsilon() -> Self::Epsilon {
|
|
|
|
|
N::default_epsilon()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2018-05-19 21:41:58 +08:00
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
|
|
|
|
|
self.iter()
|
|
|
|
|
.zip(other.iter())
|
|
|
|
|
.all(|(a, b)| a.abs_diff_eq(b, epsilon))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2018-05-19 21:41:58 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-05-19 21:41:58 +08:00
|
|
|
|
impl<N, R: Dim, C: Dim, S> RelativeEq for Matrix<N, R, C, S>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + RelativeEq,
|
2018-05-19 21:41:58 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2018-05-19 21:41:58 +08:00
|
|
|
|
fn default_max_relative() -> Self::Epsilon {
|
|
|
|
|
N::default_max_relative()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
fn relative_eq(
|
|
|
|
|
&self,
|
|
|
|
|
other: &Self,
|
|
|
|
|
epsilon: Self::Epsilon,
|
|
|
|
|
max_relative: Self::Epsilon,
|
2020-04-06 00:49:48 +08:00
|
|
|
|
) -> bool {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.relative_eq(other, epsilon, max_relative)
|
|
|
|
|
}
|
2018-05-19 21:41:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<N, R: Dim, C: Dim, S> UlpsEq for Matrix<N, R, C, S>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + UlpsEq,
|
2018-05-19 21:41:58 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
|
|
|
|
#[inline]
|
|
|
|
|
fn default_max_ulps() -> u32 {
|
|
|
|
|
N::default_max_ulps()
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(self.shape() == other.shape());
|
|
|
|
|
self.iter()
|
|
|
|
|
.zip(other.iter())
|
|
|
|
|
.all(|(a, b)| a.ulps_eq(b, epsilon, max_ulps))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<N, R: Dim, C: Dim, S> PartialOrd for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + PartialOrd,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
2018-10-13 17:32:49 +08:00
|
|
|
|
if self.shape() != other.shape() {
|
2018-10-13 17:24:11 +08:00
|
|
|
|
return None;
|
|
|
|
|
}
|
2018-02-02 19:26:35 +08:00
|
|
|
|
|
2018-10-13 17:32:49 +08:00
|
|
|
|
if self.nrows() == 0 || self.ncols() == 0 {
|
|
|
|
|
return Some(Ordering::Equal);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 17:24:11 +08:00
|
|
|
|
let mut first_ord = unsafe {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
self.data
|
|
|
|
|
.get_unchecked_linear(0)
|
|
|
|
|
.partial_cmp(other.data.get_unchecked_linear(0))
|
|
|
|
|
};
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-10-13 17:24:11 +08:00
|
|
|
|
if let Some(first_ord) = first_ord.as_mut() {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let mut it = self.iter().zip(other.iter());
|
2017-02-13 01:17:09 +08:00
|
|
|
|
let _ = it.next(); // Drop the first elements (we already tested it).
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
for (left, right) in it {
|
|
|
|
|
if let Some(ord) = left.partial_cmp(right) {
|
|
|
|
|
match ord {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
Ordering::Equal => { /* Does not change anything. */ }
|
|
|
|
|
Ordering::Less => {
|
2018-10-13 17:24:11 +08:00
|
|
|
|
if *first_ord == Ordering::Greater {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
return None;
|
|
|
|
|
}
|
2018-10-13 17:24:11 +08:00
|
|
|
|
*first_ord = ord
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Ordering::Greater => {
|
2018-10-13 17:24:11 +08:00
|
|
|
|
if *first_ord == Ordering::Less {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
return None;
|
|
|
|
|
}
|
2018-10-13 17:24:11 +08:00
|
|
|
|
*first_ord = ord
|
2018-02-02 19:26:35 +08:00
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
|
|
|
|
return None;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-24 11:58:58 +08:00
|
|
|
|
first_ord
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn lt(&self, right: &Self) -> bool {
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
self.shape(),
|
|
|
|
|
right.shape(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
"Matrix comparison error: dimensions mismatch."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.iter().zip(right.iter()).all(|(a, b)| a.lt(b))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn le(&self, right: &Self) -> bool {
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
self.shape(),
|
|
|
|
|
right.shape(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
"Matrix comparison error: dimensions mismatch."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.iter().zip(right.iter()).all(|(a, b)| a.le(b))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn gt(&self, right: &Self) -> bool {
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
self.shape(),
|
|
|
|
|
right.shape(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
"Matrix comparison error: dimensions mismatch."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.iter().zip(right.iter()).all(|(a, b)| a.gt(b))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn ge(&self, right: &Self) -> bool {
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
self.shape(),
|
|
|
|
|
right.shape(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
"Matrix comparison error: dimensions mismatch."
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.iter().zip(right.iter()).all(|(a, b)| a.ge(b))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<N, R: Dim, C: Dim, S> Eq for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + Eq,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
2020-03-18 00:58:36 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2020-01-19 10:06:36 +08:00
|
|
|
|
impl<N, R, R2, C, C2, S, S2> PartialEq<Matrix<N, R2, C2, S2>> for Matrix<N, R, C, S>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2020-01-19 10:06:36 +08:00
|
|
|
|
N: Scalar + PartialEq,
|
2020-01-25 19:57:15 +08:00
|
|
|
|
C: Dim,
|
2020-01-19 10:06:36 +08:00
|
|
|
|
C2: Dim,
|
2020-01-25 19:57:15 +08:00
|
|
|
|
R: Dim,
|
2020-01-19 10:06:36 +08:00
|
|
|
|
R2: Dim,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
2020-03-18 00:58:36 +08:00
|
|
|
|
S2: Storage<N, R2, C2>,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2020-01-19 10:06:00 +08:00
|
|
|
|
fn eq(&self, right: &Matrix<N, R2, C2, S2>) -> bool {
|
2020-01-25 19:58:05 +08:00
|
|
|
|
self.shape() == right.shape() && self.iter().zip(right.iter()).all(|(l, r)| l == r)
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
macro_rules! impl_fmt {
|
|
|
|
|
($trait: path, $fmt_str_without_precision: expr, $fmt_str_with_precision: expr) => {
|
|
|
|
|
impl<N, R: Dim, C: Dim, S> $trait for Matrix<N, R, C, S>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + $trait,
|
2019-08-21 21:53:23 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
DefaultAllocator: Allocator<usize, R, C>,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
#[cfg(feature = "std")]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
fn val_width<N: Scalar + $trait>(val: &N, f: &mut fmt::Formatter) -> usize {
|
2019-08-21 21:53:23 +08:00
|
|
|
|
match f.precision() {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
Some(precision) => format!($fmt_str_with_precision, val, precision)
|
|
|
|
|
.chars()
|
|
|
|
|
.count(),
|
2019-08-21 21:53:23 +08:00
|
|
|
|
None => format!($fmt_str_without_precision, val).chars().count(),
|
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
#[cfg(not(feature = "std"))]
|
2019-12-17 07:09:14 +08:00
|
|
|
|
fn val_width<N: Scalar + $trait>(_: &N, _: &mut fmt::Formatter) -> usize {
|
2019-08-21 21:53:23 +08:00
|
|
|
|
4
|
|
|
|
|
}
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
let (nrows, ncols) = self.data.shape();
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
if nrows.value() == 0 || ncols.value() == 0 {
|
|
|
|
|
return write!(f, "[ ]");
|
|
|
|
|
}
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
let mut max_length = 0;
|
|
|
|
|
let mut lengths: MatrixMN<usize, R, C> = Matrix::zeros_generic(nrows, ncols);
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
for j in 0..ncols {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
lengths[(i, j)] = val_width(&self[(i, j)], f);
|
2019-08-21 21:53:23 +08:00
|
|
|
|
max_length = crate::max(max_length, lengths[(i, j)]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
2019-08-21 21:53:23 +08:00
|
|
|
|
let max_length_with_space = max_length + 1;
|
|
|
|
|
|
|
|
|
|
writeln!(f)?;
|
|
|
|
|
writeln!(
|
|
|
|
|
f,
|
|
|
|
|
" ┌ {:>width$} ┐",
|
|
|
|
|
"",
|
|
|
|
|
width = max_length_with_space * ncols - 1
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
write!(f, " │")?;
|
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
let number_length = lengths[(i, j)] + 1;
|
|
|
|
|
let pad = max_length_with_space - number_length;
|
|
|
|
|
write!(f, " {:>thepad$}", "", thepad = pad)?;
|
|
|
|
|
match f.precision() {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
Some(precision) => {
|
|
|
|
|
write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)?
|
|
|
|
|
}
|
2019-08-21 21:53:23 +08:00
|
|
|
|
None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
writeln!(f, " │")?;
|
2019-08-19 21:15:14 +08:00
|
|
|
|
}
|
2019-08-21 21:53:23 +08:00
|
|
|
|
|
|
|
|
|
writeln!(
|
|
|
|
|
f,
|
|
|
|
|
" └ {:>width$} ┘",
|
|
|
|
|
"",
|
|
|
|
|
width = max_length_with_space * ncols - 1
|
|
|
|
|
)?;
|
|
|
|
|
writeln!(f)
|
2019-08-19 21:15:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-21 21:53:23 +08:00
|
|
|
|
};
|
2019-08-19 21:15:14 +08:00
|
|
|
|
}
|
2019-08-21 21:53:23 +08:00
|
|
|
|
impl_fmt!(fmt::Display, "{}", "{:.1$}");
|
|
|
|
|
impl_fmt!(fmt::LowerExp, "{:e}", "{:.1$e}");
|
|
|
|
|
impl_fmt!(fmt::UpperExp, "{:E}", "{:.1$E}");
|
|
|
|
|
impl_fmt!(fmt::Octal, "{:o}", "{:1$o}");
|
|
|
|
|
impl_fmt!(fmt::LowerHex, "{:x}", "{:1$x}");
|
|
|
|
|
impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}");
|
|
|
|
|
impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}");
|
|
|
|
|
impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}");
|
2019-08-19 21:15:14 +08:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn lower_exp() {
|
|
|
|
|
let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.);
|
2020-03-18 00:58:36 +08:00
|
|
|
|
assert_eq!(
|
|
|
|
|
format!("{:e}", test),
|
|
|
|
|
r"
|
2019-08-19 21:15:14 +08:00
|
|
|
|
┌ ┐
|
|
|
|
|
│ 1e6 2e5 │
|
|
|
|
|
│ 2e-5 1e0 │
|
|
|
|
|
└ ┘
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
"
|
|
|
|
|
)
|
2019-08-19 21:15:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-21 19:16:46 +08:00
|
|
|
|
impl<N: Scalar + ClosedAdd + ClosedSub + ClosedMul, R: Dim, C: Dim, S: Storage<N, R, C>>
|
|
|
|
|
Matrix<N, R, C, S>
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn perp<R2, C2, SB>(&self, b: &Matrix<N, R2, C2, SB>) -> N
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, U2>
|
|
|
|
|
+ SameNumberOfColumns<C, U1>
|
|
|
|
|
+ SameNumberOfRows<R2, U2>
|
|
|
|
|
+ SameNumberOfColumns<C2, U1>,
|
|
|
|
|
{
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert!(
|
|
|
|
|
self.shape() == (2, 1),
|
|
|
|
|
"2D perpendicular product requires (2, 1) vector but found {:?}",
|
|
|
|
|
self.shape()
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2019-12-06 06:54:17 +08:00
|
|
|
|
self.get_unchecked((0, 0)).inlined_clone() * b.get_unchecked((1, 0)).inlined_clone()
|
2020-03-18 00:58:36 +08:00
|
|
|
|
- self.get_unchecked((1, 0)).inlined_clone()
|
|
|
|
|
* b.get_unchecked((0, 0)).inlined_clone()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: use specialization instead of an assertion.
|
|
|
|
|
/// The 3D cross product between two vectors.
|
|
|
|
|
///
|
|
|
|
|
/// Panics if the shape is not 3D vector. In the future, this will be implemented only for
|
|
|
|
|
/// dynamically-sized matrices and statically-sized 3D matrices.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn cross<R2, C2, SB>(&self, b: &Matrix<N, R2, C2, SB>) -> MatrixCross<N, R, C, R2, C2>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
R2: Dim,
|
|
|
|
|
C2: Dim,
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
DefaultAllocator: SameShapeAllocator<N, R, C, R2, C2>,
|
|
|
|
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let shape = self.shape();
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
assert_eq!(shape, b.shape(), "Vector cross product dimension mismatch.");
|
2018-02-02 19:26:35 +08:00
|
|
|
|
assert!(
|
|
|
|
|
(shape.0 == 3 && shape.1 == 1) || (shape.0 == 1 && shape.1 == 3),
|
More verbose DMatrix dim asserts where possible.
Previously, most dimension mismatch asserts used raw `assert!` and did
not include the mismatching dimensions in the panic message. When using
dynamic matrices, this led to somewhat-opaque panics such as:
```rust
let m1 = DMatrix::<f32>::zeros(2, 3);
let m2 = DMatrix::<f32>::zeros(5, 10);
m1 + m2 // panic: Matrix addition/subtraction dimensions mismatch.
```
This patch adds dimension information in the panic messages wherever
doing so did not add additional bounds checks, mostly by simply changing
`assert!(a == b, ...)` cases to `assert_eq!`. After:
```rust
// panic: assertion failed: `(left == right)`
// left: `(2, 3)`,
// right: `(5, 10)`: Matrix addition/subtraction dimensions mismatch.
```
Note that the `gemv` and `ger` were not updated, as they are called from
within other functions on subset matricies -- e.g., `gemv` is called
from `gemm` which is called from `mul_to` . Including dimension
information in the `gemv` panic messages would be confusing to
`mul` / `mul_to` users, because it would include dimensions of the column
vectors that `gemm` passes to `gemv` rather than of the original `mul`
arguments. A fix would be to add bounds checks to `mul_to`, but that may
have performance and redundancy implications, so is left to another
patch.
2020-06-23 06:29:13 +08:00
|
|
|
|
"Vector cross product dimension mismatch: must be (3, 1) or (1, 3) but found {:?}.",
|
|
|
|
|
shape
|
2018-02-02 19:26:35 +08:00
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
if shape.0 == 3 {
|
|
|
|
|
unsafe {
|
|
|
|
|
// FIXME: soooo ugly!
|
|
|
|
|
let nrows = SameShapeR::<R, R2>::from_usize(3);
|
|
|
|
|
let ncols = SameShapeC::<C, C2>::from_usize(1);
|
|
|
|
|
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
|
|
|
|
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let ax = self.get_unchecked((0, 0));
|
|
|
|
|
let ay = self.get_unchecked((1, 0));
|
|
|
|
|
let az = self.get_unchecked((2, 0));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let bx = b.get_unchecked((0, 0));
|
|
|
|
|
let by = b.get_unchecked((1, 0));
|
|
|
|
|
let bz = b.get_unchecked((2, 0));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone()
|
|
|
|
|
- az.inlined_clone() * by.inlined_clone();
|
|
|
|
|
*res.get_unchecked_mut((1, 0)) = az.inlined_clone() * bx.inlined_clone()
|
|
|
|
|
- ax.inlined_clone() * bz.inlined_clone();
|
|
|
|
|
*res.get_unchecked_mut((2, 0)) = ax.inlined_clone() * by.inlined_clone()
|
|
|
|
|
- ay.inlined_clone() * bx.inlined_clone();
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
unsafe {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
// FIXME: ugly!
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let nrows = SameShapeR::<R, R2>::from_usize(1);
|
|
|
|
|
let ncols = SameShapeC::<C, C2>::from_usize(3);
|
|
|
|
|
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
|
|
|
|
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let ax = self.get_unchecked((0, 0));
|
|
|
|
|
let ay = self.get_unchecked((0, 1));
|
|
|
|
|
let az = self.get_unchecked((0, 2));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2019-12-06 06:54:17 +08:00
|
|
|
|
let bx = b.get_unchecked((0, 0));
|
|
|
|
|
let by = b.get_unchecked((0, 1));
|
|
|
|
|
let bz = b.get_unchecked((0, 2));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone()
|
|
|
|
|
- az.inlined_clone() * by.inlined_clone();
|
|
|
|
|
*res.get_unchecked_mut((0, 1)) = az.inlined_clone() * bx.inlined_clone()
|
|
|
|
|
- ax.inlined_clone() * bz.inlined_clone();
|
|
|
|
|
*res.get_unchecked_mut((0, 2)) = ax.inlined_clone() * by.inlined_clone()
|
|
|
|
|
- ay.inlined_clone() * bx.inlined_clone();
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar + Field, S: Storage<N, U3>> Vector<N, U3, S>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, U3>,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
{
|
2018-02-02 19:26:31 +08:00
|
|
|
|
/// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn cross_matrix(&self) -> MatrixN<N, U3> {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
MatrixN::<N, U3>::new(
|
|
|
|
|
N::zero(),
|
2019-12-06 06:54:17 +08:00
|
|
|
|
-self[2].inlined_clone(),
|
|
|
|
|
self[1].inlined_clone(),
|
|
|
|
|
self[2].inlined_clone(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
N::zero(),
|
2019-12-06 06:54:17 +08:00
|
|
|
|
-self[0].inlined_clone(),
|
|
|
|
|
-self[1].inlined_clone(),
|
|
|
|
|
self[0].inlined_clone(),
|
2018-02-02 19:26:35 +08:00
|
|
|
|
N::zero(),
|
|
|
|
|
)
|
2018-02-02 19:26:31 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 00:58:36 +08:00
|
|
|
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
/// The smallest angle between two vectors.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2020-03-18 00:58:36 +08:00
|
|
|
|
pub fn angle<R2: Dim, C2: Dim, SB>(&self, other: &Matrix<N, R2, C2, SB>) -> N::SimdRealField
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, R2, C2>,
|
|
|
|
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
|
|
|
|
{
|
2019-03-23 18:48:12 +08:00
|
|
|
|
let prod = self.dotc(other);
|
2018-02-02 19:26:35 +08:00
|
|
|
|
let n1 = self.norm();
|
|
|
|
|
let n2 = other.norm();
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
if n1.is_zero() || n2.is_zero() {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
N::SimdRealField::zero()
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
let cang = prod.simd_real() / (n1 * n2);
|
|
|
|
|
cang.simd_clamp(-N::SimdRealField::one(), N::SimdRealField::one())
|
|
|
|
|
.simd_acos()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-03 01:37:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 07:09:14 +08:00
|
|
|
|
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
|
2018-10-27 21:16:03 +08:00
|
|
|
|
Vector<N, D, S>
|
|
|
|
|
{
|
|
|
|
|
/// Returns `self * (1.0 - t) + rhs * t`, i.e., the linear blend of the vectors x and y using the scalar value a.
|
|
|
|
|
///
|
|
|
|
|
/// The value for a is not restricted to the range `[0, 1]`.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use nalgebra::Vector3;
|
|
|
|
|
/// let x = Vector3::new(1.0, 2.0, 3.0);
|
|
|
|
|
/// let y = Vector3::new(10.0, 20.0, 30.0);
|
|
|
|
|
/// assert_eq!(x.lerp(&y, 0.1), Vector3::new(1.9, 3.8, 5.7));
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn lerp<S2: Storage<N, D>>(&self, rhs: &Vector<N, D, S2>, t: N) -> VectorN<N, D>
|
2020-04-06 00:49:48 +08:00
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, D>,
|
|
|
|
|
{
|
2018-10-27 21:16:03 +08:00
|
|
|
|
let mut res = self.clone_owned();
|
2019-12-06 06:54:17 +08:00
|
|
|
|
res.axpy(t.inlined_clone(), rhs, N::one() - t);
|
2018-10-27 21:16:03 +08:00
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-24 06:27:20 +08:00
|
|
|
|
impl<N: RealField, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
|
2018-09-22 21:38:51 +08:00
|
|
|
|
/// Computes the spherical linear interpolation between two unit vectors.
|
2019-03-25 04:44:49 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Examples:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
2019-12-24 06:41:18 +08:00
|
|
|
|
/// # use nalgebra::{Unit, Vector2};
|
2019-03-25 04:44:49 +08:00
|
|
|
|
///
|
2019-12-24 06:41:18 +08:00
|
|
|
|
/// let v1 = Unit::new_normalize(Vector2::new(1.0, 2.0));
|
|
|
|
|
/// let v2 = Unit::new_normalize(Vector2::new(2.0, -3.0));
|
2019-03-25 04:44:49 +08:00
|
|
|
|
///
|
2019-12-24 06:27:20 +08:00
|
|
|
|
/// let v = v1.slerp(&v2, 1.0);
|
2019-03-25 04:44:49 +08:00
|
|
|
|
///
|
2019-12-24 06:27:20 +08:00
|
|
|
|
/// assert_eq!(v, v2);
|
2019-03-25 04:44:49 +08:00
|
|
|
|
/// ```
|
2018-10-16 04:44:01 +08:00
|
|
|
|
pub fn slerp<S2: Storage<N, D>>(
|
|
|
|
|
&self,
|
|
|
|
|
rhs: &Unit<Vector<N, D, S2>>,
|
2019-12-24 06:27:20 +08:00
|
|
|
|
t: N,
|
2018-10-16 04:44:01 +08:00
|
|
|
|
) -> Unit<VectorN<N, D>>
|
|
|
|
|
where
|
|
|
|
|
DefaultAllocator: Allocator<N, D>,
|
|
|
|
|
{
|
2018-09-22 21:38:51 +08:00
|
|
|
|
// FIXME: the result is wrong when self and rhs are collinear with opposite direction.
|
2019-12-24 06:27:20 +08:00
|
|
|
|
self.try_slerp(rhs, t, N::default_epsilon())
|
2018-10-16 04:44:01 +08:00
|
|
|
|
.unwrap_or(Unit::new_unchecked(self.clone_owned()))
|
2018-09-22 21:38:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Computes the spherical linear interpolation between two unit vectors.
|
|
|
|
|
///
|
|
|
|
|
/// Returns `None` if the two vectors are almost collinear and with opposite direction
|
|
|
|
|
/// (in this case, there is an infinity of possible results).
|
2018-10-16 04:44:01 +08:00
|
|
|
|
pub fn try_slerp<S2: Storage<N, D>>(
|
|
|
|
|
&self,
|
|
|
|
|
rhs: &Unit<Vector<N, D, S2>>,
|
2019-12-24 06:27:20 +08:00
|
|
|
|
t: N,
|
|
|
|
|
epsilon: N,
|
2018-10-16 04:44:01 +08:00
|
|
|
|
) -> Option<Unit<VectorN<N, D>>>
|
2018-09-22 21:38:51 +08:00
|
|
|
|
where
|
2018-10-16 04:44:01 +08:00
|
|
|
|
DefaultAllocator: Allocator<N, D>,
|
|
|
|
|
{
|
2019-12-24 06:27:20 +08:00
|
|
|
|
let c_hang = self.dot(rhs);
|
2018-09-22 21:38:51 +08:00
|
|
|
|
|
|
|
|
|
// self == other
|
2019-12-24 06:27:20 +08:00
|
|
|
|
if c_hang >= N::one() {
|
2018-09-22 21:38:51 +08:00
|
|
|
|
return Some(Unit::new_unchecked(self.clone_owned()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let hang = c_hang.acos();
|
2019-12-24 06:27:20 +08:00
|
|
|
|
let s_hang = (N::one() - c_hang * c_hang).sqrt();
|
2018-09-22 21:38:51 +08:00
|
|
|
|
|
|
|
|
|
// FIXME: what if s_hang is 0.0 ? The result is not well-defined.
|
2019-12-24 06:27:20 +08:00
|
|
|
|
if relative_eq!(s_hang, N::zero(), epsilon = epsilon) {
|
2018-09-22 21:38:51 +08:00
|
|
|
|
None
|
|
|
|
|
} else {
|
2019-12-24 06:27:20 +08:00
|
|
|
|
let ta = ((N::one() - t) * hang).sin() / s_hang;
|
2018-09-22 21:38:51 +08:00
|
|
|
|
let tb = (t * hang).sin() / s_hang;
|
2019-03-23 21:13:00 +08:00
|
|
|
|
let mut res = self.scale(ta);
|
2019-12-24 06:27:20 +08:00
|
|
|
|
res.axpy(tb, &**rhs, N::one());
|
2018-09-22 21:38:51 +08:00
|
|
|
|
|
|
|
|
|
Some(Unit::new_unchecked(res))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-19 21:41:58 +08:00
|
|
|
|
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + AbsDiffEq,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
2017-02-13 01:17:09 +08:00
|
|
|
|
type Epsilon = N::Epsilon;
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn default_epsilon() -> Self::Epsilon {
|
|
|
|
|
N::default_epsilon()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2018-05-19 21:41:58 +08:00
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
|
|
|
|
|
self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
|
2017-02-13 01:17:09 +08:00
|
|
|
|
}
|
2018-05-19 21:41:58 +08:00
|
|
|
|
}
|
2017-02-13 01:17:09 +08:00
|
|
|
|
|
2018-05-19 21:41:58 +08:00
|
|
|
|
impl<N, R: Dim, C: Dim, S> RelativeEq for Unit<Matrix<N, R, C, S>>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + RelativeEq,
|
2018-05-19 21:41:58 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
2017-02-13 01:17:09 +08:00
|
|
|
|
#[inline]
|
2018-05-19 21:41:58 +08:00
|
|
|
|
fn default_max_relative() -> Self::Epsilon {
|
|
|
|
|
N::default_max_relative()
|
2017-02-13 01:17:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
fn relative_eq(
|
|
|
|
|
&self,
|
|
|
|
|
other: &Self,
|
|
|
|
|
epsilon: Self::Epsilon,
|
|
|
|
|
max_relative: Self::Epsilon,
|
2020-04-06 00:49:48 +08:00
|
|
|
|
) -> bool {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
self.as_ref()
|
|
|
|
|
.relative_eq(other.as_ref(), epsilon, max_relative)
|
2017-02-13 01:17:09 +08:00
|
|
|
|
}
|
2018-05-19 21:41:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<N, R: Dim, C: Dim, S> UlpsEq for Unit<Matrix<N, R, C, S>>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + UlpsEq,
|
2018-05-19 21:41:58 +08:00
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
N::Epsilon: Copy,
|
|
|
|
|
{
|
|
|
|
|
#[inline]
|
|
|
|
|
fn default_max_ulps() -> u32 {
|
|
|
|
|
N::default_max_ulps()
|
|
|
|
|
}
|
2017-02-13 01:17:09 +08:00
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
|
|
|
|
|
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-28 01:05:25 +08:00
|
|
|
|
|
|
|
|
|
impl<N, R, C, S> Hash for Matrix<N, R, C, S>
|
|
|
|
|
where
|
2019-12-17 07:09:14 +08:00
|
|
|
|
N: Scalar + Hash,
|
2018-12-28 01:05:25 +08:00
|
|
|
|
R: Dim,
|
|
|
|
|
C: Dim,
|
|
|
|
|
S: Storage<N, R, C>,
|
|
|
|
|
{
|
|
|
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
|
|
let (nrows, ncols) = self.shape();
|
|
|
|
|
(nrows, ncols).hash(state);
|
|
|
|
|
|
|
|
|
|
for j in 0..ncols {
|
|
|
|
|
for i in 0..nrows {
|
|
|
|
|
unsafe {
|
2020-03-18 00:58:36 +08:00
|
|
|
|
self.get_unchecked((i, j)).hash(state);
|
2018-12-28 01:05:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|