nalgebra/base/
conversion.rs

1#[cfg(all(feature = "alloc", not(feature = "std")))]
2use alloc::vec::Vec;
3use simba::scalar::{SubsetOf, SupersetOf};
4use std::borrow::{Borrow, BorrowMut};
5use std::convert::{AsMut, AsRef, From, Into};
6
7use simba::simd::{PrimitiveSimdValue, SimdValue};
8
9use crate::base::allocator::{Allocator, SameShapeAllocator};
10use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
11#[cfg(any(feature = "std", feature = "alloc"))]
12use crate::base::dimension::Dynamic;
13use crate::base::dimension::{
14    Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
15};
16use crate::base::iter::{MatrixIter, MatrixIterMut};
17use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
18use crate::base::{
19    ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
20    MatrixSliceMut, OMatrix, Scalar,
21};
22#[cfg(any(feature = "std", feature = "alloc"))]
23use crate::base::{DVector, RowDVector, VecStorage};
24use crate::base::{SliceStorage, SliceStorageMut};
25use crate::constraint::DimEq;
26use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector, VectorSlice, VectorSliceMut};
27use std::mem::MaybeUninit;
28
29// TODO: too bad this won't work for slice conversions.
30impl<T1, T2, R1, C1, R2, C2> SubsetOf<OMatrix<T2, R2, C2>> for OMatrix<T1, R1, C1>
31where
32    R1: Dim,
33    C1: Dim,
34    R2: Dim,
35    C2: Dim,
36    T1: Scalar,
37    T2: Scalar + SupersetOf<T1>,
38    DefaultAllocator:
39        Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>,
40    ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
41{
42    #[inline]
43    fn to_superset(&self) -> OMatrix<T2, R2, C2> {
44        let (nrows, ncols) = self.shape();
45        let nrows2 = R2::from_usize(nrows);
46        let ncols2 = C2::from_usize(ncols);
47        let mut res = Matrix::uninit(nrows2, ncols2);
48
49        for i in 0..nrows {
50            for j in 0..ncols {
51                // Safety: all indices are in range.
52                unsafe {
53                    *res.get_unchecked_mut((i, j)) =
54                        MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
55                }
56            }
57        }
58
59        // Safety: res is now fully initialized.
60        unsafe { res.assume_init() }
61    }
62
63    #[inline]
64    fn is_in_subset(m: &OMatrix<T2, R2, C2>) -> bool {
65        m.iter().all(|e| e.is_in_subset())
66    }
67
68    #[inline]
69    fn from_superset_unchecked(m: &OMatrix<T2, R2, C2>) -> Self {
70        let (nrows2, ncols2) = m.shape();
71        let nrows = R1::from_usize(nrows2);
72        let ncols = C1::from_usize(ncols2);
73        let mut res = Matrix::uninit(nrows, ncols);
74
75        for i in 0..nrows2 {
76            for j in 0..ncols2 {
77                // Safety: all indices are in range.
78                unsafe {
79                    *res.get_unchecked_mut((i, j)) =
80                        MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked())
81                }
82            }
83        }
84
85        unsafe { res.assume_init() }
86    }
87}
88
89impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> IntoIterator
90    for &'a Matrix<T, R, C, S>
91{
92    type Item = &'a T;
93    type IntoIter = MatrixIter<'a, T, R, C, S>;
94
95    #[inline]
96    fn into_iter(self) -> Self::IntoIter {
97        self.iter()
98    }
99}
100
101impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IntoIterator
102    for &'a mut Matrix<T, R, C, S>
103{
104    type Item = &'a mut T;
105    type IntoIter = MatrixIterMut<'a, T, R, C, S>;
106
107    #[inline]
108    fn into_iter(self) -> Self::IntoIter {
109        self.iter_mut()
110    }
111}
112
113impl<T: Scalar, const D: usize> From<[T; D]> for SVector<T, D> {
114    #[inline]
115    fn from(arr: [T; D]) -> Self {
116        unsafe { Self::from_data_statically_unchecked(ArrayStorage([arr; 1])) }
117    }
118}
119
120impl<T: Scalar, const D: usize> From<SVector<T, D>> for [T; D] {
121    #[inline]
122    fn from(vec: SVector<T, D>) -> Self {
123        // TODO: unfortunately, we must clone because we can move out of an array.
124        vec.data.0[0].clone()
125    }
126}
127
128impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize>
129    From<VectorSlice<'a, T, Const<D>, RStride, CStride>> for [T; D]
130{
131    #[inline]
132    fn from(vec: VectorSlice<'a, T, Const<D>, RStride, CStride>) -> Self {
133        vec.into_owned().into()
134    }
135}
136
137impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize>
138    From<VectorSliceMut<'a, T, Const<D>, RStride, CStride>> for [T; D]
139{
140    #[inline]
141    fn from(vec: VectorSliceMut<'a, T, Const<D>, RStride, CStride>) -> Self {
142        vec.into_owned().into()
143    }
144}
145
146impl<T: Scalar, const D: usize> From<[T; D]> for RowSVector<T, D>
147where
148    Const<D>: IsNotStaticOne,
149{
150    #[inline]
151    fn from(arr: [T; D]) -> Self {
152        SVector::<T, D>::from(arr).transpose()
153    }
154}
155
156impl<T: Scalar, const D: usize> From<RowSVector<T, D>> for [T; D]
157where
158    Const<D>: IsNotStaticOne,
159{
160    #[inline]
161    fn from(vec: RowSVector<T, D>) -> [T; D] {
162        vec.transpose().into()
163    }
164}
165
166macro_rules! impl_from_into_asref_1D(
167    ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
168        impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
169        where T: Scalar,
170              S: RawStorage<T, $NRows, $NCols> + IsContiguous {
171            #[inline]
172            fn as_ref(&self) -> &[T; $SZ] {
173                // Safety: this is OK thanks to the IsContiguous trait.
174                unsafe {
175                    &*(self.data.ptr() as *const [T; $SZ])
176                }
177            }
178        }
179
180        impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
181        where T: Scalar,
182              S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
183            #[inline]
184            fn as_mut(&mut self) -> &mut [T; $SZ] {
185                // Safety: this is OK thanks to the IsContiguous trait.
186                unsafe {
187                    &mut *(self.data.ptr_mut() as *mut [T; $SZ])
188                }
189            }
190        }
191    )*}
192);
193
194// Implement for vectors of dimension 1 .. 16.
195impl_from_into_asref_1D!(
196    // Row vectors.
197    (U1, U1 ) => 1;  (U1, U2 ) => 2;  (U1, U3 ) => 3;  (U1, U4 ) => 4;
198    (U1, U5 ) => 5;  (U1, U6 ) => 6;  (U1, U7 ) => 7;  (U1, U8 ) => 8;
199    (U1, U9 ) => 9;  (U1, U10) => 10; (U1, U11) => 11; (U1, U12) => 12;
200    (U1, U13) => 13; (U1, U14) => 14; (U1, U15) => 15; (U1, U16) => 16;
201
202    // Column vectors.
203                     (U2 , U1) => 2;  (U3 , U1) => 3;  (U4 , U1) => 4;
204    (U5 , U1) => 5;  (U6 , U1) => 6;  (U7 , U1) => 7;  (U8 , U1) => 8;
205    (U9 , U1) => 9;  (U10, U1) => 10; (U11, U1) => 11; (U12, U1) => 12;
206    (U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16;
207);
208
209impl<T: Scalar, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T, R, C> {
210    #[inline]
211    fn from(arr: [[T; R]; C]) -> Self {
212        unsafe { Self::from_data_statically_unchecked(ArrayStorage(arr)) }
213    }
214}
215
216impl<T: Scalar, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] {
217    #[inline]
218    fn from(mat: SMatrix<T, R, C>) -> Self {
219        mat.data.0
220    }
221}
222
223impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
224    From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>> for [[T; R]; C]
225{
226    #[inline]
227    fn from(mat: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
228        mat.into_owned().into()
229    }
230}
231
232impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
233    From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>> for [[T; R]; C]
234{
235    #[inline]
236    fn from(mat: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
237        mat.into_owned().into()
238    }
239}
240
241macro_rules! impl_from_into_asref_borrow_2D(
242
243    //does the impls on one case for either AsRef/AsMut and Borrow/BorrowMut
244    (
245        ($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
246        $Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
247    ) => {
248        impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
249        where S: RawStorage<T, $NRows, $NCols> + IsContiguous {
250            #[inline]
251            fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
252                // Safety: OK thanks to the IsContiguous trait.
253                unsafe {
254                    &*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
255                }
256            }
257        }
258
259        impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
260        where S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
261            #[inline]
262            fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
263                // Safety: OK thanks to the IsContiguous trait.
264                unsafe {
265                    &mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
266                }
267            }
268        }
269    };
270
271    //collects the mappings from typenum pairs to consts
272    ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$(
273        impl_from_into_asref_borrow_2D!(
274            ($NRows, $NCols) => ($SZRows, $SZCols); AsRef.as_ref(), AsMut.as_mut()
275        );
276        impl_from_into_asref_borrow_2D!(
277            ($NRows, $NCols) => ($SZRows, $SZCols); Borrow.borrow(), BorrowMut.borrow_mut()
278        );
279    )*}
280);
281
282// Implement for matrices with shape 2x2 .. 6x6.
283impl_from_into_asref_borrow_2D!(
284    (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6);
285    (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6);
286    (U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6);
287    (U5, U2) => (5, 2); (U5, U3) => (5, 3); (U5, U4) => (5, 4); (U5, U5) => (5, 5); (U5, U6) => (5, 6);
288    (U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6);
289);
290
291impl<'a, T, RStride, CStride, const R: usize, const C: usize>
292    From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>>
293    for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
294where
295    T: Scalar,
296    RStride: Dim,
297    CStride: Dim,
298{
299    fn from(matrix_slice: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
300        matrix_slice.into_owned()
301    }
302}
303
304#[cfg(any(feature = "std", feature = "alloc"))]
305impl<'a, T, C, RStride, CStride> From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
306    for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
307where
308    T: Scalar,
309    C: Dim,
310    RStride: Dim,
311    CStride: Dim,
312{
313    fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self {
314        matrix_slice.into_owned()
315    }
316}
317
318#[cfg(any(feature = "std", feature = "alloc"))]
319impl<'a, T, R, RStride, CStride> From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
320    for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
321where
322    T: Scalar,
323    R: DimName,
324    RStride: Dim,
325    CStride: Dim,
326{
327    fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self {
328        matrix_slice.into_owned()
329    }
330}
331
332impl<'a, T, RStride, CStride, const R: usize, const C: usize>
333    From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>>
334    for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
335where
336    T: Scalar,
337    RStride: Dim,
338    CStride: Dim,
339{
340    fn from(matrix_slice: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
341        matrix_slice.into_owned()
342    }
343}
344
345#[cfg(any(feature = "std", feature = "alloc"))]
346impl<'a, T, C, RStride, CStride> From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
347    for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
348where
349    T: Scalar,
350    C: Dim,
351    RStride: Dim,
352    CStride: Dim,
353{
354    fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self {
355        matrix_slice.into_owned()
356    }
357}
358
359#[cfg(any(feature = "std", feature = "alloc"))]
360impl<'a, T, R, RStride, CStride> From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
361    for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
362where
363    T: Scalar,
364    R: DimName,
365    RStride: Dim,
366    CStride: Dim,
367{
368    fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self {
369        matrix_slice.into_owned()
370    }
371}
372
373impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix<T, R, C, S>>
374    for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
375where
376    T: Scalar,
377    R: Dim,
378    C: Dim,
379    RSlice: Dim,
380    CSlice: Dim,
381    RStride: Dim,
382    CStride: Dim,
383    S: RawStorage<T, R, C>,
384    ShapeConstraint: DimEq<R, RSlice>
385        + DimEq<C, CSlice>
386        + DimEq<RStride, S::RStride>
387        + DimEq<CStride, S::CStride>,
388{
389    fn from(m: &'a Matrix<T, R, C, S>) -> Self {
390        let (row, col) = m.shape_generic();
391        let row_slice = RSlice::from_usize(row.value());
392        let col_slice = CSlice::from_usize(col.value());
393
394        let (rstride, cstride) = m.strides();
395
396        let rstride_slice = RStride::from_usize(rstride);
397        let cstride_slice = CStride::from_usize(cstride);
398
399        unsafe {
400            let data = SliceStorage::from_raw_parts(
401                m.data.ptr(),
402                (row_slice, col_slice),
403                (rstride_slice, cstride_slice),
404            );
405            Matrix::from_data_statically_unchecked(data)
406        }
407    }
408}
409
410impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
411    for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
412where
413    T: Scalar,
414    R: Dim,
415    C: Dim,
416    RSlice: Dim,
417    CSlice: Dim,
418    RStride: Dim,
419    CStride: Dim,
420    S: RawStorage<T, R, C>,
421    ShapeConstraint: DimEq<R, RSlice>
422        + DimEq<C, CSlice>
423        + DimEq<RStride, S::RStride>
424        + DimEq<CStride, S::CStride>,
425{
426    fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
427        let (row, col) = m.shape_generic();
428        let row_slice = RSlice::from_usize(row.value());
429        let col_slice = CSlice::from_usize(col.value());
430
431        let (rstride, cstride) = m.strides();
432
433        let rstride_slice = RStride::from_usize(rstride);
434        let cstride_slice = CStride::from_usize(cstride);
435
436        unsafe {
437            let data = SliceStorage::from_raw_parts(
438                m.data.ptr(),
439                (row_slice, col_slice),
440                (rstride_slice, cstride_slice),
441            );
442            Matrix::from_data_statically_unchecked(data)
443        }
444    }
445}
446
447impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
448    for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
449where
450    T: Scalar,
451    R: Dim,
452    C: Dim,
453    RSlice: Dim,
454    CSlice: Dim,
455    RStride: Dim,
456    CStride: Dim,
457    S: RawStorageMut<T, R, C>,
458    ShapeConstraint: DimEq<R, RSlice>
459        + DimEq<C, CSlice>
460        + DimEq<RStride, S::RStride>
461        + DimEq<CStride, S::CStride>,
462{
463    fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
464        let (row, col) = m.shape_generic();
465        let row_slice = RSlice::from_usize(row.value());
466        let col_slice = CSlice::from_usize(col.value());
467
468        let (rstride, cstride) = m.strides();
469
470        let rstride_slice = RStride::from_usize(rstride);
471        let cstride_slice = CStride::from_usize(cstride);
472
473        unsafe {
474            let data = SliceStorageMut::from_raw_parts(
475                m.data.ptr_mut(),
476                (row_slice, col_slice),
477                (rstride_slice, cstride_slice),
478            );
479            Matrix::from_data_statically_unchecked(data)
480        }
481    }
482}
483
484#[cfg(any(feature = "std", feature = "alloc"))]
485impl<'a, T: Scalar> From<Vec<T>> for DVector<T> {
486    #[inline]
487    fn from(vec: Vec<T>) -> Self {
488        Self::from_vec(vec)
489    }
490}
491
492#[cfg(any(feature = "std", feature = "alloc"))]
493impl<'a, T: Scalar> From<Vec<T>> for RowDVector<T> {
494    #[inline]
495    fn from(vec: Vec<T>) -> Self {
496        Self::from_vec(vec)
497    }
498}
499
500impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage<T, R, C> + IsContiguous>
501    From<&'a Matrix<T, R, C, S>> for &'a [T]
502{
503    #[inline]
504    fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
505        matrix.as_slice()
506    }
507}
508
509impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut<T, R, C> + IsContiguous>
510    From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
511{
512    #[inline]
513    fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self {
514        matrix.as_mut_slice()
515    }
516}
517
518impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> {
519    #[inline]
520    fn from(slice: &'a [T]) -> Self {
521        Self::from_slice(slice, slice.len())
522    }
523}
524
525impl<'a, T: Scalar> From<DVectorSlice<'a, T>> for &'a [T] {
526    fn from(vec: DVectorSlice<'a, T>) -> &'a [T] {
527        vec.data.into_slice()
528    }
529}
530
531impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
532    #[inline]
533    fn from(slice: &'a mut [T]) -> Self {
534        Self::from_slice(slice, slice.len())
535    }
536}
537
538impl<'a, T: Scalar> From<DVectorSliceMut<'a, T>> for &'a mut [T] {
539    fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] {
540        vec.data.into_slice_mut()
541    }
542}
543
544impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 2]>
545    for OMatrix<T, R, C>
546where
547    T: From<[<T as SimdValue>::Element; 2]>,
548    T::Element: Scalar + SimdValue,
549    DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
550{
551    #[inline]
552    fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self {
553        let (nrows, ncols) = arr[0].shape_generic();
554
555        Self::from_fn_generic(nrows, ncols, |i, j| {
556            [arr[0][(i, j)].clone(), arr[1][(i, j)].clone()].into()
557        })
558    }
559}
560
561impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 4]>
562    for OMatrix<T, R, C>
563where
564    T: From<[<T as SimdValue>::Element; 4]>,
565    T::Element: Scalar + SimdValue,
566    DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
567{
568    #[inline]
569    fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self {
570        let (nrows, ncols) = arr[0].shape_generic();
571
572        Self::from_fn_generic(nrows, ncols, |i, j| {
573            [
574                arr[0][(i, j)].clone(),
575                arr[1][(i, j)].clone(),
576                arr[2][(i, j)].clone(),
577                arr[3][(i, j)].clone(),
578            ]
579            .into()
580        })
581    }
582}
583
584impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 8]>
585    for OMatrix<T, R, C>
586where
587    T: From<[<T as SimdValue>::Element; 8]>,
588    T::Element: Scalar + SimdValue,
589    DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
590{
591    #[inline]
592    fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self {
593        let (nrows, ncols) = arr[0].shape_generic();
594
595        Self::from_fn_generic(nrows, ncols, |i, j| {
596            [
597                arr[0][(i, j)].clone(),
598                arr[1][(i, j)].clone(),
599                arr[2][(i, j)].clone(),
600                arr[3][(i, j)].clone(),
601                arr[4][(i, j)].clone(),
602                arr[5][(i, j)].clone(),
603                arr[6][(i, j)].clone(),
604                arr[7][(i, j)].clone(),
605            ]
606            .into()
607        })
608    }
609}
610
611impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 16]>
612    for OMatrix<T, R, C>
613where
614    T: From<[<T as SimdValue>::Element; 16]>,
615    T::Element: Scalar + SimdValue,
616    DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
617{
618    fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self {
619        let (nrows, ncols) = arr[0].shape_generic();
620
621        Self::from_fn_generic(nrows, ncols, |i, j| {
622            [
623                arr[0][(i, j)].clone(),
624                arr[1][(i, j)].clone(),
625                arr[2][(i, j)].clone(),
626                arr[3][(i, j)].clone(),
627                arr[4][(i, j)].clone(),
628                arr[5][(i, j)].clone(),
629                arr[6][(i, j)].clone(),
630                arr[7][(i, j)].clone(),
631                arr[8][(i, j)].clone(),
632                arr[9][(i, j)].clone(),
633                arr[10][(i, j)].clone(),
634                arr[11][(i, j)].clone(),
635                arr[12][(i, j)].clone(),
636                arr[13][(i, j)].clone(),
637                arr[14][(i, j)].clone(),
638                arr[15][(i, j)].clone(),
639            ]
640            .into()
641        })
642    }
643}