From 45f2fc4f9297d3665f780f2516a59c23cd1f8888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 13 Nov 2020 17:26:47 +0100 Subject: [PATCH 1/8] Move all matrix decomposition methods under a single impl. --- src/base/matrix.rs | 15 ++ src/linalg/bidiagonal.rs | 17 +- src/linalg/cholesky.rs | 15 +- src/linalg/decomposition.rs | 232 ++++++++++++++++++++++++++++ src/linalg/full_piv_lu.rs | 12 -- src/linalg/hessenberg.rs | 12 +- src/linalg/lu.rs | 10 -- src/linalg/mod.rs | 1 + src/linalg/qr.rs | 10 -- src/linalg/schur.rs | 20 --- src/linalg/svd.rs | 25 --- src/linalg/symmetric_eigen.rs | 26 ---- src/linalg/symmetric_tridiagonal.rs | 14 +- 13 files changed, 252 insertions(+), 157 deletions(-) create mode 100644 src/linalg/decomposition.rs diff --git a/src/base/matrix.rs b/src/base/matrix.rs index ca7fa77b..2ba91826 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -75,6 +75,21 @@ pub type MatrixCross = /// Note that mixing `Dynamic` with type-level unsigned integers is allowed. Actually, a /// dynamically-sized column vector should be represented as a `Matrix` (given /// some concrete types for `N` and a compatible data storage type `S`). +/// +/// # Documentation by feature +/// Because `Matrix` is the most generic types that groups all matrix and vectors of **nalgebra** +/// this documentation page contains every single matrix/vector-related method. In order to make +/// browsing this page simpler, the next subsections contain direct links to groups of methods +/// related to a specific topic. +/// +/// #### Matrix decomposition +/// - [Rectangular matrix decomposition](#rectangular-matrix-decomposition). +/// - [Square matrix decomposition](#square-matrix-decomposition). +/// +/// #### Matrix slicing +/// - [Slicing](#slicing) +/// - [Mutable slicing](#mutable-slicing) +/// - [Range-based slicing](#range-based-slicing), [mutable range-based slicing](#mutable-range-based-slicing). #[repr(C)] #[derive(Clone, Copy)] pub struct Matrix { diff --git a/src/linalg/bidiagonal.rs b/src/linalg/bidiagonal.rs index c19a0662..3a789978 100644 --- a/src/linalg/bidiagonal.rs +++ b/src/linalg/bidiagonal.rs @@ -40,7 +40,7 @@ where + Allocator> + Allocator, U1>>, { - // FIXME: perhaps we should pack the axises into different vectors so that axises for `v_t` are + // FIXME: perhaps we should pack the axes into different vectors so that axes for `v_t` are // contiguous. This prevents some useless copies. uv: MatrixMN, /// The diagonal elements of the decomposed matrix. @@ -359,18 +359,3 @@ where // // res self.q_determinant() // // } // } - -impl, C: Dim, S: Storage> Matrix -where - DimMinimum: DimSub, - DefaultAllocator: Allocator - + Allocator - + Allocator - + Allocator> - + Allocator, U1>>, -{ - /// Computes the bidiagonalization using householder reflections. - pub fn bidiagonalize(self) -> Bidiagonal { - Bidiagonal::new(self.into_owned()) - } -} diff --git a/src/linalg/cholesky.rs b/src/linalg/cholesky.rs index 17187fdf..bd2f9281 100644 --- a/src/linalg/cholesky.rs +++ b/src/linalg/cholesky.rs @@ -6,7 +6,7 @@ use simba::scalar::ComplexField; use simba::simd::SimdComplexField; use crate::allocator::Allocator; -use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix, Vector}; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Vector}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1}; use crate::storage::{Storage, StorageMut}; @@ -363,16 +363,3 @@ where } } } - -impl> SquareMatrix -where - DefaultAllocator: Allocator, -{ - /// Attempts to compute the Cholesky decomposition of this matrix. - /// - /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed - /// to be symmetric and only the lower-triangular part is read. - pub fn cholesky(self) -> Option> { - Cholesky::new(self.into_owned()) - } -} diff --git a/src/linalg/decomposition.rs b/src/linalg/decomposition.rs new file mode 100644 index 00000000..67cc4c6a --- /dev/null +++ b/src/linalg/decomposition.rs @@ -0,0 +1,232 @@ +use crate::storage::Storage; +use crate::{ + Allocator, Bidiagonal, Cholesky, ComplexField, DefaultAllocator, Dim, DimDiff, DimMin, + DimMinimum, DimSub, FullPivLU, Hessenberg, Matrix, Schur, SymmetricEigen, SymmetricTridiagonal, + LU, QR, SVD, U1, +}; + +/// # Rectangular matrix decomposition +/// +/// This section contains the methods for computing some common decompositions of rectangular +/// matrices with real or complex components. The following are currently supported: +/// +/// | Decomposition | Factors | Details | +/// | -------------------------|---------------------|--------------| +/// | QR | `Q * R` | `Q` is an unitary matrix, and `R` is upper-triangular. | +/// | LU with partial pivoting | `P⁻¹ * L * U` | `L` is lower-triangular with a diagonal filled with `1` and `U` is upper-triangular. `P` is a permutation matrix. | +/// | LU with full pivoting | `P⁻¹ * L * U ~ Q⁻¹` | `L` is lower-triangular with a diagonal filled with `1` and `U` is upper-triangular. `P` and `Q` are permutation matrices. | +/// | SVD | `U * Σ * Vᵀ` | `U` and `V` are two orthogonal matrices and `Σ` is a diagonal matrix containing the singular values. | +impl> Matrix { + /// Computes the bidiagonalization using householder reflections. + pub fn bidiagonalize(self) -> Bidiagonal + where + R: DimMin, + DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator> + + Allocator, U1>>, + { + Bidiagonal::new(self.into_owned()) + } + + /// Computes the LU decomposition with full pivoting of `matrix`. + /// + /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`. + pub fn full_piv_lu(self) -> FullPivLU + where + R: DimMin, + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, + { + FullPivLU::new(self.into_owned()) + } + + /// Computes the LU decomposition with partial (row) pivoting of `matrix`. + pub fn lu(self) -> LU + where + R: DimMin, + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, + { + LU::new(self.into_owned()) + } + + /// Computes the QR decomposition of this matrix. + pub fn qr(self) -> QR + where + R: DimMin, + DefaultAllocator: Allocator + Allocator + Allocator>, + { + QR::new(self.into_owned()) + } + + /// Computes the Singular Value Decomposition using implicit shift. + pub fn svd(self, compute_u: bool, compute_v: bool) -> SVD + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, + { + SVD::new(self.into_owned(), compute_u, compute_v) + } + + /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. + /// + /// # Arguments + /// + /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. + /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_svd( + self, + compute_u: bool, + compute_v: bool, + eps: N::RealField, + max_niter: usize, + ) -> Option> + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, + { + SVD::try_new(self.into_owned(), compute_u, compute_v, eps, max_niter) + } +} + +/// # Square matrix decomposition +/// +/// This section contains the methods for computing some common decompositions of square +/// matrices with real or complex components. The following are currently supported: +/// +/// | Decomposition | Factors | Details | +/// | -------------------------|---------------------------|--------------| +/// | Hessenberg | `Q * H * Qᵀ` | `Q` is a unitary matrix and `H` an upper-Hessenberg matrix. | +/// | Cholesky | `L * Lᵀ` | `L` is a lower-triangular matrix. | +/// | Schur decomposition | `Q * T * Qᵀ` | `Q` is an unitary matrix and `T` a quasi-upper-triangular matrix. | +/// | Symmetric eigendecomposition | `Q ~ Λ ~ Qᵀ` | `Q` is an unitary matrix, and `Λ` is a real diagonal matrix. | +/// | Symmetric tridiagonalization | `Q ~ T ~ Qᵀ` | `Q` is an unitary matrix, and `T` is a tridiagonal matrix. | +impl> Matrix { + /// Attempts to compute the Cholesky decomposition of this matrix. + /// + /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed + /// to be symmetric and only the lower-triangular part is read. + pub fn cholesky(self) -> Option> + where + DefaultAllocator: Allocator, + { + Cholesky::new(self.into_owned()) + } + + /// Computes the Hessenberg decomposition of this matrix using householder reflections. + pub fn hessenberg(self) -> Hessenberg + where + D: DimSub, + DefaultAllocator: Allocator + Allocator + Allocator>, + { + Hessenberg::new(self.into_owned()) + } + + /// Computes the Schur decomposition of a square matrix. + pub fn schur(self) -> Schur + where + D: DimSub, // For Hessenberg. + DefaultAllocator: Allocator> + + Allocator> + + Allocator + + Allocator, + { + Schur::new(self.into_owned()) + } + + /// Attempts to compute the Schur decomposition of a square matrix. + /// + /// If only eigenvalues are needed, it is more efficient to call the matrix method + /// `.eigenvalues()` instead. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_schur(self, eps: N::RealField, max_niter: usize) -> Option> + where + D: DimSub, // For Hessenberg. + DefaultAllocator: Allocator> + + Allocator> + + Allocator + + Allocator, + { + Schur::try_new(self.into_owned(), eps, max_niter) + } + + /// Computes the eigendecomposition of this symmetric matrix. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + pub fn symmetric_eigen(self) -> SymmetricEigen + where + D: DimSub, + DefaultAllocator: Allocator + + Allocator> + + Allocator + + Allocator>, + { + SymmetricEigen::new(self.into_owned()) + } + + /// Computes the eigendecomposition of the given symmetric matrix with user-specified + /// convergence parameters. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_symmetric_eigen( + self, + eps: N::RealField, + max_niter: usize, + ) -> Option> + where + D: DimSub, + DefaultAllocator: Allocator + + Allocator> + + Allocator + + Allocator>, + { + SymmetricEigen::try_new(self.into_owned(), eps, max_niter) + } + + /// Computes the tridiagonalization of this symmetric matrix. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + pub fn symmetric_tridiagonalize(self) -> SymmetricTridiagonal + where + D: DimSub, + DefaultAllocator: Allocator + Allocator>, + { + SymmetricTridiagonal::new(self.into_owned()) + } +} diff --git a/src/linalg/full_piv_lu.rs b/src/linalg/full_piv_lu.rs index 146b2cb7..fb8ff670 100644 --- a/src/linalg/full_piv_lu.rs +++ b/src/linalg/full_piv_lu.rs @@ -257,15 +257,3 @@ where } } } - -impl, C: Dim, S: Storage> Matrix -where - DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, -{ - /// Computes the LU decomposition with full pivoting of `matrix`. - /// - /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`. - pub fn full_piv_lu(self) -> FullPivLU { - FullPivLU::new(self.into_owned()) - } -} diff --git a/src/linalg/hessenberg.rs b/src/linalg/hessenberg.rs index 57a24097..1e795b41 100644 --- a/src/linalg/hessenberg.rs +++ b/src/linalg/hessenberg.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::allocator::Allocator; -use crate::base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; +use crate::base::{DefaultAllocator, MatrixMN, MatrixN, VectorN}; use crate::dimension::{DimDiff, DimSub, U1}; use crate::storage::Storage; use simba::scalar::ComplexField; @@ -131,13 +131,3 @@ where &self.hess } } - -impl, S: Storage> SquareMatrix -where - DefaultAllocator: Allocator + Allocator + Allocator>, -{ - /// Computes the Hessenberg decomposition of this matrix using householder reflections. - pub fn hessenberg(self) -> Hessenberg { - Hessenberg::new(self.into_owned()) - } -} diff --git a/src/linalg/lu.rs b/src/linalg/lu.rs index 6aa84d62..9e417f10 100644 --- a/src/linalg/lu.rs +++ b/src/linalg/lu.rs @@ -379,13 +379,3 @@ pub fn gauss_step_swap( .axpy(-pivot_row[k].inlined_clone(), &coeffs, N::one()); } } - -impl, C: Dim, S: Storage> Matrix -where - DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, -{ - /// Computes the LU decomposition with partial (row) pivoting of `matrix`. - pub fn lu(self) -> LU { - LU::new(self.into_owned()) - } -} diff --git a/src/linalg/mod.rs b/src/linalg/mod.rs index 4a1edbcf..df265498 100644 --- a/src/linalg/mod.rs +++ b/src/linalg/mod.rs @@ -8,6 +8,7 @@ mod determinant; // FIXME: this should not be needed. However, the exp uses // explicit float operations on `f32` and `f64`. We need to // get rid of these to allow exp to be used on a no-std context. +mod decomposition; #[cfg(feature = "std")] mod exp; mod full_piv_lu; diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index 48d7a896..d3cf3275 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -288,13 +288,3 @@ where // res self.q_determinant() // } } - -impl, C: Dim, S: Storage> Matrix -where - DefaultAllocator: Allocator + Allocator + Allocator>, -{ - /// Computes the QR decomposition of this matrix. - pub fn qr(self) -> QR { - QR::new(self.into_owned()) - } -} diff --git a/src/linalg/schur.rs b/src/linalg/schur.rs index 8d8be72d..1292bad7 100644 --- a/src/linalg/schur.rs +++ b/src/linalg/schur.rs @@ -496,26 +496,6 @@ where + Allocator + Allocator, { - /// Computes the Schur decomposition of a square matrix. - pub fn schur(self) -> Schur { - Schur::new(self.into_owned()) - } - - /// Attempts to compute the Schur decomposition of a square matrix. - /// - /// If only eigenvalues are needed, it is more efficient to call the matrix method - /// `.eigenvalues()` instead. - /// - /// # Arguments - /// - /// * `eps` − tolerance used to determine when a value converged to 0. - /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this - /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm - /// continues indefinitely until convergence. - pub fn try_schur(self, eps: N::RealField, max_niter: usize) -> Option> { - Schur::try_new(self.into_owned(), eps, max_niter) - } - /// Computes the eigenvalues of this matrix. pub fn eigenvalues(&self) -> Option> { assert!( diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index 94ec4d96..93cba072 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -616,31 +616,6 @@ where + Allocator> + Allocator, U1>>, { - /// Computes the Singular Value Decomposition using implicit shift. - pub fn svd(self, compute_u: bool, compute_v: bool) -> SVD { - SVD::new(self.into_owned(), compute_u, compute_v) - } - - /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. - /// - /// # Arguments - /// - /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. - /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. - /// * `eps` − tolerance used to determine when a value converged to 0. - /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this - /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm - /// continues indefinitely until convergence. - pub fn try_svd( - self, - compute_u: bool, - compute_v: bool, - eps: N::RealField, - max_niter: usize, - ) -> Option> { - SVD::try_new(self.into_owned(), compute_u, compute_v, eps, max_niter) - } - /// Computes the singular values of this matrix. pub fn singular_values(&self) -> VectorN> { SVD::new(self.clone_owned(), false, false).singular_values diff --git a/src/linalg/symmetric_eigen.rs b/src/linalg/symmetric_eigen.rs index 2d62816e..64d3515a 100644 --- a/src/linalg/symmetric_eigen.rs +++ b/src/linalg/symmetric_eigen.rs @@ -308,32 +308,6 @@ where + Allocator + Allocator>, { - /// Computes the eigendecomposition of this symmetric matrix. - /// - /// Only the lower-triangular part (including the diagonal) of `m` is read. - pub fn symmetric_eigen(self) -> SymmetricEigen { - SymmetricEigen::new(self.into_owned()) - } - - /// Computes the eigendecomposition of the given symmetric matrix with user-specified - /// convergence parameters. - /// - /// Only the lower-triangular part (including the diagonal) of `m` is read. - /// - /// # Arguments - /// - /// * `eps` − tolerance used to determine when a value converged to 0. - /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this - /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm - /// continues indefinitely until convergence. - pub fn try_symmetric_eigen( - self, - eps: N::RealField, - max_niter: usize, - ) -> Option> { - SymmetricEigen::try_new(self.into_owned(), eps, max_niter) - } - /// Computes the eigenvalues of this symmetric matrix. /// /// Only the lower-triangular part of the matrix is read. diff --git a/src/linalg/symmetric_tridiagonal.rs b/src/linalg/symmetric_tridiagonal.rs index f4dc13ba..e8d9fb5d 100644 --- a/src/linalg/symmetric_tridiagonal.rs +++ b/src/linalg/symmetric_tridiagonal.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::allocator::Allocator; -use crate::base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; +use crate::base::{DefaultAllocator, MatrixMN, MatrixN, VectorN}; use crate::dimension::{DimDiff, DimSub, U1}; use crate::storage::Storage; use simba::scalar::ComplexField; @@ -162,15 +162,3 @@ where &q * self.tri * q.adjoint() } } - -impl, S: Storage> SquareMatrix -where - DefaultAllocator: Allocator + Allocator>, -{ - /// Computes the tridiagonalization of this symmetric matrix. - /// - /// Only the lower-triangular part (including the diagonal) of `m` is read. - pub fn symmetric_tridiagonalize(self) -> SymmetricTridiagonal { - SymmetricTridiagonal::new(self.into_owned()) - } -} From 4c2192d9e0c896c8d5d338f3e9b155d5448b1265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 13 Nov 2020 18:34:33 +0100 Subject: [PATCH 2/8] Reorganize matrix slice macros. --- src/base/matrix_slice.rs | 649 ++++++++++++++++++++------------------- 1 file changed, 329 insertions(+), 320 deletions(-) diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs index abb11725..534df70d 100644 --- a/src/base/matrix_slice.rs +++ b/src/base/matrix_slice.rs @@ -274,367 +274,370 @@ macro_rules! matrix_slice_impl( $generic_slice_with_steps: ident, $rows_range_pair: ident, $columns_range_pair: ident) => { - /// A matrix slice. - pub type $MatrixSlice<'a, N, R, C, RStride, CStride> - = Matrix>; + /* + * + * Row slicing. + * + */ + /// Returns a slice containing the i-th row of this matrix. + #[inline] + pub fn $row($me: $Me, i: usize) -> $MatrixSlice { + $me.$fixed_rows::(i) + } - impl> Matrix { - /* - * - * Row slicing. - * - */ - /// Returns a slice containing the i-th row of this matrix. - #[inline] - pub fn $row($me: $Me, i: usize) -> $MatrixSlice { - $me.$fixed_rows::(i) + /// Returns a slice containing the `n` first elements of the i-th row of this matrix. + #[inline] + pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { + $me.$generic_slice((i, 0), (U1, Dynamic::new(n))) + } + + /// Extracts from this matrix a set of consecutive rows. + #[inline] + pub fn $rows($me: $Me, first_row: usize, nrows: usize) + -> $MatrixSlice { + + $me.$rows_generic(first_row, Dynamic::new(nrows)) + } + + /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows. + #[inline] + pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) + -> $MatrixSlice { + + $me.$rows_generic_with_step(first_row, Dynamic::new(nrows), step) + } + + /// Extracts a compile-time number of consecutive rows from this matrix. + #[inline] + pub fn $fixed_rows($me: $Me, first_row: usize) + -> $MatrixSlice { + + $me.$rows_generic(first_row, RSlice::name()) + } + + /// Extracts from this matrix a compile-time number of rows regularly skipping `step` + /// rows. + #[inline] + pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) + -> $MatrixSlice { + + $me.$rows_generic_with_step(first_row, RSlice::name(), step) + } + + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic($me: $Me, row_start: usize, nrows: RSlice) + -> $MatrixSlice { + + let my_shape = $me.data.shape(); + $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); + + let shape = (nrows, my_shape.1); + + unsafe { + let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape); + Matrix::from_data_statically_unchecked(data) } + } - /// Returns a slice containing the `n` first elements of the i-th row of this matrix. - #[inline] - pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { - $me.$generic_slice((i, 0), (U1, Dynamic::new(n))) + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RSlice, step: usize) + -> $MatrixSlice + where RSlice: Dim { + + let my_shape = $me.data.shape(); + let my_strides = $me.data.strides(); + $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); + + let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1); + let shape = (nrows, my_shape.1); + + unsafe { + let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts from this matrix a set of consecutive rows. - #[inline] - pub fn $rows($me: $Me, first_row: usize, nrows: usize) - -> $MatrixSlice { + /* + * + * Column slicing. + * + */ + /// Returns a slice containing the i-th column of this matrix. + #[inline] + pub fn $column($me: $Me, i: usize) -> $MatrixSlice { + $me.$fixed_columns::(i) + } - $me.$rows_generic(first_row, Dynamic::new(nrows)) + /// Returns a slice containing the `n` first elements of the i-th column of this matrix. + #[inline] + pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { + $me.$generic_slice((0, i), (Dynamic::new(n), U1)) + } + + /// Extracts from this matrix a set of consecutive columns. + #[inline] + pub fn $columns($me: $Me, first_col: usize, ncols: usize) + -> $MatrixSlice { + + $me.$columns_generic(first_col, Dynamic::new(ncols)) + } + + /// Extracts from this matrix a set of consecutive columns regularly skipping `step` + /// columns. + #[inline] + pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) + -> $MatrixSlice { + + $me.$columns_generic_with_step(first_col, Dynamic::new(ncols), step) + } + + /// Extracts a compile-time number of consecutive columns from this matrix. + #[inline] + pub fn $fixed_columns($me: $Me, first_col: usize) + -> $MatrixSlice { + + $me.$columns_generic(first_col, CSlice::name()) + } + + /// Extracts from this matrix a compile-time number of columns regularly skipping + /// `step` columns. + #[inline] + pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) + -> $MatrixSlice { + + $me.$columns_generic_with_step(first_col, CSlice::name(), step) + } + + /// Extracts from this matrix `ncols` columns. The number of columns may or may not be + /// known at compile-time. + #[inline] + pub fn $columns_generic($me: $Me, first_col: usize, ncols: CSlice) + -> $MatrixSlice { + + let my_shape = $me.data.shape(); + $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows. - #[inline] - pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) - -> $MatrixSlice { - $me.$rows_generic_with_step(first_row, Dynamic::new(nrows), step) + /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may + /// or may not be values known at compile-time. + #[inline] + pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CSlice, step: usize) + -> $MatrixSlice { + + let my_shape = $me.data.shape(); + let my_strides = $me.data.strides(); + + $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); + + let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value())); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts a compile-time number of consecutive rows from this matrix. - #[inline] - pub fn $fixed_rows($me: $Me, first_row: usize) - -> $MatrixSlice { + /* + * + * General slicing. + * + */ + /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` + /// consecutive elements. + #[inline] + pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) + -> $MatrixSlice { - $me.$rows_generic(first_row, RSlice::name()) + $me.assert_slice_index(start, shape, (0, 0)); + let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); + + unsafe { + let data = $SliceStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts from this matrix a compile-time number of rows regularly skipping `step` - /// rows. - #[inline] - pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) - -> $MatrixSlice { - $me.$rows_generic_with_step(first_row, RSlice::name(), step) + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is + /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the + /// original matrix. + #[inline] + pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) + -> $MatrixSlice { + let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); + + $me.$generic_slice_with_steps(start, shape, steps) + } + + /// Slices this matrix starting at its component `(irow, icol)` and with `(R::dim(), + /// CSlice::dim())` consecutive components. + #[inline] + pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) + -> $MatrixSlice + where RSlice: DimName, + CSlice: DimName { + + $me.assert_slice_index((irow, icol), (RSlice::dim(), CSlice::dim()), (0, 0)); + let shape = (RSlice::name(), CSlice::name()); + + unsafe { + let data = $SliceStorage::new_unchecked($data, (irow, icol), shape); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both - /// argument may or may not be values known at compile-time. - #[inline] - pub fn $rows_generic($me: $Me, row_start: usize, nrows: RSlice) - -> $MatrixSlice { + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(R::dim(), CSlice::dim())` components. Each row (resp. column) of the sliced + /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of + /// the original matrix. + #[inline] + pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) + -> $MatrixSlice + where RSlice: DimName, + CSlice: DimName { + let shape = (RSlice::name(), CSlice::name()); + $me.$generic_slice_with_steps(start, shape, steps) + } - let my_shape = $me.data.shape(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) + -> $MatrixSlice + where RSlice: Dim, + CSlice: Dim { - let shape = (nrows, my_shape.1); + $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0)); - unsafe { - let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape); - Matrix::from_data_statically_unchecked(data) - } + unsafe { + let data = $SliceStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) } + } - /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both - /// argument may or may not be values known at compile-time. - #[inline] - pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RSlice, step: usize) - -> $MatrixSlice - where RSlice: Dim { + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_slice_with_steps($me: $Me, + start: (usize, usize), + shape: (RSlice, CSlice), + steps: (usize, usize)) + -> $MatrixSlice + where RSlice: Dim, + CSlice: Dim { - let my_shape = $me.data.shape(); - let my_strides = $me.data.strides(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); + $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), steps); - let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1); - let shape = (nrows, my_shape.1); + let my_strides = $me.data.strides(); + let strides = (Dynamic::new((steps.0 + 1) * my_strides.0.value()), + Dynamic::new((steps.1 + 1) * my_strides.1.value())); - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); - Matrix::from_data_statically_unchecked(data) - } + unsafe { + let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides); + Matrix::from_data_statically_unchecked(data) } + } - /* - * - * Column slicing. - * - */ - /// Returns a slice containing the i-th column of this matrix. - #[inline] - pub fn $column($me: $Me, i: usize) -> $MatrixSlice { - $me.$fixed_columns::(i) + /* + * + * Splitting. + * + */ + /// Splits this NxM matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $rows_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixSlice, + $MatrixSlice) { + + let (nrows, ncols) = $me.data.shape(); + let strides = $me.data.strides(); + + let start1 = r1.begin(nrows); + let start2 = r2.begin(nrows); + + let end1 = r1.end(nrows); + let end2 = r2.end(nrows); + + let nrows1 = r1.size(nrows); + let nrows2 = r2.size(nrows); + + assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the slice ranges must not overlap."); + assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(start1, 0); + let ptr2 = $data.$get_addr(start2, 0); + + let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); + let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); + let slice1 = Matrix::from_data_statically_unchecked(data1); + let slice2 = Matrix::from_data_statically_unchecked(data2); + + (slice1, slice2) } + } - /// Returns a slice containing the `n` first elements of the i-th column of this matrix. - #[inline] - pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { - $me.$generic_slice((0, i), (Dynamic::new(n), U1)) - } + /// Splits this NxM matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $columns_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixSlice, + $MatrixSlice) { - /// Extracts from this matrix a set of consecutive columns. - #[inline] - pub fn $columns($me: $Me, first_col: usize, ncols: usize) - -> $MatrixSlice { + let (nrows, ncols) = $me.data.shape(); + let strides = $me.data.strides(); - $me.$columns_generic(first_col, Dynamic::new(ncols)) - } + let start1 = r1.begin(ncols); + let start2 = r2.begin(ncols); - /// Extracts from this matrix a set of consecutive columns regularly skipping `step` - /// columns. - #[inline] - pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) - -> $MatrixSlice { + let end1 = r1.end(ncols); + let end2 = r2.end(ncols); - $me.$columns_generic_with_step(first_col, Dynamic::new(ncols), step) - } + let ncols1 = r1.size(ncols); + let ncols2 = r2.size(ncols); - /// Extracts a compile-time number of consecutive columns from this matrix. - #[inline] - pub fn $fixed_columns($me: $Me, first_col: usize) - -> $MatrixSlice { + assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the slice ranges must not overlap."); + assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); - $me.$columns_generic(first_col, CSlice::name()) - } + unsafe { + let ptr1 = $data.$get_addr(0, start1); + let ptr2 = $data.$get_addr(0, start2); - /// Extracts from this matrix a compile-time number of columns regularly skipping - /// `step` columns. - #[inline] - pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) - -> $MatrixSlice { + let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); + let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); + let slice1 = Matrix::from_data_statically_unchecked(data1); + let slice2 = Matrix::from_data_statically_unchecked(data2); - $me.$columns_generic_with_step(first_col, CSlice::name(), step) - } - - /// Extracts from this matrix `ncols` columns. The number of columns may or may not be - /// known at compile-time. - #[inline] - pub fn $columns_generic($me: $Me, first_col: usize, ncols: CSlice) - -> $MatrixSlice { - - let my_shape = $me.data.shape(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); - let shape = (my_shape.0, ncols); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); - Matrix::from_data_statically_unchecked(data) - } - } - - - /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may - /// or may not be values known at compile-time. - #[inline] - pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CSlice, step: usize) - -> $MatrixSlice { - - let my_shape = $me.data.shape(); - let my_strides = $me.data.strides(); - - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); - - let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value())); - let shape = (my_shape.0, ncols); - - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); - Matrix::from_data_statically_unchecked(data) - } - } - - /* - * - * General slicing. - * - */ - /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` - /// consecutive elements. - #[inline] - pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) - -> $MatrixSlice { - - $me.assert_slice_index(start, shape, (0, 0)); - let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); - - unsafe { - let data = $SliceStorage::new_unchecked($data, start, shape); - Matrix::from_data_statically_unchecked(data) - } - } - - - /// Slices this matrix starting at its component `(start.0, start.1)` and with - /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is - /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the - /// original matrix. - #[inline] - pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice { - let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); - - $me.$generic_slice_with_steps(start, shape, steps) - } - - /// Slices this matrix starting at its component `(irow, icol)` and with `(R::dim(), - /// CSlice::dim())` consecutive components. - #[inline] - pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) - -> $MatrixSlice - where RSlice: DimName, - CSlice: DimName { - - $me.assert_slice_index((irow, icol), (RSlice::dim(), CSlice::dim()), (0, 0)); - let shape = (RSlice::name(), CSlice::name()); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (irow, icol), shape); - Matrix::from_data_statically_unchecked(data) - } - } - - /// Slices this matrix starting at its component `(start.0, start.1)` and with - /// `(R::dim(), CSlice::dim())` components. Each row (resp. column) of the sliced - /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of - /// the original matrix. - #[inline] - pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice - where RSlice: DimName, - CSlice: DimName { - let shape = (RSlice::name(), CSlice::name()); - $me.$generic_slice_with_steps(start, shape, steps) - } - - /// Creates a slice that may or may not have a fixed size and stride. - #[inline] - pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) - -> $MatrixSlice - where RSlice: Dim, - CSlice: Dim { - - $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0)); - - unsafe { - let data = $SliceStorage::new_unchecked($data, start, shape); - Matrix::from_data_statically_unchecked(data) - } - } - - /// Creates a slice that may or may not have a fixed size and stride. - #[inline] - pub fn $generic_slice_with_steps($me: $Me, - start: (usize, usize), - shape: (RSlice, CSlice), - steps: (usize, usize)) - -> $MatrixSlice - where RSlice: Dim, - CSlice: Dim { - - $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), steps); - - let my_strides = $me.data.strides(); - let strides = (Dynamic::new((steps.0 + 1) * my_strides.0.value()), - Dynamic::new((steps.1 + 1) * my_strides.1.value())); - - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides); - Matrix::from_data_statically_unchecked(data) - } - } - - /* - * - * Splitting. - * - */ - /// Splits this NxM matrix into two parts delimited by two ranges. - /// - /// Panics if the ranges overlap or if the first range is empty. - #[inline] - pub fn $rows_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) - -> ($MatrixSlice, - $MatrixSlice) { - - let (nrows, ncols) = $me.data.shape(); - let strides = $me.data.strides(); - - let start1 = r1.begin(nrows); - let start2 = r2.begin(nrows); - - let end1 = r1.end(nrows); - let end2 = r2.end(nrows); - - let nrows1 = r1.size(nrows); - let nrows2 = r2.size(nrows); - - assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the slice ranges must not overlap."); - assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); - - unsafe { - let ptr1 = $data.$get_addr(start1, 0); - let ptr2 = $data.$get_addr(start2, 0); - - let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); - let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); - let slice1 = Matrix::from_data_statically_unchecked(data1); - let slice2 = Matrix::from_data_statically_unchecked(data2); - - (slice1, slice2) - } - } - - /// Splits this NxM matrix into two parts delimited by two ranges. - /// - /// Panics if the ranges overlap or if the first range is empty. - #[inline] - pub fn $columns_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) - -> ($MatrixSlice, - $MatrixSlice) { - - let (nrows, ncols) = $me.data.shape(); - let strides = $me.data.strides(); - - let start1 = r1.begin(ncols); - let start2 = r2.begin(ncols); - - let end1 = r1.end(ncols); - let end2 = r2.end(ncols); - - let ncols1 = r1.size(ncols); - let ncols2 = r2.size(ncols); - - assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the slice ranges must not overlap."); - assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); - - unsafe { - let ptr1 = $data.$get_addr(0, start1); - let ptr2 = $data.$get_addr(0, start2); - - let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); - let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); - let slice1 = Matrix::from_data_statically_unchecked(data1); - let slice2 = Matrix::from_data_statically_unchecked(data2); - - (slice1, slice2) - } + (slice1, slice2) } } } ); -matrix_slice_impl!( +/// A matrix slice. +pub type MatrixSlice<'a, N, R, C, RStride, CStride> = + Matrix>; +/// A mutable matrix slice. +pub type MatrixSliceMut<'a, N, R, C, RStride, CStride> = + Matrix>; + +/// # Slicing based on index and length +impl> Matrix { + matrix_slice_impl!( self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data; row, row_part, @@ -660,8 +663,11 @@ matrix_slice_impl!( generic_slice_with_steps, rows_range_pair, columns_range_pair); +} -matrix_slice_impl!( +/// # Mutable slicing based on index and length +impl> Matrix { + matrix_slice_impl!( self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut.get_address_unchecked_mut(), &mut self.data; row_mut, row_part_mut, @@ -687,6 +693,7 @@ matrix_slice_impl!( generic_slice_with_steps_mut, rows_range_pair_mut, columns_range_pair_mut); +} /// A range with a size that may be known at compile-time. /// @@ -803,6 +810,7 @@ impl SliceRange for RangeFull { } } +/// # Slicing based on ranges impl> Matrix { /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed /// by the range `cols`. @@ -842,6 +850,7 @@ impl> Matrix { } } +/// # Mutable slicing based on ranges impl> Matrix { /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns /// indexed by the range `cols`. From 9a4cf0b69fd0d320f26ce8f0afe99831fa4993c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 13 Nov 2020 18:34:47 +0100 Subject: [PATCH 3/8] Reorganize matrix construction macros. --- src/base/construction.rs | 518 ++++++++++++++++++++------------------- src/base/matrix.rs | 67 +++-- 2 files changed, 316 insertions(+), 269 deletions(-) diff --git a/src/base/construction.rs b/src/base/construction.rs index aa4cf956..4718309b 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -22,11 +22,12 @@ use crate::base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6}; use crate::base::storage::Storage; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, Unit, Vector, VectorN}; -/* - * - * Generic constructors. - * - */ +/// # Generic constructors +/// This set of matrix and vector construction functions are all generic +/// with-regard to the matrix dimensions. They all expect to be given +/// the dimension as inputs. +/// +/// These functions should only be used when working on dimension-generic code. impl MatrixMN where DefaultAllocator: Allocator, @@ -350,275 +351,290 @@ where */ macro_rules! impl_constructors( ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { - impl MatrixMN - where DefaultAllocator: Allocator { - - /// Creates a new uninitialized matrix or vector. - #[inline] - pub unsafe fn new_uninitialized($($args: usize),*) -> Self { - Self::new_uninitialized_generic($($gargs),*) - } - - /// Creates a matrix or vector with all its elements set to `elem`. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; - /// - /// let v = Vector3::from_element(2.0); - /// // The additional argument represents the vector dimension. - /// let dv = DVector::from_element(3, 2.0); - /// let m = Matrix2x3::from_element(2.0); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::from_element(2, 3, 2.0); - /// - /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); - /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); - /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && - /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); - /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && - /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); - /// ``` - #[inline] - pub fn from_element($($args: usize,)* elem: N) -> Self { - Self::from_element_generic($($gargs, )* elem) - } - - /// Creates a matrix or vector with all its elements set to `elem`. - /// - /// Same as `.from_element`. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; - /// - /// let v = Vector3::repeat(2.0); - /// // The additional argument represents the vector dimension. - /// let dv = DVector::repeat(3, 2.0); - /// let m = Matrix2x3::repeat(2.0); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::repeat(2, 3, 2.0); - /// - /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); - /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); - /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && - /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); - /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && - /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); - /// ``` - #[inline] - pub fn repeat($($args: usize,)* elem: N) -> Self { - Self::repeat_generic($($gargs, )* elem) - } - - /// Creates a matrix or vector with all its elements set to `0`. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; - /// - /// let v = Vector3::::zeros(); - /// // The argument represents the vector dimension. - /// let dv = DVector::::zeros(3); - /// let m = Matrix2x3::::zeros(); - /// // The two arguments represent the matrix dimensions. - /// let dm = DMatrix::::zeros(2, 3); - /// - /// assert!(v.x == 0.0 && v.y == 0.0 && v.z == 0.0); - /// assert!(dv[0] == 0.0 && dv[1] == 0.0 && dv[2] == 0.0); - /// assert!(m.m11 == 0.0 && m.m12 == 0.0 && m.m13 == 0.0 && - /// m.m21 == 0.0 && m.m22 == 0.0 && m.m23 == 0.0); - /// assert!(dm[(0, 0)] == 0.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && - /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 0.0 && dm[(1, 2)] == 0.0); - /// ``` - #[inline] - pub fn zeros($($args: usize),*) -> Self - where N: Zero { - Self::zeros_generic($($gargs),*) - } - - /// Creates a matrix or vector with all its elements filled by an iterator. - /// - /// The output matrix is filled column-by-column. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; - /// # use std::iter; - /// - /// let v = Vector3::from_iterator((0..3).into_iter()); - /// // The additional argument represents the vector dimension. - /// let dv = DVector::from_iterator(3, (0..3).into_iter()); - /// let m = Matrix2x3::from_iterator((0..6).into_iter()); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::from_iterator(2, 3, (0..6).into_iter()); - /// - /// assert!(v.x == 0 && v.y == 1 && v.z == 2); - /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); - /// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 && - /// m.m21 == 1 && m.m22 == 3 && m.m23 == 5); - /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 && - /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); - /// ``` - #[inline] - pub fn from_iterator($($args: usize,)* iter: I) -> Self - where I: IntoIterator { - Self::from_iterator_generic($($gargs, )* iter) - } - - /// Creates a matrix or vector filled with the results of a function applied to each of its - /// component coordinates. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; - /// # use std::iter; - /// - /// let v = Vector3::from_fn(|i, _| i); - /// // The additional argument represents the vector dimension. - /// let dv = DVector::from_fn(3, |i, _| i); - /// let m = Matrix2x3::from_fn(|i, j| i * 3 + j); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::from_fn(2, 3, |i, j| i * 3 + j); - /// - /// assert!(v.x == 0 && v.y == 1 && v.z == 2); - /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); - /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && - /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); - /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && - /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); - /// ``` - #[inline] - pub fn from_fn($($args: usize,)* f: F) -> Self - where F: FnMut(usize, usize) -> N { - Self::from_fn_generic($($gargs, )* f) - } - - /// Creates an identity matrix. If the matrix is not square, the largest square - /// submatrix (starting at the first row and column) is set to the identity while all - /// other entries are set to zero. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, DMatrix}; - /// # use std::iter; - /// - /// let m = Matrix2x3::::identity(); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::::identity(2, 3); - /// - /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && - /// m.m21 == 0.0 && m.m22 == 1.0 && m.m23 == 0.0); - /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && - /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 1.0 && dm[(1, 2)] == 0.0); - /// ``` - #[inline] - pub fn identity($($args: usize,)*) -> Self - where N: Zero + One { - Self::identity_generic($($gargs),* ) - } - - /// Creates a matrix filled with its diagonal filled with `elt` and all other - /// components set to zero. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix2x3, DMatrix}; - /// # use std::iter; - /// - /// let m = Matrix2x3::from_diagonal_element(5.0); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::from_diagonal_element(2, 3, 5.0); - /// - /// assert!(m.m11 == 5.0 && m.m12 == 0.0 && m.m13 == 0.0 && - /// m.m21 == 0.0 && m.m22 == 5.0 && m.m23 == 0.0); - /// assert!(dm[(0, 0)] == 5.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && - /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 5.0 && dm[(1, 2)] == 0.0); - /// ``` - #[inline] - pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self - where N: Zero + One { - Self::from_diagonal_element_generic($($gargs, )* elt) - } - - /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal - /// elements are filled with the content of `elts`. Others are set to 0. - /// - /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. - /// - /// # Example - /// ``` - /// # use nalgebra::{Matrix3, DMatrix}; - /// # use std::iter; - /// - /// let m = Matrix3::from_partial_diagonal(&[1.0, 2.0]); - /// // The two additional arguments represent the matrix dimensions. - /// let dm = DMatrix::from_partial_diagonal(3, 3, &[1.0, 2.0]); - /// - /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && - /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && - /// m.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 0.0); - /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && - /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 && - /// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 0.0); - /// ``` - #[inline] - pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self - where N: Zero { - Self::from_partial_diagonal_generic($($gargs, )* elts) - } - - /// Creates a matrix or vector filled with random values from the given distribution. - #[inline] - pub fn from_distribution + ?Sized, G: Rng + ?Sized>( - $($args: usize,)* - distribution: &Distr, - rng: &mut G, - ) -> Self { - Self::from_distribution_generic($($gargs, )* distribution, rng) - } + /// Creates a new uninitialized matrix or vector. + #[inline] + pub unsafe fn new_uninitialized($($args: usize),*) -> Self { + Self::new_uninitialized_generic($($gargs),*) } - impl MatrixMN - where - DefaultAllocator: Allocator, - Standard: Distribution { + /// Creates a matrix or vector with all its elements set to `elem`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::from_element(2.0); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_element(3, 2.0); + /// let m = Matrix2x3::from_element(2.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_element(2, 3, 2.0); + /// + /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); + /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); + /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && + /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); + /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && + /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); + /// ``` + #[inline] + pub fn from_element($($args: usize,)* elem: N) -> Self { + Self::from_element_generic($($gargs, )* elem) + } - /// Creates a matrix filled with random values. - #[inline] - #[cfg(feature = "std")] - pub fn new_random($($args: usize),*) -> Self { - Self::new_random_generic($($gargs),*) - } + /// Creates a matrix or vector with all its elements set to `elem`. + /// + /// Same as `.from_element`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::repeat(2.0); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::repeat(3, 2.0); + /// let m = Matrix2x3::repeat(2.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::repeat(2, 3, 2.0); + /// + /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); + /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); + /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && + /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); + /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && + /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); + /// ``` + #[inline] + pub fn repeat($($args: usize,)* elem: N) -> Self { + Self::repeat_generic($($gargs, )* elem) + } + + /// Creates a matrix or vector with all its elements set to `0`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::::zeros(); + /// // The argument represents the vector dimension. + /// let dv = DVector::::zeros(3); + /// let m = Matrix2x3::::zeros(); + /// // The two arguments represent the matrix dimensions. + /// let dm = DMatrix::::zeros(2, 3); + /// + /// assert!(v.x == 0.0 && v.y == 0.0 && v.z == 0.0); + /// assert!(dv[0] == 0.0 && dv[1] == 0.0 && dv[2] == 0.0); + /// assert!(m.m11 == 0.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 0.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 0.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 0.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn zeros($($args: usize),*) -> Self + where N: Zero { + Self::zeros_generic($($gargs),*) + } + + /// Creates a matrix or vector with all its elements filled by an iterator. + /// + /// The output matrix is filled column-by-column. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_iterator((0..3).into_iter()); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_iterator(3, (0..3).into_iter()); + /// let m = Matrix2x3::from_iterator((0..6).into_iter()); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_iterator(2, 3, (0..6).into_iter()); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 && + /// m.m21 == 1 && m.m22 == 3 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 && + /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_iterator($($args: usize,)* iter: I) -> Self + where I: IntoIterator { + Self::from_iterator_generic($($gargs, )* iter) + } + + /// Creates a matrix or vector filled with the results of a function applied to each of its + /// component coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_fn(|i, _| i); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_fn(3, |i, _| i); + /// let m = Matrix2x3::from_fn(|i, j| i * 3 + j); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_fn(2, 3, |i, j| i * 3 + j); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && + /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && + /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_fn($($args: usize,)* f: F) -> Self + where F: FnMut(usize, usize) -> N { + Self::from_fn_generic($($gargs, )* f) + } + + /// Creates an identity matrix. If the matrix is not square, the largest square + /// submatrix (starting at the first row and column) is set to the identity while all + /// other entries are set to zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix2x3::::identity(); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::::identity(2, 3); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 1.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 1.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn identity($($args: usize,)*) -> Self + where N: Zero + One { + Self::identity_generic($($gargs),* ) + } + + /// Creates a matrix filled with its diagonal filled with `elt` and all other + /// components set to zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix2x3::from_diagonal_element(5.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_diagonal_element(2, 3, 5.0); + /// + /// assert!(m.m11 == 5.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 5.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 5.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 5.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self + where N: Zero + One { + Self::from_diagonal_element_generic($($gargs, )* elt) + } + + /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal + /// elements are filled with the content of `elts`. Others are set to 0. + /// + /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix3::from_partial_diagonal(&[1.0, 2.0]); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_partial_diagonal(3, 3, &[1.0, 2.0]); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && + /// m.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 0.0); + /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 && + /// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 0.0); + /// ``` + #[inline] + pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self + where N: Zero { + Self::from_partial_diagonal_generic($($gargs, )* elts) + } + + /// Creates a matrix or vector filled with random values from the given distribution. + #[inline] + pub fn from_distribution + ?Sized, G: Rng + ?Sized>( + $($args: usize,)* + distribution: &Distr, + rng: &mut G, + ) -> Self { + Self::from_distribution_generic($($gargs, )* distribution, rng) + } + + /// Creates a matrix filled with random values. + #[inline] + #[cfg(feature = "std")] + pub fn new_random($($args: usize),*) -> Self + where Standard: Distribution { + Self::new_random_generic($($gargs),*) } } ); -// FIXME: this is not very pretty. We could find a better call syntax. -impl_constructors!(R, C; // Arguments for Matrix -=> R: DimName, => C: DimName; // Type parameters for impl -R::name(), C::name(); // Arguments for `_generic` constructors. -); // Arguments for non-generic constructors. +/// # Constructors of statically-sized vectors or statically-sized matrices +impl MatrixMN +where + DefaultAllocator: Allocator, +{ + // FIXME: this is not very pretty. We could find a better call syntax. + impl_constructors!(R, C; // Arguments for Matrix + => R: DimName, => C: DimName; // Type parameters for impl + R::name(), C::name(); // Arguments for `_generic` constructors. + ); // Arguments for non-generic constructors. +} -impl_constructors!(R, Dynamic; +/// # Constructors of matrices with a dynamic number of columns +impl MatrixMN +where + DefaultAllocator: Allocator, +{ + impl_constructors!(R, Dynamic; => R: DimName; R::name(), Dynamic::new(ncols); ncols); +} -impl_constructors!(Dynamic, C; +/// # Constructors of dynamic vectors and matrices with a dynamic number of rows +impl MatrixMN +where + DefaultAllocator: Allocator, +{ + impl_constructors!(Dynamic, C; => C: DimName; Dynamic::new(nrows), C::name(); nrows); +} -impl_constructors!(Dynamic, Dynamic; +/// # Constructors of fully dynamic matrices +impl MatrixMN +where + DefaultAllocator: Allocator, +{ + impl_constructors!(Dynamic, Dynamic; ; Dynamic::new(nrows), Dynamic::new(ncols); nrows, ncols); +} /* * * Constructors that don't necessarily require all dimensions - * to be specified whon one dimension is already known. + * to be specified when one dimension is already known. * */ macro_rules! impl_constructors_from_data( diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 2ba91826..b510d9af 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -54,7 +54,34 @@ pub type MatrixCross = /// The most generic column-major matrix (and vector) type. /// -/// It combines four type parameters: +/// # Methods summary +/// Because `Matrix` is the most generic types that groups all matrix and vectors of **nalgebra** +/// this documentation page contains every single matrix/vector-related method. In order to make +/// browsing this page simpler, the next subsections contain direct links to groups of methods +/// related to a specific topic. +/// +/// #### Vector and matrix construction +/// - [Constructors of statically-sized vectors or statically-sized matrices](#constructors-of-statically-sized-vectors-or-statically-sized-matrices) +/// (`Vector3`, `Matrix3x6`, etc.) +/// - [Constructors of fully dynamic matrices](#constructors-of-fully-dynamic-matrices) (`DMatrix`) +/// - [Constructors of dynamic vectors and matrices with a dynamic number of rows](#constructors-of-dynamic-vectors-and-matrices-with-a-dynamic-number-of-rows) +/// (`DVector`, `MatrixXx3`, etc.) +/// - [Constructors of matrices with a dynamic number of columns](#constructors-of-matrices-with-a-dynamic-number-of-columns) +/// (`Matrix2xX`, etc.) +/// - [Generic constructors](#generic-constructors) +/// (For code generic wrt. the vectors or matrices dimensions.) +/// #### Matrix decomposition +/// - [Rectangular matrix decomposition](#rectangular-matrix-decomposition) (Applicable to square matrices too) +/// - [Square matrix decomposition](#square-matrix-decomposition) +/// +/// #### Vector and matrix slicing +/// - [Slicing based on index and length](#slicing-based-on-index-and-length) +/// - [Mutable slicing based on index and length](#mutable-slicing-based-on-index-and-length) +/// - [Slicing based on ranges](#slicing-based-on-ranges) +/// - [Mutable slicing based on ranges](#mutable-slicing-based-on-ranges) +/// +/// # Type parameters +/// The generic `Matrix` type has four type parameters: /// - `N`: for the matrix components scalar type. /// - `R`: for the matrix number of rows. /// - `C`: for the matrix number of columns. @@ -75,26 +102,30 @@ pub type MatrixCross = /// Note that mixing `Dynamic` with type-level unsigned integers is allowed. Actually, a /// dynamically-sized column vector should be represented as a `Matrix` (given /// some concrete types for `N` and a compatible data storage type `S`). -/// -/// # Documentation by feature -/// Because `Matrix` is the most generic types that groups all matrix and vectors of **nalgebra** -/// this documentation page contains every single matrix/vector-related method. In order to make -/// browsing this page simpler, the next subsections contain direct links to groups of methods -/// related to a specific topic. -/// -/// #### Matrix decomposition -/// - [Rectangular matrix decomposition](#rectangular-matrix-decomposition). -/// - [Square matrix decomposition](#square-matrix-decomposition). -/// -/// #### Matrix slicing -/// - [Slicing](#slicing) -/// - [Mutable slicing](#mutable-slicing) -/// - [Range-based slicing](#range-based-slicing), [mutable range-based slicing](#mutable-range-based-slicing). #[repr(C)] #[derive(Clone, Copy)] pub struct Matrix { - /// The data storage that contains all the matrix components and informations about its number - /// of rows and column (if needed). + /// The data storage that contains all the matrix components. Disappointed? + /// + /// Well, if you came here to see how you can access the matrix components, + /// you may be in luck: you can access the individual components of all vectors with compile-time + /// dimensions <= 6 using field notation like this: + /// `vec.x`, `vec.y`, `vec.z`, `vec.w`, `vec.a`, `vec.b`. Reference and assignation work too: + /// ```.ignore + /// let mut v = Vector3::new(1.0, 2.0, 3.0); + /// vec.x = 10.0; + /// my_function(&vec.z); + /// println!("{}", vec.y + 30.0); + /// ``` + /// Similarly, for matrices with compile-time dimensions <= 6, you can use field notation + /// like this: `mat.m11`, `mat.m42`, etc. The first digit identifies the row to address + /// and the second digit identifies the column to address. So `mat.m13` identifies the component + /// at the first row and third column (note that the count of rows and columns start at 1 instead + /// of 0 here. This is so we match the mathematical notation). + /// + /// For all matrices and vectors, independently from their size, individual components can + /// be accessed and modified using indexing: `vec[20]`, `mat[(20, 19)]`. Here the indexing + /// starts at 0 as you would expect. pub data: S, _phantoms: PhantomData<(N, R, C)>, From b8d1ae3a1fe0516aa5ee06fecac8359168a51fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 13 Nov 2020 18:35:23 +0100 Subject: [PATCH 4/8] Add aliases for matrices with only one dynamic dimension. --- src/base/alias.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/base/alias.rs b/src/base/alias.rs index e798ea35..2cba116b 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -27,6 +27,44 @@ pub type MatrixN = MatrixMN; #[cfg(any(feature = "std", feature = "alloc"))] pub type DMatrix = MatrixN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 1 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx1 = MatrixMN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 2 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx2 = MatrixMN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 3 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx3 = MatrixMN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 4 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx4 = MatrixMN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 5 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx5 = MatrixMN; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 6 columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx6 = MatrixMN; + +/// A heap-allocated, row-major, matrix with 1 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix1xX = MatrixMN; +/// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix2xX = MatrixMN; +/// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix3xX = MatrixMN; +/// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix4xX = MatrixMN; +/// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix5xX = MatrixMN; +/// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix6xX = MatrixMN; + /// A stack-allocated, column-major, 1x1 square matrix. pub type Matrix1 = MatrixN; /// A stack-allocated, column-major, 2x2 square matrix. From e852df6124bd75ab3d2bcdf2e6cf26347d30cf63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sun, 15 Nov 2020 16:57:49 +0100 Subject: [PATCH 5/8] Add sections for most Matrix methods. --- nalgebra-glm/src/common.rs | 10 +- nalgebra-glm/src/gtc/constants.rs | 2 +- nalgebra-glm/src/gtc/matrix_inverse.rs | 2 +- nalgebra-glm/src/gtc/quaternion.rs | 6 +- nalgebra-lapack/src/cholesky.rs | 2 +- nalgebra-lapack/src/eigen.rs | 4 +- nalgebra-lapack/src/lapack_check.rs | 2 +- nalgebra-lapack/src/lu.rs | 2 +- nalgebra-lapack/src/svd.rs | 8 +- src/base/allocator.rs | 2 +- src/base/blas.rs | 268 +--------- src/base/cg.rs | 15 +- src/base/componentwise.rs | 365 +++++++------- src/base/construction.rs | 8 +- src/base/construction_slice.rs | 174 ++++--- src/base/conversion.rs | 2 +- src/base/dimension.rs | 2 +- src/base/edition.rs | 185 +++---- src/base/indexing.rs | 2 +- src/base/interpolation.rs | 122 +++++ src/base/iter.rs | 2 +- src/base/matrix.rs | 571 +++++++++++----------- src/base/matrix_alga.rs | 6 +- src/base/matrix_slice.rs | 6 +- src/base/min_max.rs | 390 +++++++++++++++ src/base/mod.rs | 2 + src/base/norm.rs | 69 ++- src/base/ops.rs | 156 +----- src/base/properties.rs | 6 +- src/base/statistics.rs | 34 +- src/base/storage.rs | 4 +- src/base/swizzle.rs | 98 ++-- src/base/unit.rs | 2 +- src/geometry/isometry_ops.rs | 30 +- src/geometry/mod.rs | 2 +- src/geometry/op_macros.rs | 6 +- src/geometry/orthographic.rs | 4 +- src/geometry/perspective.rs | 6 +- src/geometry/point_conversion.rs | 2 +- src/geometry/point_ops.rs | 4 +- src/geometry/quaternion.rs | 2 +- src/geometry/quaternion_construction.rs | 10 +- src/geometry/quaternion_ops.rs | 14 +- src/geometry/reflection.rs | 4 +- src/geometry/rotation_ops.rs | 10 +- src/geometry/rotation_specialization.rs | 2 +- src/geometry/similarity_conversion.rs | 4 +- src/geometry/similarity_ops.rs | 16 +- src/geometry/transform.rs | 4 +- src/geometry/transform_alga.rs | 2 +- src/geometry/transform_ops.rs | 26 +- src/geometry/translation_ops.rs | 4 +- src/geometry/unit_complex.rs | 2 +- src/geometry/unit_complex_construction.rs | 6 +- src/io/matrix_market.rs | 6 +- src/linalg/bidiagonal.rs | 14 +- src/linalg/givens.rs | 2 +- src/linalg/hessenberg.rs | 2 +- src/linalg/householder.rs | 2 +- src/linalg/mod.rs | 4 +- src/linalg/qr.rs | 8 +- src/linalg/schur.rs | 8 +- src/linalg/solve.rs | 4 +- src/linalg/svd.rs | 6 +- src/sparse/cs_matrix.rs | 2 +- src/sparse/cs_matrix_cholesky.rs | 6 +- tests/core/matrix.rs | 2 +- tests/linalg/eigen.rs | 2 +- 68 files changed, 1473 insertions(+), 1284 deletions(-) create mode 100644 src/base/interpolation.rs create mode 100644 src/base/min_max.rs diff --git a/nalgebra-glm/src/common.rs b/nalgebra-glm/src/common.rs index 1a5c0c2a..2df38714 100644 --- a/nalgebra-glm/src/common.rs +++ b/nalgebra-glm/src/common.rs @@ -239,9 +239,9 @@ where x.map(|x| x.floor()) } -//// FIXME: should be implemented for TVec/TMat? +//// TODO: should be implemented for TVec/TMat? //pub fn fma(a: N, b: N, c: N) -> N { -// // FIXME: use an actual FMA +// // TODO: use an actual FMA // a * b + c //} @@ -268,10 +268,10 @@ where x.map(|x| x.fract()) } -//// FIXME: should be implemented for TVec/TMat? +//// TODO: should be implemented for TVec/TMat? ///// Returns the (significant, exponent) of this float number. //pub fn frexp(x: N, exp: N) -> (N, N) { -// // FIXME: is there a better approach? +// // TODO: is there a better approach? // let e = x.log2().ceil(); // (x * (-e).exp2(), e) //} @@ -327,7 +327,7 @@ where ///// Returns the (significant, exponent) of this float number. //pub fn ldexp(x: N, exp: N) -> N { -// // FIXME: is there a better approach? +// // TODO: is there a better approach? // x * (exp).exp2() //} diff --git a/nalgebra-glm/src/gtc/constants.rs b/nalgebra-glm/src/gtc/constants.rs index 4112d65e..81375ee3 100644 --- a/nalgebra-glm/src/gtc/constants.rs +++ b/nalgebra-glm/src/gtc/constants.rs @@ -227,7 +227,7 @@ pub fn root_three() -> N { /// * [`root_five`](fn.root_five.html) /// * [`root_three`](fn.root_three.html) pub fn root_two() -> N { - // FIXME: there should be a crate::sqrt_2() on the RealField trait. + // TODO: there should be a crate::sqrt_2() on the RealField trait. na::convert::<_, N>(2.0).sqrt() } diff --git a/nalgebra-glm/src/gtc/matrix_inverse.rs b/nalgebra-glm/src/gtc/matrix_inverse.rs index feab0daa..c71a11f9 100644 --- a/nalgebra-glm/src/gtc/matrix_inverse.rs +++ b/nalgebra-glm/src/gtc/matrix_inverse.rs @@ -8,7 +8,7 @@ pub fn affine_inverse(m: TMat) -> TMat, { - // FIXME: this should be optimized. + // TODO: this should be optimized. m.try_inverse().unwrap_or_else(TMat::<_, D, D>::zeros) } diff --git a/nalgebra-glm/src/gtc/quaternion.rs b/nalgebra-glm/src/gtc/quaternion.rs index 36977e96..63a42511 100644 --- a/nalgebra-glm/src/gtc/quaternion.rs +++ b/nalgebra-glm/src/gtc/quaternion.rs @@ -57,18 +57,18 @@ pub fn quat_look_at_rh(direction: &TVec3, up: &TVec3) -> Qua /// The "roll" Euler angle of the quaternion `x` assumed to be normalized. pub fn quat_roll(x: &Qua) -> N { - // FIXME: optimize this. + // TODO: optimize this. quat_euler_angles(x).z } /// The "yaw" Euler angle of the quaternion `x` assumed to be normalized. pub fn quat_yaw(x: &Qua) -> N { - // FIXME: optimize this. + // TODO: optimize this. quat_euler_angles(x).y } /// The "pitch" Euler angle of the quaternion `x` assumed to be normalized. pub fn quat_pitch(x: &Qua) -> N { - // FIXME: optimize this. + // TODO: optimize this. quat_euler_angles(x).x } diff --git a/nalgebra-lapack/src/cholesky.rs b/nalgebra-lapack/src/cholesky.rs index 669fa671..93bf2443 100644 --- a/nalgebra-lapack/src/cholesky.rs +++ b/nalgebra-lapack/src/cholesky.rs @@ -48,7 +48,7 @@ where /// Only the lower-triangular part of the input matrix is considered. #[inline] pub fn new(mut m: MatrixN) -> Option { - // FIXME: check symmetry as well? + // TODO: check symmetry as well? assert!( m.is_square(), "Unable to compute the cholesky decomposition of a non-square matrix." diff --git a/nalgebra-lapack/src/eigen.rs b/nalgebra-lapack/src/eigen.rs index 8164c844..1ccd6e3f 100644 --- a/nalgebra-lapack/src/eigen.rs +++ b/nalgebra-lapack/src/eigen.rs @@ -79,7 +79,7 @@ where let lda = n as i32; let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, U1) }; - // FIXME: Tap into the workspace. + // TODO: Tap into the workspace. let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, U1) }; let mut info = 0; @@ -379,6 +379,6 @@ macro_rules! real_eigensystem_scalar_impl ( real_eigensystem_scalar_impl!(f32, lapack::sgeev); real_eigensystem_scalar_impl!(f64, lapack::dgeev); -//// FIXME: decomposition of complex matrix and matrices with complex eigenvalues. +//// TODO: decomposition of complex matrix and matrices with complex eigenvalues. // eigensystem_complex_impl!(f32, lapack::cgeev); // eigensystem_complex_impl!(f64, lapack::zgeev); diff --git a/nalgebra-lapack/src/lapack_check.rs b/nalgebra-lapack/src/lapack_check.rs index 217699dc..d98dd204 100644 --- a/nalgebra-lapack/src/lapack_check.rs +++ b/nalgebra-lapack/src/lapack_check.rs @@ -2,7 +2,7 @@ macro_rules! lapack_check( ($info: expr) => ( - // FIXME: return a richer error. + // TODO: return a richer error. if $info != 0 { return None; } diff --git a/nalgebra-lapack/src/lu.rs b/nalgebra-lapack/src/lu.rs index 0ff185d5..17245fb9 100644 --- a/nalgebra-lapack/src/lu.rs +++ b/nalgebra-lapack/src/lu.rs @@ -119,7 +119,7 @@ where id } - // FIXME: when we support resizing a matrix, we could add unwrap_u/unwrap_l that would + // TODO: when we support resizing a matrix, we could add unwrap_u/unwrap_l that would // re-use the memory from the internal matrix! /// Gets the LAPACK permutation indices. diff --git a/nalgebra-lapack/src/svd.rs b/nalgebra-lapack/src/svd.rs index 217e8f52..18b4957f 100644 --- a/nalgebra-lapack/src/svd.rs +++ b/nalgebra-lapack/src/svd.rs @@ -37,9 +37,9 @@ where DefaultAllocator: Allocator + Allocator> + Allocator, { /// The left-singular vectors `U` of this SVD. - pub u: MatrixN, // FIXME: should be MatrixMN> + pub u: MatrixN, // TODO: should be MatrixMN> /// The right-singular vectors `V^t` of this SVD. - pub vt: MatrixN, // FIXME: should be MatrixMN, C> + pub vt: MatrixN, // TODO: should be MatrixMN, C> /// The singular values of this SVD. pub singular_values: VectorN>, } @@ -134,7 +134,7 @@ macro_rules! svd_impl( } impl, C: Dim> SVD<$t, R, C> - // FIXME: All those bounds… + // TODO: All those bounds… where DefaultAllocator: Allocator<$t, R, C> + Allocator<$t, C, R> + Allocator<$t, U1, R> + @@ -219,7 +219,7 @@ macro_rules! svd_impl( i } - // FIXME: add methods to retrieve the null-space and column-space? (Respectively + // TODO: add methods to retrieve the null-space and column-space? (Respectively // corresponding to the zero and non-zero singular values). } ); diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 1b2122db..ebd55553 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -56,7 +56,7 @@ pub type SameShapeR = >::Rep /// The number of columns of the result of a componentwise operation on two matrices. pub type SameShapeC = >::Representative; -// FIXME: Bad name. +// TODO: Bad name. /// Restricts the given number of rows and columns to be respectively the same. pub trait SameShapeAllocator: Allocator + Allocator, SameShapeC> diff --git a/src/base/blas.rs b/src/base/blas.rs index f245f24a..2ebc8051 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -16,258 +16,7 @@ use crate::base::{ DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSliceN, }; -// FIXME: find a way to avoid code duplication just for complex number support. -impl> Vector { - /// Computes the index of the vector component with the largest complex or real absolute value. - /// - /// # Examples: - /// - /// ``` - /// # extern crate num_complex; - /// # extern crate nalgebra; - /// # use num_complex::Complex; - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(Complex::new(11.0, 3.0), Complex::new(-15.0, 0.0), Complex::new(13.0, 5.0)); - /// assert_eq!(vec.icamax(), 2); - /// ``` - #[inline] - pub fn icamax(&self) -> usize { - assert!(!self.is_empty(), "The input vector must not be empty."); - - let mut the_max = unsafe { self.vget_unchecked(0).norm1() }; - let mut the_i = 0; - - for i in 1..self.nrows() { - let val = unsafe { self.vget_unchecked(i).norm1() }; - - if val > the_max { - the_max = val; - the_i = i; - } - } - - the_i - } -} - -impl> Vector { - /// Computes the index and value of the vector component with the largest value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.argmax(), (2, 13)); - /// ``` - #[inline] - pub fn argmax(&self) -> (usize, N) { - assert!(!self.is_empty(), "The input vector must not be empty."); - - let mut the_max = unsafe { self.vget_unchecked(0) }; - let mut the_i = 0; - - for i in 1..self.nrows() { - let val = unsafe { self.vget_unchecked(i) }; - - if val > the_max { - the_max = val; - the_i = i; - } - } - - (the_i, the_max.inlined_clone()) - } - - /// Computes the index of the vector component with the largest value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.imax(), 2); - /// ``` - #[inline] - pub fn imax(&self) -> usize { - self.argmax().0 - } - - /// Computes the index of the vector component with the largest absolute value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.iamax(), 1); - /// ``` - #[inline] - pub fn iamax(&self) -> usize - where - N: Signed, - { - assert!(!self.is_empty(), "The input vector must not be empty."); - - let mut the_max = unsafe { self.vget_unchecked(0).abs() }; - let mut the_i = 0; - - for i in 1..self.nrows() { - let val = unsafe { self.vget_unchecked(i).abs() }; - - if val > the_max { - the_max = val; - the_i = i; - } - } - - the_i - } - - /// Computes the index and value of the vector component with the smallest value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.argmin(), (1, -15)); - /// ``` - #[inline] - pub fn argmin(&self) -> (usize, N) { - assert!(!self.is_empty(), "The input vector must not be empty."); - - let mut the_min = unsafe { self.vget_unchecked(0) }; - let mut the_i = 0; - - for i in 1..self.nrows() { - let val = unsafe { self.vget_unchecked(i) }; - - if val < the_min { - the_min = val; - the_i = i; - } - } - - (the_i, the_min.inlined_clone()) - } - - /// Computes the index of the vector component with the smallest value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.imin(), 1); - /// ``` - #[inline] - pub fn imin(&self) -> usize { - self.argmin().0 - } - - /// Computes the index of the vector component with the smallest absolute value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Vector3; - /// let vec = Vector3::new(11, -15, 13); - /// assert_eq!(vec.iamin(), 0); - /// ``` - #[inline] - pub fn iamin(&self) -> usize - where - N: Signed, - { - assert!(!self.is_empty(), "The input vector must not be empty."); - - let mut the_min = unsafe { self.vget_unchecked(0).abs() }; - let mut the_i = 0; - - for i in 1..self.nrows() { - let val = unsafe { self.vget_unchecked(i).abs() }; - - if val < the_min { - the_min = val; - the_i = i; - } - } - - the_i - } -} - -// FIXME: find a way to avoid code duplication just for complex number support. -impl> Matrix { - /// Computes the index of the matrix component with the largest absolute value. - /// - /// # Examples: - /// - /// ``` - /// # extern crate num_complex; - /// # extern crate nalgebra; - /// # use num_complex::Complex; - /// # use nalgebra::Matrix2x3; - /// let mat = Matrix2x3::new(Complex::new(11.0, 1.0), Complex::new(-12.0, 2.0), Complex::new(13.0, 3.0), - /// Complex::new(21.0, 43.0), Complex::new(22.0, 5.0), Complex::new(-23.0, 0.0)); - /// assert_eq!(mat.icamax_full(), (1, 0)); - /// ``` - #[inline] - pub fn icamax_full(&self) -> (usize, usize) { - assert!(!self.is_empty(), "The input matrix must not be empty."); - - let mut the_max = unsafe { self.get_unchecked((0, 0)).norm1() }; - let mut the_ij = (0, 0); - - for j in 0..self.ncols() { - for i in 0..self.nrows() { - let val = unsafe { self.get_unchecked((i, j)).norm1() }; - - if val > the_max { - the_max = val; - the_ij = (i, j); - } - } - } - - the_ij - } -} - -impl> Matrix { - /// Computes the index of the matrix component with the largest absolute value. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::Matrix2x3; - /// let mat = Matrix2x3::new(11, -12, 13, - /// 21, 22, -23); - /// assert_eq!(mat.iamax_full(), (1, 2)); - /// ``` - #[inline] - pub fn iamax_full(&self) -> (usize, usize) { - assert!(!self.is_empty(), "The input matrix must not be empty."); - - let mut the_max = unsafe { self.get_unchecked((0, 0)).abs() }; - let mut the_ij = (0, 0); - - for j in 0..self.ncols() { - for i in 0..self.nrows() { - let val = unsafe { self.get_unchecked((i, j)).abs() }; - - if val > the_max { - the_max = val; - the_ij = (i, j); - } - } - } - - the_ij - } -} - +/// # Dot/scalar product impl> Matrix where N: Scalar + Zero + ClosedAdd + ClosedMul, @@ -562,6 +311,7 @@ where } } +/// # BLAS functions impl Vector where N: Scalar + Zero + ClosedAdd + ClosedMul, @@ -675,7 +425,7 @@ where return; } - // FIXME: avoid bound checks. + // TODO: avoid bound checks. let col2 = a.column(0); let val = unsafe { x.vget_unchecked(0).inlined_clone() }; self.axcpy(alpha.inlined_clone(), &col2, val, beta); @@ -722,7 +472,7 @@ where return; } - // FIXME: avoid bound checks. + // TODO: avoid bound checks. let col2 = a.column(0); let val = unsafe { x.vget_unchecked(0).inlined_clone() }; self.axpy(alpha.inlined_clone() * val, &col2, beta); @@ -992,7 +742,7 @@ where ); for j in 0..ncols1 { - // FIXME: avoid bound checks. + // TODO: avoid bound checks. let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) }; self.column_mut(j) .axpy(alpha.inlined_clone() * val, x, beta.inlined_clone()); @@ -1208,7 +958,7 @@ where } for j1 in 0..ncols1 { - // FIXME: avoid bound checks. + // TODO: avoid bound checks. self.column_mut(j1).gemv( alpha.inlined_clone(), a, @@ -1270,7 +1020,7 @@ where ); for j1 in 0..ncols1 { - // FIXME: avoid bound checks. + // TODO: avoid bound checks. self.column_mut(j1).gemv_tr( alpha.inlined_clone(), a, @@ -1332,7 +1082,7 @@ where ); for j1 in 0..ncols1 { - // FIXME: avoid bound checks. + // TODO: avoid bound checks. self.column_mut(j1).gemv_ad(alpha, a, &b.column(j1), beta); } } @@ -1369,7 +1119,7 @@ where for j in 0..dim1 { let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) }; let subdim = Dynamic::new(dim1 - j); - // FIXME: avoid bound checks. + // TODO: avoid bound checks. self.generic_slice_mut((j, j), (subdim, U1)).axpy( alpha.inlined_clone() * val, &x.rows_range(j..), diff --git a/src/base/cg.rs b/src/base/cg.rs index 935388af..ba319c7e 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -21,6 +21,7 @@ use crate::geometry::{ use simba::scalar::{ClosedAdd, ClosedMul, RealField}; +/// # Translation and scaling in any dimension impl MatrixN where N: Scalar + Zero + One, @@ -65,6 +66,7 @@ where } } +/// # 2D transformations as a Matrix3 impl Matrix3 { /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian. #[inline] @@ -93,6 +95,7 @@ impl Matrix3 { } } +/// # 3D transformations as a Matrix4 impl Matrix4 { /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// @@ -200,6 +203,7 @@ impl Matrix4 { } } +/// # Append/prepend translation and scaling impl> SquareMatrix { @@ -293,15 +297,12 @@ impl> - SquareMatrix -{ /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor. #[inline] pub fn append_scaling_mut(&mut self, scaling: N) where + S: StorageMut, D: DimNameSub, { let mut to_scale = self.fixed_rows_mut::>(0); @@ -312,6 +313,7 @@ impl, D: DimNameSub, { let mut to_scale = self.fixed_columns_mut::>(0); @@ -322,6 +324,7 @@ impl(&mut self, scaling: &Vector, SB>) where + S: StorageMut, D: DimNameSub, SB: Storage>, { @@ -337,6 +340,7 @@ impl, SB>, ) where + S: StorageMut, D: DimNameSub, SB: Storage>, { @@ -350,6 +354,7 @@ impl(&mut self, shift: &Vector, SB>) where + S: StorageMut, D: DimNameSub, SB: Storage>, { @@ -366,6 +371,7 @@ impl(&mut self, shift: &Vector, SB>) where D: DimNameSub, + S: StorageMut, SB: Storage>, DefaultAllocator: Allocator>, { @@ -382,6 +388,7 @@ impl, S: Storage> SquareMatrix where DefaultAllocator: Allocator diff --git a/src/base/componentwise.rs b/src/base/componentwise.rs index d5a57b6c..dcc4ece1 100644 --- a/src/base/componentwise.rs +++ b/src/base/componentwise.rs @@ -11,6 +11,7 @@ use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstr use crate::base::dimension::Dim; use crate::base::storage::{Storage, StorageMut}; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar}; +use crate::ClosedAdd; /// The type of the result of a matrix component-wise operation. pub type MatrixComponentOp = MatrixSum; @@ -41,226 +42,256 @@ impl> Matrix { res } - // FIXME: add other operators like component_ln, component_pow, etc. ? + // TODO: add other operators like component_ln, component_pow, etc. ? } macro_rules! component_binop_impl( ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$( - impl> Matrix { - #[doc = $desc] - #[inline] - pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp - where N: $Trait, - R2: Dim, C2: Dim, - SB: Storage, - DefaultAllocator: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + #[doc = $desc] + #[inline] + pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp + where N: $Trait, + R2: Dim, C2: Dim, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); - let mut res = self.clone_owned_sum(); + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + let mut res = self.clone_owned_sum(); - for j in 0 .. res.ncols() { - for i in 0 .. res.nrows() { - unsafe { - res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); - } + for j in 0 .. res.ncols() { + for i in 0 .. res.nrows() { + unsafe { + res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); } } - - res } + + res } - impl> Matrix { - // componentwise binop plus Y. - #[doc = $desc_cmpy] - #[inline] - pub fn $cmpy(&mut self, alpha: N, a: &Matrix, b: &Matrix, beta: N) - where N: $Trait + Zero + Mul + Add, - R2: Dim, C2: Dim, - R3: Dim, C3: Dim, - SB: Storage, - SC: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + - SameNumberOfRows + SameNumberOfColumns { - assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions."); - assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions."); - - if beta.is_zero() { - for j in 0 .. self.ncols() { - for i in 0 .. self.nrows() { - unsafe { - let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); - *self.get_unchecked_mut((i, j)) = res; - } - } - } - } - else { - for j in 0 .. self.ncols() { - for i in 0 .. self.nrows() { - unsafe { - let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); - *self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res; - } - } - } - } - } - - #[doc = $desc_mut] - #[inline] - pub fn $binop_assign(&mut self, rhs: &Matrix) - where N: $Trait, - R2: Dim, - C2: Dim, - SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - - assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + // componentwise binop plus Y. + #[doc = $desc_cmpy] + #[inline] + pub fn $cmpy(&mut self, alpha: N, a: &Matrix, b: &Matrix, beta: N) + where N: $Trait + Zero + Mul + Add, + R2: Dim, C2: Dim, + R3: Dim, C3: Dim, + SA: StorageMut, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + + SameNumberOfRows + SameNumberOfColumns { + assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + if beta.is_zero() { for j in 0 .. self.ncols() { for i in 0 .. self.nrows() { unsafe { - self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); + let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); + *self.get_unchecked_mut((i, j)) = res; } } } } - - #[doc = $desc_mut] - #[inline] - #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")] - pub fn $binop_mut(&mut self, rhs: &Matrix) - where N: $Trait, - R2: Dim, - C2: Dim, - SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - self.$binop_assign(rhs) + else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone()); + *self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res; + } + } + } } } + + #[doc = $desc_mut] + #[inline] + pub fn $binop_assign(&mut self, rhs: &Matrix) + where N: $Trait, + R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone()); + } + } + } + } + + #[doc = $desc_mut] + #[inline] + #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")] + pub fn $binop_mut(&mut self, rhs: &Matrix) + where N: $Trait, + R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + self.$binop_assign(rhs) + } )*} ); -component_binop_impl!( - component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign, - r" - Componentwise matrix or vector multiplication. +/// # Componentwise operations +impl> Matrix { + component_binop_impl!( + component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign, + r" + Componentwise matrix or vector multiplication. - # Example + # Example - ``` - # use nalgebra::Matrix2; - let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); + ``` + # use nalgebra::Matrix2; + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); - assert_eq!(a.component_mul(&b), expected); - ``` - ", - r" - Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`. + assert_eq!(a.component_mul(&b), expected); + ``` + ", + r" + Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`. - # Example - ``` - # use nalgebra::Matrix2; - let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = (a.component_mul(&b) * 5.0) + m * 10.0; + # Example + ``` + # use nalgebra::Matrix2; + let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = (a.component_mul(&b) * 5.0) + m * 10.0; - m.cmpy(5.0, &a, &b, 10.0); - assert_eq!(m, expected); - ``` - ", - r" - Inplace componentwise matrix or vector multiplication. + m.cmpy(5.0, &a, &b, 10.0); + assert_eq!(m, expected); + ``` + ", + r" + Inplace componentwise matrix or vector multiplication. - # Example - ``` - # use nalgebra::Matrix2; - let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); + # Example + ``` + # use nalgebra::Matrix2; + let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); - a.component_mul_assign(&b); + a.component_mul_assign(&b); - assert_eq!(a, expected); - ``` - "; - component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign, - r" - Componentwise matrix or vector division. + assert_eq!(a, expected); + ``` + "; + component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign, + r" + Componentwise matrix or vector division. - # Example + # Example - ``` - # use nalgebra::Matrix2; - let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); + ``` + # use nalgebra::Matrix2; + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); - assert_eq!(a.component_div(&b), expected); - ``` - ", - r" - Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`. + assert_eq!(a.component_div(&b), expected); + ``` + ", + r" + Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`. - # Example - ``` - # use nalgebra::Matrix2; - let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let a = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = (a.component_div(&b) * 5.0) + m * 10.0; + # Example + ``` + # use nalgebra::Matrix2; + let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let a = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = (a.component_div(&b) * 5.0) + m * 10.0; - m.cdpy(5.0, &a, &b, 10.0); - assert_eq!(m, expected); - ``` - ", - r" - Inplace componentwise matrix or vector division. + m.cdpy(5.0, &a, &b, 10.0); + assert_eq!(m, expected); + ``` + ", + r" + Inplace componentwise matrix or vector division. - # Example - ``` - # use nalgebra::Matrix2; - let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); - let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); - let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); + # Example + ``` + # use nalgebra::Matrix2; + let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); - a.component_div_assign(&b); + a.component_div_assign(&b); - assert_eq!(a, expected); - ``` - "; - // FIXME: add other operators like bitshift, etc. ? -); + assert_eq!(a, expected); + ``` + "; + // TODO: add other operators like bitshift, etc. ? + ); -/* - * inf/sup - */ -impl> Matrix -where - N: Scalar + SimdPartialOrd, - DefaultAllocator: Allocator, -{ /// Computes the infimum (aka. componentwise min) of two matrices/vectors. #[inline] - pub fn inf(&self, other: &Self) -> MatrixMN { + pub fn inf(&self, other: &Self) -> MatrixMN + where + N: SimdPartialOrd, + DefaultAllocator: Allocator, + { self.zip_map(other, |a, b| a.simd_min(b)) } /// Computes the supremum (aka. componentwise max) of two matrices/vectors. #[inline] - pub fn sup(&self, other: &Self) -> MatrixMN { + pub fn sup(&self, other: &Self) -> MatrixMN + where + N: SimdPartialOrd, + DefaultAllocator: Allocator, + { self.zip_map(other, |a, b| a.simd_max(b)) } /// Computes the (infimum, supremum) of two matrices/vectors. #[inline] - pub fn inf_sup(&self, other: &Self) -> (MatrixMN, MatrixMN) { - // FIXME: can this be optimized? + pub fn inf_sup(&self, other: &Self) -> (MatrixMN, MatrixMN) + where + N: SimdPartialOrd, + DefaultAllocator: Allocator, + { + // TODO: can this be optimized? (self.inf(other), self.sup(other)) } + + /// Adds a scalar to `self`. + #[inline] + #[must_use = "Did you mean to use add_scalar_mut()?"] + pub fn add_scalar(&self, rhs: N) -> MatrixMN + where + N: ClosedAdd, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.add_scalar_mut(rhs); + res + } + + /// Adds a scalar to `self` in-place. + #[inline] + pub fn add_scalar_mut(&mut self, rhs: N) + where + N: ClosedAdd, + SA: StorageMut, + { + for e in self.iter_mut() { + *e += rhs.inlined_clone() + } + } } diff --git a/src/base/construction.rs b/src/base/construction.rs index 4718309b..7f293554 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -210,7 +210,7 @@ where ); } - // FIXME: optimize that. + // TODO: optimize that. Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { rows[i][(0, j)].inlined_clone() }) @@ -252,7 +252,7 @@ where ); } - // FIXME: optimize that. + // TODO: optimize that. Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { columns[j][i].inlined_clone() }) @@ -591,7 +591,7 @@ impl MatrixMN where DefaultAllocator: Allocator, { - // FIXME: this is not very pretty. We could find a better call syntax. + // TODO: this is not very pretty. We could find a better call syntax. impl_constructors!(R, C; // Arguments for Matrix => R: DimName, => C: DimName; // Type parameters for impl R::name(), C::name(); // Arguments for `_generic` constructors. @@ -727,7 +727,7 @@ macro_rules! impl_constructors_from_data( } ); -// FIXME: this is not very pretty. We could find a better call syntax. +// TODO: this is not very pretty. We could find a better call syntax. impl_constructors_from_data!(data; R, C; // Arguments for Matrix => R: DimName, => C: DimName; // Type parameters for impl R::name(), C::name(); // Arguments for `_generic` constructors. diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index 06b8be9f..6fd113b4 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -3,11 +3,8 @@ use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; use crate::base::{MatrixSliceMN, MatrixSliceMutMN, Scalar}; use num_rational::Ratio; -/* - * - * Slice constructors. - * - */ + +/// # Creating matrix slices from `&[T]` impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSliceMN<'a, N, R, C, RStride, CStride> { @@ -59,6 +56,89 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> } } +impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMN<'a, N, R, C> { + /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. + /// + /// This method is unsafe because the input data array is not checked to contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + #[inline] + pub unsafe fn from_slice_generic_unchecked( + data: &'a [N], + start: usize, + nrows: R, + ncols: C, + ) -> Self { + Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows) + } + + /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances. + /// + /// Panics if the input data array dose not contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + #[inline] + pub fn from_slice_generic(data: &'a [N], nrows: R, ncols: C) -> Self { + Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows) + } +} + +macro_rules! impl_constructors( + ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { + impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMN<'a, N, $($Dims),*> { + /// Creates a new matrix slice from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice(data: &'a [N], $($args: usize),*) -> Self { + Self::from_slice_generic(data, $($gargs),*) + } + + /// Creates, without bound checking, a new matrix slice from the given data array. + #[inline] + pub unsafe fn from_slice_unchecked(data: &'a [N], start: usize, $($args: usize),*) -> Self { + Self::from_slice_generic_unchecked(data, start, $($gargs),*) + } + } + + impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMN<'a, N, $($Dims,)* Dynamic, Dynamic> { + /// Creates a new matrix slice with the specified strides from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice_with_strides(data: &'a [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + } + + /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array. + #[inline] + pub unsafe fn from_slice_with_strides_unchecked(data: &'a [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + } + } + } +); + +// TODO: this is not very pretty. We could find a better call syntax. +impl_constructors!(R, C; // Arguments for Matrix +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. + +impl_constructors!(R, Dynamic; + => R: DimName; + R::name(), Dynamic::new(ncols); + ncols); + +impl_constructors!(Dynamic, C; + => C: DimName; + Dynamic::new(nrows), C::name(); + nrows); + +impl_constructors!(Dynamic, Dynamic; + ; + Dynamic::new(nrows), Dynamic::new(ncols); + nrows, ncols); + +/// # Creating mutable matrix slices from `&mut [T]` impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSliceMutMN<'a, N, R, C, RStride, CStride> { @@ -132,31 +212,6 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> } } -impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMN<'a, N, R, C> { - /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. - /// - /// This method is unsafe because the input data array is not checked to contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. - #[inline] - pub unsafe fn from_slice_generic_unchecked( - data: &'a [N], - start: usize, - nrows: R, - ncols: C, - ) -> Self { - Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows) - } - - /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances. - /// - /// Panics if the input data array dose not contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. - #[inline] - pub fn from_slice_generic(data: &'a [N], nrows: R, ncols: C) -> Self { - Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows) - } -} - impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, N, R, C> { /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances. /// @@ -182,63 +237,6 @@ impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, N, R, C> { } } -macro_rules! impl_constructors( - ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { - impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMN<'a, N, $($Dims),*> { - /// Creates a new matrix slice from the given data array. - /// - /// Panics if `data` does not contain enough elements. - #[inline] - pub fn from_slice(data: &'a [N], $($args: usize),*) -> Self { - Self::from_slice_generic(data, $($gargs),*) - } - - /// Creates, without bound checking, a new matrix slice from the given data array. - #[inline] - pub unsafe fn from_slice_unchecked(data: &'a [N], start: usize, $($args: usize),*) -> Self { - Self::from_slice_generic_unchecked(data, start, $($gargs),*) - } - } - - impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMN<'a, N, $($Dims,)* Dynamic, Dynamic> { - /// Creates a new matrix slice with the specified strides from the given data array. - /// - /// Panics if `data` does not contain enough elements. - #[inline] - pub fn from_slice_with_strides(data: &'a [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self { - Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) - } - - /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array. - #[inline] - pub unsafe fn from_slice_with_strides_unchecked(data: &'a [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { - Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) - } - } - } -); - -// FIXME: this is not very pretty. We could find a better call syntax. -impl_constructors!(R, C; // Arguments for Matrix -=> R: DimName, => C: DimName; // Type parameters for impl -R::name(), C::name(); // Arguments for `_generic` constructors. -); // Arguments for non-generic constructors. - -impl_constructors!(R, Dynamic; - => R: DimName; - R::name(), Dynamic::new(ncols); - ncols); - -impl_constructors!(Dynamic, C; - => C: DimName; - Dynamic::new(nrows), C::name(); - nrows); - -impl_constructors!(Dynamic, Dynamic; - ; - Dynamic::new(nrows), Dynamic::new(ncols); - nrows, ncols); - macro_rules! impl_constructors_mut( ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, N, $($Dims),*> { @@ -277,7 +275,7 @@ macro_rules! impl_constructors_mut( } ); -// FIXME: this is not very pretty. We could find a better call syntax. +// TODO: this is not very pretty. We could find a better call syntax. impl_constructors_mut!(R, C; // Arguments for Matrix => R: DimName, => C: DimName; // Type parameters for impl R::name(), C::name(); // Arguments for `_generic` constructors. diff --git a/src/base/conversion.rs b/src/base/conversion.rs index 8a856325..88d6ddf3 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -29,7 +29,7 @@ use crate::base::{ use crate::base::{SliceStorage, SliceStorageMut}; use crate::constraint::DimEq; -// FIXME: too bad this won't work allo slice conversions. +// TODO: too bad this won't work allo slice conversions. impl SubsetOf> for MatrixMN where R1: Dim, diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 3f77998e..7eed2e32 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -196,7 +196,7 @@ pub trait DimName: Dim { /// The name of this dimension, i.e., the singleton `Self`. fn name() -> Self; - // FIXME: this is not a very idiomatic name. + // TODO: this is not a very idiomatic name. /// The value of this dimension. #[inline] fn dim() -> usize { diff --git a/src/base/edition.rs b/src/base/edition.rs index d69582d9..5679dd51 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -18,6 +18,7 @@ use crate::base::storage::{ReshapableStorage, Storage, StorageMut}; use crate::base::DMatrix; use crate::base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector}; +/// # Rows and columns extraction impl> Matrix { /// Extracts the upper triangular part of this matrix (including the diagonal). #[inline] @@ -63,7 +64,7 @@ impl> Matrix { } for j in 0..ncols.value() { - // FIXME: use unchecked column indexing + // TODO: use unchecked column indexing let mut res = res.column_mut(j); let src = self.column(j); @@ -99,54 +100,8 @@ impl> Matrix { } } +/// # Set rows, columns, and diagonal impl> Matrix { - /// Sets all the elements of this matrix to `val`. - #[inline] - pub fn fill(&mut self, val: N) { - for e in self.iter_mut() { - *e = val.inlined_clone() - } - } - - /// Fills `self` with the identity matrix. - #[inline] - pub fn fill_with_identity(&mut self) - where - N: Zero + One, - { - self.fill(N::zero()); - self.fill_diagonal(N::one()); - } - - /// Sets all the diagonal elements of this matrix to `val`. - #[inline] - pub fn fill_diagonal(&mut self, val: N) { - let (nrows, ncols) = self.shape(); - let n = cmp::min(nrows, ncols); - - for i in 0..n { - unsafe { *self.get_unchecked_mut((i, i)) = val.inlined_clone() } - } - } - - /// Sets all the elements of the selected row to `val`. - #[inline] - pub fn fill_row(&mut self, i: usize, val: N) { - assert!(i < self.nrows(), "Row index out of bounds."); - for j in 0..self.ncols() { - unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() } - } - } - - /// Sets all the elements of the selected column to `val`. - #[inline] - pub fn fill_column(&mut self, j: usize, val: N) { - assert!(j < self.ncols(), "Row index out of bounds."); - for i in 0..self.nrows() { - unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() } - } - } - /// Fills the diagonal of this matrix with the content of the given vector. #[inline] pub fn set_diagonal(&mut self, diag: &Vector) @@ -198,6 +153,56 @@ impl> Matrix { { self.column_mut(i).copy_from(column); } +} + +/// # In-place filling +impl> Matrix { + /// Sets all the elements of this matrix to `val`. + #[inline] + pub fn fill(&mut self, val: N) { + for e in self.iter_mut() { + *e = val.inlined_clone() + } + } + + /// Fills `self` with the identity matrix. + #[inline] + pub fn fill_with_identity(&mut self) + where + N: Zero + One, + { + self.fill(N::zero()); + self.fill_diagonal(N::one()); + } + + /// Sets all the diagonal elements of this matrix to `val`. + #[inline] + pub fn fill_diagonal(&mut self, val: N) { + let (nrows, ncols) = self.shape(); + let n = cmp::min(nrows, ncols); + + for i in 0..n { + unsafe { *self.get_unchecked_mut((i, i)) = val.inlined_clone() } + } + } + + /// Sets all the elements of the selected row to `val`. + #[inline] + pub fn fill_row(&mut self, i: usize, val: N) { + assert!(i < self.nrows(), "Row index out of bounds."); + for j in 0..self.ncols() { + unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() } + } + } + + /// Sets all the elements of the selected column to `val`. + #[inline] + pub fn fill_column(&mut self, j: usize, val: N) { + assert!(j < self.ncols(), "Row index out of bounds."); + for i in 0..self.nrows() { + unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() } + } + } /// Sets all the elements of the lower-triangular part of this matrix to `val`. /// @@ -225,41 +230,13 @@ impl> Matrix { #[inline] pub fn fill_upper_triangle(&mut self, val: N, shift: usize) { for j in shift..self.ncols() { - // FIXME: is there a more efficient way to avoid the min ? + // TODO: is there a more efficient way to avoid the min ? // (necessary for rectangular matrices) for i in 0..cmp::min(j + 1 - shift, self.nrows()) { unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() } } } } - - /// Swaps two rows in-place. - #[inline] - pub fn swap_rows(&mut self, irow1: usize, irow2: usize) { - assert!(irow1 < self.nrows() && irow2 < self.nrows()); - - if irow1 != irow2 { - // FIXME: optimize that. - for i in 0..self.ncols() { - unsafe { self.swap_unchecked((irow1, i), (irow2, i)) } - } - } - // Otherwise do nothing. - } - - /// Swaps two columns in-place. - #[inline] - pub fn swap_columns(&mut self, icol1: usize, icol2: usize) { - assert!(icol1 < self.ncols() && icol2 < self.ncols()); - - if icol1 != icol2 { - // FIXME: optimize that. - for i in 0..self.nrows() { - unsafe { self.swap_unchecked((i, icol1), (i, icol2)) } - } - } - // Otherwise do nothing. - } } impl> Matrix { @@ -295,11 +272,43 @@ impl> Matrix { } } +/// # In-place swapping +impl> Matrix { + /// Swaps two rows in-place. + #[inline] + pub fn swap_rows(&mut self, irow1: usize, irow2: usize) { + assert!(irow1 < self.nrows() && irow2 < self.nrows()); + + if irow1 != irow2 { + // TODO: optimize that. + for i in 0..self.ncols() { + unsafe { self.swap_unchecked((irow1, i), (irow2, i)) } + } + } + // Otherwise do nothing. + } + + /// Swaps two columns in-place. + #[inline] + pub fn swap_columns(&mut self, icol1: usize, icol2: usize) { + assert!(icol1 < self.ncols() && icol2 < self.ncols()); + + if icol1 != icol2 { + // TODO: optimize that. + for i in 0..self.nrows() { + unsafe { self.swap_unchecked((i, icol1), (i, icol2)) } + } + } + // Otherwise do nothing. + } +} + /* * - * FIXME: specialize all the following for slices. + * TODO: specialize all the following for slices. * */ +/// # Rows and columns removal impl> Matrix { /* * @@ -531,7 +540,10 @@ impl> Matrix { )) } } +} +/// # Rows and columns insertion +impl> Matrix { /* * * Columns insertion. @@ -689,13 +701,10 @@ impl> Matrix { res } +} - /* - * - * Resizing. - * - */ - +/// # Resizing and reshaping +impl> Matrix { /// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more @@ -811,14 +820,7 @@ impl> Matrix { res } } -} -impl Matrix -where - N: Scalar, - R: Dim, - C: Dim, -{ /// Reshapes `self` such that it has dimensions `new_nrows × new_ncols`. /// /// This will reinterpret `self` as if it is a matrix with `new_nrows` rows and `new_ncols` @@ -887,6 +889,7 @@ where } } +/// # In-place resizing #[cfg(any(feature = "std", feature = "alloc"))] impl DMatrix { /// Resizes this matrix in-place. diff --git a/src/base/indexing.rs b/src/base/indexing.rs index 65ba5d79..998cfff8 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -390,7 +390,7 @@ pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut>: } } -/// # Indexing Operations +/// # Slicing based on ranges /// ## Indices to Individual Elements /// ### Two-Dimensional Indices /// ``` diff --git a/src/base/interpolation.rs b/src/base/interpolation.rs new file mode 100644 index 00000000..faa630d9 --- /dev/null +++ b/src/base/interpolation.rs @@ -0,0 +1,122 @@ +use crate::storage::Storage; +use crate::{ + Allocator, DefaultAllocator, Dim, One, RealField, Scalar, Unit, Vector, VectorN, Zero, +}; +use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub}; + +/// # Interpolation +impl> + Vector +{ + /// 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>(&self, rhs: &Vector, t: N) -> VectorN + where + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.axpy(t.inlined_clone(), rhs, N::one() - t); + res + } + + /// Computes the spherical linear interpolation between two non-zero vectors. + /// + /// The result is a unit vector. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Unit, Vector2}; + /// + /// let v1 =Vector2::new(1.0, 2.0); + /// let v2 = Vector2::new(2.0, -3.0); + /// + /// let v = v1.slerp(&v2, 1.0); + /// + /// assert_eq!(v, v2.normalize()); + /// ``` + pub fn slerp>(&self, rhs: &Vector, t: N) -> VectorN + where + N: RealField, + DefaultAllocator: Allocator, + { + let me = Unit::new_normalize(self.clone_owned()); + let rhs = Unit::new_normalize(rhs.clone_owned()); + me.slerp(&rhs, t).into_inner() + } +} + +impl> Unit> { + /// Computes the spherical linear interpolation between two unit vectors. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Unit, Vector2}; + /// + /// let v1 = Unit::new_normalize(Vector2::new(1.0, 2.0)); + /// let v2 = Unit::new_normalize(Vector2::new(2.0, -3.0)); + /// + /// let v = v1.slerp(&v2, 1.0); + /// + /// assert_eq!(v, v2); + /// ``` + pub fn slerp>( + &self, + rhs: &Unit>, + t: N, + ) -> Unit> + where + DefaultAllocator: Allocator, + { + // TODO: the result is wrong when self and rhs are collinear with opposite direction. + self.try_slerp(rhs, t, N::default_epsilon()) + .unwrap_or(Unit::new_unchecked(self.clone_owned())) + } + + /// 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). + pub fn try_slerp>( + &self, + rhs: &Unit>, + t: N, + epsilon: N, + ) -> Option>> + where + DefaultAllocator: Allocator, + { + let c_hang = self.dot(rhs); + + // self == other + if c_hang >= N::one() { + return Some(Unit::new_unchecked(self.clone_owned())); + } + + let hang = c_hang.acos(); + let s_hang = (N::one() - c_hang * c_hang).sqrt(); + + // TODO: what if s_hang is 0.0 ? The result is not well-defined. + if relative_eq!(s_hang, N::zero(), epsilon = epsilon) { + None + } else { + let ta = ((N::one() - t) * hang).sin() / s_hang; + let tb = (t * hang).sin() / s_hang; + let mut res = self.scale(ta); + res.axpy(tb, &**rhs, N::one()); + + Some(Unit::new_unchecked(res)) + } + } +} diff --git a/src/base/iter.rs b/src/base/iter.rs index ab040b08..304bfa93 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -19,7 +19,7 @@ macro_rules! iterator { _phantoms: PhantomData<($Ref, R, C, S)>, } - // FIXME: we need to specialize for the case where the matrix storage is owned (in which + // TODO: we need to specialize for the case where the matrix storage is owned (in which // case the iterator is trivial because it does not have any stride). impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage> $Name<'a, N, R, C, S> { /// Creates a new iterator for the given matrix storage. diff --git a/src/base/matrix.rs b/src/base/matrix.rs index b510d9af..077983bd 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -55,30 +55,76 @@ pub type MatrixCross = /// The most generic column-major matrix (and vector) type. /// /// # Methods summary -/// Because `Matrix` is the most generic types that groups all matrix and vectors of **nalgebra** -/// this documentation page contains every single matrix/vector-related method. In order to make -/// browsing this page simpler, the next subsections contain direct links to groups of methods -/// related to a specific topic. +/// Because `Matrix` is the most generic types used as a common representation of all matrices and +/// vectors of **nalgebra** this documentation page contains every single matrix/vector-related +/// method. In order to make browsing this page simpler, the next subsections contain direct links +/// to groups of methods related to a specific topic. /// /// #### Vector and matrix construction /// - [Constructors of statically-sized vectors or statically-sized matrices](#constructors-of-statically-sized-vectors-or-statically-sized-matrices) -/// (`Vector3`, `Matrix3x6`, etc.) +/// (`Vector3`, `Matrix3x6`…) /// - [Constructors of fully dynamic matrices](#constructors-of-fully-dynamic-matrices) (`DMatrix`) /// - [Constructors of dynamic vectors and matrices with a dynamic number of rows](#constructors-of-dynamic-vectors-and-matrices-with-a-dynamic-number-of-rows) -/// (`DVector`, `MatrixXx3`, etc.) +/// (`DVector`, `MatrixXx3`…) /// - [Constructors of matrices with a dynamic number of columns](#constructors-of-matrices-with-a-dynamic-number-of-columns) -/// (`Matrix2xX`, etc.) +/// (`Matrix2xX`…) /// - [Generic constructors](#generic-constructors) /// (For code generic wrt. the vectors or matrices dimensions.) -/// #### Matrix decomposition -/// - [Rectangular matrix decomposition](#rectangular-matrix-decomposition) (Applicable to square matrices too) -/// - [Square matrix decomposition](#square-matrix-decomposition) +/// +/// #### Computer graphics utilities for transformations +/// - [2D transformations as a Matrix3 `new_rotation`…](#2d-transformations-as-a-matrix3) +/// - [3D transformations as a Matrix4 `new_rotation`, `new_perspective`, `look_at_rh`…](#3d-transformations-as-a-matrix4) +/// - [Translation and scaling in any dimension `new_scaling`, `new_translation`…](#translation-and-scaling-in-any-dimension) +/// - [Append/prepend translation and scaling `append_scaling`, `prepend_translation_mut`…](#appendprepend-translation-and-scaling) +/// - [Transformation of vectors and points `transform_vector`, `transform_point`…](#transformation-of-vectors-and-points) +/// +/// #### Common math operations +/// - [Componentwise operations `component_mul`, `component_div`, `inf`…](#componentwise-operations) +/// - [Special multiplications `tr_mul`, `ad_mul`, `kronecker`…](#special-multiplications) +/// - [Dot/scalar product `dot`, `dotc`, `tr_dot`…](#dotscalar-product) +/// - [Cross product `cross`, `perp`…](#cross-product) +/// - [Magnitude and norms `norm`, `normalize`, `metric_distance`…](#magnitude-and-norms) +/// - [In-place normalization `normalize_mut`, `try_normalize_mut`…](#in-place-normalization) +/// - [Interpolation `lerp`, `slerp`…](#interpolation) +/// - [BLAS functions `gemv`, `gemm`, `syger`…](#blas-functions) +/// - [Swizzling `xx`, `yxz`…](#swizzling) +/// +/// #### Statistics +/// - [Common operations `row_sum`, `column_mean`, `variance`…](#common-statistics-operations) +/// - [Find the min and max components `min`, `max`, `amin`, `amax`, `camin`, `cmax`…](#find-the-min-and-max-components) +/// - [Find the min and max components (vector-specific methods) `argmin`, `argmax`, `icamin`, `icamax`…](#find-the-min-and-max-components-vector-specific-methods) +/// +/// #### Iteration, map, and fold +/// - [Iteration on components, rows, and columns `iter`, `column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Elementwise mapping and folding `map`, `fold`, `zip_map`…](#elementwise-mapping-and-folding) +/// - [Folding or columns and rows `compress_rows`, `compress_columns`…](#folding-on-columns-and-rows) /// /// #### Vector and matrix slicing -/// - [Slicing based on index and length](#slicing-based-on-index-and-length) -/// - [Mutable slicing based on index and length](#mutable-slicing-based-on-index-and-length) -/// - [Slicing based on ranges](#slicing-based-on-ranges) -/// - [Mutable slicing based on ranges](#mutable-slicing-based-on-ranges) +/// - [Creating matrix slices from `&[T]` `from_slice`, `from_slice_with_strides`…](#creating-matrix-slices-from-t) +/// - [Creating mutable matrix slices from `&mut [T]` `from_slice_mut`, `from_slice_with_strides_mut`…](#creating-mutable-matrix-slices-from-mut-t) +/// - [Slicing based on index and length `row`, `columns`, `slice`…](#slicing-based-on-index-and-length) +/// - [Mutable slicing based on index and length `row_mut`, `columns_mut`, `slice_mut`…](#mutable-slicing-based-on-index-and-length) +/// - [Slicing based on ranges `rows_range`, `columns_range`…](#slicing-based-on-ranges) +/// - [Mutable slicing based on ranges `rows_range_mut`, `columns_range_mut`…](#mutable-slicing-based-on-ranges) +/// +/// #### In-place modification of a single matrix or vector +/// - [In-place filling `fill`, `fill_diagonal`, `fill_with_identity`…](#in-place-filling) +/// - [In-place swapping `swap`, `swap_columns`…](#in-place-swapping) +/// - [Set rows, columns, and diagonal `set_column`, `set_diagonal`…](#set-rows-columns-and-diagonal) +/// +/// #### Vector and matrix size modification +/// - [Rows and columns insertion `insert_row`, `insert_column`…](#rows-and-columns-insertion) +/// - [Rows and columns removal `remove_row`, `remove column`…](#rows-and-columns-removal) +/// - [Rows and columns extraction `select_rows`, `select_columns`…](#rows-and-columns-extraction) +/// - [Resizing and reshaping `resize`, `reshape_generic`…](#resizing-and-reshaping) +/// - [In-place resizing `resize_mut`, `resize_vertically_mut`…](#in-place-resizing) +/// +/// #### Matrix decomposition +/// - [Rectangular matrix decomposition `qr`, `lu`, `svd`…](#rectangular-matrix-decomposition) +/// - [Square matrix decomposition `cholesky`, `symmetric_eigen`…](#square-matrix-decomposition) +/// +/// #### Vector basis computation +/// - [Basis and orthogonalization `orthonormal_subspace_basis`, `orthonormalize`…](#basis-and-orthogonalization) /// /// # Type parameters /// The generic `Matrix` type has four type parameters: @@ -111,11 +157,13 @@ pub struct Matrix { /// you may be in luck: you can access the individual components of all vectors with compile-time /// dimensions <= 6 using field notation like this: /// `vec.x`, `vec.y`, `vec.z`, `vec.w`, `vec.a`, `vec.b`. Reference and assignation work too: - /// ```.ignore - /// let mut v = Vector3::new(1.0, 2.0, 3.0); + /// ``` + /// # use nalgebra::Vector3; + /// let mut vec = Vector3::new(1.0, 2.0, 3.0); /// vec.x = 10.0; - /// my_function(&vec.z); - /// println!("{}", vec.y + 30.0); + /// vec.y += 30.0; + /// assert_eq!(vec.x, 10.0); + /// assert_eq!(vec.y + 100.0, 132.0); /// ``` /// Similarly, for matrices with compile-time dimensions <= 6, you can use field notation /// like this: `mat.m11`, `mat.m42`, etc. The first digit identifies the row to address @@ -320,58 +368,6 @@ impl> Matrix { (srows.value(), scols.value()) } - /// 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()); - #[inline] - pub fn iter(&self) -> MatrixIter { - MatrixIter::new(&self.data) - } - - /// Iterate through the rows of this matrix. - /// - /// # 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)) - /// } - /// ``` - #[inline] - pub fn row_iter(&self) -> RowIter { - RowIter::new(self) - } - - /// Iterate through the columns of this matrix. - /// # 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)) - /// } - /// ``` - #[inline] - pub fn column_iter(&self) -> ColumnIter { - ColumnIter::new(self) - } - /// Computes the row and column coordinates of the i-th element of this matrix seen as a /// vector. /// @@ -464,7 +460,7 @@ impl> Matrix { Matrix::from_data(self.data.into_owned()) } - // FIXME: this could probably benefit from specialization. + // TODO: 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. @@ -480,7 +476,7 @@ impl> Matrix { // We can just return `self.into_owned()`. unsafe { - // FIXME: check that those copies are optimized away by the compiler. + // TODO: check that those copies are optimized away by the compiler. let owned = self.into_owned(); let res = mem::transmute_copy(&owned); mem::forget(owned); @@ -517,7 +513,7 @@ impl> Matrix { let mut res: MatrixSum = unsafe { Matrix::new_uninitialized_generic(nrows, ncols) }; - // FIXME: use copy_from + // TODO: use copy_from for j in 0..res.ncols() { for i in 0..res.nrows() { unsafe { @@ -529,6 +525,51 @@ impl> Matrix { res } + /// Transposes `self` and store the result into `out`. + #[inline] + pub fn transpose_to(&self, out: &mut Matrix) + where + R2: Dim, + C2: Dim, + SB: StorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + assert!( + (ncols, nrows) == out.shape(), + "Incompatible shape for transpose-copy." + ); + + // TODO: optimize that. + for i in 0..nrows { + for j in 0..ncols { + unsafe { + *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).inlined_clone(); + } + } + } + } + + /// Transposes `self`. + #[inline] + #[must_use = "Did you mean to use transpose_mut()?"] + pub fn transpose(&self) -> MatrixMN + where + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.data.shape(); + + unsafe { + let mut res = Matrix::new_uninitialized_generic(ncols, nrows); + self.transpose_to(&mut res); + + res + } + } +} + +/// # Elementwise mapping and folding +impl> Matrix { /// Returns a matrix containing the result of `f` applied to each of its entries. #[inline] pub fn map N2>(&self, mut f: F) -> MatrixMN @@ -733,63 +774,166 @@ impl> Matrix { res } - /// Transposes `self` and store the result into `out`. + /// Replaces each component of `self` by the result of a closure `f` applied on it. #[inline] - pub fn transpose_to(&self, out: &mut Matrix) + pub fn apply N>(&mut self, mut f: F) where - R2: Dim, - C2: Dim, - SB: StorageMut, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + S: StorageMut, { let (nrows, ncols) = self.shape(); - assert!( - (ncols, nrows) == out.shape(), - "Incompatible shape for transpose-copy." - ); - // FIXME: optimize that. - for i in 0..nrows { - for j in 0..ncols { + for j in 0..ncols { + for i in 0..nrows { unsafe { - *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).inlined_clone(); + let e = self.data.get_unchecked_mut(i, j); + *e = f(e.inlined_clone()) } } } } - /// Transposes `self`. + /// Replaces each component of `self` by the result of a closure `f` applied on its components + /// joined with the components from `rhs`. #[inline] - #[must_use = "Did you mean to use transpose_mut()?"] - pub fn transpose(&self) -> MatrixMN - where - DefaultAllocator: Allocator, + pub fn zip_apply( + &mut self, + rhs: &Matrix, + mut f: impl FnMut(N, N2) -> N, + ) where + S: StorageMut, + N2: Scalar, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { - let (nrows, ncols) = self.data.shape(); + let (nrows, ncols) = self.shape(); - unsafe { - let mut res = Matrix::new_uninitialized_generic(ncols, nrows); - self.transpose_to(&mut res); + assert_eq!( + (nrows, ncols), + rhs.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); - res + for j in 0..ncols { + for i in 0..nrows { + unsafe { + let e = self.data.get_unchecked_mut(i, j); + let rhs = rhs.get_unchecked((i, j)).inlined_clone(); + *e = f(e.inlined_clone(), rhs) + } + } + } + } + + /// 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] + pub fn zip_zip_apply( + &mut self, + b: &Matrix, + c: &Matrix, + mut f: impl FnMut(N, N2, N3) -> N, + ) where + S: StorageMut, + N2: Scalar, + R2: Dim, + C2: Dim, + S2: Storage, + N3: Scalar, + R3: Dim, + C3: Dim, + S3: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + + assert_eq!( + (nrows, ncols), + b.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + assert_eq!( + (nrows, ncols), + c.shape(), + "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); + 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) + } + } } } } -impl> Matrix { - /// Mutably iterates through this matrix coordinates. +/// # Iteration on components, rows, and columns +impl> Matrix { + /// 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()); #[inline] - pub fn iter_mut(&mut self) -> MatrixIterMut { - MatrixIterMut::new(&mut self.data) + pub fn iter(&self) -> MatrixIter { + MatrixIter::new(&self.data) } - /// Returns a mutable pointer to the start of the matrix. + /// Iterate through the rows of this matrix. /// - /// If the matrix is not empty, this pointer is guaranteed to be aligned - /// and non-null. + /// # 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)) + /// } + /// ``` #[inline] - pub fn as_mut_ptr(&mut self) -> *mut N { - self.data.ptr_mut() + pub fn row_iter(&self) -> RowIter { + RowIter::new(self) + } + + /// Iterate through the columns of this matrix. + /// # 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)) + /// } + /// ``` + #[inline] + pub fn column_iter(&self) -> ColumnIter { + ColumnIter::new(self) + } + + /// Mutably iterates through this matrix coordinates. + #[inline] + pub fn iter_mut(&mut self) -> MatrixIterMut + where + S: StorageMut, + { + MatrixIterMut::new(&mut self.data) } /// Mutably iterates through this matrix rows. @@ -808,7 +952,10 @@ impl> Matrix { /// assert_eq!(a, expected); /// ``` #[inline] - pub fn row_iter_mut(&mut self) -> RowIterMut { + pub fn row_iter_mut(&mut self) -> RowIterMut + where + S: StorageMut, + { RowIterMut::new(self) } @@ -828,9 +975,23 @@ impl> Matrix { /// assert_eq!(a, expected); /// ``` #[inline] - pub fn column_iter_mut(&mut self) -> ColumnIterMut { + pub fn column_iter_mut(&mut self) -> ColumnIterMut + where + S: StorageMut, + { ColumnIterMut::new(self) } +} + +impl> Matrix { + /// 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() + } /// Swaps two entries without bound-checking. #[inline] @@ -924,106 +1085,13 @@ impl> Matrix { } } - // FIXME: rename `apply` to `apply_mut` and `apply_into` to `apply`? + // TODO: 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] pub fn apply_into N>(mut self, f: F) -> Self { self.apply(f); self } - - /// Replaces each component of `self` by the result of a closure `f` applied on it. - #[inline] - pub fn apply N>(&mut self, mut f: F) { - let (nrows, ncols) = self.shape(); - - for j in 0..ncols { - for i in 0..nrows { - unsafe { - let e = self.data.get_unchecked_mut(i, j); - *e = f(e.inlined_clone()) - } - } - } - } - - /// Replaces each component of `self` by the result of a closure `f` applied on its components - /// joined with the components from `rhs`. - #[inline] - pub fn zip_apply( - &mut self, - rhs: &Matrix, - mut f: impl FnMut(N, N2) -> N, - ) where - N2: Scalar, - R2: Dim, - C2: Dim, - S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, - { - let (nrows, ncols) = self.shape(); - - assert_eq!( - (nrows, ncols), - rhs.shape(), - "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); - let rhs = rhs.get_unchecked((i, j)).inlined_clone(); - *e = f(e.inlined_clone(), rhs) - } - } - } - } - - /// 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] - pub fn zip_zip_apply( - &mut self, - b: &Matrix, - c: &Matrix, - mut f: impl FnMut(N, N2, N3) -> N, - ) where - N2: Scalar, - R2: Dim, - C2: Dim, - S2: Storage, - N3: Scalar, - R3: Dim, - C3: Dim, - S3: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, - { - let (nrows, ncols) = self.shape(); - - assert_eq!( - (nrows, ncols), - b.shape(), - "Matrix simultaneous traversal error: dimension mismatch." - ); - assert_eq!( - (nrows, ncols), - c.shape(), - "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); - 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) - } - } - } - } } impl> Vector { @@ -1096,7 +1164,7 @@ impl> Matrix> Matrix { @@ -1701,7 +1770,7 @@ impl::from_usize(3); let ncols = SameShapeC::::from_usize(1); let mut res = Matrix::new_uninitialized_generic(nrows, ncols); @@ -1749,7 +1818,7 @@ impl::from_usize(1); let ncols = SameShapeC::::from_usize(3); let mut res = Matrix::new_uninitialized_generic(nrows, ncols); @@ -1818,96 +1887,6 @@ impl> Matrix> - Vector -{ - /// 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>(&self, rhs: &Vector, t: N) -> VectorN - where - DefaultAllocator: Allocator, - { - let mut res = self.clone_owned(); - res.axpy(t.inlined_clone(), rhs, N::one() - t); - res - } -} - -impl> Unit> { - /// Computes the spherical linear interpolation between two unit vectors. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::{Unit, Vector2}; - /// - /// let v1 = Unit::new_normalize(Vector2::new(1.0, 2.0)); - /// let v2 = Unit::new_normalize(Vector2::new(2.0, -3.0)); - /// - /// let v = v1.slerp(&v2, 1.0); - /// - /// assert_eq!(v, v2); - /// ``` - pub fn slerp>( - &self, - rhs: &Unit>, - t: N, - ) -> Unit> - where - DefaultAllocator: Allocator, - { - // FIXME: the result is wrong when self and rhs are collinear with opposite direction. - self.try_slerp(rhs, t, N::default_epsilon()) - .unwrap_or(Unit::new_unchecked(self.clone_owned())) - } - - /// 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). - pub fn try_slerp>( - &self, - rhs: &Unit>, - t: N, - epsilon: N, - ) -> Option>> - where - DefaultAllocator: Allocator, - { - let c_hang = self.dot(rhs); - - // self == other - if c_hang >= N::one() { - return Some(Unit::new_unchecked(self.clone_owned())); - } - - let hang = c_hang.acos(); - let s_hang = (N::one() - c_hang * c_hang).sqrt(); - - // FIXME: what if s_hang is 0.0 ? The result is not well-defined. - if relative_eq!(s_hang, N::zero(), epsilon = epsilon) { - None - } else { - let ta = ((N::one() - t) * hang).sin() / s_hang; - let tb = (t * hang).sin() / s_hang; - let mut res = self.scale(ta); - res.axpy(tb, &**rhs, N::one()); - - Some(Unit::new_unchecked(res)) - } - } -} - impl AbsDiffEq for Unit> where N: Scalar + AbsDiffEq, diff --git a/src/base/matrix_alga.rs b/src/base/matrix_alga.rs index 18182382..c8c08e64 100644 --- a/src/base/matrix_alga.rs +++ b/src/base/matrix_alga.rs @@ -214,7 +214,7 @@ where } } -// FIXME: specialization will greatly simplify this implementation in the future. +// TODO: specialization will greatly simplify this implementation in the future. // In particular: // − use `x()` instead of `::canonical_basis_element` // − use `::new(x, y, z)` instead of `::from_slice` @@ -244,7 +244,7 @@ where .try_normalize_mut(::RealField::zero()) .is_some() { - // FIXME: this will be efficient on dynamically-allocated vectors but for + // TODO: this will be efficient on dynamically-allocated vectors but for // statically-allocated ones, `.clone_from` would be better. vs.swap(nbasis_elements, i); nbasis_elements += 1; @@ -264,7 +264,7 @@ where where F: FnMut(&Self) -> bool, { - // FIXME: is this necessary? + // TODO: is this necessary? assert!( vs.len() <= Self::dimension(), "The given set of vectors has no chance of being a free family." diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs index 534df70d..21bcc349 100644 --- a/src/base/matrix_slice.rs +++ b/src/base/matrix_slice.rs @@ -810,7 +810,8 @@ impl SliceRange for RangeFull { } } -/// # Slicing based on ranges +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. impl> Matrix { /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed /// by the range `cols`. @@ -850,7 +851,8 @@ impl> Matrix { } } -/// # Mutable slicing based on ranges +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. impl> Matrix { /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns /// indexed by the range `cols`. diff --git a/src/base/min_max.rs b/src/base/min_max.rs new file mode 100644 index 00000000..d594ef50 --- /dev/null +++ b/src/base/min_max.rs @@ -0,0 +1,390 @@ +use crate::storage::Storage; +use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector}; +use rand_distr::num_traits::{Signed, Zero}; +use simba::simd::SimdSigned; + +/// # Find the min and max components +impl> Matrix { + /// Returns the absolute value of the component with the largest absolute value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).amax(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); + /// ``` + #[inline] + pub fn amax(&self) -> N + where + N: Zero + SimdSigned + SimdPartialOrd, + { + self.fold_with( + |e| e.unwrap_or(&N::zero()).simd_abs(), + |a, b| a.simd_max(b.simd_abs()), + ) + } + + /// Returns the the 1-norm of the complex component with the largest 1-norm. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camax(), 5.0); + /// ``` + #[inline] + pub fn camax(&self) -> N::SimdRealField + where + N: SimdComplexField, + { + self.fold_with( + |e| e.unwrap_or(&N::zero()).simd_norm1(), + |a, b| a.simd_max(b.simd_norm1()), + ) + } + + /// Returns the component with the largest value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).max(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).max(), -1.0); + /// assert_eq!(Vector3::new(5u32, 2, 3).max(), 5); + /// ``` + #[inline] + pub fn max(&self) -> N + where + N: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), + |a, b| a.simd_max(b.inlined_clone()), + ) + } + + /// Returns the absolute value of the component with the smallest absolute value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, -3.0).amin(), 1.0); + /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); + /// ``` + #[inline] + pub fn amin(&self) -> N + where + N: Zero + SimdPartialOrd + SimdSigned, + { + self.fold_with( + |e| e.map(|e| e.simd_abs()).unwrap_or(N::zero()), + |a, b| a.simd_min(b.simd_abs()), + ) + } + + /// Returns the the 1-norm of the complex component with the smallest 1-norm. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camin(), 3.0); + /// ``` + #[inline] + pub fn camin(&self) -> N::SimdRealField + where + N: SimdComplexField, + { + self.fold_with( + |e| { + e.map(|e| e.simd_norm1()) + .unwrap_or(N::SimdRealField::zero()) + }, + |a, b| a.simd_min(b.simd_norm1()), + ) + } + + /// Returns the component with the smallest value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).min(), -1.0); + /// assert_eq!(Vector3::new(1.0, 2.0, 3.0).min(), 1.0); + /// assert_eq!(Vector3::new(5u32, 2, 3).min(), 2); + /// ``` + #[inline] + pub fn min(&self) -> N + where + N: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), + |a, b| a.simd_min(b.inlined_clone()), + ) + } + + /// Computes the index of the matrix component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(Complex::new(11.0, 1.0), Complex::new(-12.0, 2.0), Complex::new(13.0, 3.0), + /// Complex::new(21.0, 43.0), Complex::new(22.0, 5.0), Complex::new(-23.0, 0.0)); + /// assert_eq!(mat.icamax_full(), (1, 0)); + /// ``` + #[inline] + pub fn icamax_full(&self) -> (usize, usize) + where + N: ComplexField, + { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked((0, 0)).norm1() }; + let mut the_ij = (0, 0); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + let val = unsafe { self.get_unchecked((i, j)).norm1() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + +impl> Matrix { + /// Computes the index of the matrix component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(11, -12, 13, + /// 21, 22, -23); + /// assert_eq!(mat.iamax_full(), (1, 2)); + /// ``` + #[inline] + pub fn iamax_full(&self) -> (usize, usize) { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked((0, 0)).abs() }; + let mut the_ij = (0, 0); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + let val = unsafe { self.get_unchecked((i, j)).abs() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + +// TODO: find a way to avoid code duplication just for complex number support. +/// # Find the min and max components (vector-specific methods) +impl> Vector { + /// Computes the index of the vector component with the largest complex or real absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(Complex::new(11.0, 3.0), Complex::new(-15.0, 0.0), Complex::new(13.0, 5.0)); + /// assert_eq!(vec.icamax(), 2); + /// ``` + #[inline] + pub fn icamax(&self) -> usize + where + N: ComplexField, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).norm1() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).norm1() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } + + /// Computes the index and value of the vector component with the largest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.argmax(), (2, 13)); + /// ``` + #[inline] + pub fn argmax(&self) -> (usize, N) + where + N: PartialOrd, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0) }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i) }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + (the_i, the_max.inlined_clone()) + } + + /// Computes the index of the vector component with the largest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.imax(), 2); + /// ``` + #[inline] + pub fn imax(&self) -> usize + where + N: PartialOrd, + { + self.argmax().0 + } + + /// Computes the index of the vector component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.iamax(), 1); + /// ``` + #[inline] + pub fn iamax(&self) -> usize + where + N: PartialOrd + Signed, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).abs() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).abs() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } + + /// Computes the index and value of the vector component with the smallest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.argmin(), (1, -15)); + /// ``` + #[inline] + pub fn argmin(&self) -> (usize, N) + where + N: PartialOrd, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_min = unsafe { self.vget_unchecked(0) }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i) }; + + if val < the_min { + the_min = val; + the_i = i; + } + } + + (the_i, the_min.inlined_clone()) + } + + /// Computes the index of the vector component with the smallest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.imin(), 1); + /// ``` + #[inline] + pub fn imin(&self) -> usize + where + N: PartialOrd, + { + self.argmin().0 + } + + /// Computes the index of the vector component with the smallest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.iamin(), 0); + /// ``` + #[inline] + pub fn iamin(&self) -> usize + where + N: PartialOrd + Signed, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_min = unsafe { self.vget_unchecked(0).abs() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).abs() }; + + if val < the_min { + the_min = val; + the_i = i; + } + } + + the_i + } +} diff --git a/src/base/mod.rs b/src/base/mod.rs index 0e8ea72d..edea4a2d 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -36,6 +36,8 @@ mod vec_storage; #[doc(hidden)] pub mod helper; +mod interpolation; +mod min_max; pub use self::matrix::*; pub use self::norm::*; diff --git a/src/base/norm.rs b/src/base/norm.rs index d0f593ce..07994b79 100644 --- a/src/base/norm.rs +++ b/src/base/norm.rs @@ -12,7 +12,7 @@ use crate::{ComplexField, Scalar, SimdComplexField, Unit}; use simba::scalar::ClosedNeg; use simba::simd::{SimdOption, SimdPartialOrd}; -// FIXME: this should be be a trait on alga? +// TODO: this should be be a trait on alga? /// A trait for abstract matrix norms. /// /// This may be moved to the alga crate in the future. @@ -154,10 +154,14 @@ impl Norm for UniformNorm { } } -impl> Matrix { +/// # Magnitude and norms +impl> Matrix { /// The squared L2 norm of this vector. #[inline] - pub fn norm_squared(&self) -> N::SimdRealField { + pub fn norm_squared(&self) -> N::SimdRealField + where + N: SimdComplexField, + { let mut res = N::SimdRealField::zero(); for i in 0..self.ncols() { @@ -172,7 +176,10 @@ impl> Matrix N::SimdRealField { + pub fn norm(&self) -> N::SimdRealField + where + N: SimdComplexField, + { self.norm_squared().simd_sqrt() } @@ -182,6 +189,7 @@ impl> Matrix(&self, rhs: &Matrix) -> N::SimdRealField where + N: SimdComplexField, R2: Dim, C2: Dim, S2: Storage, @@ -203,7 +211,10 @@ impl> Matrix) -> N::SimdRealField { + pub fn apply_norm(&self, norm: &impl Norm) -> N::SimdRealField + where + N: SimdComplexField, + { norm.norm(self) } @@ -228,6 +239,7 @@ impl> Matrix, ) -> N::SimdRealField where + N: SimdComplexField, R2: Dim, C2: Dim, S2: Storage, @@ -242,7 +254,10 @@ impl> Matrix N::SimdRealField { + pub fn magnitude(&self) -> N::SimdRealField + where + N: SimdComplexField, + { self.norm() } @@ -252,7 +267,10 @@ impl> Matrix N::SimdRealField { + pub fn magnitude_squared(&self) -> N::SimdRealField + where + N: SimdComplexField, + { self.norm_squared() } @@ -260,6 +278,7 @@ impl> Matrix, { let n = self.norm(); @@ -271,6 +290,7 @@ impl> Matrix MatrixMN where + N: SimdComplexField, DefaultAllocator: Allocator, { self.unscale(self.norm()) @@ -278,7 +298,10 @@ impl> Matrix N::SimdRealField { + pub fn lp_norm(&self, p: i32) -> N::SimdRealField + where + N: SimdComplexField, + { self.apply_norm(&LpNorm(p)) } @@ -289,6 +312,7 @@ impl> Matrix SimdOption> where + N: SimdComplexField, N::Element: Scalar, DefaultAllocator: Allocator + Allocator, { @@ -297,9 +321,7 @@ impl> Matrix> Matrix { /// Sets the magnitude of this vector unless it is smaller than `min_magnitude`. /// /// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged. @@ -307,6 +329,7 @@ impl> Matrix { #[inline] pub fn try_set_magnitude(&mut self, magnitude: N::RealField, min_magnitude: N::RealField) where + N: ComplexField, S: StorageMut, { let n = self.norm(); @@ -323,6 +346,7 @@ impl> Matrix { #[must_use = "Did you mean to use try_normalize_mut()?"] pub fn try_normalize(&self, min_norm: N::RealField) -> Option> where + N: ComplexField, DefaultAllocator: Allocator, { let n = self.norm(); @@ -335,12 +359,16 @@ impl> Matrix { } } -impl> Matrix { +/// # In-place normalization +impl> Matrix { /// Normalizes this matrix in-place and returns its norm. /// /// The components of the matrix cannot be SIMD types (see `simd_try_normalize_mut` instead). #[inline] - pub fn normalize_mut(&mut self) -> N::SimdRealField { + pub fn normalize_mut(&mut self) -> N::SimdRealField + where + N: SimdComplexField, + { let n = self.norm(); self.unscale_mut(n); @@ -357,6 +385,7 @@ impl> Matrix SimdOption where + N: SimdComplexField, N::Element: Scalar, DefaultAllocator: Allocator + Allocator, { @@ -365,14 +394,15 @@ impl> Matrix> Matrix { /// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`. /// /// If the normalization succeeded, returns the old norm of this matrix. #[inline] - pub fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option { + pub fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option + where + N: ComplexField, + { let n = self.norm(); if n <= min_norm { @@ -423,10 +453,11 @@ where } } -// FIXME: specialization will greatly simplify this implementation in the future. +// TODO: specialization will greatly simplify this implementation in the future. // In particular: // − use `x()` instead of `::canonical_basis_element` // − use `::new(x, y, z)` instead of `::from_slice` +/// # Basis and orthogonalization impl VectorN where DefaultAllocator: Allocator, @@ -461,7 +492,7 @@ where } if vs[i].try_normalize_mut(N::RealField::zero()).is_some() { - // FIXME: this will be efficient on dynamically-allocated vectors but for + // TODO: this will be efficient on dynamically-allocated vectors but for // statically-allocated ones, `.clone_from` would be better. vs.swap(nbasis_elements, i); nbasis_elements += 1; @@ -479,13 +510,13 @@ where /// Applies the given closure to each element of the orthonormal basis of the subspace /// orthogonal to free family of vectors `vs`. If `vs` is not a free family, the result is /// unspecified. - // FIXME: return an iterator instead when `-> impl Iterator` will be supported by Rust. + // TODO: return an iterator instead when `-> impl Iterator` will be supported by Rust. #[inline] pub fn orthonormal_subspace_basis(vs: &[Self], mut f: F) where F: FnMut(&Self) -> bool, { - // FIXME: is this necessary? + // TODO: is this necessary? assert!( vs.len() <= D::dim(), "The given set of vectors has no chance of being a free family." diff --git a/src/base/ops.rs b/src/base/ops.rs index 7f0c6e4e..7bda546d 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -158,7 +158,7 @@ macro_rules! componentwise_binop_impl( assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch."); // This is the most common case and should be deduced at compile-time. - // FIXME: use specialization instead? + // TODO: use specialization instead? if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() { let arr1 = self.data.as_slice(); let arr2 = rhs.data.as_slice(); @@ -191,7 +191,7 @@ macro_rules! componentwise_binop_impl( assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); // This is the most common case and should be deduced at compile-time. - // FIXME: use specialization instead? + // TODO: use specialization instead? if self.data.is_contiguous() && rhs.data.is_contiguous() { let arr1 = self.data.as_mut_slice(); let arr2 = rhs.data.as_slice(); @@ -221,7 +221,7 @@ macro_rules! componentwise_binop_impl( assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); // This is the most common case and should be deduced at compile-time. - // FIXME: use specialization instead? + // TODO: use specialization instead? if self.data.is_contiguous() && rhs.data.is_contiguous() { let arr1 = self.data.as_slice(); let arr2 = rhs.data.as_mut_slice(); @@ -633,7 +633,7 @@ where } } -// FIXME: this is too restrictive: +// TODO: this is too restrictive: // − we can't use `a *= b` when `a` is a mutable slice. // − we can't use `a *= b` when C2 is not equal to C1. impl MulAssign> for Matrix @@ -662,7 +662,7 @@ where SB: Storage, SA: ContiguousStorageMut + Clone, ShapeConstraint: AreMultipliable, - // FIXME: this is too restrictive. See comments for the non-ref version. + // TODO: this is too restrictive. See comments for the non-ref version. DefaultAllocator: Allocator, { #[inline] @@ -671,7 +671,7 @@ where } } -// Transpose-multiplication. +/// # Special multiplications. impl Matrix where N: Scalar + Zero + One + ClosedAdd + ClosedMul, @@ -843,31 +843,6 @@ where } } -impl> Matrix { - /// Adds a scalar to `self`. - #[inline] - #[must_use = "Did you mean to use add_scalar_mut()?"] - pub fn add_scalar(&self, rhs: N) -> MatrixMN - where - DefaultAllocator: Allocator, - { - let mut res = self.clone_owned(); - res.add_scalar_mut(rhs); - res - } - - /// Adds a scalar to `self` in-place. - #[inline] - pub fn add_scalar_mut(&mut self, rhs: N) - where - S: StorageMut, - { - for e in self.iter_mut() { - *e += rhs.inlined_clone() - } - } -} - impl iter::Product for MatrixN where N: Scalar + Zero + One + ClosedMul + ClosedAdd, @@ -887,122 +862,3 @@ where iter.fold(Matrix::one(), |acc, x| acc * x) } } - -impl> Matrix { - /// Returns the absolute value of the component with the largest absolute value. - /// # Example - /// ``` - /// # use nalgebra::Vector3; - /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).amax(), 3.0); - /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); - /// ``` - #[inline] - pub fn amax(&self) -> N - where - N: Zero + SimdSigned + SimdPartialOrd, - { - self.fold_with( - |e| e.unwrap_or(&N::zero()).simd_abs(), - |a, b| a.simd_max(b.simd_abs()), - ) - } - - /// Returns the the 1-norm of the complex component with the largest 1-norm. - /// # Example - /// ``` - /// # use nalgebra::{Vector3, Complex}; - /// assert_eq!(Vector3::new( - /// Complex::new(-3.0, -2.0), - /// Complex::new(1.0, 2.0), - /// Complex::new(1.0, 3.0)).camax(), 5.0); - /// ``` - #[inline] - pub fn camax(&self) -> N::SimdRealField - where - N: SimdComplexField, - { - self.fold_with( - |e| e.unwrap_or(&N::zero()).simd_norm1(), - |a, b| a.simd_max(b.simd_norm1()), - ) - } - - /// Returns the component with the largest value. - /// # Example - /// ``` - /// # use nalgebra::Vector3; - /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).max(), 3.0); - /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).max(), -1.0); - /// assert_eq!(Vector3::new(5u32, 2, 3).max(), 5); - /// ``` - #[inline] - pub fn max(&self) -> N - where - N: SimdPartialOrd + Zero, - { - self.fold_with( - |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), - |a, b| a.simd_max(b.inlined_clone()), - ) - } - - /// Returns the absolute value of the component with the smallest absolute value. - /// # Example - /// ``` - /// # use nalgebra::Vector3; - /// assert_eq!(Vector3::new(-1.0, 2.0, -3.0).amin(), 1.0); - /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); - /// ``` - #[inline] - pub fn amin(&self) -> N - where - N: Zero + SimdPartialOrd + SimdSigned, - { - self.fold_with( - |e| e.map(|e| e.simd_abs()).unwrap_or(N::zero()), - |a, b| a.simd_min(b.simd_abs()), - ) - } - - /// Returns the the 1-norm of the complex component with the smallest 1-norm. - /// # Example - /// ``` - /// # use nalgebra::{Vector3, Complex}; - /// assert_eq!(Vector3::new( - /// Complex::new(-3.0, -2.0), - /// Complex::new(1.0, 2.0), - /// Complex::new(1.0, 3.0)).camin(), 3.0); - /// ``` - #[inline] - pub fn camin(&self) -> N::SimdRealField - where - N: SimdComplexField, - { - self.fold_with( - |e| { - e.map(|e| e.simd_norm1()) - .unwrap_or(N::SimdRealField::zero()) - }, - |a, b| a.simd_min(b.simd_norm1()), - ) - } - - /// Returns the component with the smallest value. - /// # Example - /// ``` - /// # use nalgebra::Vector3; - /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).min(), -1.0); - /// assert_eq!(Vector3::new(1.0, 2.0, 3.0).min(), 1.0); - /// assert_eq!(Vector3::new(5u32, 2, 3).min(), 2); - /// ``` - #[inline] - pub fn min(&self) -> N - where - N: SimdPartialOrd + Zero, - { - self.fold_with( - |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), - |a, b| a.simd_min(b.inlined_clone()), - ) - } -} diff --git a/src/base/properties.rs b/src/base/properties.rs index 69ca5d66..a3664d48 100644 --- a/src/base/properties.rs +++ b/src/base/properties.rs @@ -24,7 +24,7 @@ impl> Matrix { nrows == ncols } - // FIXME: RelativeEq prevents us from using those methods on integer matrices… + // TODO: RelativeEq prevents us from using those methods on integer matrices… /// Indicated if this is the identity matrix within a relative error of `eps`. /// /// If the matrix is diagonal, this checks that diagonal elements (i.e. at coordinates `(i, i)` @@ -64,7 +64,7 @@ impl> Matrix { // Off-diagonal elements of the sub-square matrix. for i in 1..d { for j in 0..i { - // FIXME: use unsafe indexing. + // TODO: use unsafe indexing. if !relative_eq!(self[(i, j)], N::zero(), epsilon = eps) || !relative_eq!(self[(j, i)], N::zero(), epsilon = eps) { @@ -118,7 +118,7 @@ where /// Returns `true` if this matrix is invertible. #[inline] pub fn is_invertible(&self) -> bool { - // FIXME: improve this? + // TODO: improve this? self.clone_owned().try_inverse().is_some() } } diff --git a/src/base/statistics.rs b/src/base/statistics.rs index afd9eedd..37ca8d75 100644 --- a/src/base/statistics.rs +++ b/src/base/statistics.rs @@ -4,6 +4,7 @@ use crate::{DefaultAllocator, Dim, Matrix, RowVectorN, Scalar, VectorN, VectorSl use num::Zero; use simba::scalar::{ClosedAdd, Field, SupersetOf}; +/// # Folding on columns and rows impl> Matrix { /// Returns a row vector where each element is the result of the application of `f` on the /// corresponding column of the original matrix. @@ -19,7 +20,7 @@ impl> Matrix { let mut res = unsafe { RowVectorN::new_uninitialized_generic(U1, ncols) }; for i in 0..ncols.value() { - // FIXME: avoid bound checking of column. + // TODO: avoid bound checking of column. unsafe { *res.get_unchecked_mut((0, i)) = f(self.column(i)); } @@ -44,7 +45,7 @@ impl> Matrix { let mut res = unsafe { VectorN::new_uninitialized_generic(ncols, U1) }; for i in 0..ncols.value() { - // FIXME: avoid bound checking of column. + // TODO: avoid bound checking of column. unsafe { *res.vget_unchecked_mut(i) = f(self.column(i)); } @@ -73,7 +74,8 @@ impl> Matrix { } } -impl> Matrix { +/// # Common statistics operations +impl> Matrix { /* * * Sum computation. @@ -91,7 +93,10 @@ impl> Matrix N { + pub fn sum(&self) -> N + where + N: ClosedAdd + Zero, + { self.iter().cloned().fold(N::zero(), |a, b| a + b) } @@ -115,6 +120,7 @@ impl> Matrix RowVectorN where + N: ClosedAdd + Zero, DefaultAllocator: Allocator, { self.compress_rows(|col| col.sum()) @@ -138,6 +144,7 @@ impl> Matrix VectorN where + N: ClosedAdd + Zero, DefaultAllocator: Allocator, { self.compress_rows_tr(|col| col.sum()) @@ -161,6 +168,7 @@ impl> Matrix VectorN where + N: ClosedAdd + Zero, DefaultAllocator: Allocator, { let nrows = self.data.shape().0; @@ -168,9 +176,7 @@ impl> Matrix, R: Dim, C: Dim, S: Storage> Matrix { /* * * Variance computation. @@ -189,7 +195,10 @@ impl, R: Dim, C: Dim, S: Storage> M /// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8); /// ``` #[inline] - pub fn variance(&self) -> N { + pub fn variance(&self) -> N + where + N: Field + SupersetOf, + { if self.len() == 0 { N::zero() } else { @@ -217,6 +226,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn row_variance(&self) -> RowVectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { self.compress_rows(|col| col.variance()) @@ -236,6 +246,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn row_variance_tr(&self) -> VectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { self.compress_rows_tr(|col| col.variance()) @@ -256,6 +267,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn column_variance(&self) -> VectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { let (nrows, ncols) = self.data.shape(); @@ -292,7 +304,10 @@ impl, R: Dim, C: Dim, S: Storage> M /// assert_eq!(m.mean(), 3.5); /// ``` #[inline] - pub fn mean(&self) -> N { + pub fn mean(&self) -> N + where + N: Field + SupersetOf, + { if self.len() == 0 { N::zero() } else { @@ -316,6 +331,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn row_mean(&self) -> RowVectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { self.compress_rows(|col| col.mean()) @@ -335,6 +351,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn row_mean_tr(&self) -> VectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { self.compress_rows_tr(|col| col.mean()) @@ -354,6 +371,7 @@ impl, R: Dim, C: Dim, S: Storage> M #[inline] pub fn column_mean(&self) -> VectorN where + N: Field + SupersetOf, DefaultAllocator: Allocator, { let (nrows, ncols) = self.data.shape(); diff --git a/src/base/storage.rs b/src/base/storage.rs index 598cb061..77e7c13f 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -15,7 +15,7 @@ use crate::base::Scalar; pub type SameShapeStorage = , SameShapeC>>::Buffer; -// FIXME: better name than Owned ? +// TODO: better name than Owned ? /// The owned data storage that can be allocated from `S`. pub type Owned = >::Buffer; @@ -29,7 +29,7 @@ pub type CStride = /// The trait shared by all matrix data storage. /// -/// FIXME: doc +/// TODO: doc /// /// Note that `Self` must always have a number of elements compatible with the matrix length (given /// by `R` and `C` if they are known at compile-time). For example, implementors of this trait diff --git a/src/base/swizzle.rs b/src/base/swizzle.rs index 02e48834..b8578925 100644 --- a/src/base/swizzle.rs +++ b/src/base/swizzle.rs @@ -5,58 +5,58 @@ use typenum::{self, Cmp, Greater}; macro_rules! impl_swizzle { ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => { $( - impl> Vector - where D::Value: Cmp - { - $( - /// Builds a new vector from components of `self`. - #[inline] - pub fn $name(&self) -> $Result { - $Result::new($(self[$i].inlined_clone()),*) - } - )* - } + $( + /// Builds a new vector from components of `self`. + #[inline] + pub fn $name(&self) -> $Result + where D::Value: Cmp { + $Result::new($(self[$i].inlined_clone()),*) + } + )* )* } } -impl_swizzle!( - where U0: xx() -> Vector2[0, 0], - xxx() -> Vector3[0, 0, 0]; +/// # Swizzling +impl> Vector { + impl_swizzle!( + where U0: xx() -> Vector2[0, 0], + xxx() -> Vector3[0, 0, 0]; - where U1: xy() -> Vector2[0, 1], - yx() -> Vector2[1, 0], - yy() -> Vector2[1, 1], - xxy() -> Vector3[0, 0, 1], - xyx() -> Vector3[0, 1, 0], - xyy() -> Vector3[0, 1, 1], - yxx() -> Vector3[1, 0, 0], - yxy() -> Vector3[1, 0, 1], - yyx() -> Vector3[1, 1, 0], - yyy() -> Vector3[1, 1, 1]; + where U1: xy() -> Vector2[0, 1], + yx() -> Vector2[1, 0], + yy() -> Vector2[1, 1], + xxy() -> Vector3[0, 0, 1], + xyx() -> Vector3[0, 1, 0], + xyy() -> Vector3[0, 1, 1], + yxx() -> Vector3[1, 0, 0], + yxy() -> Vector3[1, 0, 1], + yyx() -> Vector3[1, 1, 0], + yyy() -> Vector3[1, 1, 1]; - where U2: xz() -> Vector2[0, 2], - yz() -> Vector2[1, 2], - zx() -> Vector2[2, 0], - zy() -> Vector2[2, 1], - zz() -> Vector2[2, 2], - xxz() -> Vector3[0, 0, 2], - xyz() -> Vector3[0, 1, 2], - xzx() -> Vector3[0, 2, 0], - xzy() -> Vector3[0, 2, 1], - xzz() -> Vector3[0, 2, 2], - yxz() -> Vector3[1, 0, 2], - yyz() -> Vector3[1, 1, 2], - yzx() -> Vector3[1, 2, 0], - yzy() -> Vector3[1, 2, 1], - yzz() -> Vector3[1, 2, 2], - zxx() -> Vector3[2, 0, 0], - zxy() -> Vector3[2, 0, 1], - zxz() -> Vector3[2, 0, 2], - zyx() -> Vector3[2, 1, 0], - zyy() -> Vector3[2, 1, 1], - zyz() -> Vector3[2, 1, 2], - zzx() -> Vector3[2, 2, 0], - zzy() -> Vector3[2, 2, 1], - zzz() -> Vector3[2, 2, 2]; -); + where U2: xz() -> Vector2[0, 2], + yz() -> Vector2[1, 2], + zx() -> Vector2[2, 0], + zy() -> Vector2[2, 1], + zz() -> Vector2[2, 2], + xxz() -> Vector3[0, 0, 2], + xyz() -> Vector3[0, 1, 2], + xzx() -> Vector3[0, 2, 0], + xzy() -> Vector3[0, 2, 1], + xzz() -> Vector3[0, 2, 2], + yxz() -> Vector3[1, 0, 2], + yyz() -> Vector3[1, 1, 2], + yzx() -> Vector3[1, 2, 0], + yzy() -> Vector3[1, 2, 1], + yzz() -> Vector3[1, 2, 2], + zxx() -> Vector3[2, 0, 0], + zxy() -> Vector3[2, 0, 1], + zxz() -> Vector3[2, 0, 2], + zyx() -> Vector3[2, 1, 0], + zyy() -> Vector3[2, 1, 1], + zyz() -> Vector3[2, 1, 2], + zzx() -> Vector3[2, 2, 0], + zzy() -> Vector3[2, 2, 1], + zzz() -> Vector3[2, 2, 2]; + ); +} diff --git a/src/base/unit.rs b/src/base/unit.rs index f0334679..9a32dd2f 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -237,7 +237,7 @@ where T::RealField: RelativeEq // } // } */ -// FIXME:re-enable this impl when specialization is possible. +// TODO:re-enable this impl when specialization is possible. // Currently, it is disabled so that we can have a nice output for the `UnitQuaternion` display. /* impl fmt::Display for Unit { diff --git a/src/geometry/isometry_ops.rs b/src/geometry/isometry_ops.rs index aaaefc6f..20e96f3e 100644 --- a/src/geometry/isometry_ops.rs +++ b/src/geometry/isometry_ops.rs @@ -13,7 +13,7 @@ use crate::geometry::{ AbstractRotation, Isometry, Point, Rotation, Translation, UnitComplex, UnitQuaternion, }; -// FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't +// TODO: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` // which is quite ugly. @@ -151,7 +151,7 @@ isometry_binop_impl_all!( #[allow(clippy::suspicious_arithmetic_impl)] Isometry::from_parts(Translation::from(&self.translation.vector + shift), - self.rotation.clone() * rhs.rotation.clone()) // FIXME: too bad we have to clone. + self.rotation.clone() * rhs.rotation.clone()) // TODO: too bad we have to clone. }; ); @@ -209,7 +209,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (D, U1), (D, D) for D: DimName; self: Isometry>, rhs: Rotation; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -226,7 +226,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (U3, U3), (U3, U3) for; self: Isometry>, rhs: UnitQuaternion; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -243,7 +243,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (U2, U2), (U2, U2) for; self: Isometry>, rhs: UnitComplex; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -261,7 +261,7 @@ isometry_binop_impl_all!( // Isometry × Vector isometry_binop_impl_all!( Mul, mul; - // FIXME: because of `transform_vector`, we cant use a generic storage type for the rhs vector, + // TODO: because of `transform_vector`, we cant use a generic storage type for the rhs vector, // i.e., right: Vector where S: Storage. self: Isometry, right: VectorN, Output = VectorN; [val val] => self.rotation.transform_vector(&right); @@ -273,7 +273,7 @@ isometry_binop_impl_all!( // Isometry × Unit isometry_binop_impl_all!( Mul, mul; - // FIXME: because of `transform_vector`, we cant use a generic storage type for the rhs vector, + // TODO: because of `transform_vector`, we cant use a generic storage type for the rhs vector, // i.e., right: Vector where S: Storage. self: Isometry, right: Unit>, Output = Unit>; [val val] => Unit::new_unchecked(self.rotation.transform_vector(right.as_ref())); @@ -390,7 +390,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: Rotation, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); ); @@ -417,7 +417,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: Rotation, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); ); @@ -428,7 +428,7 @@ isometry_from_composition_impl_all!( (D, D), (D, U1) for D: DimName; self: Rotation, right: Isometry>, Output = Isometry>; - // FIXME: don't call inverse explicitly? + // TODO: don't call inverse explicitly? [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; @@ -442,7 +442,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: UnitQuaternion, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); ); @@ -469,7 +469,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: UnitQuaternion, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); ); @@ -480,7 +480,7 @@ isometry_from_composition_impl_all!( (U4, U1), (U3, U1); self: UnitQuaternion, right: Isometry>, Output = Isometry>; - // FIXME: don't call inverse explicitly? + // TODO: don't call inverse explicitly? [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; @@ -516,7 +516,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: UnitComplex, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); ); @@ -528,7 +528,7 @@ isometry_from_composition_impl_all!( self: Isometry>, rhs: UnitComplex, Output = Isometry>; [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // TODO: do not clone. [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); ); diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 6f991f72..5701aa8f 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -22,7 +22,7 @@ mod rotation_alias; mod rotation_construction; mod rotation_conversion; mod rotation_ops; -mod rotation_simba; // FIXME: implement Rotation methods. +mod rotation_simba; // TODO: implement Rotation methods. mod rotation_specialization; mod quaternion; diff --git a/src/geometry/op_macros.rs b/src/geometry/op_macros.rs index 19d348f4..5a9cfa00 100644 --- a/src/geometry/op_macros.rs +++ b/src/geometry/op_macros.rs @@ -1,6 +1,6 @@ #![macro_use] -// FIXME: merge with `md_impl`. +// TODO: merge with `md_impl`. /// Macro for the implementation of multiplication and division. macro_rules! md_impl( ( @@ -140,7 +140,7 @@ macro_rules! md_assign_impl_all( } ); -// FIXME: merge with `as_impl`. +// TODO: merge with `as_impl`. /// Macro for the implementation of addition and subtraction. macro_rules! add_sub_impl( ($Op: ident, $op: ident, $bound: ident; @@ -164,7 +164,7 @@ macro_rules! add_sub_impl( } ); -// FIXME: merge with `md_assign_impl`. +// TODO: merge with `md_assign_impl`. /// Macro for the implementation of assignment-addition and assignment-subtraction. macro_rules! add_sub_assign_impl( ($Op: ident, $op: ident, $bound: ident; diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 9f0eadaf..9840f271 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -392,7 +392,7 @@ impl Orthographic3 { (-N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)] } - // FIXME: when we get specialization, specialize the Mul impl instead. + // TODO: when we get specialization, specialize the Mul impl instead. /// Projects a point. Faster than matrix multiplication. /// /// # Example @@ -463,7 +463,7 @@ impl Orthographic3 { ) } - // FIXME: when we get specialization, specialize the Mul impl instead. + // TODO: when we get specialization, specialize the Mul impl instead. /// Projects a vector. Faster than matrix multiplication. /// /// Vectors are not affected by the translation part of the projection. diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index f550bcc6..c11b7632 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -186,9 +186,9 @@ impl Perspective3 { (self.matrix[(2, 3)] - ratio * self.matrix[(2, 3)]) / crate::convert(2.0) } - // FIXME: add a method to retrieve znear and zfar simultaneously? + // TODO: add a method to retrieve znear and zfar simultaneously? - // FIXME: when we get specialization, specialize the Mul impl instead. + // TODO: when we get specialization, specialize the Mul impl instead. /// Projects a point. Faster than matrix multiplication. #[inline] pub fn project_point(&self, p: &Point3) -> Point3 { @@ -212,7 +212,7 @@ impl Perspective3 { ) } - // FIXME: when we get specialization, specialize the Mul impl instead. + // TODO: when we get specialization, specialize the Mul impl instead. /// Projects a vector. Faster than matrix multiplication. #[inline] pub fn project_vector(&self, p: &Vector) -> Vector3 diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 83b4521d..2723e626 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -39,7 +39,7 @@ where #[inline] fn is_in_subset(m: &Point) -> bool { - // FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of + // TODO: is there a way to reuse the `.is_in_subset` from the matrix implementation of // SubsetOf? m.iter().all(|e| e.is_in_subset()) } diff --git a/src/geometry/point_ops.rs b/src/geometry/point_ops.rs index e6547fc4..029286ff 100644 --- a/src/geometry/point_ops.rs +++ b/src/geometry/point_ops.rs @@ -107,7 +107,7 @@ add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; self: &'a Point, right: Vector, Output = Point; - Self::Output::from(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`. + Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`. add_sub_impl!(Sub, sub, ClosedSub; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; @@ -128,7 +128,7 @@ add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; self: &'a Point, right: Vector, Output = Point; - Self::Output::from(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`. + Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`. add_sub_impl!(Add, add, ClosedAdd; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 69d54967..8c4537dc 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -1519,7 +1519,7 @@ where /// ``` #[inline] pub fn inverse_transform_point(&self, pt: &Point3) -> Point3 { - // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement + // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 33e05867..0c8d769f 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -69,7 +69,7 @@ impl Quaternion { /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); /// ``` #[inline] - // FIXME: take a reference to `vector`? + // TODO: take a reference to `vector`? pub fn from_parts(scalar: N, vector: Vector) -> Self where SB: Storage, @@ -100,7 +100,7 @@ impl Quaternion { } } -// FIXME: merge with the previous block. +// TODO: merge with the previous block. impl Quaternion where N::Element: SimdRealField, @@ -108,7 +108,7 @@ where /// Creates a new quaternion from its polar decomposition. /// /// Note that `axis` is assumed to be a unit vector. - // FIXME: take a reference to `axis`? + // TODO: take a reference to `axis`? pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) -> Self where SB: Storage, @@ -422,7 +422,7 @@ where SB: Storage, SC: Storage, { - // FIXME: code duplication with Rotation. + // TODO: code duplication with Rotation. if let (Some(na), Some(nb)) = ( Unit::try_new(a.clone_owned(), N::zero()), Unit::try_new(b.clone_owned(), N::zero()), @@ -484,7 +484,7 @@ where SB: Storage, SC: Storage, { - // FIXME: code duplication with Rotation. + // TODO: code duplication with Rotation. let c = na.cross(&nb); if let Some(axis) = Unit::try_new(c, N::default_epsilon()) { diff --git a/src/geometry/quaternion_ops.rs b/src/geometry/quaternion_ops.rs index d91d7fd8..2961362e 100644 --- a/src/geometry/quaternion_ops.rs +++ b/src/geometry/quaternion_ops.rs @@ -45,8 +45,8 @@ * UnitQuaternion ÷= UnitQuaternion * UnitQuaternion ÷= Rotation * - * FIXME: Rotation ×= UnitQuaternion - * FIXME: Rotation ÷= UnitQuaternion + * TODO: Rotation ×= UnitQuaternion + * TODO: Rotation ÷= UnitQuaternion * */ @@ -248,7 +248,7 @@ quaternion_op_impl!( (U4, U1), (U3, U3); self: &'a UnitQuaternion, rhs: &'b Rotation, Output = UnitQuaternion => U3, U3; - // FIXME: can we avoid the conversion from a rotation matrix? + // TODO: can we avoid the conversion from a rotation matrix? self * UnitQuaternion::::from_rotation_matrix(rhs); 'a, 'b); @@ -281,7 +281,7 @@ quaternion_op_impl!( (U4, U1), (U3, U3); self: &'a UnitQuaternion, rhs: &'b Rotation, Output = UnitQuaternion => U3, U3; - // FIXME: can we avoid the conversion to a rotation matrix? + // TODO: can we avoid the conversion to a rotation matrix? self / UnitQuaternion::::from_rotation_matrix(rhs); 'a, 'b); @@ -314,7 +314,7 @@ quaternion_op_impl!( (U3, U3), (U4, U1); self: &'a Rotation, rhs: &'b UnitQuaternion, Output = UnitQuaternion => U3, U3; - // FIXME: can we avoid the conversion from a rotation matrix? + // TODO: can we avoid the conversion from a rotation matrix? UnitQuaternion::::from_rotation_matrix(self) * rhs; 'a, 'b); @@ -347,7 +347,7 @@ quaternion_op_impl!( (U3, U3), (U4, U1); self: &'a Rotation, rhs: &'b UnitQuaternion, Output = UnitQuaternion => U3, U3; - // FIXME: can we avoid the conversion from a rotation matrix? + // TODO: can we avoid the conversion from a rotation matrix? UnitQuaternion::::from_rotation_matrix(self) / rhs; 'a, 'b); @@ -615,7 +615,7 @@ quaternion_op_impl!( self: Quaternion, rhs: &'b Quaternion; { let res = &*self * rhs; - // FIXME: will this be optimized away? + // TODO: will this be optimized away? self.coords.copy_from(&res.coords); }; 'b); diff --git a/src/geometry/reflection.rs b/src/geometry/reflection.rs index c0500e84..d5e950ec 100644 --- a/src/geometry/reflection.rs +++ b/src/geometry/reflection.rs @@ -41,7 +41,7 @@ impl> Reflection { &self.axis } - // FIXME: naming convention: reflect_to, reflect_assign ? + // TODO: naming convention: reflect_to, reflect_assign ? /// Applies the reflection to the columns of `rhs`. pub fn reflect(&self, rhs: &mut Matrix) where @@ -58,7 +58,7 @@ impl> Reflection { } } - // FIXME: naming convention: reflect_to, reflect_assign ? + // TODO: naming convention: reflect_to, reflect_assign ? /// Applies the reflection to the columns of `rhs`. pub fn reflect_with_sign(&self, rhs: &mut Matrix, sign: N) where diff --git a/src/geometry/rotation_ops.rs b/src/geometry/rotation_ops.rs index 9b90c856..ae66c02e 100644 --- a/src/geometry/rotation_ops.rs +++ b/src/geometry/rotation_ops.rs @@ -54,7 +54,7 @@ md_impl_all!( ); // Rotation ÷ Rotation -// FIXME: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? +// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? md_impl_all!( Div, div; (D, D), (D, D) for D: DimName; @@ -105,7 +105,7 @@ md_impl_all!( ); // Rotation × Point -// FIXME: we don't handle properly non-zero origins here. Do we want this to be the intended +// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended // behavior? md_impl_all!( Mul, mul; @@ -133,7 +133,7 @@ md_impl_all!( ); // Rotation ×= Rotation -// FIXME: try not to call `inverse()` explicitly. +// TODO: try not to call `inverse()` explicitly. md_assign_impl_all!( MulAssign, mul_assign; @@ -152,8 +152,8 @@ md_assign_impl_all!( ); // Matrix *= Rotation -// FIXME: try not to call `inverse()` explicitly. -// FIXME: this shares the same limitations as for the current impl. of MulAssign for matrices. +// TODO: try not to call `inverse()` explicitly. +// TODO: this shares the same limitations as for the current impl. of MulAssign for matrices. // (In particular the number of matrix column must be equal to the number of rotation columns, // i.e., equal to the rotation dimension. diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 085cb2d8..11b63cde 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -706,7 +706,7 @@ where SB: Storage, SC: Storage, { - // FIXME: code duplication with Rotation. + // TODO: code duplication with Rotation. if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { let c = na.cross(&nb); diff --git a/src/geometry/similarity_conversion.rs b/src/geometry/similarity_conversion.rs index 7953bc47..abcd7187 100644 --- a/src/geometry/similarity_conversion.rs +++ b/src/geometry/similarity_conversion.rs @@ -120,7 +120,7 @@ where .try_normalize_mut(N2::zero()) .is_some() { - // FIXME: could we avoid explicit the computation of the determinant? + // TODO: could we avoid explicit the computation of the determinant? // (its sign is needed to see if the scaling factor is negative). if rot.determinant() < N2::zero() { rot.fixed_columns_mut::(0).neg_mut(); @@ -149,7 +149,7 @@ where let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness. - // FIXME: could we avoid the explicit computation of the determinant? + // TODO: could we avoid the explicit computation of the determinant? // (its sign is needed to see if the scaling factor is negative). if mm.fixed_slice::(0, 0).determinant() < N2::zero() { mm.fixed_slice_mut::(0, 0).neg_mut(); diff --git a/src/geometry/similarity_ops.rs b/src/geometry/similarity_ops.rs index 09d40f05..959ac3a3 100644 --- a/src/geometry/similarity_ops.rs +++ b/src/geometry/similarity_ops.rs @@ -13,7 +13,7 @@ use crate::geometry::{ UnitQuaternion, }; -// FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't +// TODO: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` // which is quite ugly. @@ -191,7 +191,7 @@ similarity_binop_assign_impl_all!( DivAssign, div_assign; self: Similarity, rhs: Similarity; [val] => *self /= &rhs; - // FIXME: don't invert explicitly. + // TODO: don't invert explicitly. [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -212,7 +212,7 @@ similarity_binop_assign_impl_all!( DivAssign, div_assign; self: Similarity, rhs: Isometry; [val] => *self /= &rhs; - // FIXME: don't invert explicitly. + // TODO: don't invert explicitly. [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -230,7 +230,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (D, U1), (D, D) for D: DimName; self: Similarity>, rhs: Rotation; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -247,7 +247,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (U3, U3), (U3, U3) for; self: Similarity>, rhs: UnitQuaternion; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -264,7 +264,7 @@ md_assign_impl_all!( DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; (U2, U2), (U2, U2) for; self: Similarity>, rhs: UnitComplex; - // FIXME: don't invert explicitly? + // TODO: don't invert explicitly? [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; ); @@ -495,7 +495,7 @@ similarity_from_composition_impl_all!( (D, D), (D, U1) for D: DimName; self: Rotation, right: Similarity>, Output = Similarity>; - // FIXME: don't call inverse explicitly? + // TODO: don't call inverse explicitly? [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; @@ -556,7 +556,7 @@ similarity_from_composition_impl_all!( (U4, U1), (U3, U1); self: UnitQuaternion, right: Similarity>, Output = Similarity>; - // FIXME: don't call inverse explicitly? + // TODO: don't call inverse explicitly? [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index 80b72771..b15eb28f 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -165,7 +165,7 @@ where _phantom: PhantomData, } -// FIXME +// TODO // impl + hash::Hash, C: TCategory> hash::Hash for Transform // where DefaultAllocator: Allocator, DimNameSum>, // Owned, DimNameSum>: hash::Hash { @@ -411,7 +411,7 @@ where where C: SubTCategoryOf, { - // FIXME: specialize for TAffine? + // TODO: specialize for TAffine? Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) } diff --git a/src/geometry/transform_alga.rs b/src/geometry/transform_alga.rs index 3ba6eb7d..f83a0f8c 100755 --- a/src/geometry/transform_alga.rs +++ b/src/geometry/transform_alga.rs @@ -129,7 +129,7 @@ where } } -// FIXME: we need to implement an SVD for this. +// TODO: we need to implement an SVD for this. // // impl, C> AffineTransformation> for Transform // where N: RealField, diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index 2fe9d245..01cf4d3d 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -27,7 +27,7 @@ use crate::geometry::{ * Transform × Similarity * Transform × Transform * Transform × UnitQuaternion - * FIXME: Transform × UnitComplex + * TODO: Transform × UnitComplex * Transform × Translation * Transform × Vector * Transform × Point @@ -37,21 +37,21 @@ use crate::geometry::{ * Similarity × Transform * Translation × Transform * UnitQuaternion × Transform - * FIXME: UnitComplex × Transform + * TODO: UnitComplex × Transform * - * FIXME: Transform ÷ Isometry + * TODO: Transform ÷ Isometry * Transform ÷ Rotation - * FIXME: Transform ÷ Similarity + * TODO: Transform ÷ Similarity * Transform ÷ Transform * Transform ÷ UnitQuaternion * Transform ÷ Translation * - * FIXME: Isometry ÷ Transform + * TODO: Isometry ÷ Transform * Rotation ÷ Transform - * FIXME: Similarity ÷ Transform + * TODO: Similarity ÷ Transform * Translation ÷ Transform * UnitQuaternion ÷ Transform - * FIXME: UnitComplex ÷ Transform + * TODO: UnitComplex ÷ Transform * * * (Assignment Operators) @@ -62,15 +62,15 @@ use crate::geometry::{ * Transform ×= Isometry * Transform ×= Rotation * Transform ×= UnitQuaternion - * FIXME: Transform ×= UnitComplex + * TODO: Transform ×= UnitComplex * Transform ×= Translation * * Transform ÷= Transform - * FIXME: Transform ÷= Similarity - * FIXME: Transform ÷= Isometry + * TODO: Transform ÷= Similarity + * TODO: Transform ÷= Isometry * Transform ÷= Rotation * Transform ÷= UnitQuaternion - * FIXME: Transform ÷= UnitComplex + * TODO: Transform ÷= UnitComplex * */ @@ -260,7 +260,7 @@ md_impl_all!( /* * - * FIXME: don't explicitly build the homogeneous translation matrix. + * TODO: don't explicitly build the homogeneous translation matrix. * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from * `DimNameAdd` requirement). @@ -452,7 +452,7 @@ md_assign_impl_all!( /* * - * FIXME: don't explicitly build the homogeneous translation matrix. + * TODO: don't explicitly build the homogeneous translation matrix. * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from * `DimNameAdd` requirement). diff --git a/src/geometry/translation_ops.rs b/src/geometry/translation_ops.rs index acd1795f..fc53b1e6 100644 --- a/src/geometry/translation_ops.rs +++ b/src/geometry/translation_ops.rs @@ -34,7 +34,7 @@ add_sub_impl!(Mul, mul, ClosedAdd; #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + right.vector) }; ); // Translation ÷ Translation -// FIXME: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? +// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? add_sub_impl!(Div, div, ClosedSub; (D, U1), (D, U1) -> (D) for D: DimName; self: &'a Translation, right: &'b Translation, Output = Translation; @@ -59,7 +59,7 @@ add_sub_impl!(Div, div, ClosedSub; #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - right.vector) }; ); // Translation × Point -// FIXME: we don't handle properly non-zero origins here. Do we want this to be the intended +// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended // behavior? add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index a31f3ddf..76d7f392 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -340,7 +340,7 @@ where /// ``` #[inline] pub fn inverse_transform_point(&self, pt: &Point2) -> Point2 { - // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement + // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index cfe8d918..826b5671 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -65,7 +65,7 @@ where /// /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); /// ``` - // FIXME: deprecate this. + // TODO: deprecate this. #[inline] pub fn from_angle(angle: N) -> Self { Self::new(angle) @@ -127,7 +127,7 @@ where /// let complex = UnitComplex::from_rotation_matrix(&rot); /// assert_eq!(complex, UnitComplex::new(1.7)); /// ``` - // FIXME: add UnitComplex::from(...) instead? + // TODO: add UnitComplex::from(...) instead? #[inline] pub fn from_rotation_matrix(rotmat: &Rotation2) -> Self { Self::new_unchecked(Complex::new(rotmat[(0, 0)], rotmat[(1, 0)])) @@ -213,7 +213,7 @@ where SB: Storage, SC: Storage, { - // FIXME: code duplication with Rotation. + // TODO: code duplication with Rotation. if let (Some(na), Some(nb)) = ( Unit::try_new(a.clone_owned(), N::zero()), Unit::try_new(b.clone_owned(), N::zero()), diff --git a/src/io/matrix_market.rs b/src/io/matrix_market.rs index 3f7834ac..9df66661 100644 --- a/src/io/matrix_market.rs +++ b/src/io/matrix_market.rs @@ -9,14 +9,14 @@ use pest::Parser; #[grammar = "io/matrix_market.pest"] struct MatrixMarketParser; -// FIXME: return an Error instead of an Option. +// TODO: return an Error instead of an Option. /// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix. pub fn cs_matrix_from_matrix_market>(path: P) -> Option> { let file = fs::read_to_string(path).ok()?; cs_matrix_from_matrix_market_str(&file) } -// FIXME: return an Error instead of an Option. +// TODO: return an Error instead of an Option. /// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix. pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option> { let file = MatrixMarketParser::parse(Rule::Document, data) @@ -43,7 +43,7 @@ pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option().ok()? - 1); data.push(crate::convert(inner.next()?.as_str().parse::().ok()?)); } - _ => return None, // FIXME: return an Err instead. + _ => return None, // TODO: return an Err instead. } } diff --git a/src/linalg/bidiagonal.rs b/src/linalg/bidiagonal.rs index 3a789978..3ae38432 100644 --- a/src/linalg/bidiagonal.rs +++ b/src/linalg/bidiagonal.rs @@ -40,7 +40,7 @@ where + Allocator> + Allocator, U1>>, { - // FIXME: perhaps we should pack the axes into different vectors so that axes for `v_t` are + // TODO: perhaps we should pack the axes into different vectors so that axes for `v_t` are // contiguous. This prevents some useless copies. uv: MatrixMN, /// The diagonal elements of the decomposed matrix. @@ -176,7 +176,7 @@ where + Allocator> + Allocator, C>, { - // FIXME: optimize by calling a reallocator. + // TODO: optimize by calling a reallocator. (self.u(), self.d(), self.v_t()) } @@ -199,7 +199,7 @@ where } /// Computes the orthogonal matrix `U` of this `U * D * V` decomposition. - // FIXME: code duplication with householder::assemble_q. + // TODO: code duplication with householder::assemble_q. // Except that we are returning a rectangular matrix here. pub fn u(&self) -> MatrixMN> where @@ -213,7 +213,7 @@ where for i in (0..dim - shift).rev() { let axis = self.uv.slice_range(i + shift.., i); - // FIXME: sometimes, the axis might have a zero magnitude. + // TODO: sometimes, the axis might have a zero magnitude. let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); let mut res_rows = res.slice_range_mut(i + shift.., i..); @@ -248,7 +248,7 @@ where let axis = self.uv.slice_range(i, i + shift..); let mut axis_packed = axis_packed.rows_range_mut(i + shift..); axis_packed.tr_copy_from(&axis); - // FIXME: sometimes, the axis might have a zero magnitude. + // TODO: sometimes, the axis might have a zero magnitude. let refl = Reflection::new(Unit::new_unchecked(axis_packed), N::zero()); let mut res_rows = res.slice_range_mut(i.., i + shift..); @@ -312,7 +312,7 @@ where // self.solve_upper_triangular_mut(b); // } // -// // FIXME: duplicate code from the `solve` module. +// // TODO: duplicate code from the `solve` module. // fn solve_upper_triangular_mut(&self, b: &mut Matrix) // where S2: StorageMut, // ShapeConstraint: SameNumberOfRows { @@ -339,7 +339,7 @@ where // pub fn inverse(&self) -> MatrixN { // assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix."); // -// // FIXME: is there a less naive method ? +// // TODO: is there a less naive method ? // let (nrows, ncols) = self.uv.data.shape(); // let mut res = MatrixN::identity_generic(nrows, ncols); // self.solve_mut(&mut res); diff --git a/src/linalg/givens.rs b/src/linalg/givens.rs index 164a0971..32a4204e 100644 --- a/src/linalg/givens.rs +++ b/src/linalg/givens.rs @@ -147,7 +147,7 @@ impl GivensRotation { let s = self.s; let c = self.c; - // FIXME: can we optimize that to iterate on one column at a time ? + // TODO: can we optimize that to iterate on one column at a time ? for j in 0..lhs.nrows() { unsafe { let a = *lhs.get_unchecked((j, 0)); diff --git a/src/linalg/hessenberg.rs b/src/linalg/hessenberg.rs index 1e795b41..beff5420 100644 --- a/src/linalg/hessenberg.rs +++ b/src/linalg/hessenberg.rs @@ -107,7 +107,7 @@ where self.hess } - // FIXME: add a h that moves out of self. + // TODO: add a h that moves out of self. /// Retrieves the upper trapezoidal submatrix `H` of this decomposition. /// /// This is less efficient than `.unpack_h()` as it allocates a new matrix. diff --git a/src/linalg/householder.rs b/src/linalg/householder.rs index 9f4c9e69..ebbffd30 100644 --- a/src/linalg/householder.rs +++ b/src/linalg/householder.rs @@ -36,7 +36,7 @@ pub fn reflection_axis_mut>( column.unscale_mut(factor.sqrt()); (-signed_norm, true) } else { - // FIXME: not sure why we don't have a - sign here. + // TODO: not sure why we don't have a - sign here. (signed_norm, false) } } diff --git a/src/linalg/mod.rs b/src/linalg/mod.rs index df265498..c602bfa7 100644 --- a/src/linalg/mod.rs +++ b/src/linalg/mod.rs @@ -5,7 +5,7 @@ mod bidiagonal; mod cholesky; mod convolution; mod determinant; -// FIXME: this should not be needed. However, the exp uses +// TODO: this should not be needed. However, the exp uses // explicit float operations on `f32` and `f64`. We need to // get rid of these to allow exp to be used on a no-std context. mod decomposition; @@ -25,7 +25,7 @@ mod svd; mod symmetric_eigen; mod symmetric_tridiagonal; -//// FIXME: Not complete enough for publishing. +//// TODO: Not complete enough for publishing. //// This handles only cases where each eigenvalue has multiplicity one. // mod eigen; diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index d3cf3275..f404aa5a 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -108,7 +108,7 @@ where for i in (0..dim).rev() { let axis = self.qr.slice_range(i.., i); - // FIXME: sometimes, the axis might have a zero magnitude. + // TODO: sometimes, the axis might have a zero magnitude. let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); let mut res_rows = res.slice_range_mut(i.., i..); @@ -140,7 +140,7 @@ where /// Multiplies the provided matrix by the transpose of the `Q` matrix of this decomposition. pub fn q_tr_mul(&self, rhs: &mut Matrix) - // FIXME: do we need a static constraint on the number of rows of rhs? + // TODO: do we need a static constraint on the number of rows of rhs? where S2: StorageMut, { @@ -204,7 +204,7 @@ where self.solve_upper_triangular_mut(b) } - // FIXME: duplicate code from the `solve` module. + // TODO: duplicate code from the `solve` module. fn solve_upper_triangular_mut( &self, b: &mut Matrix, @@ -248,7 +248,7 @@ where "QR inverse: unable to compute the inverse of a non-square matrix." ); - // FIXME: is there a less naive method ? + // TODO: is there a less naive method ? let (nrows, ncols) = self.qr.data.shape(); let mut res = MatrixN::identity_generic(nrows, ncols); diff --git a/src/linalg/schur.rs b/src/linalg/schur.rs index 1292bad7..72c9b5ac 100644 --- a/src/linalg/schur.rs +++ b/src/linalg/schur.rs @@ -115,7 +115,7 @@ where let mut t; if compute_q { - // FIXME: could we work without unpacking? Using only the internal representation of + // TODO: could we work without unpacking? Using only the internal representation of // hessenberg decomposition. let (vecs, vals) = hess.unpack(); q = Some(vecs); @@ -507,7 +507,7 @@ where // Special case for 2x2 matrices. if self.nrows() == 2 { - // FIXME: can we avoid this slicing + // TODO: can we avoid this slicing // (which is needed here just to transform D to U2)? let me = self.fixed_slice::(0, 0); return match compute_2x2_eigvals(&me) { @@ -520,7 +520,7 @@ where }; } - // FIXME: add balancing? + // TODO: add balancing? let schur = Schur::do_decompose( self.clone_owned(), &mut work, @@ -538,7 +538,7 @@ where /// Computes the eigenvalues of this matrix. pub fn complex_eigenvalues(&self) -> VectorN, D> - // FIXME: add balancing? + // TODO: add balancing? where N: RealField, DefaultAllocator: Allocator, D>, diff --git a/src/linalg/solve.rs b/src/linalg/solve.rs index ac5bff46..dddc5ecf 100644 --- a/src/linalg/solve.rs +++ b/src/linalg/solve.rs @@ -97,7 +97,7 @@ impl> SquareMatrix { true } - // FIXME: add the same but for solving upper-triangular. + // TODO: add the same but for solving upper-triangular. /// Solves the linear system `self . x = b` where `x` is the unknown and only the /// lower-triangular part of `self` is considered not-zero. The diagonal is never read as it is /// assumed to be equal to `diag`. Returns `false` and does not modify its inputs if `diag` is zero. @@ -510,7 +510,7 @@ impl> SquareMatrix { } } - // FIXME: add the same but for solving upper-triangular. + // TODO: add the same but for solving upper-triangular. /// Solves the linear system `self . x = b` where `x` is the unknown and only the /// lower-triangular part of `self` is considered not-zero. The diagonal is never read as it is /// assumed to be equal to `diag`. Returns `false` and does not modify its inputs if `diag` is zero. diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index 93cba072..2e51dc85 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -191,7 +191,7 @@ where } let v = Vector2::new(subm[(0, 0)], subm[(1, 0)]); - // FIXME: does the case `v.y == 0` ever happen? + // TODO: does the case `v.y == 0` ever happen? let (rot2, norm2) = GivensRotation::cancel_y(&v) .unwrap_or((GivensRotation::identity(), subm[(0, 0)])); @@ -395,7 +395,7 @@ where off_diagonal[m] = N::RealField::zero(); break; } - // FIXME: write a test that enters this case. + // TODO: write a test that enters this case. else if diagonal[m].norm1() <= eps { diagonal[m] = N::RealField::zero(); Self::cancel_horizontal_off_diagonal_elt( @@ -562,7 +562,7 @@ where /// /// Any singular value smaller than `eps` is assumed to be zero. /// Returns `Err` if the singular vectors `U` and `V` have not been computed. - // FIXME: make this more generic wrt the storage types and the dimensions for `b`. + // TODO: make this more generic wrt the storage types and the dimensions for `b`. pub fn solve( &self, b: &Matrix, diff --git a/src/sparse/cs_matrix.rs b/src/sparse/cs_matrix.rs index 9ff656d4..45a2bbf7 100644 --- a/src/sparse/cs_matrix.rs +++ b/src/sparse/cs_matrix.rs @@ -42,7 +42,7 @@ impl<'a, N: Clone> Iterator for ColumnEntries<'a, N> { } } -// FIXME: this structure exists for now only because impl trait +// TODO: this structure exists for now only because impl trait // cannot be used for trait method return types. /// Trait for iterable compressed-column matrix storage. pub trait CsStorageIter<'a, N, R, C = U1> { diff --git a/src/sparse/cs_matrix_cholesky.rs b/src/sparse/cs_matrix_cholesky.rs index db3c221a..277f9316 100644 --- a/src/sparse/cs_matrix_cholesky.rs +++ b/src/sparse/cs_matrix_cholesky.rs @@ -18,7 +18,7 @@ where // Decomposition result. l: CsMatrix, // Used only for the pattern. - // FIXME: store only the nonzero pattern instead. + // TODO: store only the nonzero pattern instead. u: CsMatrix, ok: bool, // Workspaces. @@ -266,7 +266,7 @@ where marks.clear(); marks.resize(tree.len(), false); - // FIXME: avoid all those allocations. + // TODO: avoid all those allocations. let mut tmp = Vec::new(); let mut res = Vec::new(); @@ -347,7 +347,7 @@ where } fn tree_postorder(tree: &[usize]) -> Vec { - // FIXME: avoid all those allocations? + // TODO: avoid all those allocations? let mut first_child: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect(); let mut other_children: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect(); diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 6ade807f..ed7b26d2 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -946,7 +946,7 @@ mod normalization_tests { } #[cfg(all(feature = "arbitrary", feature = "alga"))] -// FIXME: move this to alga ? +// TODO: move this to alga ? mod finite_dim_inner_space_tests { use super::*; use alga::linear::FiniteDimInnerSpace; diff --git a/tests/linalg/eigen.rs b/tests/linalg/eigen.rs index 1269ed45..c0d3171f 100644 --- a/tests/linalg/eigen.rs +++ b/tests/linalg/eigen.rs @@ -110,7 +110,7 @@ fn symmetric_eigen_singular_24x24() { // #[cfg(feature = "arbitrary")] // quickcheck! { -// FIXME: full eigendecomposition is not implemented yet because of its complexity when some +// TODO: full eigendecomposition is not implemented yet because of its complexity when some // eigenvalues have multiplicity > 1. // // /* From f2da993c8b498fc348532a4287508f93908af836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sun, 15 Nov 2020 17:22:37 +0100 Subject: [PATCH 6/8] Reduce matrix and slice aliases depth to 1. --- src/base/alias.rs | 128 +++++++-------- src/base/alias_slice.rs | 346 ++++++++++++++++++++-------------------- 2 files changed, 237 insertions(+), 237 deletions(-) diff --git a/src/base/alias.rs b/src/base/alias.rs index 2cba116b..7e64de0d 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -21,132 +21,132 @@ pub type MatrixNM = Matrix>; pub type MatrixMN = Matrix>; /// A statically sized column-major square matrix with `D` rows and columns. -pub type MatrixN = MatrixMN; +pub type MatrixN = Matrix>; /// A dynamically sized column-major matrix. #[cfg(any(feature = "std", feature = "alloc"))] -pub type DMatrix = MatrixN; +pub type DMatrix = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 1 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx1 = MatrixMN; +pub type MatrixXx1 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 2 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx2 = MatrixMN; +pub type MatrixXx2 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 3 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx3 = MatrixMN; +pub type MatrixXx3 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 4 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx4 = MatrixMN; +pub type MatrixXx4 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 5 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx5 = MatrixMN; +pub type MatrixXx5 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 6 columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx6 = MatrixMN; +pub type MatrixXx6 = Matrix>; /// A heap-allocated, row-major, matrix with 1 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix1xX = MatrixMN; +pub type Matrix1xX = Matrix>; /// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix2xX = MatrixMN; +pub type Matrix2xX = Matrix>; /// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix3xX = MatrixMN; +pub type Matrix3xX = Matrix>; /// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix4xX = MatrixMN; +pub type Matrix4xX = Matrix>; /// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix5xX = MatrixMN; +pub type Matrix5xX = Matrix>; /// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns. #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix6xX = MatrixMN; +pub type Matrix6xX = Matrix>; /// A stack-allocated, column-major, 1x1 square matrix. -pub type Matrix1 = MatrixN; +pub type Matrix1 = Matrix>; /// A stack-allocated, column-major, 2x2 square matrix. -pub type Matrix2 = MatrixN; +pub type Matrix2 = Matrix>; /// A stack-allocated, column-major, 3x3 square matrix. -pub type Matrix3 = MatrixN; +pub type Matrix3 = Matrix>; /// A stack-allocated, column-major, 4x4 square matrix. -pub type Matrix4 = MatrixN; +pub type Matrix4 = Matrix>; /// A stack-allocated, column-major, 5x5 square matrix. -pub type Matrix5 = MatrixN; +pub type Matrix5 = Matrix>; /// A stack-allocated, column-major, 6x6 square matrix. -pub type Matrix6 = MatrixN; +pub type Matrix6 = Matrix>; /// A stack-allocated, column-major, 1x2 matrix. -pub type Matrix1x2 = MatrixMN; +pub type Matrix1x2 = Matrix>; /// A stack-allocated, column-major, 1x3 matrix. -pub type Matrix1x3 = MatrixMN; +pub type Matrix1x3 = Matrix>; /// A stack-allocated, column-major, 1x4 matrix. -pub type Matrix1x4 = MatrixMN; +pub type Matrix1x4 = Matrix>; /// A stack-allocated, column-major, 1x5 matrix. -pub type Matrix1x5 = MatrixMN; +pub type Matrix1x5 = Matrix>; /// A stack-allocated, column-major, 1x6 matrix. -pub type Matrix1x6 = MatrixMN; +pub type Matrix1x6 = Matrix>; /// A stack-allocated, column-major, 2x3 matrix. -pub type Matrix2x3 = MatrixMN; +pub type Matrix2x3 = Matrix>; /// A stack-allocated, column-major, 2x4 matrix. -pub type Matrix2x4 = MatrixMN; +pub type Matrix2x4 = Matrix>; /// A stack-allocated, column-major, 2x5 matrix. -pub type Matrix2x5 = MatrixMN; +pub type Matrix2x5 = Matrix>; /// A stack-allocated, column-major, 2x6 matrix. -pub type Matrix2x6 = MatrixMN; +pub type Matrix2x6 = Matrix>; /// A stack-allocated, column-major, 3x4 matrix. -pub type Matrix3x4 = MatrixMN; +pub type Matrix3x4 = Matrix>; /// A stack-allocated, column-major, 3x5 matrix. -pub type Matrix3x5 = MatrixMN; +pub type Matrix3x5 = Matrix>; /// A stack-allocated, column-major, 3x6 matrix. -pub type Matrix3x6 = MatrixMN; +pub type Matrix3x6 = Matrix>; /// A stack-allocated, column-major, 4x5 matrix. -pub type Matrix4x5 = MatrixMN; +pub type Matrix4x5 = Matrix>; /// A stack-allocated, column-major, 4x6 matrix. -pub type Matrix4x6 = MatrixMN; +pub type Matrix4x6 = Matrix>; /// A stack-allocated, column-major, 5x6 matrix. -pub type Matrix5x6 = MatrixMN; +pub type Matrix5x6 = Matrix>; /// A stack-allocated, column-major, 2x1 matrix. -pub type Matrix2x1 = MatrixMN; +pub type Matrix2x1 = Matrix>; /// A stack-allocated, column-major, 3x1 matrix. -pub type Matrix3x1 = MatrixMN; +pub type Matrix3x1 = Matrix>; /// A stack-allocated, column-major, 4x1 matrix. -pub type Matrix4x1 = MatrixMN; +pub type Matrix4x1 = Matrix>; /// A stack-allocated, column-major, 5x1 matrix. -pub type Matrix5x1 = MatrixMN; +pub type Matrix5x1 = Matrix>; /// A stack-allocated, column-major, 6x1 matrix. -pub type Matrix6x1 = MatrixMN; +pub type Matrix6x1 = Matrix>; /// A stack-allocated, column-major, 3x2 matrix. -pub type Matrix3x2 = MatrixMN; +pub type Matrix3x2 = Matrix>; /// A stack-allocated, column-major, 4x2 matrix. -pub type Matrix4x2 = MatrixMN; +pub type Matrix4x2 = Matrix>; /// A stack-allocated, column-major, 5x2 matrix. -pub type Matrix5x2 = MatrixMN; +pub type Matrix5x2 = Matrix>; /// A stack-allocated, column-major, 6x2 matrix. -pub type Matrix6x2 = MatrixMN; +pub type Matrix6x2 = Matrix>; /// A stack-allocated, column-major, 4x3 matrix. -pub type Matrix4x3 = MatrixMN; +pub type Matrix4x3 = Matrix>; /// A stack-allocated, column-major, 5x3 matrix. -pub type Matrix5x3 = MatrixMN; +pub type Matrix5x3 = Matrix>; /// A stack-allocated, column-major, 6x3 matrix. -pub type Matrix6x3 = MatrixMN; +pub type Matrix6x3 = Matrix>; /// A stack-allocated, column-major, 5x4 matrix. -pub type Matrix5x4 = MatrixMN; +pub type Matrix5x4 = Matrix>; /// A stack-allocated, column-major, 6x4 matrix. -pub type Matrix6x4 = MatrixMN; +pub type Matrix6x4 = Matrix>; /// A stack-allocated, column-major, 6x5 matrix. -pub type Matrix6x5 = MatrixMN; +pub type Matrix6x5 = Matrix>; /* * @@ -160,20 +160,20 @@ pub type Matrix6x5 = MatrixMN; pub type DVector = Matrix>; /// A statically sized D-dimensional column vector. -pub type VectorN = MatrixMN; +pub type VectorN = Matrix>; /// A stack-allocated, 1-dimensional column vector. -pub type Vector1 = VectorN; +pub type Vector1 = Matrix>; /// A stack-allocated, 2-dimensional column vector. -pub type Vector2 = VectorN; +pub type Vector2 = Matrix>; /// A stack-allocated, 3-dimensional column vector. -pub type Vector3 = VectorN; +pub type Vector3 = Matrix>; /// A stack-allocated, 4-dimensional column vector. -pub type Vector4 = VectorN; +pub type Vector4 = Matrix>; /// A stack-allocated, 5-dimensional column vector. -pub type Vector5 = VectorN; +pub type Vector5 = Matrix>; /// A stack-allocated, 6-dimensional column vector. -pub type Vector6 = VectorN; +pub type Vector6 = Matrix>; /* * @@ -187,17 +187,17 @@ pub type Vector6 = VectorN; pub type RowDVector = Matrix>; /// A statically sized D-dimensional row vector. -pub type RowVectorN = MatrixMN; +pub type RowVectorN = Matrix>; /// A stack-allocated, 1-dimensional row vector. -pub type RowVector1 = RowVectorN; +pub type RowVector1 = Matrix>; /// A stack-allocated, 2-dimensional row vector. -pub type RowVector2 = RowVectorN; +pub type RowVector2 = Matrix>; /// A stack-allocated, 3-dimensional row vector. -pub type RowVector3 = RowVectorN; +pub type RowVector3 = Matrix>; /// A stack-allocated, 4-dimensional row vector. -pub type RowVector4 = RowVectorN; +pub type RowVector4 = Matrix>; /// A stack-allocated, 5-dimensional row vector. -pub type RowVector5 = RowVectorN; +pub type RowVector5 = Matrix>; /// A stack-allocated, 6-dimensional row vector. -pub type RowVector6 = RowVectorN; +pub type RowVector6 = Matrix>; diff --git a/src/base/alias_slice.rs b/src/base/alias_slice.rs index ee55f15b..9efbf857 100644 --- a/src/base/alias_slice.rs +++ b/src/base/alias_slice.rs @@ -15,164 +15,164 @@ pub type MatrixSliceMN<'a, N, R, C, RStride = U1, CStride = R> = /// A column-major matrix slice with `D` rows and columns. pub type MatrixSliceN<'a, N, D, RStride = U1, CStride = D> = - MatrixSliceMN<'a, N, D, D, RStride, CStride>; + Matrix>; /// A column-major matrix slice dynamic numbers of rows and columns. pub type DMatrixSlice<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceN<'a, N, Dynamic, RStride, CStride>; + Matrix>; /// A column-major 1x1 matrix slice. pub type MatrixSlice1<'a, N, RStride = U1, CStride = U1> = - MatrixSliceN<'a, N, U1, RStride, CStride>; + Matrix>; /// A column-major 2x2 matrix slice. pub type MatrixSlice2<'a, N, RStride = U1, CStride = U2> = - MatrixSliceN<'a, N, U2, RStride, CStride>; + Matrix>; /// A column-major 3x3 matrix slice. pub type MatrixSlice3<'a, N, RStride = U1, CStride = U3> = - MatrixSliceN<'a, N, U3, RStride, CStride>; + Matrix>; /// A column-major 4x4 matrix slice. pub type MatrixSlice4<'a, N, RStride = U1, CStride = U4> = - MatrixSliceN<'a, N, U4, RStride, CStride>; + Matrix>; /// A column-major 5x5 matrix slice. pub type MatrixSlice5<'a, N, RStride = U1, CStride = U5> = - MatrixSliceN<'a, N, U5, RStride, CStride>; + Matrix>; /// A column-major 6x6 matrix slice. pub type MatrixSlice6<'a, N, RStride = U1, CStride = U6> = - MatrixSliceN<'a, N, U6, RStride, CStride>; + Matrix>; /// A column-major 1x2 matrix slice. pub type MatrixSlice1x2<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, U2, RStride, CStride>; + Matrix>; /// A column-major 1x3 matrix slice. pub type MatrixSlice1x3<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, U3, RStride, CStride>; + Matrix>; /// A column-major 1x4 matrix slice. pub type MatrixSlice1x4<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, U4, RStride, CStride>; + Matrix>; /// A column-major 1x5 matrix slice. pub type MatrixSlice1x5<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, U5, RStride, CStride>; + Matrix>; /// A column-major 1x6 matrix slice. pub type MatrixSlice1x6<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, U6, RStride, CStride>; + Matrix>; /// A column-major 2x1 matrix slice. pub type MatrixSlice2x1<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, U1, RStride, CStride>; + Matrix>; /// A column-major 2x3 matrix slice. pub type MatrixSlice2x3<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, U3, RStride, CStride>; + Matrix>; /// A column-major 2x4 matrix slice. pub type MatrixSlice2x4<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, U4, RStride, CStride>; + Matrix>; /// A column-major 2x5 matrix slice. pub type MatrixSlice2x5<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, U5, RStride, CStride>; + Matrix>; /// A column-major 2x6 matrix slice. pub type MatrixSlice2x6<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, U6, RStride, CStride>; + Matrix>; /// A column-major 3x1 matrix slice. pub type MatrixSlice3x1<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, U1, RStride, CStride>; + Matrix>; /// A column-major 3x2 matrix slice. pub type MatrixSlice3x2<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, U2, RStride, CStride>; + Matrix>; /// A column-major 3x4 matrix slice. pub type MatrixSlice3x4<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, U4, RStride, CStride>; + Matrix>; /// A column-major 3x5 matrix slice. pub type MatrixSlice3x5<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, U5, RStride, CStride>; + Matrix>; /// A column-major 3x6 matrix slice. pub type MatrixSlice3x6<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, U6, RStride, CStride>; + Matrix>; /// A column-major 4x1 matrix slice. pub type MatrixSlice4x1<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, U1, RStride, CStride>; + Matrix>; /// A column-major 4x2 matrix slice. pub type MatrixSlice4x2<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, U2, RStride, CStride>; + Matrix>; /// A column-major 4x3 matrix slice. pub type MatrixSlice4x3<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, U3, RStride, CStride>; + Matrix>; /// A column-major 4x5 matrix slice. pub type MatrixSlice4x5<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, U5, RStride, CStride>; + Matrix>; /// A column-major 4x6 matrix slice. pub type MatrixSlice4x6<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, U6, RStride, CStride>; + Matrix>; /// A column-major 5x1 matrix slice. pub type MatrixSlice5x1<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, U1, RStride, CStride>; + Matrix>; /// A column-major 5x2 matrix slice. pub type MatrixSlice5x2<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, U2, RStride, CStride>; + Matrix>; /// A column-major 5x3 matrix slice. pub type MatrixSlice5x3<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, U3, RStride, CStride>; + Matrix>; /// A column-major 5x4 matrix slice. pub type MatrixSlice5x4<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, U4, RStride, CStride>; + Matrix>; /// A column-major 5x6 matrix slice. pub type MatrixSlice5x6<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, U6, RStride, CStride>; + Matrix>; /// A column-major 6x1 matrix slice. pub type MatrixSlice6x1<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, U1, RStride, CStride>; + Matrix>; /// A column-major 6x2 matrix slice. pub type MatrixSlice6x2<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, U2, RStride, CStride>; + Matrix>; /// A column-major 6x3 matrix slice. pub type MatrixSlice6x3<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, U3, RStride, CStride>; + Matrix>; /// A column-major 6x4 matrix slice. pub type MatrixSlice6x4<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, U4, RStride, CStride>; + Matrix>; /// A column-major 6x5 matrix slice. pub type MatrixSlice6x5<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, U6, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 1 row and a number of columns chosen at runtime. pub type MatrixSlice1xX<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMN<'a, N, U1, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. pub type MatrixSlice2xX<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMN<'a, N, U2, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. pub type MatrixSlice3xX<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMN<'a, N, U3, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. pub type MatrixSlice4xX<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMN<'a, N, U4, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. pub type MatrixSlice5xX<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMN<'a, N, U5, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. pub type MatrixSlice6xX<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMN<'a, N, U6, Dynamic, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 1 column. pub type MatrixSliceXx1<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U1, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. pub type MatrixSliceXx2<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U2, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. pub type MatrixSliceXx3<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U3, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. pub type MatrixSliceXx4<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U4, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. pub type MatrixSliceXx5<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U5, RStride, CStride>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. pub type MatrixSliceXx6<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>; + Matrix>; /// A column vector slice with `D` rows. pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> = @@ -180,26 +180,26 @@ pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> = /// A column vector slice dynamic numbers of rows and columns. pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = - VectorSliceN<'a, N, Dynamic, RStride, CStride>; + Matrix>; /// A 1D column vector slice. pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = - VectorSliceN<'a, N, U1, RStride, CStride>; + Matrix>; /// A 2D column vector slice. pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = - VectorSliceN<'a, N, U2, RStride, CStride>; + Matrix>; /// A 3D column vector slice. pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = - VectorSliceN<'a, N, U3, RStride, CStride>; + Matrix>; /// A 4D column vector slice. pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = - VectorSliceN<'a, N, U4, RStride, CStride>; + Matrix>; /// A 5D column vector slice. pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = - VectorSliceN<'a, N, U5, RStride, CStride>; + Matrix>; /// A 6D column vector slice. pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = - VectorSliceN<'a, N, U6, RStride, CStride>; + Matrix>; /* * @@ -208,194 +208,194 @@ pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = * * */ -/// A column-major mutable matrix slice with `R` rows and `C` columns. +/// A column-major matrix slice with `R` rows and `C` columns. pub type MatrixSliceMutMN<'a, N, R, C, RStride = U1, CStride = R> = Matrix>; -/// A column-major mutable matrix slice with `D` rows and columns. +/// A column-major matrix slice with `D` rows and columns. pub type MatrixSliceMutN<'a, N, D, RStride = U1, CStride = D> = - MatrixSliceMutMN<'a, N, D, D, RStride, CStride>; + Matrix>; -/// A column-major mutable matrix slice dynamic numbers of rows and columns. +/// A column-major matrix slice dynamic numbers of rows and columns. pub type DMatrixSliceMut<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutN<'a, N, Dynamic, RStride, CStride>; + Matrix>; -/// A column-major 1x1 mutable matrix slice. +/// A column-major 1x1 matrix slice. pub type MatrixSliceMut1<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutN<'a, N, U1, RStride, CStride>; -/// A column-major 2x2 mutable matrix slice. + Matrix>; +/// A column-major 2x2 matrix slice. pub type MatrixSliceMut2<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutN<'a, N, U2, RStride, CStride>; -/// A column-major 3x3 mutable matrix slice. + Matrix>; +/// A column-major 3x3 matrix slice. pub type MatrixSliceMut3<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutN<'a, N, U3, RStride, CStride>; -/// A column-major 4x4 mutable matrix slice. + Matrix>; +/// A column-major 4x4 matrix slice. pub type MatrixSliceMut4<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutN<'a, N, U4, RStride, CStride>; -/// A column-major 5x5 mutable matrix slice. + Matrix>; +/// A column-major 5x5 matrix slice. pub type MatrixSliceMut5<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutN<'a, N, U5, RStride, CStride>; -/// A column-major 6x6 mutable matrix slice. + Matrix>; +/// A column-major 6x6 matrix slice. pub type MatrixSliceMut6<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutN<'a, N, U6, RStride, CStride>; + Matrix>; -/// A column-major 1x2 mutable matrix slice. +/// A column-major 1x2 matrix slice. pub type MatrixSliceMut1x2<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, U2, RStride, CStride>; -/// A column-major 1x3 mutable matrix slice. + Matrix>; +/// A column-major 1x3 matrix slice. pub type MatrixSliceMut1x3<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, U3, RStride, CStride>; -/// A column-major 1x4 mutable matrix slice. + Matrix>; +/// A column-major 1x4 matrix slice. pub type MatrixSliceMut1x4<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, U4, RStride, CStride>; -/// A column-major 1x5 mutable matrix slice. + Matrix>; +/// A column-major 1x5 matrix slice. pub type MatrixSliceMut1x5<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, U5, RStride, CStride>; -/// A column-major 1x6 mutable matrix slice. + Matrix>; +/// A column-major 1x6 matrix slice. pub type MatrixSliceMut1x6<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, U6, RStride, CStride>; + Matrix>; -/// A column-major 2x1 mutable matrix slice. +/// A column-major 2x1 matrix slice. pub type MatrixSliceMut2x1<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, U1, RStride, CStride>; -/// A column-major 2x3 mutable matrix slice. + Matrix>; +/// A column-major 2x3 matrix slice. pub type MatrixSliceMut2x3<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, U3, RStride, CStride>; -/// A column-major 2x4 mutable matrix slice. + Matrix>; +/// A column-major 2x4 matrix slice. pub type MatrixSliceMut2x4<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, U4, RStride, CStride>; -/// A column-major 2x5 mutable matrix slice. + Matrix>; +/// A column-major 2x5 matrix slice. pub type MatrixSliceMut2x5<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, U5, RStride, CStride>; -/// A column-major 2x6 mutable matrix slice. + Matrix>; +/// A column-major 2x6 matrix slice. pub type MatrixSliceMut2x6<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, U6, RStride, CStride>; + Matrix>; -/// A column-major 3x1 mutable matrix slice. +/// A column-major 3x1 matrix slice. pub type MatrixSliceMut3x1<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, U1, RStride, CStride>; -/// A column-major 3x2 mutable matrix slice. + Matrix>; +/// A column-major 3x2 matrix slice. pub type MatrixSliceMut3x2<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, U2, RStride, CStride>; -/// A column-major 3x4 mutable matrix slice. + Matrix>; +/// A column-major 3x4 matrix slice. pub type MatrixSliceMut3x4<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, U4, RStride, CStride>; -/// A column-major 3x5 mutable matrix slice. + Matrix>; +/// A column-major 3x5 matrix slice. pub type MatrixSliceMut3x5<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, U5, RStride, CStride>; -/// A column-major 3x6 mutable matrix slice. + Matrix>; +/// A column-major 3x6 matrix slice. pub type MatrixSliceMut3x6<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, U6, RStride, CStride>; + Matrix>; -/// A column-major 4x1 mutable matrix slice. +/// A column-major 4x1 matrix slice. pub type MatrixSliceMut4x1<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, U1, RStride, CStride>; -/// A column-major 4x2 mutable matrix slice. + Matrix>; +/// A column-major 4x2 matrix slice. pub type MatrixSliceMut4x2<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, U2, RStride, CStride>; -/// A column-major 4x3 mutable matrix slice. + Matrix>; +/// A column-major 4x3 matrix slice. pub type MatrixSliceMut4x3<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, U3, RStride, CStride>; -/// A column-major 4x5 mutable matrix slice. + Matrix>; +/// A column-major 4x5 matrix slice. pub type MatrixSliceMut4x5<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, U5, RStride, CStride>; -/// A column-major 4x6 mutable matrix slice. + Matrix>; +/// A column-major 4x6 matrix slice. pub type MatrixSliceMut4x6<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, U6, RStride, CStride>; + Matrix>; -/// A column-major 5x1 mutable matrix slice. +/// A column-major 5x1 matrix slice. pub type MatrixSliceMut5x1<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, U1, RStride, CStride>; -/// A column-major 5x2 mutable matrix slice. + Matrix>; +/// A column-major 5x2 matrix slice. pub type MatrixSliceMut5x2<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, U2, RStride, CStride>; -/// A column-major 5x3 mutable matrix slice. + Matrix>; +/// A column-major 5x3 matrix slice. pub type MatrixSliceMut5x3<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, U3, RStride, CStride>; -/// A column-major 5x4 mutable matrix slice. + Matrix>; +/// A column-major 5x4 matrix slice. pub type MatrixSliceMut5x4<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, U4, RStride, CStride>; -/// A column-major 5x6 mutable matrix slice. + Matrix>; +/// A column-major 5x6 matrix slice. pub type MatrixSliceMut5x6<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, U6, RStride, CStride>; + Matrix>; -/// A column-major 6x1 mutable matrix slice. +/// A column-major 6x1 matrix slice. pub type MatrixSliceMut6x1<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, U1, RStride, CStride>; -/// A column-major 6x2 mutable matrix slice. + Matrix>; +/// A column-major 6x2 matrix slice. pub type MatrixSliceMut6x2<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, U2, RStride, CStride>; -/// A column-major 6x3 mutable matrix slice. + Matrix>; +/// A column-major 6x3 matrix slice. pub type MatrixSliceMut6x3<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, U3, RStride, CStride>; -/// A column-major 6x4 mutable matrix slice. + Matrix>; +/// A column-major 6x4 matrix slice. pub type MatrixSliceMut6x4<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, U4, RStride, CStride>; -/// A column-major 6x5 mutable matrix slice. + Matrix>; +/// A column-major 6x5 matrix slice. pub type MatrixSliceMut6x5<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, U5, RStride, CStride>; + Matrix>; -/// A column-major mutable matrix slice with 1 row and a number of columns chosen at runtime. +/// A column-major matrix slice with 1 row and a number of columns chosen at runtime. pub type MatrixSliceMut1xX<'a, N, RStride = U1, CStride = U1> = - MatrixSliceMutMN<'a, N, U1, Dynamic, RStride, CStride>; -/// A column-major mutable matrix slice with 2 rows and a number of columns chosen at runtime. + Matrix>; +/// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. pub type MatrixSliceMut2xX<'a, N, RStride = U1, CStride = U2> = - MatrixSliceMutMN<'a, N, U2, Dynamic, RStride, CStride>; -/// A column-major mutable matrix slice with 3 rows and a number of columns chosen at runtime. + Matrix>; +/// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. pub type MatrixSliceMut3xX<'a, N, RStride = U1, CStride = U3> = - MatrixSliceMutMN<'a, N, U3, Dynamic, RStride, CStride>; -/// A column-major mutable matrix slice with 4 rows and a number of columns chosen at runtime. + Matrix>; +/// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. pub type MatrixSliceMut4xX<'a, N, RStride = U1, CStride = U4> = - MatrixSliceMutMN<'a, N, U4, Dynamic, RStride, CStride>; -/// A column-major mutable matrix slice with 5 rows and a number of columns chosen at runtime. + Matrix>; +/// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. pub type MatrixSliceMut5xX<'a, N, RStride = U1, CStride = U5> = - MatrixSliceMutMN<'a, N, U5, Dynamic, RStride, CStride>; -/// A column-major mutable matrix slice with 6 rows and a number of columns chosen at runtime. + Matrix>; +/// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. pub type MatrixSliceMut6xX<'a, N, RStride = U1, CStride = U6> = - MatrixSliceMutMN<'a, N, U6, Dynamic, RStride, CStride>; + Matrix>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 1 column. +/// A column-major matrix slice with a number of rows chosen at runtime and 1 column. pub type MatrixSliceMutXx1<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U1, RStride, CStride>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 2 columns. + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. pub type MatrixSliceMutXx2<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U2, RStride, CStride>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 3 columns. + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. pub type MatrixSliceMutXx3<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U3, RStride, CStride>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 4 columns. + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. pub type MatrixSliceMutXx4<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U4, RStride, CStride>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 5 columns. + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. pub type MatrixSliceMutXx5<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U5, RStride, CStride>; -/// A column-major mutable matrix slice with a number of rows chosen at runtime and 6 columns. + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. pub type MatrixSliceMutXx6<'a, N, RStride = U1, CStride = Dynamic> = - MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>; + Matrix>; -/// A mutable column vector slice with `D` rows. +/// A column vector slice with `D` rows. pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> = Matrix>; -/// A mutable column vector slice dynamic numbers of rows and columns. +/// A column vector slice dynamic numbers of rows and columns. pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = - VectorSliceMutN<'a, N, Dynamic, RStride, CStride>; + Matrix>; -/// A 1D mutable column vector slice. +/// A 1D column vector slice. pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = - VectorSliceMutN<'a, N, U1, RStride, CStride>; -/// A 2D mutable column vector slice. + Matrix>; +/// A 2D column vector slice. pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = - VectorSliceMutN<'a, N, U2, RStride, CStride>; -/// A 3D mutable column vector slice. + Matrix>; +/// A 3D column vector slice. pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = - VectorSliceMutN<'a, N, U3, RStride, CStride>; -/// A 4D mutable column vector slice. + Matrix>; +/// A 4D column vector slice. pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = - VectorSliceMutN<'a, N, U4, RStride, CStride>; -/// A 5D mutable column vector slice. + Matrix>; +/// A 5D column vector slice. pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = - VectorSliceMutN<'a, N, U5, RStride, CStride>; -/// A 6D mutable column vector slice. + Matrix>; +/// A 6D column vector slice. pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = - VectorSliceMutN<'a, N, U6, RStride, CStride>; + Matrix>; From 17eb626018e6e73ecd31bc29dde0b23d3fd10201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sun, 15 Nov 2020 17:25:29 +0100 Subject: [PATCH 7/8] Fix typo. --- src/base/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/storage.rs b/src/base/storage.rs index 77e7c13f..c09551c0 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -60,7 +60,7 @@ pub unsafe trait Storage: Debug + Sized { /// /// ```.ignore /// let lindex = self.linear_index(irow, icol); - /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex) + /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex)) /// ``` #[inline] fn linear_index(&self, irow: usize, icol: usize) -> usize { From 05210516650edafeee0cda20ea66ede7e83c15ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sun, 15 Nov 2020 17:44:58 +0100 Subject: [PATCH 8/8] Fix wrong import of Signed an Zero. --- src/base/min_max.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/min_max.rs b/src/base/min_max.rs index d594ef50..90af0142 100644 --- a/src/base/min_max.rs +++ b/src/base/min_max.rs @@ -1,6 +1,6 @@ use crate::storage::Storage; use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector}; -use rand_distr::num_traits::{Signed, Zero}; +use num::{Signed, Zero}; use simba::simd::SimdSigned; /// # Find the min and max components