Finally figured out some trait nitty-gritty

This commit is contained in:
Violeta Hernández 2021-07-14 13:24:27 -05:00
parent 1a78b00476
commit 8d10e69e33
9 changed files with 105 additions and 95 deletions

View File

@ -153,15 +153,15 @@ where
where
DefaultAllocator: Allocator<Complex<T>, D>,
{
let mut out = unsafe {
OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>).assume_init()
};
let mut out =
unsafe { OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>) };
for i in 0..out.len() {
out[i] = Complex::new(self.re[i], self.im[i])
out[i] = MaybeUninit::new(Complex::new(self.re[i], self.im[i]));
}
out
// Safety: all entries have been initialized.
unsafe { out.assume_init() }
}
}

View File

@ -1,3 +1,4 @@
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};

View File

@ -1,6 +1,5 @@
//! Abstract definition of a matrix data storage allocator.
use std::any::Any;
use std::mem::MaybeUninit;
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
@ -17,7 +16,7 @@ use crate::base::DefaultAllocator;
///
/// Every allocator must be both static and dynamic. Though not all implementations may share the
/// same `Buffer` type.
pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
pub trait Allocator<T, R: Dim, C: Dim = U1>: 'static + Sized {
/// The type of buffer this allocator can instanciate.
type Buffer: ContiguousStorageMut<T, R, C>;

View File

@ -30,16 +30,8 @@ use crate::base::{
#[macro_export]
macro_rules! unimplemented_or_uninitialized_generic {
($nrows:expr, $ncols:expr) => {{
#[cfg(feature="no_unsound_assume_init")] {
// Some of the call sites need the number of rows and columns from this to infer a type, so
// uninitialized memory is used to infer the type, as `T: Zero` isn't available at all callsites.
// This may technically still be UB even though the assume_init is dead code, but all callsites should be fixed before #556 is closed.
let typeinference_helper = crate::base::Matrix::new_uninitialized_generic($nrows, $ncols);
unimplemented!();
typeinference_helper.assume_init()
}
#[cfg(not(feature="no_unsound_assume_init"))] { crate::base::Matrix::new_uninitialized_generic($nrows, $ncols).assume_init() }
}}
crate::base::Matrix::new_uninitialized_generic($nrows, $ncols)
}};
}
/// # Generic constructors
@ -78,7 +70,7 @@ where
#[inline]
pub fn zeros_generic(nrows: R, ncols: C) -> Self
where
T: Zero,
T: Zero + Clone,
{
Self::from_element_generic(nrows, ncols, T::zero())
}
@ -98,22 +90,28 @@ where
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
#[inline]
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self
where
T: Clone,
{
assert!(
slice.len() == nrows.value() * ncols.value(),
"Matrix init. error: the slice did not contain the right number of elements."
);
let mut res = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let mut iter = slice.iter();
for i in 0..nrows.value() {
for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut((i, j)) = iter.next().unwrap().inlined_clone() }
unsafe {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone());
}
}
}
res
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
}
/// Creates a matrix with its elements filled with the components provided by a slice. The
@ -130,15 +128,18 @@ where
where
F: FnMut(usize, usize) -> T,
{
let mut res: Self = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
unsafe {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
}
}
}
res
// Safety: all entries have been initialized.
unsafe { Matrix::assume_init(res) }
}
/// Creates a new identity matrix.
@ -160,7 +161,7 @@ where
#[inline]
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self
where
T: Zero + One,
T: Zero + One+Clone,
{
let mut res = Self::zeros_generic(nrows, ncols);
@ -178,7 +179,7 @@ where
#[inline]
pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self
where
T: Zero,
T: Zero+Clone,
{
let mut res = Self::zeros_generic(nrows, ncols);
assert!(
@ -187,7 +188,7 @@ where
);
for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut((i, i)) = elt.inlined_clone() }
unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() }
}
res
@ -211,7 +212,7 @@ where
/// ```
#[inline]
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
where
where T:Clone,
SB: Storage<T, Const<1>, C>,
{
assert!(!rows.is_empty(), "At least one row must be given.");
@ -231,7 +232,7 @@ where
// TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
rows[i][(0, j)].inlined_clone()
rows[i][(0, j)].clone()
})
}
@ -253,7 +254,7 @@ where
/// ```
#[inline]
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
where
where T:Clone,
SB: Storage<T, R>,
{
assert!(!columns.is_empty(), "At least one column must be given.");
@ -273,7 +274,7 @@ where
// TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
columns[j][i].inlined_clone()
columns[j][i].clone()
})
}
@ -458,7 +459,7 @@ macro_rules! impl_constructors(
#[inline]
pub fn zeros($($args: usize),*) -> Self
where
T: Zero
T: Zero + Clone
{
Self::zeros_generic($($gargs),*)
}

View File

@ -3,6 +3,7 @@ use alloc::vec::Vec;
use simba::scalar::{SubsetOf, SupersetOf};
use std::borrow::{Borrow, BorrowMut};
use std::convert::{AsMut, AsRef, From, Into};
use std::mem::MaybeUninit;
use simba::simd::{PrimitiveSimdValue, SimdValue};
@ -44,17 +45,19 @@ where
let nrows2 = R2::from_usize(nrows);
let ncols2 = C2::from_usize(ncols);
let mut res: OMatrix<T2, R2, C2> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows2, ncols2) };
let mut res = OMatrix::<T2, R2, C2>::new_uninitialized_generic(nrows2, ncols2);
for i in 0..nrows {
for j in 0..ncols {
unsafe {
*res.get_unchecked_mut((i, j)) = T2::from_subset(self.get_unchecked((i, j)))
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
}
}
}
res
// Safety: all entries have been initialized.
unsafe { Matrix::assume_init(res) }
}
#[inline]
@ -68,16 +71,18 @@ where
let nrows = R1::from_usize(nrows2);
let ncols = C1::from_usize(ncols2);
let mut res: Self = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = OMatrix::new_uninitialized_generic(nrows, ncols);
for i in 0..nrows2 {
for j in 0..ncols2 {
unsafe {
*res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked()
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked());
}
}
}
res
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
}
}

View File

@ -68,7 +68,7 @@ impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for Def
);
// Safety: we have initialized all entries.
unsafe { Self::assume_init(res) }
unsafe { <Self as Allocator<T, Const<R>, Const<C>>>::assume_init(res) }
}
}

View File

@ -34,6 +34,10 @@ use crate::{ArrayStorage, SMatrix, SimdComplexField};
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::{DMatrix, DVector, Dynamic, VecStorage};
/// An uninitialized matrix.
pub type UninitMatrix<T, R, C> =
Matrix<MaybeUninit<T>, R, C, <DefaultAllocator as Allocator<T, R, C>>::UninitBuffer>;
/// A square matrix.
pub type SquareMatrix<T, D, S> = Matrix<T, D, D, S>;
@ -347,39 +351,34 @@ impl<T, R, C, S> Matrix<T, R, C, S> {
}
}
impl<T, R: Dim, C: Dim, S> Matrix<T, R, C, S>
impl<T, R: Dim, C: Dim>
Matrix<MaybeUninit<T>, R, C, <DefaultAllocator as Allocator<T, R, C>>::UninitBuffer>
where
S: Storage<T, R, C>,
DefaultAllocator: Allocator<T, R, C, Buffer = S>,
DefaultAllocator: Allocator<T, R, C>,
{
/// Allocates a matrix with the given number of rows and columns without initializing its content.
pub fn new_uninitialized_generic(
nrows: R,
ncols: C,
) -> Matrix<MaybeUninit<T>, R, C, <DefaultAllocator as Allocator<T, R, C>>::UninitBuffer> {
Matrix {
///
/// Note: calling `Self::new_uninitialized_generic` is often **not** what you want to do. Consider
/// calling `Matrix::new_uninitialized_generic` instead.
pub fn new_uninitialized_generic(nrows: R, ncols: C) -> Self {
Self {
data: <DefaultAllocator as Allocator<T, R, C>>::allocate_uninitialized(nrows, ncols),
_phantoms: PhantomData,
}
}
}
impl<T, R: Dim, C: Dim, S> Matrix<MaybeUninit<T>, R, C, S>
impl<T, R: Dim, C: Dim>
Matrix<MaybeUninit<T>, R, C, <DefaultAllocator as Allocator<T, R, C>>::UninitBuffer>
where
S: Storage<T, R, C>,
DefaultAllocator: Allocator<T, R, C, Buffer = S>,
DefaultAllocator: Allocator<T, R, C>,
{
/// Assumes a matrix's entries to be initialized. This operation should be near zero-cost.
pub unsafe fn assume_init(
uninit: Matrix<
MaybeUninit<T>,
R,
C,
<DefaultAllocator as Allocator<T, R, C>>::UninitBuffer,
>,
) -> Matrix<T, R, C, S> {
self,
) -> Matrix<T, R, C, <DefaultAllocator as Allocator<T, R, C>>::Buffer> {
Matrix {
data: <DefaultAllocator as Allocator<T, R, C>>::assume_init(uninit.data),
data: <DefaultAllocator as Allocator<T, R, C>>::assume_init(self.data),
_phantoms: PhantomData,
}
}
@ -654,24 +653,25 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
let nrows: SameShapeR<R, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C, C2> = Dim::from_usize(ncols);
let mut res: MatrixSum<T, R, C, R2, C2> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
// TODO: use copy_from
for j in 0..res.ncols() {
for i in 0..res.nrows() {
unsafe {
*res.get_unchecked_mut((i, j)) = self.get_unchecked((i, j)).clone();
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(self.get_unchecked((i, j)).clone());
}
}
}
res
unsafe { Matrix::assume_init(res) }
}
/// Transposes `self` and store the result into `out`.
/// Transposes `self` and store the result into `out`, which will become
/// fully initialized.
#[inline]
pub fn transpose_to<R2: Dim, C2: Dim, SB>(&self, out: &mut Matrix<T, R2, C2, SB>)
pub fn transpose_to<R2: Dim, C2: Dim, SB>(&self, out: &mut Matrix<MaybeUninit<T>, R2, C2, SB>)
where
T: Clone,
SB: StorageMut<T, R2, C2>,
@ -687,7 +687,8 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
for i in 0..nrows {
for j in 0..ncols {
unsafe {
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).clone();
*out.get_unchecked_mut((j, i)) =
MaybeUninit::new(self.get_unchecked((i, j)).clone());
}
}
}
@ -702,17 +703,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, C, R>,
{
let (nrows, ncols) = self.data.shape();
unsafe {
let mut res = crate::unimplemented_or_uninitialized_generic!(ncols, nrows);
let mut res = OMatrix::new_uninitialized_generic(ncols, nrows);
self.transpose_to(&mut res);
res
unsafe {
// Safety: res is now fully initialized due to the guarantees of transpose_to.
res.assume_init()
}
}
}
/// # Elementwise mapping and folding
// Todo: maybe make ref versions of these methods that can be used when T is expensive to clone?
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each of its entries.
#[inline]
@ -724,19 +726,19 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
{
let (nrows, ncols) = self.data.shape();
let mut res: OMatrix<T2, R, C> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = OMatrix::new_uninitialized_generic(nrows, ncols);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = self.data.get_unchecked(i, j).clone();
*res.data.get_unchecked_mut(i, j) = f(a)
*res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a));
}
}
}
res
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
}
/// Cast the components of `self` to another type.
@ -821,8 +823,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
{
let (nrows, ncols) = self.data.shape();
let mut res: OMatrix<N3, R, C> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = OMatrix::<N3, R, C>::new_uninitialized_generic(nrows, ncols);
assert_eq!(
(nrows.value(), ncols.value()),
@ -835,12 +836,13 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
unsafe {
let a = self.data.get_unchecked(i, j).clone();
let b = rhs.data.get_unchecked(i, j).clone();
*res.data.get_unchecked_mut(i, j) = f(a, b)
*res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a, b));
}
}
}
res
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
}
/// Returns a matrix containing the result of `f` applied to each entries of `self` and
@ -862,8 +864,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
{
let (nrows, ncols) = self.data.shape();
let mut res: OMatrix<N4, R, C> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = OMatrix::new_uninitialized_generic(nrows, ncols);
assert_eq!(
(nrows.value(), ncols.value()),
@ -882,12 +883,13 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
let a = self.data.get_unchecked(i, j).clone();
let b = b.data.get_unchecked(i, j).clone();
let c = c.data.get_unchecked(i, j).clone();
*res.data.get_unchecked_mut(i, j) = f(a, b, c)
*res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a, b, c));
}
}
}
res
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
}
/// Folds a function `f` on each entry of `self`.
@ -1322,7 +1324,7 @@ impl<T, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
impl<T: SimdComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`.
#[inline]
pub fn adjoint_to<R2, C2, SB>(&self, out: &mut Matrix<T, R2, C2, SB>)
pub fn adjoint_to<R2, C2, SB>(&self, out: &mut Matrix<MaybeUninit<T>, R2, C2, SB>)
where
R2: Dim,
C2: Dim,
@ -1339,7 +1341,8 @@ impl<T: SimdComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S
for i in 0..nrows {
for j in 0..ncols {
unsafe {
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).simd_conjugate();
*out.get_unchecked_mut((j, i)) =
MaybeUninit::new(self.get_unchecked((i, j)).simd_conjugate());
}
}
}
@ -1355,8 +1358,7 @@ impl<T: SimdComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S
let (nrows, ncols) = self.data.shape();
unsafe {
let mut res: OMatrix<_, C, R> =
crate::unimplemented_or_uninitialized_generic!(ncols, nrows);
let mut res = OMatrix::new_uninitialized_generic(ncols, nrows);
self.adjoint_to(&mut res);
res
@ -1480,7 +1482,7 @@ impl<T, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
pub fn diagonal(&self) -> OVector<T, D>
where
T: Clone,
DefaultAllocator: Allocator<T, D> + Allocator<MaybeUninit<T>, D>,
DefaultAllocator: Allocator<T, D>,
{
self.map_diagonal(|e| e)
}
@ -1493,7 +1495,7 @@ impl<T, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
pub fn map_diagonal<T2: Clone>(&self, mut f: impl FnMut(T) -> T2) -> OVector<T2, D>
where
T: Clone,
DefaultAllocator: Allocator<T2, D> + Allocator<MaybeUninit<T2>, D>,
DefaultAllocator: Allocator<T2, D>,
{
assert!(
self.is_square(),

View File

@ -297,10 +297,10 @@ where
/// Computes the complex eigenvalues of the decomposed matrix.
fn do_complex_eigenvalues(
t: &OMatrix<T, D, D>,
out: &mut OVector<MaybeUninit<NumComplex<T>>, D>,
out: &mut OVector<NumComplex<T>, D>,
) where
T: RealField,
DefaultAllocator: Allocator<MaybeUninit<NumComplex<T>>, D>,
DefaultAllocator: Allocator<NumComplex<T>, D>,
{
let dim = t.nrows();
let mut m = 0;

View File

@ -263,6 +263,8 @@ where
/// `nvals` possible non-zero values.
pub fn new_uninitialized_generic(nrows: R, ncols: C, nvals: usize) -> Self {
let mut i = Vec::with_capacity(nvals);
//BEEP BEEP!!!! UNDEFINED BEHAVIOR ALERT!!! BEEP BEEEP!!!
unsafe {
i.set_len(nvals);
}