nalgebra/base/
edition.rs

1use num::{One, Zero};
2use std::cmp;
3#[cfg(any(feature = "std", feature = "alloc"))]
4use std::iter::ExactSizeIterator;
5use std::ptr;
6
7use crate::base::allocator::{Allocator, Reallocator};
8use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
9#[cfg(any(feature = "std", feature = "alloc"))]
10use crate::base::dimension::Dyn;
11use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
12use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage};
13use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
14use crate::{Storage, UninitMatrix};
15use std::mem::MaybeUninit;
16
17/// # Triangular matrix extraction
18impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
19    /// Extracts the upper triangular part of this matrix (including the diagonal).
20    #[inline]
21    #[must_use]
22    pub fn upper_triangle(&self) -> OMatrix<T, R, C>
23    where
24        DefaultAllocator: Allocator<R, C>,
25    {
26        let mut res = self.clone_owned();
27        res.fill_lower_triangle(T::zero(), 1);
28
29        res
30    }
31
32    /// Extracts the lower triangular part of this matrix (including the diagonal).
33    #[inline]
34    #[must_use]
35    pub fn lower_triangle(&self) -> OMatrix<T, R, C>
36    where
37        DefaultAllocator: Allocator<R, C>,
38    {
39        let mut res = self.clone_owned();
40        res.fill_upper_triangle(T::zero(), 1);
41
42        res
43    }
44}
45
46/// # Rows and columns extraction
47impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
48    /// Creates a new matrix by extracting the given set of rows from `self`.
49    #[cfg(any(feature = "std", feature = "alloc"))]
50    #[must_use]
51    pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix<T, Dyn, C>
52    where
53        I: IntoIterator<Item = &'a usize>,
54        I::IntoIter: ExactSizeIterator + Clone,
55        DefaultAllocator: Allocator<Dyn, C>,
56    {
57        let irows = irows.into_iter();
58        let ncols = self.shape_generic().1;
59        let mut res = Matrix::uninit(Dyn(irows.len()), ncols);
60
61        // First, check that all the indices from irows are valid.
62        // This will allow us to use unchecked access in the inner loop.
63        for i in irows.clone() {
64            assert!(*i < self.nrows(), "Row index out of bounds.")
65        }
66
67        for j in 0..ncols.value() {
68            // TODO: use unchecked column indexing
69            let mut res = res.column_mut(j);
70            let src = self.column(j);
71
72            for (destination, source) in irows.clone().enumerate() {
73                // Safety: all indices are in range.
74                unsafe {
75                    *res.vget_unchecked_mut(destination) =
76                        MaybeUninit::new(src.vget_unchecked(*source).clone());
77                }
78            }
79        }
80
81        // Safety: res is now fully initialized.
82        unsafe { res.assume_init() }
83    }
84
85    /// Creates a new matrix by extracting the given set of columns from `self`.
86    #[cfg(any(feature = "std", feature = "alloc"))]
87    #[must_use]
88    pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix<T, R, Dyn>
89    where
90        I: IntoIterator<Item = &'a usize>,
91        I::IntoIter: ExactSizeIterator,
92        DefaultAllocator: Allocator<R, Dyn>,
93    {
94        let icols = icols.into_iter();
95        let nrows = self.shape_generic().0;
96        let mut res = Matrix::uninit(nrows, Dyn(icols.len()));
97
98        for (destination, source) in icols.enumerate() {
99            // NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit.
100            res.column_mut(destination)
101                .zip_apply(&self.column(*source), |out, e| *out = MaybeUninit::new(e));
102        }
103
104        // Safety: res is now fully initialized.
105        unsafe { res.assume_init() }
106    }
107}
108
109/// # Set rows, columns, and diagonal
110impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
111    /// Fills the diagonal of this matrix with the content of the given vector.
112    #[inline]
113    pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
114    where
115        R: DimMin<C>,
116        S2: RawStorage<T, R2>,
117        ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
118    {
119        let (nrows, ncols) = self.shape();
120        let min_nrows_ncols = cmp::min(nrows, ncols);
121        assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
122
123        for i in 0..min_nrows_ncols {
124            unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone() }
125        }
126    }
127
128    /// Fills the diagonal of this matrix with the content of the given iterator.
129    ///
130    /// This will fill as many diagonal elements as the iterator yields, up to the
131    /// minimum of the number of rows and columns of `self`, and starting with the
132    /// diagonal element at index (0, 0).
133    #[inline]
134    pub fn set_partial_diagonal(&mut self, diag: impl Iterator<Item = T>) {
135        let (nrows, ncols) = self.shape();
136        let min_nrows_ncols = cmp::min(nrows, ncols);
137
138        for (i, val) in diag.enumerate().take(min_nrows_ncols) {
139            unsafe { *self.get_unchecked_mut((i, i)) = val }
140        }
141    }
142
143    /// Fills the selected row of this matrix with the content of the given vector.
144    #[inline]
145    pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
146    where
147        S2: RawStorage<T, U1, C2>,
148        ShapeConstraint: SameNumberOfColumns<C, C2>,
149    {
150        self.row_mut(i).copy_from(row);
151    }
152
153    /// Fills the selected column of this matrix with the content of the given vector.
154    #[inline]
155    pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
156    where
157        S2: RawStorage<T, R2, U1>,
158        ShapeConstraint: SameNumberOfRows<R, R2>,
159    {
160        self.column_mut(i).copy_from(column);
161    }
162}
163
164/// # In-place filling
165impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
166    /// Sets all the elements of this matrix to the value returned by the closure.
167    #[inline]
168    pub fn fill_with(&mut self, val: impl Fn() -> T) {
169        for e in self.iter_mut() {
170            *e = val()
171        }
172    }
173
174    /// Sets all the elements of this matrix to `val`.
175    #[inline]
176    pub fn fill(&mut self, val: T)
177    where
178        T: Scalar,
179    {
180        for e in self.iter_mut() {
181            *e = val.clone()
182        }
183    }
184
185    /// Fills `self` with the identity matrix.
186    #[inline]
187    pub fn fill_with_identity(&mut self)
188    where
189        T: Scalar + Zero + One,
190    {
191        self.fill(T::zero());
192        self.fill_diagonal(T::one());
193    }
194
195    /// Sets all the diagonal elements of this matrix to `val`.
196    #[inline]
197    pub fn fill_diagonal(&mut self, val: T)
198    where
199        T: Scalar,
200    {
201        let (nrows, ncols) = self.shape();
202        let n = cmp::min(nrows, ncols);
203
204        for i in 0..n {
205            unsafe { *self.get_unchecked_mut((i, i)) = val.clone() }
206        }
207    }
208
209    /// Sets all the elements of the selected row to `val`.
210    #[inline]
211    pub fn fill_row(&mut self, i: usize, val: T)
212    where
213        T: Scalar,
214    {
215        assert!(i < self.nrows(), "Row index out of bounds.");
216        for j in 0..self.ncols() {
217            unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
218        }
219    }
220
221    /// Sets all the elements of the selected column to `val`.
222    #[inline]
223    pub fn fill_column(&mut self, j: usize, val: T)
224    where
225        T: Scalar,
226    {
227        assert!(j < self.ncols(), "Row index out of bounds.");
228        for i in 0..self.nrows() {
229            unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
230        }
231    }
232
233    /// Sets all the elements of the lower-triangular part of this matrix to `val`.
234    ///
235    /// The parameter `shift` allows some subdiagonals to be left untouched:
236    /// * If `shift = 0` then the diagonal is overwritten as well.
237    /// * If `shift = 1` then the diagonal is left untouched.
238    /// * If `shift > 1`, then the diagonal and the first `shift - 1` subdiagonals are left
239    ///   untouched.
240    #[inline]
241    pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
242    where
243        T: Scalar,
244    {
245        for j in 0..self.ncols() {
246            for i in (j + shift)..self.nrows() {
247                unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
248            }
249        }
250    }
251
252    /// Sets all the elements of the upper-triangular part of this matrix to `val`.
253    ///
254    /// The parameter `shift` allows some superdiagonals to be left untouched:
255    /// * If `shift = 0` then the diagonal is overwritten as well.
256    /// * If `shift = 1` then the diagonal is left untouched.
257    /// * If `shift > 1`, then the diagonal and the first `shift - 1` superdiagonals are left
258    ///   untouched.
259    #[inline]
260    pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
261    where
262        T: Scalar,
263    {
264        for j in shift..self.ncols() {
265            // TODO: is there a more efficient way to avoid the min ?
266            // (necessary for rectangular matrices)
267            for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
268                unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
269            }
270        }
271    }
272}
273
274impl<T: Scalar, D: Dim, S: RawStorageMut<T, D, D>> Matrix<T, D, D, S> {
275    /// Copies the upper-triangle of this matrix to its lower-triangular part.
276    ///
277    /// This makes the matrix symmetric. Panics if the matrix is not square.
278    pub fn fill_lower_triangle_with_upper_triangle(&mut self) {
279        assert!(self.is_square(), "The input matrix should be square.");
280
281        let dim = self.nrows();
282        for j in 0..dim {
283            for i in j + 1..dim {
284                unsafe {
285                    *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
286                }
287            }
288        }
289    }
290
291    /// Copies the upper-triangle of this matrix to its upper-triangular part.
292    ///
293    /// This makes the matrix symmetric. Panics if the matrix is not square.
294    pub fn fill_upper_triangle_with_lower_triangle(&mut self) {
295        assert!(self.is_square(), "The input matrix should be square.");
296
297        for j in 1..self.ncols() {
298            for i in 0..j {
299                unsafe {
300                    *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
301                }
302            }
303        }
304    }
305}
306
307/// # In-place swapping
308impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
309    /// Swaps two rows in-place.
310    #[inline]
311    pub fn swap_rows(&mut self, irow1: usize, irow2: usize) {
312        assert!(irow1 < self.nrows() && irow2 < self.nrows());
313
314        if irow1 != irow2 {
315            // TODO: optimize that.
316            for i in 0..self.ncols() {
317                unsafe { self.swap_unchecked((irow1, i), (irow2, i)) }
318            }
319        }
320        // Otherwise do nothing.
321    }
322
323    /// Swaps two columns in-place.
324    #[inline]
325    pub fn swap_columns(&mut self, icol1: usize, icol2: usize) {
326        assert!(icol1 < self.ncols() && icol2 < self.ncols());
327
328        if icol1 != icol2 {
329            // TODO: optimize that.
330            for i in 0..self.nrows() {
331                unsafe { self.swap_unchecked((i, icol1), (i, icol2)) }
332            }
333        }
334        // Otherwise do nothing.
335    }
336}
337
338/*
339 *
340 * TODO: specialize all the following for slices.
341 *
342 */
343/// # Rows and columns removal
344impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
345    /*
346     *
347     * Column removal.
348     *
349     */
350    /// Removes the `i`-th column from this matrix.
351    #[inline]
352    pub fn remove_column(self, i: usize) -> OMatrix<T, R, DimDiff<C, U1>>
353    where
354        C: DimSub<U1>,
355        DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, U1>>,
356    {
357        self.remove_fixed_columns::<1>(i)
358    }
359
360    /// Removes all columns in `indices`   
361    #[cfg(any(feature = "std", feature = "alloc"))]
362    pub fn remove_columns_at(self, indices: &[usize]) -> OMatrix<T, R, Dyn>
363    where
364        C: DimSub<Dyn, Output = Dyn>,
365        DefaultAllocator: Reallocator<T, R, C, R, Dyn>,
366    {
367        let mut m = self.into_owned();
368        let (nrows, ncols) = m.shape_generic();
369        let mut offset: usize = 0;
370        let mut target: usize = 0;
371        while offset + target < ncols.value() {
372            if indices.contains(&(target + offset)) {
373                // Safety: the resulting pointer is within range.
374                let col_ptr = unsafe { m.data.ptr_mut().add((target + offset) * nrows.value()) };
375                // Drop every element in the column we are about to overwrite.
376                // We use the a similar technique as in `Vec::truncate`.
377                let s = ptr::slice_from_raw_parts_mut(col_ptr, nrows.value());
378                // Safety: we drop the column in-place, which is OK because we will overwrite these
379                //         entries later in the loop, or discard them with the `reallocate_copy`
380                //         afterwards.
381                unsafe { ptr::drop_in_place(s) };
382
383                offset += 1;
384            } else {
385                unsafe {
386                    let ptr_source = m.data.ptr().add((target + offset) * nrows.value());
387                    let ptr_target = m.data.ptr_mut().add(target * nrows.value());
388
389                    // Copy the data, overwriting what we dropped.
390                    ptr::copy(ptr_source, ptr_target, nrows.value());
391                    target += 1;
392                }
393            }
394        }
395
396        // Safety: The new size is smaller than the old size, so
397        //         DefaultAllocator::reallocate_copy will initialize
398        //         every element of the new matrix which can then
399        //         be assumed to be initialized.
400        unsafe {
401            let new_data = DefaultAllocator::reallocate_copy(
402                nrows,
403                ncols.sub(Dyn::from_usize(offset)),
404                m.data,
405            );
406
407            Matrix::from_data(new_data).assume_init()
408        }
409    }
410
411    /// Removes all rows in `indices`   
412    #[cfg(any(feature = "std", feature = "alloc"))]
413    pub fn remove_rows_at(self, indices: &[usize]) -> OMatrix<T, Dyn, C>
414    where
415        R: DimSub<Dyn, Output = Dyn>,
416        DefaultAllocator: Reallocator<T, R, C, Dyn, C>,
417    {
418        let mut m = self.into_owned();
419        let (nrows, ncols) = m.shape_generic();
420        let mut offset: usize = 0;
421        let mut target: usize = 0;
422        while offset + target < nrows.value() * ncols.value() {
423            if indices.contains(&((target + offset) % nrows.value())) {
424                // Safety: the resulting pointer is within range.
425                unsafe {
426                    let elt_ptr = m.data.ptr_mut().add(target + offset);
427                    // Safety: we drop the component in-place, which is OK because we will overwrite these
428                    //         entries later in the loop, or discard them with the `reallocate_copy`
429                    //         afterwards.
430                    ptr::drop_in_place(elt_ptr)
431                };
432                offset += 1;
433            } else {
434                unsafe {
435                    let ptr_source = m.data.ptr().add(target + offset);
436                    let ptr_target = m.data.ptr_mut().add(target);
437
438                    // Copy the data, overwriting what we dropped in the previous iterations.
439                    ptr::copy(ptr_source, ptr_target, 1);
440                    target += 1;
441                }
442            }
443        }
444
445        // Safety: The new size is smaller than the old size, so
446        //         DefaultAllocator::reallocate_copy will initialize
447        //         every element of the new matrix which can then
448        //         be assumed to be initialized.
449        unsafe {
450            let new_data = DefaultAllocator::reallocate_copy(
451                nrows.sub(Dyn::from_usize(offset / ncols.value())),
452                ncols,
453                m.data,
454            );
455
456            Matrix::from_data(new_data).assume_init()
457        }
458    }
459
460    /// Removes `D::dim()` consecutive columns from this matrix, starting with the `i`-th
461    /// (included).
462    #[inline]
463    pub fn remove_fixed_columns<const D: usize>(
464        self,
465        i: usize,
466    ) -> OMatrix<T, R, DimDiff<C, Const<D>>>
467    where
468        C: DimSub<Const<D>>,
469        DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, Const<D>>>,
470    {
471        self.remove_columns_generic(i, Const::<D>)
472    }
473
474    /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included).
475    #[inline]
476    #[cfg(any(feature = "std", feature = "alloc"))]
477    pub fn remove_columns(self, i: usize, n: usize) -> OMatrix<T, R, Dyn>
478    where
479        C: DimSub<Dyn, Output = Dyn>,
480        DefaultAllocator: Reallocator<T, R, C, R, Dyn>,
481    {
482        self.remove_columns_generic(i, Dyn(n))
483    }
484
485    /// Removes `nremove.value()` columns from this matrix, starting with the `i`-th (included).
486    ///
487    /// This is the generic implementation of `.remove_columns(...)` and
488    /// `.remove_fixed_columns(...)` which have nicer API interfaces.
489    #[inline]
490    pub fn remove_columns_generic<D>(self, i: usize, nremove: D) -> OMatrix<T, R, DimDiff<C, D>>
491    where
492        D: Dim,
493        C: DimSub<D>,
494        DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>,
495    {
496        let mut m = self.into_owned();
497        let (nrows, ncols) = m.shape_generic();
498        assert!(
499            i + nremove.value() <= ncols.value(),
500            "Column index out of range."
501        );
502
503        let need_column_shifts = nremove.value() != 0 && i + nremove.value() < ncols.value();
504        if need_column_shifts {
505            // The first `deleted_i * nrows` are left untouched.
506            let copied_value_start = i + nremove.value();
507
508            unsafe {
509                let ptr_in = m.data.ptr().add(copied_value_start * nrows.value());
510                let ptr_out = m.data.ptr_mut().add(i * nrows.value());
511
512                // Drop all the elements of the columns we are about to overwrite.
513                // We use the a similar technique as in `Vec::truncate`.
514                let s = ptr::slice_from_raw_parts_mut(ptr_out, nremove.value() * nrows.value());
515                // Safety: we drop the column in-place, which is OK because we will overwrite these
516                //         entries with `ptr::copy` afterward.
517                ptr::drop_in_place(s);
518
519                ptr::copy(
520                    ptr_in,
521                    ptr_out,
522                    (ncols.value() - copied_value_start) * nrows.value(),
523                );
524            }
525        } else {
526            // All the columns to remove are at the end of the buffer. Drop them.
527            unsafe {
528                let ptr = m.data.ptr_mut().add(i * nrows.value());
529                let s = ptr::slice_from_raw_parts_mut(ptr, nremove.value() * nrows.value());
530                ptr::drop_in_place(s)
531            };
532        }
533
534        // Safety: The new size is smaller than the old size, so
535        //         DefaultAllocator::reallocate_copy will initialize
536        //         every element of the new matrix which can then
537        //         be assumed to be initialized.
538        unsafe {
539            let new_data = DefaultAllocator::reallocate_copy(nrows, ncols.sub(nremove), m.data);
540            Matrix::from_data(new_data).assume_init()
541        }
542    }
543
544    /*
545     *
546     * Row removal.
547     *
548     */
549    /// Removes the `i`-th row from this matrix.
550    #[inline]
551    pub fn remove_row(self, i: usize) -> OMatrix<T, DimDiff<R, U1>, C>
552    where
553        R: DimSub<U1>,
554        DefaultAllocator: Reallocator<T, R, C, DimDiff<R, U1>, C>,
555    {
556        self.remove_fixed_rows::<1>(i)
557    }
558
559    /// Removes `D::dim()` consecutive rows from this matrix, starting with the `i`-th (included).
560    #[inline]
561    pub fn remove_fixed_rows<const D: usize>(self, i: usize) -> OMatrix<T, DimDiff<R, Const<D>>, C>
562    where
563        R: DimSub<Const<D>>,
564        DefaultAllocator: Reallocator<T, R, C, DimDiff<R, Const<D>>, C>,
565    {
566        self.remove_rows_generic(i, Const::<D>)
567    }
568
569    /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included).
570    #[inline]
571    #[cfg(any(feature = "std", feature = "alloc"))]
572    pub fn remove_rows(self, i: usize, n: usize) -> OMatrix<T, Dyn, C>
573    where
574        R: DimSub<Dyn, Output = Dyn>,
575        DefaultAllocator: Reallocator<T, R, C, Dyn, C>,
576    {
577        self.remove_rows_generic(i, Dyn(n))
578    }
579
580    /// Removes `nremove.value()` rows from this matrix, starting with the `i`-th (included).
581    ///
582    /// This is the generic implementation of `.remove_rows(...)` and `.remove_fixed_rows(...)`
583    /// which have nicer API interfaces.
584    #[inline]
585    pub fn remove_rows_generic<D>(self, i: usize, nremove: D) -> OMatrix<T, DimDiff<R, D>, C>
586    where
587        D: Dim,
588        R: DimSub<D>,
589        DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>,
590    {
591        let mut m = self.into_owned();
592        let (nrows, ncols) = m.shape_generic();
593        assert!(
594            i + nremove.value() <= nrows.value(),
595            "Row index out of range."
596        );
597
598        if nremove.value() != 0 {
599            unsafe {
600                compress_rows(
601                    m.as_mut_slice(),
602                    nrows.value(),
603                    ncols.value(),
604                    i,
605                    nremove.value(),
606                );
607            }
608        }
609
610        // Safety: The new size is smaller than the old size, so
611        //         DefaultAllocator::reallocate_copy will initialize
612        //         every element of the new matrix which can then
613        //         be assumed to be initialized.
614        unsafe {
615            let new_data = DefaultAllocator::reallocate_copy(nrows.sub(nremove), ncols, m.data);
616            Matrix::from_data(new_data).assume_init()
617        }
618    }
619}
620
621/// # Rows and columns insertion
622impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
623    /*
624     *
625     * Columns insertion.
626     *
627     */
628    /// Inserts a column filled with `val` at the `i-th` position.
629    #[inline]
630    pub fn insert_column(self, i: usize, val: T) -> OMatrix<T, R, DimSum<C, U1>>
631    where
632        C: DimAdd<U1>,
633        DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, U1>>,
634    {
635        self.insert_fixed_columns::<1>(i, val)
636    }
637
638    /// Inserts `D` columns filled with `val` starting at the `i-th` position.
639    #[inline]
640    pub fn insert_fixed_columns<const D: usize>(
641        self,
642        i: usize,
643        val: T,
644    ) -> OMatrix<T, R, DimSum<C, Const<D>>>
645    where
646        C: DimAdd<Const<D>>,
647        DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, Const<D>>>,
648    {
649        let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Const::<D>) };
650        res.fixed_columns_mut::<D>(i)
651            .fill_with(|| MaybeUninit::new(val.clone()));
652
653        // Safety: the result is now fully initialized. The added columns have
654        //         been initialized by the `fill_with` above, and the rest have
655        //         been initialized by `insert_columns_generic_uninitialized`.
656        unsafe { res.assume_init() }
657    }
658
659    /// Inserts `n` columns filled with `val` starting at the `i-th` position.
660    #[inline]
661    #[cfg(any(feature = "std", feature = "alloc"))]
662    pub fn insert_columns(self, i: usize, n: usize, val: T) -> OMatrix<T, R, Dyn>
663    where
664        C: DimAdd<Dyn, Output = Dyn>,
665        DefaultAllocator: Reallocator<T, R, C, R, Dyn>,
666    {
667        let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dyn(n)) };
668        res.columns_mut(i, n)
669            .fill_with(|| MaybeUninit::new(val.clone()));
670
671        // Safety: the result is now fully initialized. The added columns have
672        //         been initialized by the `fill_with` above, and the rest have
673        //         been initialized by `insert_columns_generic_uninitialized`.
674        unsafe { res.assume_init() }
675    }
676
677    /// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix.
678    ///
679    /// # Safety
680    /// The output matrix has all its elements initialized except for the the components of the
681    /// added columns.
682    #[inline]
683    pub unsafe fn insert_columns_generic_uninitialized<D>(
684        self,
685        i: usize,
686        ninsert: D,
687    ) -> UninitMatrix<T, R, DimSum<C, D>>
688    where
689        D: Dim,
690        C: DimAdd<D>,
691        DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>,
692    {
693        unsafe {
694            let m = self.into_owned();
695            let (nrows, ncols) = m.shape_generic();
696            let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
697                nrows,
698                ncols.add(ninsert),
699                m.data,
700            ));
701
702            assert!(i <= ncols.value(), "Column insertion index out of range.");
703
704            if ninsert.value() != 0 && i != ncols.value() {
705                let ptr_in = res.data.ptr().add(i * nrows.value());
706                let ptr_out = res
707                    .data
708                    .ptr_mut()
709                    .add((i + ninsert.value()) * nrows.value());
710
711                ptr::copy(ptr_in, ptr_out, (ncols.value() - i) * nrows.value())
712            }
713
714            res
715        }
716    }
717
718    /*
719     *
720     * Rows insertion.
721     *
722     */
723    /// Inserts a row filled with `val` at the `i-th` position.
724    #[inline]
725    pub fn insert_row(self, i: usize, val: T) -> OMatrix<T, DimSum<R, U1>, C>
726    where
727        R: DimAdd<U1>,
728        DefaultAllocator: Reallocator<T, R, C, DimSum<R, U1>, C>,
729    {
730        self.insert_fixed_rows::<1>(i, val)
731    }
732
733    /// Inserts `D::dim()` rows filled with `val` starting at the `i-th` position.
734    #[inline]
735    pub fn insert_fixed_rows<const D: usize>(
736        self,
737        i: usize,
738        val: T,
739    ) -> OMatrix<T, DimSum<R, Const<D>>, C>
740    where
741        R: DimAdd<Const<D>>,
742        DefaultAllocator: Reallocator<T, R, C, DimSum<R, Const<D>>, C>,
743    {
744        let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Const::<D>) };
745        res.fixed_rows_mut::<D>(i)
746            .fill_with(|| MaybeUninit::new(val.clone()));
747
748        // Safety: the result is now fully initialized. The added rows have
749        //         been initialized by the `fill_with` above, and the rest have
750        //         been initialized by `insert_rows_generic_uninitialized`.
751        unsafe { res.assume_init() }
752    }
753
754    /// Inserts `n` rows filled with `val` starting at the `i-th` position.
755    #[inline]
756    #[cfg(any(feature = "std", feature = "alloc"))]
757    pub fn insert_rows(self, i: usize, n: usize, val: T) -> OMatrix<T, Dyn, C>
758    where
759        R: DimAdd<Dyn, Output = Dyn>,
760        DefaultAllocator: Reallocator<T, R, C, Dyn, C>,
761    {
762        let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dyn(n)) };
763        res.rows_mut(i, n)
764            .fill_with(|| MaybeUninit::new(val.clone()));
765
766        // Safety: the result is now fully initialized. The added rows have
767        //         been initialized by the `fill_with` above, and the rest have
768        //         been initialized by `insert_rows_generic_uninitialized`.
769        unsafe { res.assume_init() }
770    }
771
772    /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix.
773    ///
774    /// # Safety
775    /// The added rows values are not initialized.
776    /// This is the generic implementation of `.insert_rows(...)` and
777    /// `.insert_fixed_rows(...)` which have nicer API interfaces.
778    #[inline]
779    pub unsafe fn insert_rows_generic_uninitialized<D>(
780        self,
781        i: usize,
782        ninsert: D,
783    ) -> UninitMatrix<T, DimSum<R, D>, C>
784    where
785        D: Dim,
786        R: DimAdd<D>,
787        DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>,
788    {
789        unsafe {
790            let m = self.into_owned();
791            let (nrows, ncols) = m.shape_generic();
792            let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
793                nrows.add(ninsert),
794                ncols,
795                m.data,
796            ));
797
798            assert!(i <= nrows.value(), "Row insertion index out of range.");
799
800            if ninsert.value() != 0 {
801                extend_rows(
802                    res.as_mut_slice(),
803                    nrows.value(),
804                    ncols.value(),
805                    i,
806                    ninsert.value(),
807                );
808            }
809
810            res
811        }
812    }
813}
814
815/// # Resizing and reshaping
816impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
817    /// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns.
818    ///
819    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
820    /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
821    #[cfg(any(feature = "std", feature = "alloc"))]
822    pub fn resize(self, new_nrows: usize, new_ncols: usize, val: T) -> OMatrix<T, Dyn, Dyn>
823    where
824        DefaultAllocator: Reallocator<T, R, C, Dyn, Dyn>,
825    {
826        self.resize_generic(Dyn(new_nrows), Dyn(new_ncols), val)
827    }
828
829    /// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns.
830    ///
831    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
832    /// rows than `self`, then the extra rows are filled with `val`.
833    #[cfg(any(feature = "std", feature = "alloc"))]
834    pub fn resize_vertically(self, new_nrows: usize, val: T) -> OMatrix<T, Dyn, C>
835    where
836        DefaultAllocator: Reallocator<T, R, C, Dyn, C>,
837    {
838        let ncols = self.shape_generic().1;
839        self.resize_generic(Dyn(new_nrows), ncols, val)
840    }
841
842    /// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns.
843    ///
844    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
845    /// columns than `self`, then the extra columns are filled with `val`.
846    #[cfg(any(feature = "std", feature = "alloc"))]
847    pub fn resize_horizontally(self, new_ncols: usize, val: T) -> OMatrix<T, R, Dyn>
848    where
849        DefaultAllocator: Reallocator<T, R, C, R, Dyn>,
850    {
851        let nrows = self.shape_generic().0;
852        self.resize_generic(nrows, Dyn(new_ncols), val)
853    }
854
855    /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns.
856    ///
857    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
858    /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
859    pub fn fixed_resize<const R2: usize, const C2: usize>(
860        self,
861        val: T,
862    ) -> OMatrix<T, Const<R2>, Const<C2>>
863    where
864        DefaultAllocator: Reallocator<T, R, C, Const<R2>, Const<C2>>,
865    {
866        self.resize_generic(Const::<R2>, Const::<C2>, val)
867    }
868
869    /// Resizes `self` such that it has dimensions `new_nrows × new_ncols`.
870    ///
871    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
872    /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
873    #[inline]
874    pub fn resize_generic<R2: Dim, C2: Dim>(
875        self,
876        new_nrows: R2,
877        new_ncols: C2,
878        val: T,
879    ) -> OMatrix<T, R2, C2>
880    where
881        DefaultAllocator: Reallocator<T, R, C, R2, C2>,
882    {
883        let (nrows, ncols) = self.shape();
884        let mut data = self.into_owned();
885
886        if new_nrows.value() == nrows {
887            if new_ncols.value() < ncols {
888                unsafe {
889                    let num_cols_to_delete = ncols - new_ncols.value();
890                    let col_ptr = data.data.ptr_mut().add(new_ncols.value() * nrows);
891                    let s = ptr::slice_from_raw_parts_mut(col_ptr, num_cols_to_delete * nrows);
892                    // Safety: drop the elements of the deleted columns.
893                    //         these are the elements that will be truncated
894                    //         by the `reallocate_copy` afterward.
895                    ptr::drop_in_place(s)
896                };
897            }
898
899            let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.data) };
900            let mut res = Matrix::from_data(res);
901
902            if new_ncols.value() > ncols {
903                res.columns_range_mut(ncols..)
904                    .fill_with(|| MaybeUninit::new(val.clone()));
905            }
906
907            // Safety: the result is now fully initialized by `reallocate_copy` and
908            //         `fill_with` (if the output has more columns than the input).
909            unsafe { res.assume_init() }
910        } else {
911            let mut res;
912
913            unsafe {
914                if new_nrows.value() < nrows {
915                    compress_rows(
916                        data.as_mut_slice(),
917                        nrows,
918                        ncols,
919                        new_nrows.value(),
920                        nrows - new_nrows.value(),
921                    );
922                    res = Matrix::from_data(DefaultAllocator::reallocate_copy(
923                        new_nrows, new_ncols, data.data,
924                    ));
925                } else {
926                    res = Matrix::from_data(DefaultAllocator::reallocate_copy(
927                        new_nrows, new_ncols, data.data,
928                    ));
929                    extend_rows(
930                        res.as_mut_slice(),
931                        nrows,
932                        new_ncols.value(),
933                        nrows,
934                        new_nrows.value() - nrows,
935                    );
936                }
937            }
938
939            if new_ncols.value() > ncols {
940                res.columns_range_mut(ncols..)
941                    .fill_with(|| MaybeUninit::new(val.clone()));
942            }
943
944            if new_nrows.value() > nrows {
945                res.view_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value()))
946                    .fill_with(|| MaybeUninit::new(val.clone()));
947            }
948
949            // Safety: the result is now fully initialized by `reallocate_copy` and
950            //         `fill_with` (whenever applicable).
951            unsafe { res.assume_init() }
952        }
953    }
954
955    /// Reshapes `self` such that it has dimensions `new_nrows × new_ncols`.
956    ///
957    /// This will reinterpret `self` as if it is a matrix with `new_nrows` rows and `new_ncols`
958    /// columns. The arrangements of the component in the output matrix are the same as what
959    /// would be obtained by `Matrix::from_slice_generic(self.as_slice(), new_nrows, new_ncols)`.
960    ///
961    /// If `self` is a dynamically-sized matrix, then its components are neither copied nor moved.
962    /// If `self` is staticyll-sized, then a copy may happen in some situations.
963    /// This function will panic if the given dimensions are such that the number of elements of
964    /// the input matrix are not equal to the number of elements of the output matrix.
965    ///
966    /// # Examples
967    ///
968    /// ```
969    /// # use nalgebra::{Matrix3x2, Matrix2x3, DMatrix, Const, Dyn};
970    ///
971    /// let m1 = Matrix2x3::new(
972    ///     1.1, 1.2, 1.3,
973    ///     2.1, 2.2, 2.3
974    /// );
975    /// let m2 = Matrix3x2::new(
976    ///     1.1, 2.2,
977    ///     2.1, 1.3,
978    ///     1.2, 2.3
979    /// );
980    /// let reshaped = m1.reshape_generic(Const::<3>, Const::<2>);
981    /// assert_eq!(reshaped, m2);
982    ///
983    /// let dm1 = DMatrix::from_row_slice(
984    ///     4,
985    ///     3,
986    ///     &[
987    ///         1.0, 0.0, 0.0,
988    ///         0.0, 0.0, 1.0,
989    ///         0.0, 0.0, 0.0,
990    ///         0.0, 1.0, 0.0
991    ///     ],
992    /// );
993    /// let dm2 = DMatrix::from_row_slice(
994    ///     6,
995    ///     2,
996    ///     &[
997    ///         1.0, 0.0,
998    ///         0.0, 1.0,
999    ///         0.0, 0.0,
1000    ///         0.0, 1.0,
1001    ///         0.0, 0.0,
1002    ///         0.0, 0.0,
1003    ///     ],
1004    /// );
1005    /// let reshaped = dm1.reshape_generic(Dyn(6), Dyn(2));
1006    /// assert_eq!(reshaped, dm2);
1007    /// ```
1008    pub fn reshape_generic<R2, C2>(
1009        self,
1010        new_nrows: R2,
1011        new_ncols: C2,
1012    ) -> Matrix<T, R2, C2, S::Output>
1013    where
1014        R2: Dim,
1015        C2: Dim,
1016        S: ReshapableStorage<T, R, C, R2, C2>,
1017    {
1018        let data = self.data.reshape_generic(new_nrows, new_ncols);
1019        Matrix::from_data(data)
1020    }
1021}
1022
1023/// # In-place resizing
1024#[cfg(any(feature = "std", feature = "alloc"))]
1025impl<T: Scalar> OMatrix<T, Dyn, Dyn> {
1026    /// Resizes this matrix in-place.
1027    ///
1028    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
1029    /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
1030    ///
1031    /// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`.
1032    pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: T)
1033    where
1034        DefaultAllocator: Reallocator<T, Dyn, Dyn, Dyn, Dyn>,
1035    {
1036        // TODO: avoid the clone.
1037        *self = self.clone().resize(new_nrows, new_ncols, val);
1038    }
1039}
1040
1041#[cfg(any(feature = "std", feature = "alloc"))]
1042impl<T: Scalar, C: Dim> OMatrix<T, Dyn, C>
1043where
1044    DefaultAllocator: Allocator<Dyn, C>,
1045{
1046    /// Changes the number of rows of this matrix in-place.
1047    ///
1048    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
1049    /// rows than `self`, then the extra rows are filled with `val`.
1050    ///
1051    /// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`).
1052    #[cfg(any(feature = "std", feature = "alloc"))]
1053    pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: T)
1054    where
1055        DefaultAllocator: Reallocator<T, Dyn, C, Dyn, C>,
1056    {
1057        // TODO: avoid the clone.
1058        *self = self.clone().resize_vertically(new_nrows, val);
1059    }
1060}
1061
1062#[cfg(any(feature = "std", feature = "alloc"))]
1063impl<T: Scalar, R: Dim> OMatrix<T, R, Dyn>
1064where
1065    DefaultAllocator: Allocator<R, Dyn>,
1066{
1067    /// Changes the number of column of this matrix in-place.
1068    ///
1069    /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
1070    /// columns than `self`, then the extra columns are filled with `val`.
1071    ///
1072    /// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`).
1073    #[cfg(any(feature = "std", feature = "alloc"))]
1074    pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: T)
1075    where
1076        DefaultAllocator: Reallocator<T, R, Dyn, R, Dyn>,
1077    {
1078        // TODO: avoid the clone.
1079        *self = self.clone().resize_horizontally(new_ncols, val);
1080    }
1081}
1082
1083// Move the elements of `data` in such a way that the matrix with
1084// the rows `[i, i + nremove[` deleted is represented in a contiguous
1085// way in `data` after this method completes.
1086// Every deleted element are manually dropped by this method.
1087unsafe fn compress_rows<T: Scalar>(
1088    data: &mut [T],
1089    nrows: usize,
1090    ncols: usize,
1091    i: usize,
1092    nremove: usize,
1093) {
1094    unsafe {
1095        let new_nrows = nrows - nremove;
1096
1097        if nremove == 0 {
1098            return; // Nothing to remove or drop.
1099        }
1100
1101        if new_nrows == 0 || ncols == 0 {
1102            // The output matrix is empty, drop everything.
1103            ptr::drop_in_place(data);
1104            return;
1105        }
1106
1107        // Safety: because `nremove != 0`, the pointers given to `ptr::copy`
1108        //         won’t alias.
1109        let ptr_in = data.as_ptr();
1110        let ptr_out = data.as_mut_ptr();
1111
1112        let mut curr_i = i;
1113
1114        for k in 0..ncols - 1 {
1115            // Safety: we drop the row elements in-place because we will overwrite these
1116            //         entries later with the `ptr::copy`.
1117            let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove);
1118            ptr::drop_in_place(s);
1119            ptr::copy(
1120                ptr_in.add(curr_i + (k + 1) * nremove),
1121                ptr_out.add(curr_i),
1122                new_nrows,
1123            );
1124
1125            curr_i += new_nrows;
1126        }
1127
1128        /*
1129         * Deal with the last column from which less values have to be copied.
1130         */
1131        // Safety: we drop the row elements in-place because we will overwrite these
1132        //         entries later with the `ptr::copy`.
1133        let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove);
1134        ptr::drop_in_place(s);
1135        let remaining_len = nrows - i - nremove;
1136        ptr::copy(
1137            ptr_in.add(nrows * ncols - remaining_len),
1138            ptr_out.add(curr_i),
1139            remaining_len,
1140        );
1141    }
1142}
1143
1144// Moves entries of a matrix buffer to make place for `ninsert` empty rows starting at the `i-th` row index.
1145// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements.
1146unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, ninsert: usize) {
1147    unsafe {
1148        let new_nrows = nrows + ninsert;
1149
1150        if new_nrows == 0 || ncols == 0 {
1151            return; // Nothing to do as the output matrix is empty.
1152        }
1153
1154        let ptr_in = data.as_ptr();
1155        let ptr_out = data.as_mut_ptr();
1156
1157        let remaining_len = nrows - i;
1158        let mut curr_i = new_nrows * ncols - remaining_len;
1159
1160        // Deal with the last column from which less values have to be copied.
1161        ptr::copy(
1162            ptr_in.add(nrows * ncols - remaining_len),
1163            ptr_out.add(curr_i),
1164            remaining_len,
1165        );
1166
1167        for k in (0..ncols - 1).rev() {
1168            curr_i -= new_nrows;
1169
1170            ptr::copy(ptr_in.add(k * nrows + i), ptr_out.add(curr_i), nrows);
1171        }
1172    }
1173}
1174
1175/// Extend the number of columns of the `Matrix` with elements from
1176/// a given iterator.
1177#[cfg(any(feature = "std", feature = "alloc"))]
1178impl<T, R, S> Extend<T> for Matrix<T, R, Dyn, S>
1179where
1180    T: Scalar,
1181    R: Dim,
1182    S: Extend<T>,
1183{
1184    /// Extend the number of columns of the `Matrix` with elements
1185    /// from the given iterator.
1186    ///
1187    /// # Example
1188    /// ```
1189    /// # use nalgebra::{DMatrix, Dyn, Matrix, OMatrix, Matrix3};
1190    ///
1191    /// let data = vec![0, 1, 2,      // column 1
1192    ///                 3, 4, 5];     // column 2
1193    ///
1194    /// let mut matrix = DMatrix::from_vec(3, 2, data);
1195    ///
1196    /// matrix.extend(vec![6, 7, 8]); // column 3
1197    ///
1198    /// assert!(matrix.eq(&Matrix3::new(0, 3, 6,
1199    ///                                 1, 4, 7,
1200    ///                                 2, 5, 8)));
1201    /// ```
1202    ///
1203    /// # Panics
1204    /// This function panics if the number of elements yielded by the
1205    /// given iterator is not a multiple of the number of rows of the
1206    /// `Matrix`.
1207    ///
1208    /// ```should_panic
1209    /// # use nalgebra::{DMatrix, Dyn, OMatrix};
1210    /// let data = vec![0, 1, 2,  // column 1
1211    ///                 3, 4, 5]; // column 2
1212    ///
1213    /// let mut matrix = DMatrix::from_vec(3, 2, data);
1214    ///
1215    /// // The following panics because the vec length is not a multiple of 3.
1216    /// matrix.extend(vec![6, 7, 8, 9]);
1217    /// ```
1218    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1219        self.data.extend(iter);
1220    }
1221}
1222
1223/// Extend the number of rows of the `Vector` with elements from
1224/// a given iterator.
1225#[cfg(any(feature = "std", feature = "alloc"))]
1226impl<T, S> Extend<T> for Matrix<T, Dyn, U1, S>
1227where
1228    T: Scalar,
1229    S: Extend<T>,
1230{
1231    /// Extend the number of rows of a `Vector` with elements
1232    /// from the given iterator.
1233    ///
1234    /// # Example
1235    /// ```
1236    /// # use nalgebra::DVector;
1237    /// let mut vector = DVector::from_vec(vec![0, 1, 2]);
1238    /// vector.extend(vec![3, 4, 5]);
1239    /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5])));
1240    /// ```
1241    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1242        self.data.extend(iter);
1243    }
1244}
1245
1246#[cfg(any(feature = "std", feature = "alloc"))]
1247impl<T, R, S, RV, SV> Extend<Vector<T, RV, SV>> for Matrix<T, R, Dyn, S>
1248where
1249    T: Scalar,
1250    R: Dim,
1251    S: Extend<Vector<T, RV, SV>>,
1252    RV: Dim,
1253    SV: RawStorage<T, RV>,
1254    ShapeConstraint: SameNumberOfRows<R, RV>,
1255{
1256    /// Extends the number of columns of a `Matrix` with `Vector`s
1257    /// from a given iterator.
1258    ///
1259    /// # Example
1260    /// ```
1261    /// # use nalgebra::{DMatrix, Vector3, Matrix3x4};
1262    ///
1263    /// let data = vec![0, 1, 2,          // column 1
1264    ///                 3, 4, 5];         // column 2
1265    ///
1266    /// let mut matrix = DMatrix::from_vec(3, 2, data);
1267    ///
1268    /// matrix.extend(
1269    ///   vec![Vector3::new(6,  7,  8),   // column 3
1270    ///        Vector3::new(9, 10, 11)]); // column 4
1271    ///
1272    /// assert!(matrix.eq(&Matrix3x4::new(0, 3, 6,  9,
1273    ///                                   1, 4, 7, 10,
1274    ///                                   2, 5, 8, 11)));
1275    /// ```
1276    ///
1277    /// # Panics
1278    /// This function panics if the dimension of each `Vector` yielded
1279    /// by the given iterator is not equal to the number of rows of
1280    /// this `Matrix`.
1281    ///
1282    /// ```should_panic
1283    /// # use nalgebra::{DMatrix, Vector2, Matrix3x4};
1284    /// let mut matrix =
1285    ///   DMatrix::from_vec(3, 2,
1286    ///                     vec![0, 1, 2,   // column 1
1287    ///                          3, 4, 5]); // column 2
1288    ///
1289    /// // The following panics because this matrix can only be extended with 3-dimensional vectors.
1290    /// matrix.extend(
1291    ///   vec![Vector2::new(6,  7)]); // too few dimensions!
1292    /// ```
1293    ///
1294    /// ```should_panic
1295    /// # use nalgebra::{DMatrix, Vector4, Matrix3x4};
1296    /// let mut matrix =
1297    ///   DMatrix::from_vec(3, 2,
1298    ///                     vec![0, 1, 2,   // column 1
1299    ///                          3, 4, 5]); // column 2
1300    ///
1301    /// // The following panics because this matrix can only be extended with 3-dimensional vectors.
1302    /// matrix.extend(
1303    ///   vec![Vector4::new(6, 7, 8, 9)]); // too few dimensions!
1304    /// ```
1305    fn extend<I: IntoIterator<Item = Vector<T, RV, SV>>>(&mut self, iter: I) {
1306        self.data.extend(iter);
1307    }
1308}