use num::{One, Zero}; use std::cmp; use std::ptr; use std::iter::ExactSizeIterator; use base::allocator::{Allocator, Reallocator}; use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::dimension::{ Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, Dynamic, U1, }; use base::storage::{Storage, StorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use base::DMatrix; use base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector}; impl> Matrix { /// Extracts the upper triangular part of this matrix (including the diagonal). #[inline] pub fn upper_triangle(&self) -> MatrixMN where DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.fill_lower_triangle(N::zero(), 1); res } /// Extracts the lower triangular part of this matrix (including the diagonal). #[inline] pub fn lower_triangle(&self) -> MatrixMN where DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.fill_upper_triangle(N::zero(), 1); res } /// Creates a new matrix by extracting the given set of rows from `self`. pub fn select_rows(&self, irows: impl ExactSizeIterator + Clone) -> MatrixMN where DefaultAllocator: Allocator { let ncols = self.data.shape().1; let mut res = unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) }; // First, check that all the indices from irows are valid. // This will allow us to use unchecked access in the inner loop. for i in irows.clone() { assert!(i < self.nrows(), "Row index out of bounds.") } for j in 0..ncols.value() { // FIXME: use unchecked column indexing let mut res = res.column_mut(j); let mut src = self.column(j); for (destination, source) in irows.clone().enumerate() { unsafe { *res.vget_unchecked_mut(destination) = *src.vget_unchecked(source) } } } res } /// Creates a new matrix by extracting the given set of columns from `self`. pub fn select_columns(&self, icols: impl ExactSizeIterator) -> MatrixMN where DefaultAllocator: Allocator { let nrows = self.data.shape().0; let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) }; for (destination, source) in icols.enumerate() { res.column_mut(destination).copy_from(&self.column(source)) } res } } 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 } } /// 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 } } } /// 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 } } } /// 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 } } } /// Fills the diagonal of this matrix with the content of the given vector. #[inline] pub fn set_diagonal(&mut self, diag: &Vector) where R: DimMin, S2: Storage, ShapeConstraint: DimEq, R2>, { let (nrows, ncols) = self.shape(); let min_nrows_ncols = cmp::min(nrows, ncols); assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions."); for i in 0..min_nrows_ncols { unsafe { *self.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i) } } } /// Fills the selected row of this matrix with the content of the given vector. #[inline] pub fn set_row(&mut self, i: usize, row: &RowVector) where S2: Storage, ShapeConstraint: SameNumberOfColumns, { self.row_mut(i).copy_from(row); } /// Fills the selected column of this matrix with the content of the given vector. #[inline] pub fn set_column(&mut self, i: usize, column: &Vector) where S2: Storage, ShapeConstraint: SameNumberOfRows, { self.column_mut(i).copy_from(column); } /// Sets all the elements of the lower-triangular part of this matrix to `val`. /// /// The parameter `shift` allows some subdiagonals to be left untouched: /// * If `shift = 0` then the diagonal is overwritten as well. /// * If `shift = 1` then the diagonal is left untouched. /// * If `shift > 1`, then the diagonal and the first `shift - 1` subdiagonals are left /// untouched. #[inline] pub fn fill_lower_triangle(&mut self, val: N, shift: usize) { for j in 0..self.ncols() { for i in (j + shift)..self.nrows() { unsafe { *self.get_unchecked_mut((i, j)) = val } } } } /// Sets all the elements of the lower-triangular part of this matrix to `val`. /// /// The parameter `shift` allows some superdiagonals to be left untouched: /// * If `shift = 0` then the diagonal is overwritten as well. /// * If `shift = 1` then the diagonal is left untouched. /// * If `shift > 1`, then the diagonal and the first `shift - 1` superdiagonals are left /// untouched. #[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 ? // (necessary for rectangular matrices) for i in 0..cmp::min(j + 1 - shift, self.nrows()) { unsafe { *self.get_unchecked_mut((i, j)) = val } } } } /// 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 { /// Copies the upper-triangle of this matrix to its lower-triangular part. /// /// This makes the matrix symmetric. Panics if the matrix is not square. pub fn fill_lower_triangle_with_upper_triangle(&mut self) { assert!(self.is_square(), "The input matrix should be square."); let dim = self.nrows(); for j in 0..dim { for i in j + 1..dim { unsafe { *self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i)); } } } } /// Copies the upper-triangle of this matrix to its upper-triangular part. /// /// This makes the matrix symmetric. Panics if the matrix is not square. pub fn fill_upper_triangle_with_lower_triangle(&mut self) { assert!(self.is_square(), "The input matrix should be square."); for j in 1..self.ncols() { for i in 0..j { unsafe { *self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i)); } } } } } /* * * FIXME: specialize all the following for slices. * */ impl> Matrix { /* * * Column removal. * */ /// Removes the `i`-th column from this matrix. #[inline] pub fn remove_column(self, i: usize) -> MatrixMN> where C: DimSub, DefaultAllocator: Reallocator>, { self.remove_fixed_columns::(i) } /// Removes `D::dim()` consecutive columns from this matrix, starting with the `i`-th /// (included). #[inline] pub fn remove_fixed_columns(self, i: usize) -> MatrixMN> where D: DimName, C: DimSub, DefaultAllocator: Reallocator>, { self.remove_columns_generic(i, D::name()) } /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). #[inline] pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN where C: DimSub, DefaultAllocator: Reallocator, { self.remove_columns_generic(i, Dynamic::new(n)) } /// Removes `nremove.value()` columns from this matrix, starting with the `i`-th (included). /// /// This is the generic implementation of `.remove_columns(...)` and /// `.remove_fixed_columns(...)` which have nicer API interfaces. #[inline] pub fn remove_columns_generic(self, i: usize, nremove: D) -> MatrixMN> where D: Dim, C: DimSub, DefaultAllocator: Reallocator>, { let mut m = self.into_owned(); let (nrows, ncols) = m.data.shape(); assert!( i + nremove.value() <= ncols.value(), "Column index out of range." ); if nremove.value() != 0 && i + nremove.value() < ncols.value() { // The first `deleted_i * nrows` are left untouched. let copied_value_start = i + nremove.value(); unsafe { let ptr_in = m .data .ptr() .offset((copied_value_start * nrows.value()) as isize); let ptr_out = m.data.ptr_mut().offset((i * nrows.value()) as isize); ptr::copy( ptr_in, ptr_out, (ncols.value() - copied_value_start) * nrows.value(), ); } } unsafe { Matrix::from_data(DefaultAllocator::reallocate_copy( nrows, ncols.sub(nremove), m.data, )) } } /* * * Row removal. * */ /// Removes the `i`-th row from this matrix. #[inline] pub fn remove_row(self, i: usize) -> MatrixMN, C> where R: DimSub, DefaultAllocator: Reallocator, C>, { self.remove_fixed_rows::(i) } /// Removes `D::dim()` consecutive rows from this matrix, starting with the `i`-th (included). #[inline] pub fn remove_fixed_rows(self, i: usize) -> MatrixMN, C> where D: DimName, R: DimSub, DefaultAllocator: Reallocator, C>, { self.remove_rows_generic(i, D::name()) } /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). #[inline] pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN where R: DimSub, DefaultAllocator: Reallocator, { self.remove_rows_generic(i, Dynamic::new(n)) } /// Removes `nremove.value()` rows from this matrix, starting with the `i`-th (included). /// /// This is the generic implementation of `.remove_rows(...)` and `.remove_fixed_rows(...)` /// which have nicer API interfaces. #[inline] pub fn remove_rows_generic(self, i: usize, nremove: D) -> MatrixMN, C> where D: Dim, R: DimSub, DefaultAllocator: Reallocator, C>, { let mut m = self.into_owned(); let (nrows, ncols) = m.data.shape(); assert!( i + nremove.value() <= nrows.value(), "Row index out of range." ); if nremove.value() != 0 { unsafe { compress_rows( &mut m.data.as_mut_slice(), nrows.value(), ncols.value(), i, nremove.value(), ); } } unsafe { Matrix::from_data(DefaultAllocator::reallocate_copy( nrows.sub(nremove), ncols, m.data, )) } } /* * * Columns insertion. * */ /// Inserts a column filled with `val` at the `i-th` position. #[inline] pub fn insert_column(self, i: usize, val: N) -> MatrixMN> where C: DimAdd, DefaultAllocator: Reallocator>, { self.insert_fixed_columns::(i, val) } /// Inserts `D::dim()` columns filled with `val` starting at the `i-th` position. #[inline] pub fn insert_fixed_columns(self, i: usize, val: N) -> MatrixMN> where D: DimName, C: DimAdd, DefaultAllocator: Reallocator>, { let mut res = unsafe { self.insert_columns_generic_uninitialized(i, D::name()) }; res.fixed_columns_mut::(i).fill(val); res } /// Inserts `n` columns filled with `val` starting at the `i-th` position. #[inline] pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN where C: DimAdd, DefaultAllocator: Reallocator, { let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dynamic::new(n)) }; res.columns_mut(i, n).fill(val); res } /// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix. /// /// The added column values are not initialized. #[inline] pub unsafe fn insert_columns_generic_uninitialized( self, i: usize, ninsert: D, ) -> MatrixMN> where D: Dim, C: DimAdd, DefaultAllocator: Reallocator>, { let m = self.into_owned(); let (nrows, ncols) = m.data.shape(); let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( nrows, ncols.add(ninsert), m.data, )); assert!(i <= ncols.value(), "Column insertion index out of range."); if ninsert.value() != 0 && i != ncols.value() { let ptr_in = res.data.ptr().offset((i * nrows.value()) as isize); let ptr_out = res .data .ptr_mut() .offset(((i + ninsert.value()) * nrows.value()) as isize); ptr::copy(ptr_in, ptr_out, (ncols.value() - i) * nrows.value()) } res } /* * * Rows insertion. * */ /// Inserts a row filled with `val` at the `i-th` position. #[inline] pub fn insert_row(self, i: usize, val: N) -> MatrixMN, C> where R: DimAdd, DefaultAllocator: Reallocator, C>, { self.insert_fixed_rows::(i, val) } /// Inserts `D::dim()` rows filled with `val` starting at the `i-th` position. #[inline] pub fn insert_fixed_rows(self, i: usize, val: N) -> MatrixMN, C> where D: DimName, R: DimAdd, DefaultAllocator: Reallocator, C>, { let mut res = unsafe { self.insert_rows_generic_uninitialized(i, D::name()) }; res.fixed_rows_mut::(i).fill(val); res } /// Inserts `n` rows filled with `val` starting at the `i-th` position. #[inline] pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN where R: DimAdd, DefaultAllocator: Reallocator, { let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dynamic::new(n)) }; res.rows_mut(i, n).fill(val); res } /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix. /// /// The added rows values are not initialized. /// This is the generic implementation of `.insert_rows(...)` and /// `.insert_fixed_rows(...)` which have nicer API interfaces. #[inline] pub unsafe fn insert_rows_generic_uninitialized( self, i: usize, ninsert: D, ) -> MatrixMN, C> where D: Dim, R: DimAdd, DefaultAllocator: Reallocator, C>, { let m = self.into_owned(); let (nrows, ncols) = m.data.shape(); let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( nrows.add(ninsert), ncols, m.data, )); assert!(i <= nrows.value(), "Row insertion index out of range."); if ninsert.value() != 0 { extend_rows( &mut res.data.as_mut_slice(), nrows.value(), ncols.value(), i, ninsert.value(), ); } res } /* * * Resizing. * */ /// 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 /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize(self, new_nrows: usize, new_ncols: usize, val: N) -> DMatrix where DefaultAllocator: Reallocator { self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) } /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. pub fn fixed_resize(self, val: N) -> MatrixMN where DefaultAllocator: Reallocator { self.resize_generic(R2::name(), C2::name(), val) } /// Resizes `self` such that it has dimensions `new_nrows × now_ncols`. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. #[inline] pub fn resize_generic( self, new_nrows: R2, new_ncols: C2, val: N, ) -> MatrixMN where DefaultAllocator: Reallocator, { let (nrows, ncols) = self.shape(); let mut data = self.data.into_owned(); if new_nrows.value() == nrows { let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data) }; let mut res = Matrix::from_data(res); if new_ncols.value() > ncols { res.columns_range_mut(ncols..).fill(val); } res } else { let mut res; unsafe { if new_nrows.value() < nrows { compress_rows( &mut data.as_mut_slice(), nrows, ncols, new_nrows.value(), nrows - new_nrows.value(), ); res = Matrix::from_data(DefaultAllocator::reallocate_copy( new_nrows, new_ncols, data, )); } else { res = Matrix::from_data(DefaultAllocator::reallocate_copy( new_nrows, new_ncols, data, )); extend_rows( &mut res.data.as_mut_slice(), nrows, new_ncols.value(), nrows, new_nrows.value() - nrows, ); } } if new_ncols.value() > ncols { res.columns_range_mut(ncols..).fill(val); } if new_nrows.value() > nrows { res.slice_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value())) .fill(val); } res } } } unsafe fn compress_rows( data: &mut [N], nrows: usize, ncols: usize, i: usize, nremove: usize, ) { let new_nrows = nrows - nremove; if new_nrows == 0 || ncols == 0 { return; // Nothing to do as the output matrix is empty. } let ptr_in = data.as_ptr(); let ptr_out = data.as_mut_ptr(); let mut curr_i = i; for k in 0..ncols - 1 { ptr::copy( ptr_in.offset((curr_i + (k + 1) * nremove) as isize), ptr_out.offset(curr_i as isize), new_nrows, ); curr_i += new_nrows; } // Deal with the last column from which less values have to be copied. let remaining_len = nrows - i - nremove; ptr::copy( ptr_in.offset((nrows * ncols - remaining_len) as isize), ptr_out.offset(curr_i as isize), remaining_len, ); } // Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index. // The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements. unsafe fn extend_rows( data: &mut [N], nrows: usize, ncols: usize, i: usize, ninsert: usize, ) { let new_nrows = nrows + ninsert; if new_nrows == 0 || ncols == 0 { return; // Nothing to do as the output matrix is empty. } let ptr_in = data.as_ptr(); let ptr_out = data.as_mut_ptr(); let remaining_len = nrows - i; let mut curr_i = new_nrows * ncols - remaining_len; // Deal with the last column from which less values have to be copied. ptr::copy( ptr_in.offset((nrows * ncols - remaining_len) as isize), ptr_out.offset(curr_i as isize), remaining_len, ); for k in (0..ncols - 1).rev() { curr_i -= new_nrows; ptr::copy( ptr_in.offset((k * nrows + i) as isize), ptr_out.offset(curr_i as isize), nrows, ); } } /// Extend the number of columns of the `Matrix` with elements from /// a given iterator. impl Extend for Matrix where N: Scalar, R: Dim, S: Extend, { /// Extend the number of columns of the `Matrix` with elements /// from the given iterator. /// /// # Example /// ``` /// # use nalgebra::{DMatrix, Dynamic, Matrix, MatrixMN, Matrix3}; /// /// let data = vec![0, 1, 2, // column 1 /// 3, 4, 5]; // column 2 /// /// let mut matrix = DMatrix::from_vec(3, 2, data); /// /// matrix.extend(vec![6, 7, 8]); // column 3 /// /// assert!(matrix.eq(&Matrix3::new(0, 3, 6, /// 1, 4, 7, /// 2, 5, 8))); /// ``` /// /// # Panics /// This function panics if the number of elements yielded by the /// given iterator is not a multiple of the number of rows of the /// `Matrix`. /// /// ```should_panic /// # use nalgebra::{DMatrix, Dynamic, MatrixMN}; /// let data = vec![0, 1, 2, // column 1 /// 3, 4, 5]; // column 2 /// /// let mut matrix = DMatrix::from_vec(3, 2, data); /// /// // The following panics because the vec length is not a multiple of 3. /// matrix.extend(vec![6, 7, 8, 9]); /// ``` fn extend>(&mut self, iter: I) { self.data.extend(iter); } } /// Extend the number of rows of the `Vector` with elements from /// a given iterator. impl Extend for Matrix where N: Scalar, S: Extend, { /// Extend the number of rows of a `Vector` with elements /// from the given iterator. /// /// # Example /// ``` /// # use nalgebra::DVector; /// let mut vector = DVector::from_vec(vec![0, 1, 2]); /// vector.extend(vec![3, 4, 5]); /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5]))); /// ``` fn extend>(&mut self, iter: I) { self.data.extend(iter); } } impl Extend> for Matrix where N: Scalar, R: Dim, S: Extend>, RV: Dim, SV: Storage, ShapeConstraint: SameNumberOfRows, { /// Extends the number of columns of a `Matrix` with `Vector`s /// from a given iterator. /// /// # Example /// ``` /// # use nalgebra::{DMatrix, Vector3, Matrix3x4}; /// /// let data = vec![0, 1, 2, // column 1 /// 3, 4, 5]; // column 2 /// /// let mut matrix = DMatrix::from_vec(3, 2, data); /// /// matrix.extend( /// vec![Vector3::new(6, 7, 8), // column 3 /// Vector3::new(9, 10, 11)]); // column 4 /// /// assert!(matrix.eq(&Matrix3x4::new(0, 3, 6, 9, /// 1, 4, 7, 10, /// 2, 5, 8, 11))); /// ``` /// /// # Panics /// This function panics if the dimension of each `Vector` yielded /// by the given iterator is not equal to the number of rows of /// this `Matrix`. /// /// ```should_panic /// # use nalgebra::{DMatrix, Vector2, Matrix3x4}; /// let mut matrix = /// DMatrix::from_vec(3, 2, /// vec![0, 1, 2, // column 1 /// 3, 4, 5]); // column 2 /// /// // The following panics because this matrix can only be extended with 3-dimensional vectors. /// matrix.extend( /// vec![Vector2::new(6, 7)]); // too few dimensions! /// ``` /// /// ```should_panic /// # use nalgebra::{DMatrix, Vector4, Matrix3x4}; /// let mut matrix = /// DMatrix::from_vec(3, 2, /// vec![0, 1, 2, // column 1 /// 3, 4, 5]); // column 2 /// /// // The following panics because this matrix can only be extended with 3-dimensional vectors. /// matrix.extend( /// vec![Vector4::new(6, 7, 8, 9)]); // too few dimensions! /// ``` fn extend>>(&mut self, iter: I) { self.data.extend(iter); } }