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}