Implement the single-allocator-trait approach.

This commit is contained in:
Sébastien Crozet 2021-08-02 18:41:46 +02:00
parent d34fed45bc
commit 8c6ebf2757
110 changed files with 2877 additions and 3795 deletions

View File

@ -4,6 +4,13 @@ documented here.
This project adheres to [Semantic Versioning](https://semver.org/). This project adheres to [Semantic Versioning](https://semver.org/).
## [0.29.0]
### Modified
- The closure given to `apply`, `zip_apply`, `zip_zip_apply` must now modify the
first argument inplace, instead of returning a new value. This makes these
methods more versatile, and avoid useless clones when using non-Copy scalar
types.
## [0.28.0] ## [0.28.0]
### Added ### Added
- Implement `Hash` for `Transform`. - Implement `Hash` for `Transform`.

View File

@ -1,7 +1,4 @@
use na::{ use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3, Vector4, U10};
Const, DMatrix, DVector, Dynamic, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3,
Vector4, U10,
};
use rand::Rng; use rand::Rng;
use rand_isaac::IsaacRng; use rand_isaac::IsaacRng;
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};
@ -189,7 +186,7 @@ fn axpy(bench: &mut criterion::Criterion) {
fn tr_mul_to(bench: &mut criterion::Criterion) { fn tr_mul_to(bench: &mut criterion::Criterion) {
let a = DMatrix::<f64>::new_random(1000, 1000); let a = DMatrix::<f64>::new_random(1000, 1000);
let b = DVector::<f64>::new_random(1000); let b = DVector::<f64>::new_random(1000);
let mut c = DVector::new_uninitialized_generic(Dynamic::new(1000), Const::<1>); let mut c = DVector::from_element(1000, 0.0);
bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c))); bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c)));
} }
@ -197,7 +194,7 @@ fn tr_mul_to(bench: &mut criterion::Criterion) {
fn mat_mul_mat(bench: &mut criterion::Criterion) { fn mat_mul_mat(bench: &mut criterion::Criterion) {
let a = DMatrix::<f64>::new_random(100, 100); let a = DMatrix::<f64>::new_random(100, 100);
let b = DMatrix::<f64>::new_random(100, 100); let b = DMatrix::<f64>::new_random(100, 100);
let mut ab = DMatrix::new_uninitialized_generic(Dynamic::new(100), Dynamic::new(100)); let mut ab = DMatrix::<f64>::from_element(100, 100, 0.0);
bench.bench_function("mat_mul_mat", move |bh| { bench.bench_function("mat_mul_mat", move |bh| {
bh.iter(|| { bh.iter(|| {

View File

@ -6,7 +6,7 @@ use num_complex::Complex;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::Dim; use na::dimension::Dim;
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, Scalar};
use lapack; use lapack;
@ -24,17 +24,17 @@ use lapack;
OMatrix<T, D, D>: Deserialize<'de>")) OMatrix<T, D, D>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Cholesky<T, D: Dim> pub struct Cholesky<T: Scalar, D: Dim>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
l: OMatrix<T, D, D>, l: OMatrix<T, D, D>,
} }
impl<T: Copy, D: Dim> Copy for Cholesky<T, D> impl<T: Scalar + Copy, D: Dim> Copy for Cholesky<T, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
{ {
} }
@ -104,7 +104,7 @@ where
b: &Matrix<T, R2, C2, S2>, b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>> ) -> Option<OMatrix<T, R2, C2>>
where where
S2: Storage<T, R2, C2>, S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2>, DefaultAllocator: Allocator<T, R2, C2>,
{ {
let mut res = b.clone_owned(); let mut res = b.clone_owned();

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -11,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim}; use na::dimension::{Const, Dim};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -34,7 +32,8 @@ use lapack;
OMatrix<T, D, D>: Deserialize<'de>") OMatrix<T, D, D>: Deserialize<'de>")
) )
)] )]
pub struct Eigen<T, D: Dim> #[derive(Clone, Debug)]
pub struct Eigen<T: Scalar, D: Dim>
where where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>, DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
{ {
@ -46,7 +45,7 @@ where
pub left_eigenvectors: Option<OMatrix<T, D, D>>, pub left_eigenvectors: Option<OMatrix<T, D, D>>,
} }
impl<T: Copy, D: Dim> Copy for Eigen<T, D> impl<T: Scalar + Copy, D: Dim> Copy for Eigen<T, D>
where where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>, DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
OVector<T, D>: Copy, OVector<T, D>: Copy,
@ -54,36 +53,6 @@ where
{ {
} }
impl<T: Clone, D: Dim> Clone for Eigen<T, D>
where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
OVector<T, D>: Clone,
OMatrix<T, D, D>: Clone,
{
fn clone(&self) -> Self {
Self {
eigenvalues: self.eigenvalues.clone(),
eigenvectors: self.eigenvectors.clone(),
left_eigenvectors: self.left_eigenvectors.clone(),
}
}
}
impl<T: fmt::Debug, D: Dim> fmt::Debug for Eigen<T, D>
where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
OVector<T, D>: fmt::Debug,
OMatrix<T, D, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Eigen")
.field("eigenvalues", &self.eigenvalues)
.field("eigenvectors", &self.eigenvectors)
.field("left_eigenvectors", &self.left_eigenvectors)
.finish()
}
}
impl<T: EigenScalar + RealField, D: Dim> Eigen<T, D> impl<T: EigenScalar + RealField, D: Dim> Eigen<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
@ -104,13 +73,11 @@ where
let ljob = if left_eigenvectors { b'V' } else { b'T' }; let ljob = if left_eigenvectors { b'V' } else { b'T' };
let rjob = if eigenvectors { b'V' } else { b'T' }; let rjob = if eigenvectors { b'V' } else { b'T' };
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let n = nrows.value(); let n = nrows.value();
let lda = n as i32; let lda = n as i32;
// IMPORTANT TODO: this is still UB.
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() }; let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
// TODO: Tap into the workspace. // TODO: Tap into the workspace.
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() }; let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
@ -275,7 +242,7 @@ where
"Unable to compute the eigenvalue decomposition of a non-square matrix." "Unable to compute the eigenvalue decomposition of a non-square matrix."
); );
let nrows = m.data.shape().0; let nrows = m.shape_generic().0;
let n = nrows.value(); let n = nrows.value();
let lda = n as i32; let lda = n as i32;

View File

@ -4,7 +4,7 @@ use num_complex::Complex;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, DimDiff, DimSub, U1}; use na::dimension::{Const, DimDiff, DimSub, U1};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -48,7 +48,7 @@ where
{ {
/// Computes the hessenberg decomposition of the matrix `m`. /// Computes the hessenberg decomposition of the matrix `m`.
pub fn new(mut m: OMatrix<T, D, D>) -> Self { pub fn new(mut m: OMatrix<T, D, D>) -> Self {
let nrows = m.data.shape().0; let nrows = m.shape_generic().0;
let n = nrows.value() as i32; let n = nrows.value() as i32;
assert!( assert!(
@ -60,7 +60,6 @@ where
"Unable to compute the hessenberg decomposition of an empty matrix." "Unable to compute the hessenberg decomposition of an empty matrix."
); );
// IMPORTANT TODO: this is still UB.
let mut tau = unsafe { let mut tau = unsafe {
Matrix::new_uninitialized_generic(nrows.sub(Const::<1>), Const::<1>).assume_init() Matrix::new_uninitialized_generic(nrows.sub(Const::<1>), Const::<1>).assume_init()
}; };

View File

@ -140,7 +140,6 @@ impl ComplexHelper for Complex<f64> {
} }
} }
// This is UB.
unsafe fn uninitialized_vec<T: Copy>(n: usize) -> Vec<T> { unsafe fn uninitialized_vec<T: Copy>(n: usize) -> Vec<T> {
let mut res = Vec::new(); let mut res = Vec::new();
res.reserve_exact(n); res.reserve_exact(n);

View File

@ -4,7 +4,7 @@ use num_complex::Complex;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum}; use na::dimension::{Const, Dim, DimMin, DimMinimum};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -61,7 +61,7 @@ where
{ {
/// Computes the LU decomposition with partial (row) pivoting of `matrix`. /// Computes the LU decomposition with partial (row) pivoting of `matrix`.
pub fn new(mut m: OMatrix<T, R, C>) -> Self { pub fn new(mut m: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let nrows = nrows.value() as i32; let nrows = nrows.value() as i32;
let ncols = ncols.value() as i32; let ncols = ncols.value() as i32;
@ -87,7 +87,7 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> { pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
res.fill_upper_triangle(Zero::zero(), 1); res.fill_upper_triangle(Zero::zero(), 1);
@ -100,7 +100,7 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> { pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned(); let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned();
res.fill_lower_triangle(Zero::zero(), 1); res.fill_lower_triangle(Zero::zero(), 1);
@ -115,7 +115,7 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn p(&self) -> OMatrix<T, R, R> { pub fn p(&self) -> OMatrix<T, R, R> {
let (dim, _) = self.lu.data.shape(); let (dim, _) = self.lu.shape_generic();
let mut id = Matrix::identity_generic(dim, dim); let mut id = Matrix::identity_generic(dim, dim);
self.permute(&mut id); self.permute(&mut id);
@ -191,7 +191,7 @@ where
b: &Matrix<T, R2, C2, S2>, b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>> ) -> Option<OMatrix<T, R2, C2>>
where where
S2: Storage<T, R2, C2>, S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>, DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{ {
let mut res = b.clone_owned(); let mut res = b.clone_owned();
@ -209,7 +209,7 @@ where
b: &Matrix<T, R2, C2, S2>, b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>> ) -> Option<OMatrix<T, R2, C2>>
where where
S2: Storage<T, R2, C2>, S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>, DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{ {
let mut res = b.clone_owned(); let mut res = b.clone_owned();
@ -227,7 +227,7 @@ where
b: &Matrix<T, R2, C2, S2>, b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>> ) -> Option<OMatrix<T, R2, C2>>
where where
S2: Storage<T, R2, C2>, S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>, DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{ {
let mut res = b.clone_owned(); let mut res = b.clone_owned();

View File

@ -7,7 +7,7 @@ use num_complex::Complex;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum}; use na::dimension::{Const, Dim, DimMin, DimMinimum};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -54,11 +54,12 @@ where
{ {
/// Computes the QR decomposition of the matrix `m`. /// Computes the QR decomposition of the matrix `m`.
pub fn new(mut m: OMatrix<T, R, C>) -> Self { pub fn new(mut m: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let mut info = 0; let mut info = 0;
let mut tau = let mut tau = unsafe {
unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), U1).assume_init() }; Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init()
};
if nrows.value() == 0 || ncols.value() == 0 { if nrows.value() == 0 || ncols.value() == 0 {
return Self { qr: m, tau }; return Self { qr: m, tau };
@ -93,7 +94,7 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> { pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle() self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle()
} }
} }
@ -119,7 +120,7 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> { pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
if min_nrows_ncols.value() == 0 { if min_nrows_ncols.value() == 0 {

View File

@ -9,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim}; use na::dimension::{Const, Dim};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -71,7 +71,7 @@ where
"Unable to compute the eigenvalue decomposition of a non-square matrix." "Unable to compute the eigenvalue decomposition of a non-square matrix."
); );
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let n = nrows.value(); let n = nrows.value();
let lda = n as i32; let lda = n as i32;
@ -153,15 +153,15 @@ where
where where
DefaultAllocator: Allocator<Complex<T>, D>, DefaultAllocator: Allocator<Complex<T>, D>,
{ {
let mut out = let mut out = unsafe {
unsafe { OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>) }; OVector::new_uninitialized_generic(self.t.shape_generic().0, Const::<1>).assume_init()
};
for i in 0..out.len() { for i in 0..out.len() {
out[i] = MaybeUninit::new(Complex::new(self.re[i], self.im[i])); out[i] = Complex::new(self.re[i], self.im[i])
} }
// Safety: all entries have been initialized. out
unsafe { out.assume_init() }
} }
} }

View File

@ -6,7 +6,7 @@ use std::cmp;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum, U1}; use na::dimension::{Const, Dim, DimMin, DimMinimum, U1};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -89,7 +89,7 @@ macro_rules! svd_impl(
Allocator<$t, DimMinimum<R, C>> { Allocator<$t, DimMinimum<R, C>> {
fn compute(mut m: OMatrix<$t, R, C>) -> Option<SVD<$t, R, C>> { fn compute(mut m: OMatrix<$t, R, C>) -> Option<SVD<$t, R, C>> {
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
if nrows.value() == 0 || ncols.value() == 0 { if nrows.value() == 0 || ncols.value() == 0 {
return None; return None;
@ -99,7 +99,6 @@ macro_rules! svd_impl(
let lda = nrows.value() as i32; let lda = nrows.value() as i32;
// IMPORTANT TODO: this is still UB.
let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows).assume_init() }; let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows).assume_init() };
let mut s = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init() }; let mut s = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init() };
let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols).assume_init() }; let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols).assume_init() };
@ -152,8 +151,8 @@ macro_rules! svd_impl(
/// been manually changed by the user. /// been manually changed by the user.
#[inline] #[inline]
pub fn recompose(self) -> OMatrix<$t, R, C> { pub fn recompose(self) -> OMatrix<$t, R, C> {
let nrows = self.u.data.shape().0; let nrows = self.u.shape_generic().0;
let ncols = self.vt.data.shape().1; let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols); let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols);
@ -178,8 +177,8 @@ macro_rules! svd_impl(
#[inline] #[inline]
#[must_use] #[must_use]
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> { pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
let nrows = self.u.data.shape().0; let nrows = self.u.shape_generic().0;
let ncols = self.vt.data.shape().1; let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows); let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows);
@ -242,7 +241,7 @@ macro_rules! svd_complex_impl(
Allocator<Complex<$t>, R, R> + Allocator<Complex<$t>, R, R> +
Allocator<Complex<$t>, C, C> + Allocator<Complex<$t>, C, C> +
Allocator<$t, DimMinimum<R, C>> { Allocator<$t, DimMinimum<R, C>> {
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
if nrows.value() == 0 || ncols.value() == 0 { if nrows.value() == 0 || ncols.value() == 0 {
return None; return None;

View File

@ -9,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper; use crate::ComplexHelper;
use na::allocator::Allocator; use na::allocator::Allocator;
use na::dimension::{Const, Dim}; use na::dimension::{Const, Dim};
use na::storage::Storage; use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack; use lapack;
@ -89,12 +89,11 @@ where
let jobz = if eigenvectors { b'V' } else { b'T' }; let jobz = if eigenvectors { b'V' } else { b'T' };
let nrows = m.data.shape().0; let nrows = m.shape_generic().0;
let n = nrows.value(); let n = nrows.value();
let lda = n as i32; let lda = n as i32;
// IMPORTANT TODO: this is still UB.
let mut values = let mut values =
unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() }; unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut info = 0; let mut info = 0;

View File

@ -2,14 +2,16 @@ use crate::convert::serial::*;
use crate::coo::CooMatrix; use crate::coo::CooMatrix;
use crate::csc::CscMatrix; use crate::csc::CscMatrix;
use crate::csr::CsrMatrix; use crate::csr::CsrMatrix;
use nalgebra::storage::Storage; use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar}; use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
use num_traits::Zero; use num_traits::Zero;
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CooMatrix<T> impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CooMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
S: Storage<T, R, C>, R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self { fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_coo(matrix) convert_dense_coo(matrix)
@ -43,10 +45,12 @@ where
} }
} }
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CsrMatrix<T> impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CsrMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
S: Storage<T, R, C>, R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self { fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_csr(matrix) convert_dense_csr(matrix)
@ -80,10 +84,12 @@ where
} }
} }
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CscMatrix<T> impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CscMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
S: Storage<T, R, C>, R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self { fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_csc(matrix) convert_dense_csc(matrix)

View File

@ -7,7 +7,7 @@ use std::ops::Add;
use num_traits::Zero; use num_traits::Zero;
use nalgebra::storage::Storage; use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar}; use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
use crate::coo::CooMatrix; use crate::coo::CooMatrix;
@ -16,10 +16,12 @@ use crate::csc::CscMatrix;
use crate::csr::CsrMatrix; use crate::csr::CsrMatrix;
/// Converts a dense matrix to [`CooMatrix`]. /// Converts a dense matrix to [`CooMatrix`].
pub fn convert_dense_coo<T, R: Dim, C: Dim, S>(dense: &Matrix<T, R, C, S>) -> CooMatrix<T> pub fn convert_dense_coo<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CooMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
S: Storage<T, R, C>, R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols()); let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
@ -91,10 +93,10 @@ where
/// Converts a dense matrix to a [`CsrMatrix`]. /// Converts a dense matrix to a [`CsrMatrix`].
pub fn convert_dense_csr<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CsrMatrix<T> pub fn convert_dense_csr<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CsrMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
R: Dim, R: Dim,
C: Dim, C: Dim,
S: Storage<T, R, C>, S: RawStorage<T, R, C>,
{ {
let mut row_offsets = Vec::with_capacity(dense.nrows() + 1); let mut row_offsets = Vec::with_capacity(dense.nrows() + 1);
let mut col_idx = Vec::new(); let mut col_idx = Vec::new();
@ -168,10 +170,10 @@ where
/// Converts a dense matrix to a [`CscMatrix`]. /// Converts a dense matrix to a [`CscMatrix`].
pub fn convert_dense_csc<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CscMatrix<T> pub fn convert_dense_csc<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CscMatrix<T>
where where
T: Scalar + Zero + PartialEq, T: Scalar + Zero,
R: Dim, R: Dim,
C: Dim, C: Dim,
S: Storage<T, R, C>, S: RawStorage<T, R, C>,
{ {
let mut col_offsets = Vec::with_capacity(dense.ncols() + 1); let mut col_offsets = Vec::with_capacity(dense.ncols() + 1);
let mut row_idx = Vec::new(); let mut row_idx = Vec::new();

View File

@ -57,7 +57,7 @@ impl<T: na::Scalar> CooMatrix<T> {
/// Panics if any part of the dense matrix is out of bounds of the sparse matrix /// Panics if any part of the dense matrix is out of bounds of the sparse matrix
/// when inserted at `(r, c)`. /// when inserted at `(r, c)`.
#[inline] #[inline]
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::Storage<T, R, C>>( pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::RawStorage<T, R, C>>(
&mut self, &mut self,
r: usize, r: usize,
c: usize, c: usize,

View File

@ -6,8 +6,8 @@ use crate::ops::serial::{
spmm_csc_prealloc, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc, spmm_csc_prealloc, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc,
}; };
use crate::ops::Op; use crate::ops::Op;
use nalgebra::allocator::{Allocator, InnerAllocator}; use nalgebra::allocator::Allocator;
use nalgebra::base::storage::Storage; use nalgebra::base::storage::RawStorage;
use nalgebra::constraint::{DimEq, ShapeConstraint}; use nalgebra::constraint::{DimEq, ShapeConstraint};
use nalgebra::{ use nalgebra::{
ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix, ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix,
@ -28,7 +28,7 @@ macro_rules! impl_bin_op {
// Note: The Neg bound is currently required because we delegate e.g. // Note: The Neg bound is currently required because we delegate e.g.
// Sub to SpAdd with negative coefficients. This is not well-defined for // Sub to SpAdd with negative coefficients. This is not well-defined for
// unsigned data types. // unsigned data types.
$($scalar_type: $($bounds + )? Scalar + ClosedAdd + ClosedSub + ClosedMul + Zero + One + Neg<Output=T> + PartialEq)? $($scalar_type: $($bounds + )? Scalar + ClosedAdd + ClosedSub + ClosedMul + Zero + One + Neg<Output=T>)?
{ {
type Output = $ret; type Output = $ret;
fn $method(self, $b: $b_type) -> Self::Output { fn $method(self, $b: $b_type) -> Self::Output {
@ -272,7 +272,7 @@ macro_rules! impl_spmm_cs_dense {
($matrix_type_name:ident, $spmm_fn:ident) => { ($matrix_type_name:ident, $spmm_fn:ident) => {
// Implement ref-ref // Implement ref-ref
impl_spmm_cs_dense!(&'a $matrix_type_name<T>, &'a Matrix<T, R, C, S>, $spmm_fn, |lhs, rhs| { impl_spmm_cs_dense!(&'a $matrix_type_name<T>, &'a Matrix<T, R, C, S>, $spmm_fn, |lhs, rhs| {
let (_, ncols) = rhs.data.shape(); let (_, ncols) = rhs.shape_generic();
let nrows = Dynamic::new(lhs.nrows()); let nrows = Dynamic::new(lhs.nrows());
let mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols); let mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols);
$spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs)); $spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs));
@ -301,14 +301,14 @@ macro_rules! impl_spmm_cs_dense {
T: Scalar + ClosedMul + ClosedAdd + ClosedSub + ClosedDiv + Neg + Zero + One, T: Scalar + ClosedMul + ClosedAdd + ClosedSub + ClosedDiv + Neg + Zero + One,
R: Dim, R: Dim,
C: Dim, C: Dim,
S: Storage<T, R, C>, S: RawStorage<T, R, C>,
DefaultAllocator: Allocator<T, Dynamic, C>, DefaultAllocator: Allocator<T, Dynamic, C>,
// TODO: Is it possible to simplify these bounds? // TODO: Is it possible to simplify these bounds?
ShapeConstraint: ShapeConstraint:
// Bounds so that we can turn OMatrix<T, Dynamic, C> into a DMatrixSliceMut // Bounds so that we can turn OMatrix<T, Dynamic, C> into a DMatrixSliceMut
DimEq<U1, <<DefaultAllocator as InnerAllocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::RStride> DimEq<U1, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::RStride>
+ DimEq<C, Dynamic> + DimEq<C, Dynamic>
+ DimEq<Dynamic, <<DefaultAllocator as InnerAllocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::CStride> + DimEq<Dynamic, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::CStride>
// Bounds so that we can turn &Matrix<T, R, C, S> into a DMatrixSlice // Bounds so that we can turn &Matrix<T, R, C, S> into a DMatrixSlice
+ DimEq<U1, S::RStride> + DimEq<U1, S::RStride>
+ DimEq<R, Dynamic> + DimEq<R, Dynamic>

View File

@ -74,7 +74,7 @@ pub fn spadd_cs_prealloc<T>(
a: Op<&CsMatrix<T>>, a: Op<&CsMatrix<T>>,
) -> Result<(), OperationError> ) -> Result<(), OperationError>
where where
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq, T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{ {
match a { match a {
Op::NoOp(a) => { Op::NoOp(a) => {

View File

@ -55,7 +55,7 @@ pub fn spadd_csc_prealloc<T>(
a: Op<&CscMatrix<T>>, a: Op<&CscMatrix<T>>,
) -> Result<(), OperationError> ) -> Result<(), OperationError>
where where
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq, T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{ {
assert_compatible_spadd_dims!(c, a); assert_compatible_spadd_dims!(c, a);
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs)) spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))

View File

@ -50,7 +50,7 @@ pub fn spadd_csr_prealloc<T>(
a: Op<&CsrMatrix<T>>, a: Op<&CsrMatrix<T>>,
) -> Result<(), OperationError> ) -> Result<(), OperationError>
where where
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq, T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{ {
assert_compatible_spadd_dims!(c, a); assert_compatible_spadd_dims!(c, a);
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs)) spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))

View File

@ -311,7 +311,7 @@ impl From<SparsityPatternFormatError> for SparseFormatError {
} }
impl fmt::Display for SparsityPatternFormatError { impl fmt::Display for SparsityPatternFormatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
SparsityPatternFormatError::InvalidOffsetArrayLength => { SparsityPatternFormatError::InvalidOffsetArrayLength => {
write!(f, "Length of offset array is not equal to (major_dim + 1).") write!(f, "Length of offset array is not equal to (major_dim + 1).")

View File

@ -1,9 +1,12 @@
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic; use crate::base::dimension::Dynamic;
use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
use crate::base::storage::Owned;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage; use crate::base::vec_storage::VecStorage;
use crate::base::{ArrayStorage, Const, Matrix, Owned, Unit}; use crate::base::{ArrayStorage, Const, Matrix, Unit};
use crate::storage::OwnedUninit;
use std::mem::MaybeUninit;
/* /*
* *
@ -18,13 +21,16 @@ use crate::base::{ArrayStorage, Const, Matrix, Owned, Unit};
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
pub type OMatrix<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>; pub type OMatrix<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
/// An owned matrix with uninitialized data.
pub type UninitMatrix<T, R, C> = Matrix<MaybeUninit<T>, R, C, OwnedUninit<T, R, C>>;
/// An owned matrix column-major matrix with `R` rows and `C` columns. /// An owned matrix column-major matrix with `R` rows and `C` columns.
/// ///
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
#[deprecated( #[deprecated(
note = "use SMatrix for a statically-sized matrix using integer dimensions, or OMatrix for an owned matrix using types as dimensions." note = "use SMatrix for a statically-sized matrix using integer dimensions, or OMatrix for an owned matrix using types as dimensions."
)] )]
pub type MatrixMN<T, R, C> = OMatrix<T, R, C>; pub type MatrixMN<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
/// An owned matrix column-major matrix with `D` columns. /// An owned matrix column-major matrix with `D` columns.
/// ///
@ -277,6 +283,9 @@ pub type OVector<T, D> = Matrix<T, D, U1, Owned<T, D, U1>>;
/// A statically sized D-dimensional column vector. /// A statically sized D-dimensional column vector.
pub type SVector<T, const D: usize> = Matrix<T, Const<D>, U1, ArrayStorage<T, D, 1>>; // Owned<T, Const<D>, U1>>; pub type SVector<T, const D: usize> = Matrix<T, Const<D>, U1, ArrayStorage<T, D, 1>>; // Owned<T, Const<D>, U1>>;
/// An owned matrix with uninitialized data.
pub type UninitVector<T, D> = Matrix<MaybeUninit<T>, D, U1, OwnedUninit<T, D, U1>>;
/// An owned matrix column-major matrix with `R` rows and `C` columns. /// An owned matrix column-major matrix with `R` rows and `C` columns.
/// ///
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**

View File

@ -1,11 +1,14 @@
//! Abstract definition of a matrix data storage allocator. //! Abstract definition of a matrix data storage allocator.
use std::mem::{ManuallyDrop, MaybeUninit}; use std::any::Any;
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::{Dim, U1}; use crate::base::dimension::{Dim, U1};
use crate::base::storage::ContiguousStorageMut; use crate::base::{DefaultAllocator, Scalar};
use crate::base::DefaultAllocator; use crate::storage::{IsContiguous, RawStorageMut};
use crate::StorageMut;
use std::fmt::Debug;
use std::mem::MaybeUninit;
/// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()` /// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()`
/// elements of type `T`. /// elements of type `T`.
@ -16,12 +19,23 @@ use crate::base::DefaultAllocator;
/// ///
/// Every allocator must be both static and dynamic. Though not all implementations may share the /// Every allocator must be both static and dynamic. Though not all implementations may share the
/// same `Buffer` type. /// same `Buffer` type.
/// pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
/// If you also want to be able to create uninitizalized or manually dropped memory buffers, see
/// [`Allocator`].
pub trait InnerAllocator<T, R: Dim, C: Dim = U1>: 'static + Sized {
/// The type of buffer this allocator can instanciate. /// The type of buffer this allocator can instanciate.
type Buffer: ContiguousStorageMut<T, R, C>; type Buffer: StorageMut<T, R, C> + IsContiguous + Clone + Debug;
/// The type of buffer with uninitialized components this allocator can instanciate.
type BufferUninit: RawStorageMut<MaybeUninit<T>, R, C> + IsContiguous;
/// Allocates a buffer with the given number of rows and columns without initializing its content.
unsafe fn allocate_uninitialized(nrows: R, ncols: C) -> MaybeUninit<Self::Buffer>;
/// Allocates a buffer with the given number of rows and columns without initializing its content.
fn allocate_uninit(nrows: R, ncols: C) -> Self::BufferUninit;
/// Assumes a data buffer to be initialized.
///
/// # Safety
/// The user must make sure that every single entry of the buffer has been initialized,
/// or Undefined Behavior will immediately occur.
unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer;
/// Allocates a buffer initialized with the content of the given iterator. /// Allocates a buffer initialized with the content of the given iterator.
fn allocate_from_iterator<I: IntoIterator<Item = T>>( fn allocate_from_iterator<I: IntoIterator<Item = T>>(
@ -31,45 +45,15 @@ pub trait InnerAllocator<T, R: Dim, C: Dim = U1>: 'static + Sized {
) -> Self::Buffer; ) -> Self::Buffer;
} }
/// Same as the [`InnerAllocator`] trait, but also provides methods to build uninitialized buffers, /// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` ×
/// or buffers whose entries must be manually dropped. /// `CFrom`) elements to a smaller or larger size (`RTo`, `CTo`).
pub trait Allocator<T, R: Dim, C: Dim = U1>: pub trait Reallocator<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
InnerAllocator<T, R, C>
+ InnerAllocator<MaybeUninit<T>, R, C>
+ InnerAllocator<ManuallyDrop<T>, R, C>
{
/// Allocates a buffer with the given number of rows and columns without initializing its content.
fn allocate_uninitialized(
nrows: R,
ncols: C,
) -> <Self as InnerAllocator<MaybeUninit<T>, R, C>>::Buffer;
/// Assumes a data buffer to be initialized. This operation should be near zero-cost.
///
/// # Safety
/// The user must make sure that every single entry of the buffer has been initialized,
/// or Undefined Behavior will immediately occur.
unsafe fn assume_init(
uninit: <Self as InnerAllocator<MaybeUninit<T>, R, C>>::Buffer,
) -> <Self as InnerAllocator<T, R, C>>::Buffer;
/// Specifies that a given buffer's entries should be manually dropped.
fn manually_drop(
buf: <Self as InnerAllocator<T, R, C>>::Buffer,
) -> <Self as InnerAllocator<ManuallyDrop<T>, R, C>>::Buffer;
}
/// A matrix reallocator. Changes the size of the memory buffer that initially contains (RFrom ×
/// CFrom) elements to a smaller or larger size (RTo, CTo).
pub trait Reallocator<T, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo> Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo>
{ {
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
/// `buf`. Data stored by `buf` are linearly copied to the output: /// `buf`. Data stored by `buf` are linearly copied to the output:
/// ///
/// # Safety /// # Safety
/// **NO! THIS IS STILL UB!**
/// * The copy is performed as if both were just arrays (without a matrix structure). /// * The copy is performed as if both were just arrays (without a matrix structure).
/// * If `buf` is larger than the output size, then extra elements of `buf` are truncated. /// * If `buf` is larger than the output size, then extra elements of `buf` are truncated.
/// * If `buf` is smaller than the output size, then extra elements of the output are left /// * If `buf` is smaller than the output size, then extra elements of the output are left
@ -77,8 +61,8 @@ pub trait Reallocator<T, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
nrows: RTo, nrows: RTo,
ncols: CTo, ncols: CTo,
buf: <Self as InnerAllocator<T, RFrom, CFrom>>::Buffer, buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> <Self as InnerAllocator<T, RTo, CTo>>::Buffer; ) -> <Self as Allocator<T, RTo, CTo>>::Buffer;
} }
/// The number of rows of the result of a componentwise operation on two matrices. /// The number of rows of the result of a componentwise operation on two matrices.
@ -89,16 +73,23 @@ pub type SameShapeC<C1, C2> = <ShapeConstraint as SameNumberOfColumns<C1, C2>>::
// TODO: Bad name. // TODO: Bad name.
/// Restricts the given number of rows and columns to be respectively the same. /// Restricts the given number of rows and columns to be respectively the same.
pub trait SameShapeAllocator<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim>: pub trait SameShapeAllocator<T, R1, C1, R2, C2>:
Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>> Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>
where where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{ {
} }
impl<T, R1: Dim, R2: Dim, C1: Dim, C2: Dim> SameShapeAllocator<T, R1, C1, R2, C2> impl<T, R1, R2, C1, C2> SameShapeAllocator<T, R1, C1, R2, C2> for DefaultAllocator
for DefaultAllocator
where where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>, DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{ {
@ -106,15 +97,19 @@ where
// XXX: Bad name. // XXX: Bad name.
/// Restricts the given number of rows to be equal. /// Restricts the given number of rows to be equal.
pub trait SameShapeVectorAllocator<T, R1: Dim, R2: Dim>: pub trait SameShapeVectorAllocator<T, R1, R2>:
Allocator<T, R1> + Allocator<T, SameShapeR<R1, R2>> + SameShapeAllocator<T, R1, U1, R2, U1> Allocator<T, R1> + Allocator<T, SameShapeR<R1, R2>> + SameShapeAllocator<T, R1, U1, R2, U1>
where where
R1: Dim,
R2: Dim,
ShapeConstraint: SameNumberOfRows<R1, R2>, ShapeConstraint: SameNumberOfRows<R1, R2>,
{ {
} }
impl<T, R1: Dim, R2: Dim> SameShapeVectorAllocator<T, R1, R2> for DefaultAllocator impl<T, R1, R2> SameShapeVectorAllocator<T, R1, R2> for DefaultAllocator
where where
R1: Dim,
R2: Dim,
DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>, DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>,
ShapeConstraint: SameNumberOfRows<R1, R2>, ShapeConstraint: SameNumberOfRows<R1, R2>,
{ {

View File

@ -1,5 +1,4 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem;
// use std::hash::{Hash, Hasher}; // use std::hash::{Hash, Hasher};
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
@ -13,28 +12,43 @@ use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use std::marker::PhantomData; use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")]
use std::mem;
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
use crate::allocator::InnerAllocator; use crate::base::allocator::Allocator;
use crate::base::default_allocator::DefaultAllocator; use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Const, ToTypenum}; use crate::base::dimension::{Const, ToTypenum};
use crate::base::storage::{ use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
ContiguousStorage, ContiguousStorageMut, ReshapableStorage, Storage, StorageMut, use crate::base::Scalar;
}; use crate::Storage;
use crate::base::Owned;
/* /*
* *
* Static Storage. * Static RawStorage.
* *
*/ */
/// A array-based statically sized matrix data storage. /// A array-based statically sized matrix data storage.
#[repr(transparent)] #[repr(C)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]); pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]);
impl<T, const R: usize, const C: usize> ArrayStorage<T, R, C> {
#[inline]
pub fn as_slice(&self) -> &[T] {
// SAFETY: this is OK because ArrayStorage is contiguous.
unsafe { self.as_slice_unchecked() }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: this is OK because ArrayStorage is contiguous.
unsafe { self.as_mut_slice_unchecked() }
}
}
// TODO: remove this once the stdlib implements Default for arrays. // TODO: remove this once the stdlib implements Default for arrays.
impl<T: Default, const R: usize, const C: usize> Default for ArrayStorage<T, R, C> impl<T: Default, const R: usize, const C: usize> Default for ArrayStorage<T, R, C>
where where
@ -53,10 +67,8 @@ impl<T: Debug, const R: usize, const C: usize> Debug for ArrayStorage<T, R, C> {
} }
} }
unsafe impl<T, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>> unsafe impl<T, const R: usize, const C: usize> RawStorage<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C> for ArrayStorage<T, R, C>
where
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
{ {
type RStride = Const<1>; type RStride = Const<1>;
type CStride = Const<R>; type CStride = Const<R>;
@ -81,38 +93,36 @@ where
true true
} }
#[inline]
fn into_owned(self) -> Owned<T, Const<R>, Const<C>>
where
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>>,
{
Owned(self)
}
#[inline]
fn clone_owned(&self) -> Owned<T, Const<R>, Const<C>>
where
T: Clone,
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>>,
{
let it = self.as_slice().iter().cloned();
Owned(DefaultAllocator::allocate_from_iterator(
self.shape().0,
self.shape().1,
it,
))
}
#[inline] #[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
std::slice::from_raw_parts(self.ptr(), R * C) std::slice::from_raw_parts(self.ptr(), R * C)
} }
} }
unsafe impl<T, const R: usize, const C: usize> StorageMut<T, Const<R>, Const<C>> unsafe impl<T: Scalar, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C> for ArrayStorage<T, R, C>
where where
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>, DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
#[inline]
fn into_owned(self) -> Owned<T, Const<R>, Const<C>>
where
DefaultAllocator: Allocator<T, Const<R>, Const<C>>,
{
self
}
#[inline]
fn clone_owned(&self) -> Owned<T, Const<R>, Const<C>>
where
DefaultAllocator: Allocator<T, Const<R>, Const<C>>,
{
self.clone()
}
}
unsafe impl<T, const R: usize, const C: usize> RawStorageMut<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
{ {
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut T { fn ptr_mut(&mut self) -> *mut T {
@ -125,23 +135,12 @@ where
} }
} }
unsafe impl<T, const R: usize, const C: usize> ContiguousStorage<T, Const<R>, Const<C>> unsafe impl<T, const R: usize, const C: usize> IsContiguous for ArrayStorage<T, R, C> {}
for ArrayStorage<T, R, C>
where
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
{
}
unsafe impl<T, const R: usize, const C: usize> ContiguousStorageMut<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
{
}
impl<T, const R1: usize, const C1: usize, const R2: usize, const C2: usize> impl<T, const R1: usize, const C1: usize, const R2: usize, const C2: usize>
ReshapableStorage<T, Const<R1>, Const<C1>, Const<R2>, Const<C2>> for ArrayStorage<T, R1, C1> ReshapableStorage<T, Const<R1>, Const<C1>, Const<R2>, Const<C2>> for ArrayStorage<T, R1, C1>
where where
T: Scalar,
Const<R1>: ToTypenum, Const<R1>: ToTypenum,
Const<C1>: ToTypenum, Const<C1>: ToTypenum,
Const<R2>: ToTypenum, Const<R2>: ToTypenum,
@ -159,8 +158,8 @@ where
fn reshape_generic(self, _: Const<R2>, _: Const<C2>) -> Self::Output { fn reshape_generic(self, _: Const<R2>, _: Const<C2>) -> Self::Output {
unsafe { unsafe {
let data: [[T; R2]; C2] = mem::transmute_copy(&self.0); let data: [[T; R2]; C2] = std::mem::transmute_copy(&self.0);
mem::forget(self.0); std::mem::forget(self.0);
ArrayStorage(data) ArrayStorage(data)
} }
} }
@ -175,7 +174,7 @@ where
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T, const R: usize, const C: usize> Serialize for ArrayStorage<T, R, C> impl<T, const R: usize, const C: usize> Serialize for ArrayStorage<T, R, C>
where where
T: Serialize, T: Scalar + Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -194,7 +193,7 @@ where
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T, const R: usize, const C: usize> Deserialize<'a> for ArrayStorage<T, R, C> impl<'a, T, const R: usize, const C: usize> Deserialize<'a> for ArrayStorage<T, R, C>
where where
T: Deserialize<'a>, T: Scalar + Deserialize<'a>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@ -211,7 +210,10 @@ struct ArrayStorageVisitor<T, const R: usize, const C: usize> {
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C> { impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C>
where
T: Scalar,
{
/// Construct a new sequence visitor. /// Construct a new sequence visitor.
pub fn new() -> Self { pub fn new() -> Self {
ArrayStorageVisitor { ArrayStorageVisitor {
@ -223,7 +225,7 @@ impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C> {
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T, const R: usize, const C: usize> Visitor<'a> for ArrayStorageVisitor<T, R, C> impl<'a, T, const R: usize, const C: usize> Visitor<'a> for ArrayStorageVisitor<T, R, C>
where where
T: Deserialize<'a>, T: Scalar + Deserialize<'a>,
{ {
type Value = ArrayStorage<T, R, C>; type Value = ArrayStorage<T, R, C>;
@ -255,13 +257,13 @@ where
} }
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T: Copy + bytemuck::Zeroable, const R: usize, const C: usize> bytemuck::Zeroable unsafe impl<T: Scalar + Copy + bytemuck::Zeroable, const R: usize, const C: usize>
for ArrayStorage<T, R, C> bytemuck::Zeroable for ArrayStorage<T, R, C>
{ {
} }
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T: Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::Pod unsafe impl<T: Scalar + Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::Pod
for ArrayStorage<T, R, C> for ArrayStorage<T, R, C>
{ {
} }
@ -269,7 +271,7 @@ unsafe impl<T: Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::P
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, const R: usize, const C: usize> Abomonation for ArrayStorage<T, R, C> impl<T, const R: usize, const C: usize> Abomonation for ArrayStorage<T, R, C>
where where
T: Abomonation, T: Scalar + Abomonation,
{ {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> { unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
for element in self.as_slice() { for element in self.as_slice() {

View File

@ -1,21 +1,9 @@
//! Implements a subset of the Basic Linear Algebra Subprograms (BLAS), a use crate::{RawStorage, SimdComplexField};
//! standard and highly optimized set of basic vector and matrix operations.
//!
//! To avoid unsoundness due to mishandling of uninitialized data, we divide our
//! methods into two groups: those that take in a `&mut` to a matrix, and those
//! that return an owned matrix that would otherwise result from setting a
//! parameter to zero in the other methods.
use crate::{MatrixSliceMut, SimdComplexField, VectorSliceMut};
#[cfg(feature = "std")]
use matrixmultiply;
use num::{One, Zero}; use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul}; use simba::scalar::{ClosedAdd, ClosedMul};
#[cfg(feature = "std")]
use std::mem;
use std::mem::MaybeUninit;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit};
use crate::base::constraint::{ use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
}; };
@ -24,9 +12,10 @@ use crate::base::storage::{Storage, StorageMut};
use crate::base::{ use crate::base::{
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice, DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice,
}; };
use crate::core::uninit::Init;
/// # Dot/scalar product /// # Dot/scalar product
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S>
where where
T: Scalar + Zero + ClosedAdd + ClosedMul, T: Scalar + Zero + ClosedAdd + ClosedMul,
{ {
@ -37,7 +26,7 @@ where
conjugate: impl Fn(T) -> T, conjugate: impl Fn(T) -> T,
) -> T ) -> T
where where
SB: Storage<T, R2, C2>, SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{ {
assert!( assert!(
@ -205,7 +194,7 @@ where
#[must_use] #[must_use]
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
SB: Storage<T, R2, C2>, SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{ {
self.dotx(rhs, |e| e) self.dotx(rhs, |e| e)
@ -235,7 +224,7 @@ where
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
T: SimdComplexField, T: SimdComplexField,
SB: Storage<T, R2, C2>, SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>, ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{ {
self.dotx(rhs, T::simd_conjugate) self.dotx(rhs, T::simd_conjugate)
@ -262,7 +251,7 @@ where
#[must_use] #[must_use]
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
SB: Storage<T, R2, C2>, SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>, ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,
{ {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
@ -293,10 +282,7 @@ where
T: Scalar + Zero + ClosedAdd + ClosedMul, T: Scalar + Zero + ClosedAdd + ClosedMul,
S: StorageMut<T, D>, S: StorageMut<T, D>,
{ {
/// Computes `self = a * x * c + b * self`, where `a`, `b`, `c` are scalars, /// Computes `self = a * x * c + b * self`.
/// and `x` is a vector of the same size as `self`.
///
/// For commutative scalars, this is equivalent to an [`axpy`] call.
/// ///
/// If `b` is zero, `self` is never read from. /// If `b` is zero, `self` is never read from.
/// ///
@ -316,34 +302,7 @@ where
SB: Storage<T, D2>, SB: Storage<T, D2>,
ShapeConstraint: DimEq<D, D2>, ShapeConstraint: DimEq<D, D2>,
{ {
assert_eq!(self.nrows(), x.nrows(), "Axcpy: mismatched vector shapes."); unsafe { axcpy_uninit(Init, self, a, x, c, b) };
let rstride1 = self.strides().0;
let rstride2 = x.strides().0;
unsafe {
// SAFETY: the conversion to slices is OK because we access the
// elements taking the strides into account.
let y = self.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
if !b.is_zero() {
for i in 0..x.len() {
let y = y.get_unchecked_mut(i * rstride1);
*y = a.inlined_clone()
* x.get_unchecked(i * rstride2).inlined_clone()
* c.inlined_clone()
+ b.inlined_clone() * y.inlined_clone();
}
} else {
for i in 0..x.len() {
let y = y.get_unchecked_mut(i * rstride1);
*y = a.inlined_clone()
* x.get_unchecked(i * rstride2).inlined_clone()
* c.inlined_clone();
}
}
}
} }
/// Computes `self = a * x + b * self`. /// Computes `self = a * x + b * self`.
@ -399,38 +358,8 @@ where
SC: Storage<T, D3>, SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>, ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
{ {
let dim1 = self.nrows(); // Safety: this is safe because we are passing Status == Init.
let (nrows2, ncols2) = a.shape(); unsafe { gemv_uninit(Init, self, alpha, a, x, beta) }
let dim3 = x.nrows();
assert!(
ncols2 == dim3 && dim1 == nrows2,
"Gemv: dimensions mismatch."
);
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
self.fill(T::zero());
} else {
*self *= beta;
}
return;
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
self.axcpy(alpha.inlined_clone(), &col2, val, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = unsafe { x.vget_unchecked(j).inlined_clone() };
self.axcpy(alpha.inlined_clone(), &col2, val, T::one());
}
} }
#[inline(always)] #[inline(always)]
@ -490,25 +419,6 @@ where
} }
} }
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
/// vector, and `alpha, beta` two scalars. DEPRECATED: use `sygemv` instead.
#[inline]
#[deprecated(note = "This is renamed `sygemv` to match the original BLAS terminology.")]
pub fn gemv_symm<D2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &SquareMatrix<T, D2, SB>,
x: &Vector<T, D3, SC>,
beta: T,
) where
T: One,
SB: Storage<T, D2, D2>,
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
{
self.sygemv(alpha, a, x, beta)
}
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
/// vector, and `alpha, beta` two scalars. /// vector, and `alpha, beta` two scalars.
/// ///
@ -709,331 +619,6 @@ where
} }
} }
impl<T, D: Dim, S> Vector<MaybeUninit<T>, D, S>
where
T: Scalar + Zero + ClosedAdd + ClosedMul,
S: StorageMut<MaybeUninit<T>, D>,
{
/// Computes `alpha * a * x`, where `a` is a matrix, `x` a vector, and
/// `alpha` is a scalar.
///
/// `self` must be completely uninitialized, or data leaks will occur. After
/// this method is called, all entries in `self` will be initialized.
#[inline]
pub fn axc<D2: Dim, S2>(
&mut self,
a: T,
x: &Vector<T, D2, S2>,
c: T,
) -> VectorSliceMut<T, D, S::RStride, S::CStride>
where
S2: Storage<T, D2>,
ShapeConstraint: DimEq<D, D2>,
{
let rstride1 = self.strides().0;
let rstride2 = x.strides().0;
// Safety: see each individual remark.
unsafe {
// We don't mind `x` and `y` not being contiguous, as we'll only
// access the elements we're allowed to. (TODO: double check this)
let y = self.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
// The indices are within range, and only access elements that belong
// to `x` and `y` themselves.
for i in 0..y.len() {
*y.get_unchecked_mut(i * rstride1) = MaybeUninit::new(
a.inlined_clone()
* x.get_unchecked(i * rstride2).inlined_clone()
* c.inlined_clone(),
);
}
// We've initialized all elements.
self.assume_init_mut()
}
}
/// Computes `alpha * a * x`, where `a` is a matrix, `x` a vector, and
/// `alpha` is a scalar.
///
/// `self` must be completely uninitialized, or data leaks will occur. After
/// the method is called, `self` will be completely initialized. We return
/// an initialized mutable vector slice to `self` for convenience.
#[inline]
pub fn gemv_z<R2: Dim, C2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
x: &Vector<T, D3, SC>,
) -> VectorSliceMut<T, D, S::RStride, S::CStride>
where
T: One,
SB: Storage<T, R2, C2>,
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
{
let dim1 = self.nrows();
let (nrows2, ncols2) = a.shape();
let dim3 = x.nrows();
assert!(
ncols2 == dim3 && dim1 == nrows2,
"Gemv: dimensions mismatch."
);
if ncols2 == 0 {
self.fill_fn(|| MaybeUninit::new(T::zero()));
// Safety: all entries have just been initialized.
unsafe {
return self.assume_init_mut();
}
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
let mut init = self.axc(alpha.inlined_clone(), &col2, val);
// Safety: all indices are within range.
unsafe {
for j in 1..ncols2 {
let col2 = a.column(j);
let val = x.vget_unchecked(j).inlined_clone();
init.axcpy(alpha.inlined_clone(), &col2, val, T::one());
}
}
init
}
#[inline(always)]
fn xxgemv_z<D2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &SquareMatrix<T, D2, SB>,
x: &Vector<T, D3, SC>,
dot: impl Fn(
&DVectorSlice<T, SB::RStride, SB::CStride>,
&DVectorSlice<T, SC::RStride, SC::CStride>,
) -> T,
) where
T: One,
SB: Storage<T, D2, D2>,
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
{
let dim1 = self.nrows();
let dim2 = a.nrows();
let dim3 = x.nrows();
assert!(
a.is_square(),
"Symmetric cgemv: the input matrix must be square."
);
assert!(
dim2 == dim3 && dim1 == dim2,
"Symmetric cgemv: dimensions mismatch."
);
if dim2 == 0 {
return;
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
let mut res = self.axc(alpha.inlined_clone(), &col2, val);
res[0] += alpha.inlined_clone() * dot(&a.slice_range(1.., 0), &x.rows_range(1..));
for j in 1..dim2 {
let col2 = a.column(j);
let dot = dot(&col2.rows_range(j..), &x.rows_range(j..));
let val;
unsafe {
val = x.vget_unchecked(j).inlined_clone();
*res.vget_unchecked_mut(j) += alpha.inlined_clone() * dot;
}
res.rows_range_mut(j + 1..).axpy(
alpha.inlined_clone() * val,
&col2.rows_range(j + 1..),
T::one(),
);
}
}
/// Computes `self = alpha * a * x`, where `a` is an **hermitian** matrix, `x` a
/// vector, and `alpha, beta` two scalars.
pub fn hegemv_z<D2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &SquareMatrix<T, D2, SB>,
x: &Vector<T, D3, SC>,
) where
T: SimdComplexField,
SB: Storage<T, D2, D2>,
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
{
self.xxgemv_z(alpha, a, x, |a, b| a.dotc(b))
}
}
impl<T, R1: Dim, C1: Dim, S: StorageMut<MaybeUninit<T>, R1, C1>> Matrix<MaybeUninit<T>, R1, C1, S>
where
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
// DefaultAllocator: Allocator<T, R1, C1>,
{
/// Computes `alpha * a * b`, where `a` and `b` are matrices, and `alpha` is
/// a scalar.
///
/// # Examples:
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4,
/// 0.5, 0.6, 0.7, 0.8,
/// 0.9, 1.0, 1.1, 1.2);
/// let expected = mat2 * mat3 * 10.0 + mat1 * 5.0;
///
/// mat1.gemm(10.0, &mat2, &mat3, 5.0);
/// assert_relative_eq!(mat1, expected);
/// ```
#[inline]
pub fn gemm_z<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
b: &Matrix<T, R3, C3, SC>,
) -> MatrixSliceMut<T, R1, C1, S::RStride, S::CStride>
where
SB: Storage<T, R2, C2>,
SC: Storage<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2>
+ SameNumberOfColumns<C1, C3>
+ AreMultipliable<R2, C2, R3, C3>,
{
let ncols1 = self.ncols();
#[cfg(feature = "std")]
{
// We assume large matrices will be Dynamic but small matrices static.
// We could use matrixmultiply for large statically-sized matrices but the performance
// threshold to activate it would be different from SMALL_DIM because our code optimizes
// better for statically-sized matrices.
if R1::is::<Dynamic>()
|| C1::is::<Dynamic>()
|| R2::is::<Dynamic>()
|| C2::is::<Dynamic>()
|| R3::is::<Dynamic>()
|| C3::is::<Dynamic>()
{
// matrixmultiply can be used only if the std feature is available.
let nrows1 = self.nrows();
let (nrows2, ncols2) = a.shape();
let (nrows3, ncols3) = b.shape();
// Threshold determined empirically.
const SMALL_DIM: usize = 5;
if nrows1 > SMALL_DIM
&& ncols1 > SMALL_DIM
&& nrows2 > SMALL_DIM
&& ncols2 > SMALL_DIM
{
assert_eq!(
ncols2, nrows3,
"gemm: dimensions mismatch for multiplication."
);
assert_eq!(
(nrows1, ncols1),
(nrows2, ncols3),
"gemm: dimensions mismatch for addition."
);
// NOTE: this case should never happen because we enter this
// codepath only when ncols2 > SMALL_DIM. Though we keep this
// here just in case if in the future we change the conditions to
// enter this codepath.
if ncols1 == 0 {
self.fill_fn(|| MaybeUninit::new(T::zero()));
// Safety: there's no (uninitialized) values.
return unsafe { self.assume_init_mut() };
}
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = self.strides();
if T::is::<f32>() {
unsafe {
matrixmultiply::sgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f32,
rsa as isize,
csa as isize,
b.data.ptr() as *const f32,
rsb as isize,
csb as isize,
0.0,
self.data.ptr_mut() as *mut f32,
rsc as isize,
csc as isize,
);
}
} else if T::is::<f64>() {
unsafe {
matrixmultiply::dgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f64,
rsa as isize,
csa as isize,
b.data.ptr() as *const f64,
rsb as isize,
csb as isize,
0.0,
self.data.ptr_mut() as *mut f64,
rsc as isize,
csc as isize,
);
}
}
// Safety: all entries have been initialized.
unsafe {
return self.assume_init_mut();
}
}
}
}
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
let _ = self
.column_mut(j1)
.gemv_z(alpha.inlined_clone(), a, &b.column(j1));
}
// Safety: all entries have been initialized.
unsafe { self.assume_init_mut() }
}
}
impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S> impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S>
where where
T: Scalar + Zero + ClosedAdd + ClosedMul, T: Scalar + Zero + ClosedAdd + ClosedMul,
@ -1170,122 +755,9 @@ where
+ SameNumberOfColumns<C1, C3> + SameNumberOfColumns<C1, C3>
+ AreMultipliable<R2, C2, R3, C3>, + AreMultipliable<R2, C2, R3, C3>,
{ {
let ncols1 = self.ncols(); // SAFETY: this is valid because our matrices are initialized and
// we are using status = Init.
#[cfg(feature = "std")] unsafe { gemm_uninit(Init, self, alpha, a, b, beta) }
{
// We assume large matrices will be Dynamic but small matrices static.
// We could use matrixmultiply for large statically-sized matrices but the performance
// threshold to activate it would be different from SMALL_DIM because our code optimizes
// better for statically-sized matrices.
if R1::is::<Dynamic>()
|| C1::is::<Dynamic>()
|| R2::is::<Dynamic>()
|| C2::is::<Dynamic>()
|| R3::is::<Dynamic>()
|| C3::is::<Dynamic>()
{
// matrixmultiply can be used only if the std feature is available.
let nrows1 = self.nrows();
let (nrows2, ncols2) = a.shape();
let (nrows3, ncols3) = b.shape();
// Threshold determined empirically.
const SMALL_DIM: usize = 5;
if nrows1 > SMALL_DIM
&& ncols1 > SMALL_DIM
&& nrows2 > SMALL_DIM
&& ncols2 > SMALL_DIM
{
assert_eq!(
ncols2, nrows3,
"gemm: dimensions mismatch for multiplication."
);
assert_eq!(
(nrows1, ncols1),
(nrows2, ncols3),
"gemm: dimensions mismatch for addition."
);
// NOTE: this case should never happen because we enter this
// codepath only when ncols2 > SMALL_DIM. Though we keep this
// here just in case if in the future we change the conditions to
// enter this codepath.
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
self.fill(T::zero());
} else {
*self *= beta;
}
return;
}
if T::is::<f32>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = self.strides();
unsafe {
matrixmultiply::sgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f32,
rsa as isize,
csa as isize,
b.data.ptr() as *const f32,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
self.data.ptr_mut() as *mut f32,
rsc as isize,
csc as isize,
);
}
return;
} else if T::is::<f64>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = self.strides();
unsafe {
matrixmultiply::dgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f64,
rsa as isize,
csa as isize,
b.data.ptr() as *const f64,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
self.data.ptr_mut() as *mut f64,
rsc as isize,
csc as isize,
);
}
return;
}
}
}
}
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
self.column_mut(j1).gemv(
alpha.inlined_clone(),
a,
&b.column(j1),
beta.inlined_clone(),
);
}
} }
/// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices. /// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices.
@ -1579,33 +1051,78 @@ where
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
/// 0.5, 0.6, 0.7, /// 0.5, 0.6, 0.7,
/// 0.9, 1.0, 1.1]); /// 0.9, 1.0, 1.1]);
/// /// // The random shows that values on the workspace do not
/// // matter as they will be overwritten.
/// let mut workspace = DVector::new_random(2);
/// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0; /// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0;
/// ///
/// mat.quadform_tr_with_workspace(&mut workspace, 10.0, &lhs, &mid, 5.0);
/// assert_relative_eq!(mat, expected);
pub fn quadform_tr_with_workspace<D2, S2, R3, C3, S3, D4, S4>(
&mut self,
work: &mut Vector<T, D2, S2>,
alpha: T,
lhs: &Matrix<T, R3, C3, S3>,
mid: &SquareMatrix<T, D4, S4>,
beta: T,
) where
D2: Dim,
R3: Dim,
C3: Dim,
D4: Dim,
S2: StorageMut<T, D2>,
S3: Storage<T, R3, C3>,
S4: Storage<T, D4, D4>,
ShapeConstraint: DimEq<D1, D2> + DimEq<D1, R3> + DimEq<D2, R3> + DimEq<C3, D4>,
{
work.gemv(T::one(), lhs, &mid.column(0), T::zero());
self.ger(alpha.inlined_clone(), work, &lhs.column(0), beta);
for j in 1..mid.ncols() {
work.gemv(T::one(), lhs, &mid.column(j), T::zero());
self.ger(alpha.inlined_clone(), work, &lhs.column(j), T::one());
}
}
/// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`.
///
/// This allocates a workspace vector of dimension D1 for intermediate results.
/// If `D1` is a type-level integer, then the allocation is performed on the stack.
/// Use `.quadform_tr_with_workspace(...)` instead to avoid allocations.
///
/// # Examples:
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
/// let mut mat = Matrix2::identity();
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// let mid = Matrix3::new(0.1, 0.2, 0.3,
/// 0.5, 0.6, 0.7,
/// 0.9, 1.0, 1.1);
/// let expected = lhs * mid * lhs.transpose() * 10.0 + mat * 5.0;
///
/// mat.quadform_tr(10.0, &lhs, &mid, 5.0); /// mat.quadform_tr(10.0, &lhs, &mid, 5.0);
/// assert_relative_eq!(mat, expected); /// assert_relative_eq!(mat, expected);
pub fn quadform_tr<R3: Dim, C3: Dim, S3, D4: Dim, S4>( pub fn quadform_tr<R3, C3, S3, D4, S4>(
&mut self, &mut self,
alpha: T, alpha: T,
lhs: &Matrix<T, R3, C3, S3>, lhs: &Matrix<T, R3, C3, S3>,
mid: &SquareMatrix<T, D4, S4>, mid: &SquareMatrix<T, D4, S4>,
beta: T, beta: T,
) where ) where
R3: Dim,
C3: Dim,
D4: Dim,
S3: Storage<T, R3, C3>, S3: Storage<T, R3, C3>,
S4: Storage<T, D4, D4>, S4: Storage<T, D4, D4>,
ShapeConstraint: DimEq<D1, R3> + DimEq<C3, D4>, ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>,
DefaultAllocator: Allocator<T, R3>, DefaultAllocator: Allocator<T, D1>,
{ {
let mut work = // TODO: would it be useful to avoid the zero-initialization of the workspace data?
Matrix::new_uninitialized_generic(R3::from_usize(self.shape().0), Const::<1>); let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
let mut work = work.gemv_z(T::one(), lhs, &mid.column(0)); self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta)
self.ger(alpha.inlined_clone(), &work, &lhs.column(0), beta);
for j in 1..mid.ncols() {
work.gemv(T::one(), lhs, &mid.column(j), T::zero());
self.ger(alpha.inlined_clone(), &work, &lhs.column(j), T::one());
}
} }
/// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`. /// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`.
@ -1626,34 +1143,79 @@ where
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
/// 0.5, 0.6, 0.7, /// 0.5, 0.6, 0.7,
/// 0.9, 1.0, 1.1]); /// 0.9, 1.0, 1.1]);
/// /// // The random shows that values on the workspace do not
/// // matter as they will be overwritten.
/// let mut workspace = DVector::new_random(3);
/// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0; /// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0;
/// ///
/// mat.quadform(10.0, &mid, &rhs, 5.0); /// mat.quadform_with_workspace(&mut workspace, 10.0, &mid, &rhs, 5.0);
/// assert_relative_eq!(mat, expected); /// assert_relative_eq!(mat, expected);
pub fn quadform<D3: Dim, S3, R4: Dim, C4: Dim, S4>( pub fn quadform_with_workspace<D2, S2, D3, S3, R4, C4, S4>(
&mut self, &mut self,
work: &mut Vector<T, D2, S2>,
alpha: T, alpha: T,
mid: &SquareMatrix<T, D3, S3>, mid: &SquareMatrix<T, D3, S3>,
rhs: &Matrix<T, R4, C4, S4>, rhs: &Matrix<T, R4, C4, S4>,
beta: T, beta: T,
) where ) where
D2: Dim,
D3: Dim,
R4: Dim,
C4: Dim,
S2: StorageMut<T, D2>,
S3: Storage<T, D3, D3>, S3: Storage<T, D3, D3>,
S4: Storage<T, R4, C4>, S4: Storage<T, R4, C4>,
ShapeConstraint: DimEq<D3, R4> + DimEq<R4, D3> + DimEq<D1, C4>, ShapeConstraint:
DefaultAllocator: Allocator<T, D3>, DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>,
{ {
// TODO: figure out why type inference isn't doing its job. work.gemv(T::one(), mid, &rhs.column(0), T::zero());
let mut work = Matrix::new_uninitialized_generic(D3::from_usize(mid.shape().0), Const::<1>);
let mut work = work.gemv_z::<D3, _, _, _, _>(T::one(), mid, &rhs.column(0));
self.column_mut(0) self.column_mut(0)
.gemv_tr(alpha.inlined_clone(), rhs, &work, beta.inlined_clone()); .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
for j in 1..rhs.ncols() { for j in 1..rhs.ncols() {
work.gemv::<D3, D3, R4, S3, _>(T::one(), mid, &rhs.column(j), T::zero()); work.gemv(T::one(), mid, &rhs.column(j), T::zero());
self.column_mut(j) self.column_mut(j)
.gemv_tr(alpha.inlined_clone(), rhs, &work, beta.inlined_clone()); .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
} }
} }
/// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`.
///
/// This allocates a workspace vector of dimension D2 for intermediate results.
/// If `D2` is a type-level integer, then the allocation is performed on the stack.
/// Use `.quadform_with_workspace(...)` instead to avoid allocations.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
/// let mut mat = Matrix2::identity();
/// let rhs = Matrix3x2::new(1.0, 2.0,
/// 3.0, 4.0,
/// 5.0, 6.0);
/// let mid = Matrix3::new(0.1, 0.2, 0.3,
/// 0.5, 0.6, 0.7,
/// 0.9, 1.0, 1.1);
/// let expected = rhs.transpose() * mid * rhs * 10.0 + mat * 5.0;
///
/// mat.quadform(10.0, &mid, &rhs, 5.0);
/// assert_relative_eq!(mat, expected);
pub fn quadform<D2, S2, R3, C3, S3>(
&mut self,
alpha: T,
mid: &SquareMatrix<T, D2, S2>,
rhs: &Matrix<T, R3, C3, S3>,
beta: T,
) where
D2: Dim,
R3: Dim,
C3: Dim,
S2: Storage<T, D2, D2>,
S3: Storage<T, R3, C3>,
ShapeConstraint: DimEq<D2, R3> + DimEq<D1, C3> + AreMultipliable<C3, R3, D2, U1>,
DefaultAllocator: Allocator<T, D2>,
{
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
let mut work = Vector::zeros_generic(mid.shape_generic().0, Const::<1>);
self.quadform_with_workspace(&mut work, alpha, mid, rhs, beta)
}
} }

359
src/base/blas_uninit.rs Normal file
View File

@ -0,0 +1,359 @@
/*
* This file implements some BLAS operations in such a way that they work
* even if the first argument (the output parameter) is an uninitialized matrix.
*
* Because doing this makes the code harder to read, we only implemented the operations that we
* know would benefit from this performance-wise, namely, GEMM (which we use for our matrix
* multiplication code). If we identify other operations like that in the future, we could add
* them here.
*/
#[cfg(feature = "std")]
use matrixmultiply;
use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul};
#[cfg(feature = "std")]
use std::mem;
use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
};
use crate::base::dimension::{Dim, Dynamic, U1};
use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::uninit::{InitStatus, Initialized};
use crate::base::{Matrix, Scalar, Vector};
// # Safety
// The content of `y` must only contain values for which
// `Status::assume_init_mut` is sound.
#[allow(clippy::too_many_arguments)]
unsafe fn array_axcpy<Status, T>(
_: Status,
y: &mut [Status::Value],
a: T,
x: &[T],
c: T,
beta: T,
stride1: usize,
stride2: usize,
len: usize,
) where
Status: InitStatus<T>,
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
let y = Status::assume_init_mut(y.get_unchecked_mut(i * stride1));
*y = a.inlined_clone() * x.get_unchecked(i * stride2).inlined_clone() * c.inlined_clone()
+ beta.inlined_clone() * y.inlined_clone();
}
}
fn array_axc<Status, T>(
_: Status,
y: &mut [Status::Value],
a: T,
x: &[T],
c: T,
stride1: usize,
stride2: usize,
len: usize,
) where
Status: InitStatus<T>,
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
unsafe {
Status::init(
y.get_unchecked_mut(i * stride1),
a.inlined_clone()
* x.get_unchecked(i * stride2).inlined_clone()
* c.inlined_clone(),
);
}
}
}
/// Computes `self = a * x * c + b * self`.
///
/// If `b` is zero, `self` is never read from.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let mut vec1 = Vector3::new(1.0, 2.0, 3.0);
/// let vec2 = Vector3::new(0.1, 0.2, 0.3);
/// vec1.axcpy(5.0, &vec2, 2.0, 5.0);
/// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0));
/// ```
#[inline]
#[allow(clippy::many_single_char_names)]
pub unsafe fn axcpy_uninit<Status, T, D1: Dim, D2: Dim, SA, SB>(
status: Status,
y: &mut Vector<Status::Value, D1, SA>,
a: T,
x: &Vector<T, D2, SB>,
c: T,
b: T,
) where
T: Scalar + Zero + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, D1>,
SB: RawStorage<T, D2>,
ShapeConstraint: DimEq<D1, D2>,
Status: InitStatus<T>,
{
assert_eq!(y.nrows(), x.nrows(), "Axcpy: mismatched vector shapes.");
let rstride1 = y.strides().0;
let rstride2 = x.strides().0;
// SAFETY: the conversion to slices is OK because we access the
// elements taking the strides into account.
let y = y.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
if !b.is_zero() {
array_axcpy(status, y, a, x, c, b, rstride1, rstride2, x.len());
} else {
array_axc(status, y, a, x, c, rstride1, rstride2, x.len());
}
}
/// Computes `self = alpha * a * x + beta * self`, where `a` is a matrix, `x` a vector, and
/// `alpha, beta` two scalars.
///
/// If `beta` is zero, `self` is never read.
///
/// # Examples:
///
/// ```
/// # use nalgebra::{Matrix2, Vector2};
/// let mut vec1 = Vector2::new(1.0, 2.0);
/// let vec2 = Vector2::new(0.1, 0.2);
/// let mat = Matrix2::new(1.0, 2.0,
/// 3.0, 4.0);
/// vec1.gemv(10.0, &mat, &vec2, 5.0);
/// assert_eq!(vec1, Vector2::new(10.0, 21.0));
/// ```
#[inline]
pub unsafe fn gemv_uninit<Status, T, D1: Dim, R2: Dim, C2: Dim, D3: Dim, SA, SB, SC>(
status: Status,
y: &mut Vector<Status::Value, D1, SA>,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
x: &Vector<T, D3, SC>,
beta: T,
) where
Status: InitStatus<T>,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, D1>,
SB: RawStorage<T, R2, C2>,
SC: RawStorage<T, D3>,
ShapeConstraint: DimEq<D1, R2> + AreMultipliable<R2, C2, D3, U1>,
{
let dim1 = y.nrows();
let (nrows2, ncols2) = a.shape();
let dim3 = x.nrows();
assert!(
ncols2 == dim3 && dim1 == nrows2,
"Gemv: dimensions mismatch."
);
if ncols2 == 0 {
if beta.is_zero() {
y.apply(|e| Status::init(e, T::zero()));
} else {
// SAFETY: this is UB if y is uninitialized.
y.apply(|e| *Status::assume_init_mut(e) *= beta.inlined_clone());
}
return;
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = x.vget_unchecked(0).inlined_clone();
// SAFETY: this is the call that makes this method unsafe: it is UB if Status = Uninit and beta != 0.
axcpy_uninit(status, y, alpha.inlined_clone(), &col2, val, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = x.vget_unchecked(j).inlined_clone();
// SAFETY: because y was initialized above, we can use the initialized status.
axcpy_uninit(
Initialized(status),
y,
alpha.inlined_clone(),
&col2,
val,
T::one(),
);
}
}
/// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices.
/// `alpha` and `beta` are scalar.
///
/// If `beta` is zero, `self` is never read.
///
/// # Examples:
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4,
/// 0.5, 0.6, 0.7, 0.8,
/// 0.9, 1.0, 1.1, 1.2);
/// let expected = mat2 * mat3 * 10.0 + mat1 * 5.0;
///
/// mat1.gemm(10.0, &mat2, &mat3, 5.0);
/// assert_relative_eq!(mat1, expected);
/// ```
#[inline]
pub unsafe fn gemm_uninit<
Status,
T,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
R3: Dim,
C3: Dim,
SA,
SB,
SC,
>(
status: Status,
y: &mut Matrix<Status::Value, R1, C1, SA>,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
b: &Matrix<T, R3, C3, SC>,
beta: T,
) where
Status: InitStatus<T>,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, R1, C1>,
SB: RawStorage<T, R2, C2>,
SC: RawStorage<T, R3, C3>,
ShapeConstraint:
SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C3> + AreMultipliable<R2, C2, R3, C3>,
{
let ncols1 = y.ncols();
#[cfg(feature = "std")]
{
// We assume large matrices will be Dynamic but small matrices static.
// We could use matrixmultiply for large statically-sized matrices but the performance
// threshold to activate it would be different from SMALL_DIM because our code optimizes
// better for statically-sized matrices.
if R1::is::<Dynamic>()
|| C1::is::<Dynamic>()
|| R2::is::<Dynamic>()
|| C2::is::<Dynamic>()
|| R3::is::<Dynamic>()
|| C3::is::<Dynamic>()
{
// matrixmultiply can be used only if the std feature is available.
let nrows1 = y.nrows();
let (nrows2, ncols2) = a.shape();
let (nrows3, ncols3) = b.shape();
// Threshold determined empirically.
const SMALL_DIM: usize = 5;
if nrows1 > SMALL_DIM && ncols1 > SMALL_DIM && nrows2 > SMALL_DIM && ncols2 > SMALL_DIM
{
assert_eq!(
ncols2, nrows3,
"gemm: dimensions mismatch for multiplication."
);
assert_eq!(
(nrows1, ncols1),
(nrows2, ncols3),
"gemm: dimensions mismatch for addition."
);
// NOTE: this case should never happen because we enter this
// codepath only when ncols2 > SMALL_DIM. Though we keep this
// here just in case if in the future we change the conditions to
// enter this codepath.
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
y.apply(|e| Status::init(e, T::zero()));
} else {
// SAFETY: this is UB if Status = Uninit
y.apply(|e| *Status::assume_init_mut(e) *= beta.inlined_clone());
}
return;
}
if T::is::<f32>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = y.strides();
matrixmultiply::sgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f32,
rsa as isize,
csa as isize,
b.data.ptr() as *const f32,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
y.data.ptr_mut() as *mut f32,
rsc as isize,
csc as isize,
);
return;
} else if T::is::<f64>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = y.strides();
matrixmultiply::dgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f64,
rsa as isize,
csa as isize,
b.data.ptr() as *const f64,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
y.data.ptr_mut() as *mut f64,
rsc as isize,
csc as isize,
);
return;
}
}
}
}
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
// SAFETY: this is UB if Status = Uninit && beta != 0
gemv_uninit(
status,
&mut y.column_mut(j1),
alpha.inlined_clone(),
a,
&b.column(j1),
beta.inlined_clone(),
);
}
}

View File

@ -1,6 +1,8 @@
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
#[cfg(feature = "arbitrary")]
use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -11,17 +13,49 @@ use rand::{
Rng, Rng,
}; };
use std::{iter, mem::MaybeUninit}; use std::iter;
use typenum::{self, Cmp, Greater}; use typenum::{self, Cmp, Greater};
use simba::scalar::{ClosedAdd, ClosedMul}; use simba::scalar::{ClosedAdd, ClosedMul};
use crate::base::allocator::{Allocator, InnerAllocator}; use crate::base::allocator::Allocator;
use crate::base::dimension::{Dim, DimName, Dynamic, ToTypenum}; use crate::base::dimension::{Dim, DimName, Dynamic, ToTypenum};
use crate::base::storage::Storage; use crate::base::storage::RawStorage;
use crate::base::{ use crate::base::{
ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector, ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector,
}; };
use crate::UninitMatrix;
use std::mem::MaybeUninit;
/// When "no_unsound_assume_init" is enabled, expands to `unimplemented!()` instead of `new_uninitialized_generic().assume_init()`.
/// Intended as a placeholder, each callsite should be refactored to use uninitialized memory soundly
#[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() }
}}
}
impl<T: Scalar, R: Dim, C: Dim> UninitMatrix<T, R, C>
where
DefaultAllocator: Allocator<T, R, C>,
{
pub fn uninit(nrows: R, ncols: C) -> Self {
// SAFETY: this is OK because the dimension automatically match the storage
// because we are building an owned storage.
unsafe {
Self::from_data_statically_unchecked(DefaultAllocator::allocate_uninit(nrows, ncols))
}
}
}
/// # Generic constructors /// # Generic constructors
/// This set of matrix and vector construction functions are all generic /// This set of matrix and vector construction functions are all generic
@ -29,16 +63,23 @@ use crate::base::{
/// the dimension as inputs. /// the dimension as inputs.
/// ///
/// These functions should only be used when working on dimension-generic code. /// These functions should only be used when working on dimension-generic code.
impl<T, R: Dim, C: Dim> OMatrix<T, R, C> impl<T: Scalar, R: Dim, C: Dim> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
{ {
/// Creates a new uninitialized matrix.
///
/// # Safety
/// If the matrix has a compile-time dimension, this panics
/// if `nrows != R::to_usize()` or `ncols != C::to_usize()`.
#[inline]
pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> MaybeUninit<Self> {
Self::from_uninitialized_data(DefaultAllocator::allocate_uninitialized(nrows, ncols))
}
/// Creates a matrix with all its elements set to `elem`. /// Creates a matrix with all its elements set to `elem`.
#[inline] #[inline]
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self {
where
T: Clone,
{
let len = nrows.value() * ncols.value(); let len = nrows.value() * ncols.value();
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
} }
@ -47,10 +88,7 @@ where
/// ///
/// Same as `from_element_generic`. /// Same as `from_element_generic`.
#[inline] #[inline]
pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self {
where
T: Clone,
{
let len = nrows.value() * ncols.value(); let len = nrows.value() * ncols.value();
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
} }
@ -59,7 +97,7 @@ where
#[inline] #[inline]
pub fn zeros_generic(nrows: R, ncols: C) -> Self pub fn zeros_generic(nrows: R, ncols: C) -> Self
where where
T: Zero + Clone, T: Zero,
{ {
Self::from_element_generic(nrows, ncols, T::zero()) Self::from_element_generic(nrows, ncols, T::zero())
} }
@ -79,37 +117,32 @@ where
/// The order of elements in the slice must follow the usual mathematic writing, i.e., /// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row. /// row-by-row.
#[inline] #[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!( assert!(
slice.len() == nrows.value() * ncols.value(), slice.len() == nrows.value() * ncols.value(),
"Matrix init. error: the slice did not contain the right number of elements." "Matrix init. error: the slice did not contain the right number of elements."
); );
let mut res = Self::new_uninitialized_generic(nrows, ncols); let mut res = Matrix::uninit(nrows, ncols);
let mut iter = slice.iter(); let mut iter = slice.iter();
unsafe {
for i in 0..nrows.value() { for i in 0..nrows.value() {
for j in 0..ncols.value() { for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut((i, j)) =
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone()); MaybeUninit::new(iter.next().unwrap().inlined_clone())
}
} }
} }
// Safety: all entries have been initialized. // SAFETY: the result has been fully initialized above.
unsafe { res.assume_init() } res.assume_init()
}
} }
/// Creates a matrix with its elements filled with the components provided by a slice. The /// Creates a matrix with its elements filled with the components provided by a slice. The
/// components must have the same layout as the matrix data storage (i.e. column-major). /// components must have the same layout as the matrix data storage (i.e. column-major).
#[inline] #[inline]
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
where
T: Clone,
{
Self::from_iterator_generic(nrows, ncols, slice.iter().cloned()) Self::from_iterator_generic(nrows, ncols, slice.iter().cloned())
} }
@ -120,18 +153,18 @@ where
where where
F: FnMut(usize, usize) -> T, F: FnMut(usize, usize) -> T,
{ {
let mut res = Self::new_uninitialized_generic(nrows, ncols); let mut res = Matrix::uninit(nrows, ncols);
unsafe {
for j in 0..ncols.value() { for j in 0..ncols.value() {
for i in 0..nrows.value() { for i in 0..nrows.value() {
unsafe {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j)); *res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
} }
} }
}
// Safety: all entries have been initialized. // SAFETY: the result has been fully initialized above.
unsafe { res.assume_init() } res.assume_init()
}
} }
/// Creates a new identity matrix. /// Creates a new identity matrix.
@ -141,7 +174,7 @@ where
#[inline] #[inline]
pub fn identity_generic(nrows: R, ncols: C) -> Self pub fn identity_generic(nrows: R, ncols: C) -> Self
where where
T: Zero + One + Scalar, T: Zero + One,
{ {
Self::from_diagonal_element_generic(nrows, ncols, T::one()) Self::from_diagonal_element_generic(nrows, ncols, T::one())
} }
@ -153,7 +186,7 @@ where
#[inline] #[inline]
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self
where where
T: Zero + One + Scalar, T: Zero + One,
{ {
let mut res = Self::zeros_generic(nrows, ncols); let mut res = Self::zeros_generic(nrows, ncols);
@ -171,7 +204,7 @@ where
#[inline] #[inline]
pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self
where where
T: Zero + Clone, T: Zero,
{ {
let mut res = Self::zeros_generic(nrows, ncols); let mut res = Self::zeros_generic(nrows, ncols);
assert!( assert!(
@ -180,7 +213,7 @@ where
); );
for (i, elt) in elts.iter().enumerate() { for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() } unsafe { *res.get_unchecked_mut((i, i)) = elt.inlined_clone() }
} }
res res
@ -205,8 +238,7 @@ where
#[inline] #[inline]
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
where where
T: Clone, SB: RawStorage<T, Const<1>, C>,
SB: Storage<T, Const<1>, C>,
{ {
assert!(!rows.is_empty(), "At least one row must be given."); assert!(!rows.is_empty(), "At least one row must be given.");
let nrows = R::try_to_usize().unwrap_or_else(|| rows.len()); let nrows = R::try_to_usize().unwrap_or_else(|| rows.len());
@ -225,7 +257,7 @@ where
// TODO: optimize that. // TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
rows[i][(0, j)].clone() rows[i][(0, j)].inlined_clone()
}) })
} }
@ -248,8 +280,7 @@ where
#[inline] #[inline]
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
where where
T: Clone, SB: RawStorage<T, R>,
SB: Storage<T, R>,
{ {
assert!(!columns.is_empty(), "At least one column must be given."); assert!(!columns.is_empty(), "At least one column must be given.");
let ncols = C::try_to_usize().unwrap_or_else(|| columns.len()); let ncols = C::try_to_usize().unwrap_or_else(|| columns.len());
@ -268,7 +299,7 @@ where
// TODO: optimize that. // TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
columns[j][i].clone() columns[j][i].inlined_clone()
}) })
} }
@ -321,6 +352,7 @@ where
impl<T, D: Dim> OMatrix<T, D, D> impl<T, D: Dim> OMatrix<T, D, D>
where where
T: Scalar,
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
@ -342,11 +374,11 @@ where
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0); /// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0);
/// ``` /// ```
#[inline] #[inline]
pub fn from_diagonal<SB: Storage<T, D>>(diag: &Vector<T, D, SB>) -> Self pub fn from_diagonal<SB: RawStorage<T, D>>(diag: &Vector<T, D, SB>) -> Self
where where
T: Zero + Scalar, T: Zero,
{ {
let (dim, _) = diag.data.shape(); let (dim, _) = diag.shape_generic();
let mut res = Self::zeros_generic(dim, dim); let mut res = Self::zeros_generic(dim, dim);
for i in 0..diag.len() { for i in 0..diag.len() {
@ -366,6 +398,12 @@ where
*/ */
macro_rules! impl_constructors( macro_rules! impl_constructors(
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
/// Creates a new uninitialized matrix or vector.
#[inline]
pub unsafe fn new_uninitialized($($args: usize),*) -> MaybeUninit<Self> {
Self::new_uninitialized_generic($($gargs),*)
}
/// Creates a matrix or vector with all its elements set to `elem`. /// Creates a matrix or vector with all its elements set to `elem`.
/// ///
/// # Example /// # Example
@ -387,10 +425,7 @@ macro_rules! impl_constructors(
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
/// ``` /// ```
#[inline] #[inline]
pub fn from_element($($args: usize,)* elem: T) -> Self pub fn from_element($($args: usize,)* elem: T) -> Self {
where
T: Clone
{
Self::from_element_generic($($gargs, )* elem) Self::from_element_generic($($gargs, )* elem)
} }
@ -417,10 +452,7 @@ macro_rules! impl_constructors(
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
/// ``` /// ```
#[inline] #[inline]
pub fn repeat($($args: usize,)* elem: T) -> Self pub fn repeat($($args: usize,)* elem: T) -> Self {
where
T: Clone
{
Self::repeat_generic($($gargs, )* elem) Self::repeat_generic($($gargs, )* elem)
} }
@ -446,9 +478,7 @@ macro_rules! impl_constructors(
/// ``` /// ```
#[inline] #[inline]
pub fn zeros($($args: usize),*) -> Self pub fn zeros($($args: usize),*) -> Self
where where T: Zero {
T: Zero + Clone
{
Self::zeros_generic($($gargs),*) Self::zeros_generic($($gargs),*)
} }
@ -504,7 +534,8 @@ macro_rules! impl_constructors(
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ``` /// ```
#[inline] #[inline]
pub fn from_fn<F: FnMut(usize, usize) -> T>($($args: usize,)* f: F) -> Self { pub fn from_fn<F>($($args: usize,)* f: F) -> Self
where F: FnMut(usize, usize) -> T {
Self::from_fn_generic($($gargs, )* f) Self::from_fn_generic($($gargs, )* f)
} }
@ -528,9 +559,7 @@ macro_rules! impl_constructors(
/// ``` /// ```
#[inline] #[inline]
pub fn identity($($args: usize,)*) -> Self pub fn identity($($args: usize,)*) -> Self
where where T: Zero + One {
T: Zero + One + Scalar
{
Self::identity_generic($($gargs),* ) Self::identity_generic($($gargs),* )
} }
@ -553,9 +582,7 @@ macro_rules! impl_constructors(
/// ``` /// ```
#[inline] #[inline]
pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self
where where T: Zero + One {
T: Zero + One + Scalar
{
Self::from_diagonal_element_generic($($gargs, )* elt) Self::from_diagonal_element_generic($($gargs, )* elt)
} }
@ -582,9 +609,7 @@ macro_rules! impl_constructors(
/// ``` /// ```
#[inline] #[inline]
pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self
where where T: Zero {
T: Zero + Scalar
{
Self::from_partial_diagonal_generic($($gargs, )* elts) Self::from_partial_diagonal_generic($($gargs, )* elts)
} }
@ -603,16 +628,14 @@ macro_rules! impl_constructors(
#[inline] #[inline]
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
pub fn new_random($($args: usize),*) -> Self pub fn new_random($($args: usize),*) -> Self
where where Standard: Distribution<T> {
Standard: Distribution<T>
{
Self::new_random_generic($($gargs),*) Self::new_random_generic($($gargs),*)
} }
} }
); );
/// # Constructors of statically-sized vectors or statically-sized matrices /// # Constructors of statically-sized vectors or statically-sized matrices
impl<T, R: DimName, C: DimName> OMatrix<T, R, C> impl<T: Scalar, R: DimName, C: DimName> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
{ {
@ -623,19 +646,8 @@ where
); // Arguments for non-generic constructors. ); // Arguments for non-generic constructors.
} }
impl<T, R: DimName, C: DimName> OMatrix<T, R, C>
where
DefaultAllocator: Allocator<T, R, C>,
{
/// Creates a new uninitialized matrix or vector.
#[inline]
pub fn new_uninitialized() -> OMatrix<MaybeUninit<T>, R, C> {
Self::new_uninitialized_generic(R::name(), C::name())
}
}
/// # Constructors of matrices with a dynamic number of columns /// # Constructors of matrices with a dynamic number of columns
impl<T, R: DimName> OMatrix<T, R, Dynamic> impl<T: Scalar, R: DimName> OMatrix<T, R, Dynamic>
where where
DefaultAllocator: Allocator<T, R, Dynamic>, DefaultAllocator: Allocator<T, R, Dynamic>,
{ {
@ -645,19 +657,8 @@ where
ncols); ncols);
} }
impl<T, R: DimName> OMatrix<T, R, Dynamic>
where
DefaultAllocator: Allocator<T, R, Dynamic>,
{
/// Creates a new uninitialized matrix or vector.
#[inline]
pub fn new_uninitialized(ncols: usize) -> OMatrix<MaybeUninit<T>, R, Dynamic> {
Self::new_uninitialized_generic(R::name(), Dynamic::new(ncols))
}
}
/// # Constructors of dynamic vectors and matrices with a dynamic number of rows /// # Constructors of dynamic vectors and matrices with a dynamic number of rows
impl<T, C: DimName> OMatrix<T, Dynamic, C> impl<T: Scalar, C: DimName> OMatrix<T, Dynamic, C>
where where
DefaultAllocator: Allocator<T, Dynamic, C>, DefaultAllocator: Allocator<T, Dynamic, C>,
{ {
@ -667,19 +668,8 @@ where
nrows); nrows);
} }
impl<T, C: DimName> OMatrix<T, Dynamic, C>
where
DefaultAllocator: Allocator<T, Dynamic, C>,
{
/// Creates a new uninitialized matrix or vector.
#[inline]
pub fn new_uninitialized(nrows: usize) -> OMatrix<MaybeUninit<T>, Dynamic, C> {
Self::new_uninitialized_generic(Dynamic::new(nrows), C::name())
}
}
/// # Constructors of fully dynamic matrices /// # Constructors of fully dynamic matrices
impl<T> OMatrix<T, Dynamic, Dynamic> impl<T: Scalar> OMatrix<T, Dynamic, Dynamic>
where where
DefaultAllocator: Allocator<T, Dynamic, Dynamic>, DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
{ {
@ -689,20 +679,6 @@ where
nrows, ncols); nrows, ncols);
} }
impl<T> OMatrix<T, Dynamic, Dynamic>
where
DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
{
/// Creates a new uninitialized matrix or vector.
#[inline]
pub fn new_uninitialized(
nrows: usize,
ncols: usize,
) -> OMatrix<MaybeUninit<T>, Dynamic, Dynamic> {
Self::new_uninitialized_generic(Dynamic::new(nrows), Dynamic::new(ncols))
}
}
/* /*
* *
* Constructors that don't necessarily require all dimensions * Constructors that don't necessarily require all dimensions
@ -711,10 +687,8 @@ where
*/ */
macro_rules! impl_constructors_from_data( macro_rules! impl_constructors_from_data(
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { ($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<T, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*> impl<T: Scalar, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*>
where where DefaultAllocator: Allocator<T $(, $Dims)*> {
DefaultAllocator: Allocator<T $(, $Dims)*>
{
/// Creates a matrix with its elements filled with the components provided by a slice /// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order. /// in row-major order.
/// ///
@ -741,10 +715,7 @@ macro_rules! impl_constructors_from_data(
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ``` /// ```
#[inline] #[inline]
pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self {
where
T: Clone
{
Self::from_row_slice_generic($($gargs, )* $data) Self::from_row_slice_generic($($gargs, )* $data)
} }
@ -771,10 +742,7 @@ macro_rules! impl_constructors_from_data(
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ``` /// ```
#[inline] #[inline]
pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self {
where
T: Clone
{
Self::from_column_slice_generic($($gargs, )* $data) Self::from_column_slice_generic($($gargs, )* $data)
} }
@ -877,7 +845,7 @@ where
} }
#[cfg(feature = "rand-no-std")] #[cfg(feature = "rand-no-std")]
impl<T, R: Dim, C: Dim> Distribution<OMatrix<T, R, C>> for Standard impl<T: Scalar, R: Dim, C: Dim> Distribution<OMatrix<T, R, C>> for Standard
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
Standard: Distribution<T>, Standard: Distribution<T>,
@ -892,10 +860,13 @@ where
} }
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T, R: Dim, C: Dim> Arbitrary for OMatrix<T, R, C> impl<T, R, C> Arbitrary for OMatrix<T, R, C>
where where
T: Arbitrary + Send, R: Dim,
C: Dim,
T: Scalar + Arbitrary + Send,
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
Owned<T, R, C>: Clone + Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {

View File

@ -1,11 +1,13 @@
use crate::base::dimension::{Const, Dim, DimName, Dynamic}; use crate::base::dimension::{Const, Dim, DimName, Dynamic};
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
use crate::base::{MatrixSlice, MatrixSliceMutMN}; use crate::base::{MatrixSlice, MatrixSliceMutMN, Scalar};
use num_rational::Ratio; use num_rational::Ratio;
/// # Creating matrix slices from `&[T]` /// # Creating matrix slices from `&[T]`
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSlice<'a, T, R, C, RStride, CStride> { impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
MatrixSlice<'a, T, R, C, RStride, CStride>
{
/// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances. /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
/// ///
/// # Safety /// # Safety
@ -55,7 +57,7 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSlice<'a, T, R, C,
} }
} }
impl<'a, T, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
/// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
/// ///
/// # Safety /// # Safety
@ -85,7 +87,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
macro_rules! impl_constructors( macro_rules! impl_constructors(
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<'a, T, $($DimIdent: $DimBound),*> MatrixSlice<'a, T, $($Dims),*> { impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSlice<'a, T, $($Dims),*> {
/// Creates a new matrix slice from the given data array. /// Creates a new matrix slice from the given data array.
/// ///
/// Panics if `data` does not contain enough elements. /// Panics if `data` does not contain enough elements.
@ -101,7 +103,7 @@ macro_rules! impl_constructors(
} }
} }
impl<'a, T, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> { impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> {
/// Creates a new matrix slice with the specified strides from the given data array. /// Creates a new matrix slice with the specified strides from the given data array.
/// ///
/// Panics if `data` does not contain enough elements. /// Panics if `data` does not contain enough elements.
@ -141,7 +143,7 @@ impl_constructors!(Dynamic, Dynamic;
nrows, ncols); nrows, ncols);
/// # Creating mutable matrix slices from `&mut [T]` /// # Creating mutable matrix slices from `&mut [T]`
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
MatrixSliceMutMN<'a, T, R, C, RStride, CStride> MatrixSliceMutMN<'a, T, R, C, RStride, CStride>
{ {
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
@ -215,7 +217,7 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
} }
} }
impl<'a, T, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances. /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
/// ///
/// # Safety /// # Safety
@ -245,7 +247,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
macro_rules! impl_constructors_mut( macro_rules! impl_constructors_mut(
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<'a, T, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> { impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> {
/// Creates a new mutable matrix slice from the given data array. /// Creates a new mutable matrix slice from the given data array.
/// ///
/// Panics if `data` does not contain enough elements. /// Panics if `data` does not contain enough elements.
@ -261,7 +263,7 @@ macro_rules! impl_constructors_mut(
} }
} }
impl<'a, T, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> { impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> {
/// Creates a new mutable matrix slice with the specified strides from the given data array. /// Creates a new mutable matrix slice with the specified strides from the given data array.
/// ///
/// Panics if `data` does not contain enough elements. /// Panics if `data` does not contain enough elements.

View File

@ -1,10 +1,8 @@
use std::borrow::{Borrow, BorrowMut};
use std::convert::{AsMut, AsRef, From, Into};
use std::mem::{self, ManuallyDrop, MaybeUninit};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
use simba::scalar::{SubsetOf, SupersetOf}; use simba::scalar::{SubsetOf, SupersetOf};
use std::borrow::{Borrow, BorrowMut};
use std::convert::{AsMut, AsRef, From, Into};
use simba::simd::{PrimitiveSimdValue, SimdValue}; use simba::simd::{PrimitiveSimdValue, SimdValue};
@ -16,7 +14,7 @@ use crate::base::dimension::{
Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
}; };
use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
use crate::base::{ use crate::base::{
ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice, ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
MatrixSliceMut, OMatrix, Scalar, MatrixSliceMut, OMatrix, Scalar,
@ -26,12 +24,17 @@ use crate::base::{DVector, VecStorage};
use crate::base::{SliceStorage, SliceStorageMut}; use crate::base::{SliceStorage, SliceStorageMut};
use crate::constraint::DimEq; use crate::constraint::DimEq;
use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector}; use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector};
use std::mem::MaybeUninit;
// TODO: too bad this won't work for slice conversions. // TODO: too bad this won't work for slice conversions.
impl<T1, T2, R1: Dim, C1: Dim, R2: Dim, C2: Dim> SubsetOf<OMatrix<T2, R2, C2>> impl<T1, T2, R1, C1, R2, C2> SubsetOf<OMatrix<T2, R2, C2>> for OMatrix<T1, R1, C1>
for OMatrix<T1, R1, C1>
where where
T2: SupersetOf<T1>, R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
T1: Scalar,
T2: Scalar + SupersetOf<T1>,
DefaultAllocator: DefaultAllocator:
Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>, Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
@ -41,11 +44,11 @@ where
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
let nrows2 = R2::from_usize(nrows); let nrows2 = R2::from_usize(nrows);
let ncols2 = C2::from_usize(ncols); let ncols2 = C2::from_usize(ncols);
let mut res = Matrix::uninit(nrows2, ncols2);
let mut res = Matrix::new_uninitialized_generic(nrows2, ncols2);
for i in 0..nrows { for i in 0..nrows {
for j in 0..ncols { for j in 0..ncols {
// Safety: all indices are in range.
unsafe { unsafe {
*res.get_unchecked_mut((i, j)) = *res.get_unchecked_mut((i, j)) =
MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j)))); MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
@ -53,7 +56,7 @@ where
} }
} }
// Safety: all entries have been initialized. // Safety: res is now fully initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
@ -67,23 +70,25 @@ where
let (nrows2, ncols2) = m.shape(); let (nrows2, ncols2) = m.shape();
let nrows = R1::from_usize(nrows2); let nrows = R1::from_usize(nrows2);
let ncols = C1::from_usize(ncols2); let ncols = C1::from_usize(ncols2);
let mut res = Matrix::uninit(nrows, ncols);
let mut res = OMatrix::new_uninitialized_generic(nrows, ncols);
for i in 0..nrows2 { for i in 0..nrows2 {
for j in 0..ncols2 { for j in 0..ncols2 {
// Safety: all indices are in range.
unsafe { unsafe {
*res.get_unchecked_mut((i, j)) = *res.get_unchecked_mut((i, j)) =
MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked()); MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked())
} }
} }
} }
// Safety: all entries have been initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
} }
impl<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Matrix<T, R, C, S> { impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> IntoIterator
for &'a Matrix<T, R, C, S>
{
type Item = &'a T; type Item = &'a T;
type IntoIter = MatrixIter<'a, T, R, C, S>; type IntoIter = MatrixIter<'a, T, R, C, S>;
@ -93,7 +98,9 @@ impl<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Matrix<T,
} }
} }
impl<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IntoIterator for &'a mut Matrix<T, R, C, S> { impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IntoIterator
for &'a mut Matrix<T, R, C, S>
{
type Item = &'a mut T; type Item = &'a mut T;
type IntoIter = MatrixIterMut<'a, T, R, C, S>; type IntoIter = MatrixIterMut<'a, T, R, C, S>;
@ -103,35 +110,32 @@ impl<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IntoIterator for &'a mut Mat
} }
} }
impl<T, const D: usize> From<[T; D]> for SVector<T, D> { impl<T: Scalar, const D: usize> From<[T; D]> for SVector<T, D> {
#[inline] #[inline]
fn from(arr: [T; D]) -> Self { fn from(arr: [T; D]) -> Self {
Self::from_data(ArrayStorage([arr; 1])) unsafe { Self::from_data_statically_unchecked(ArrayStorage([arr; 1])) }
} }
} }
impl<T, const D: usize> From<SVector<T, D>> for [T; D] { impl<T: Scalar, const D: usize> From<SVector<T, D>> for [T; D] {
#[inline] #[inline]
fn from(vec: SVector<T, D>) -> Self { fn from(vec: SVector<T, D>) -> Self {
let data = ManuallyDrop::new(vec.data.0); // TODO: unfortunately, we must clone because we can move out of an array.
// Safety: [[T; D]; 1] always has the same data layout as [T; D]. vec.data.0[0].clone()
let res = unsafe { (data.as_ptr() as *const [_; D]).read() };
mem::forget(data);
res
} }
} }
impl<T: Clone, const D: usize> From<[T; D]> for RowSVector<T, D> impl<T: Scalar, const D: usize> From<[T; D]> for RowSVector<T, D>
where where
Const<D>: IsNotStaticOne, Const<D>: IsNotStaticOne,
{ {
#[inline] #[inline]
fn from(arr: [T; D]) -> Self { fn from(arr: [T; D]) -> Self {
SVector::<T, D>::from(arr).transpose_into() SVector::<T, D>::from(arr).transpose()
} }
} }
impl<T: Clone, const D: usize> From<RowSVector<T, D>> for [T; D] impl<T: Scalar, const D: usize> From<RowSVector<T, D>> for [T; D]
where where
Const<D>: IsNotStaticOne, Const<D>: IsNotStaticOne,
{ {
@ -144,10 +148,11 @@ where
macro_rules! impl_from_into_asref_1D( macro_rules! impl_from_into_asref_1D(
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S> impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
where where T: Scalar,
S: ContiguousStorage<T, $NRows, $NCols> { S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline] #[inline]
fn as_ref(&self) -> &[T; $SZ] { fn as_ref(&self) -> &[T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe { unsafe {
&*(self.data.ptr() as *const [T; $SZ]) &*(self.data.ptr() as *const [T; $SZ])
} }
@ -155,10 +160,11 @@ macro_rules! impl_from_into_asref_1D(
} }
impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S> impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
where where T: Scalar,
S: ContiguousStorageMut<T, $NRows, $NCols> { S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [T; $SZ] { fn as_mut(&mut self) -> &mut [T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe { unsafe {
&mut *(self.data.ptr_mut() as *mut [T; $SZ]) &mut *(self.data.ptr_mut() as *mut [T; $SZ])
} }
@ -182,14 +188,14 @@ impl_from_into_asref_1D!(
(U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16; (U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16;
); );
impl<T, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T, R, C> { impl<T: Scalar, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T, R, C> {
#[inline] #[inline]
fn from(arr: [[T; R]; C]) -> Self { fn from(arr: [[T; R]; C]) -> Self {
Self::from_data(ArrayStorage(arr)) unsafe { Self::from_data_statically_unchecked(ArrayStorage(arr)) }
} }
} }
impl<T, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] { impl<T: Scalar, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] {
#[inline] #[inline]
fn from(vec: SMatrix<T, R, C>) -> Self { fn from(vec: SMatrix<T, R, C>) -> Self {
vec.data.0 vec.data.0
@ -203,20 +209,22 @@ macro_rules! impl_from_into_asref_borrow_2D(
($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr); ($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident() $Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
) => { ) => {
impl<T, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S> impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorage<T, $NRows, $NCols> { where S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline] #[inline]
fn $ref(&self) -> &[[T; $SZRows]; $SZCols] { fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe { unsafe {
&*(self.data.ptr() as *const [[T; $SZRows]; $SZCols]) &*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
} }
} }
} }
impl<T, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S> impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorageMut<T, $NRows, $NCols> { where S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline] #[inline]
fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] { fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe { unsafe {
&mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols]) &mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
} }
@ -244,9 +252,13 @@ impl_from_into_asref_borrow_2D!(
(U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6); (U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6);
); );
impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize> impl<'a, T, RStride, CStride, const R: usize, const C: usize>
From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>> From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>>
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>> for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
where
T: Scalar,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
@ -254,9 +266,13 @@ impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T, C, RStride, CStride> From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>> for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
where
T: Scalar,
C: Dim,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
@ -264,18 +280,26 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim> impl<'a, T, R, RStride, CStride> From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>> for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
where
T: Scalar,
R: DimName,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
} }
} }
impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize> impl<'a, T, RStride, CStride, const R: usize, const C: usize>
From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>> From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>>
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>> for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
where
T: Scalar,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
@ -283,9 +307,13 @@ impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T, C, RStride, CStride> From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>> for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
where
T: Scalar,
C: Dim,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
@ -293,26 +321,37 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim> impl<'a, T, R, RStride, CStride> From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>> for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
where
T: Scalar,
R: DimName,
RStride: Dim,
CStride: Dim,
{ {
fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self { fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self {
matrix_slice.into_owned() matrix_slice.into_owned()
} }
} }
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S> impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix<T, R, C, S>>
From<&'a Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
where where
S: Storage<T, R, C>, T: Scalar,
R: Dim,
C: Dim,
RSlice: Dim,
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: RawStorage<T, R, C>,
ShapeConstraint: DimEq<R, RSlice> ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice> + DimEq<C, CSlice>
+ DimEq<RStride, S::RStride> + DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>, + DimEq<CStride, S::CStride>,
{ {
fn from(m: &'a Matrix<T, R, C, S>) -> Self { fn from(m: &'a Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape(); let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value()); let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value()); let col_slice = CSlice::from_usize(col.value());
@ -327,23 +366,29 @@ where
(row_slice, col_slice), (row_slice, col_slice),
(rstride_slice, cstride_slice), (rstride_slice, cstride_slice),
); );
Matrix::from_data_statically_unchecked(data)
Self::from_data(data)
} }
} }
} }
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S> impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
From<&'a mut Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
where where
S: Storage<T, R, C>, T: Scalar,
R: Dim,
C: Dim,
RSlice: Dim,
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: RawStorage<T, R, C>,
ShapeConstraint: DimEq<R, RSlice> ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice> + DimEq<C, CSlice>
+ DimEq<RStride, S::RStride> + DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>, + DimEq<CStride, S::CStride>,
{ {
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self { fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape(); let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value()); let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value()); let col_slice = CSlice::from_usize(col.value());
@ -358,23 +403,29 @@ where
(row_slice, col_slice), (row_slice, col_slice),
(rstride_slice, cstride_slice), (rstride_slice, cstride_slice),
); );
Matrix::from_data_statically_unchecked(data)
Matrix::from_data(data)
} }
} }
} }
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S> impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
From<&'a mut Matrix<T, R, C, S>> for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride> for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
where where
S: StorageMut<T, R, C>, T: Scalar,
R: Dim,
C: Dim,
RSlice: Dim,
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: RawStorageMut<T, R, C>,
ShapeConstraint: DimEq<R, RSlice> ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice> + DimEq<C, CSlice>
+ DimEq<RStride, S::RStride> + DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>, + DimEq<CStride, S::CStride>,
{ {
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self { fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape(); let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value()); let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value()); let col_slice = CSlice::from_usize(col.value());
@ -389,22 +440,21 @@ where
(row_slice, col_slice), (row_slice, col_slice),
(rstride_slice, cstride_slice), (rstride_slice, cstride_slice),
); );
Matrix::from_data_statically_unchecked(data)
Matrix::from_data(data)
} }
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T> From<Vec<T>> for DVector<T> { impl<'a, T: Scalar> From<Vec<T>> for DVector<T> {
#[inline] #[inline]
fn from(vec: Vec<T>) -> Self { fn from(vec: Vec<T>) -> Self {
Self::from_vec(vec) Self::from_vec(vec)
} }
} }
impl<'a, T, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> From<&'a Matrix<T, R, C, S>> impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage<T, R, C> + IsContiguous>
for &'a [T] From<&'a Matrix<T, R, C, S>> for &'a [T]
{ {
#[inline] #[inline]
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self { fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
@ -412,8 +462,8 @@ impl<'a, T, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> From<&'a Matrix<T, R,
} }
} }
impl<'a, T, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> From<&'a mut Matrix<T, R, C, S>> impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut<T, R, C> + IsContiguous>
for &'a mut [T] From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
{ {
#[inline] #[inline]
fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self { fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self {
@ -421,27 +471,27 @@ impl<'a, T, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> From<&'a mut Matri
} }
} }
impl<'a, T> From<&'a [T]> for DVectorSlice<'a, T> { impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> {
#[inline] #[inline]
fn from(slice: &'a [T]) -> Self { fn from(slice: &'a [T]) -> Self {
Self::from_slice(slice, slice.len()) Self::from_slice(slice, slice.len())
} }
} }
impl<'a, T> From<DVectorSlice<'a, T>> for &'a [T] { impl<'a, T: Scalar> From<DVectorSlice<'a, T>> for &'a [T] {
fn from(vec: DVectorSlice<'a, T>) -> &'a [T] { fn from(vec: DVectorSlice<'a, T>) -> &'a [T] {
vec.data.into_slice() vec.data.into_slice()
} }
} }
impl<'a, T> From<&'a mut [T]> for DVectorSliceMut<'a, T> { impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
#[inline] #[inline]
fn from(slice: &'a mut [T]) -> Self { fn from(slice: &'a mut [T]) -> Self {
Self::from_slice(slice, slice.len()) Self::from_slice(slice, slice.len())
} }
} }
impl<'a, T> From<DVectorSliceMut<'a, T>> for &'a mut [T] { impl<'a, T: Scalar> From<DVectorSliceMut<'a, T>> for &'a mut [T] {
fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] { fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] {
vec.data.into_slice_mut() vec.data.into_slice_mut()
} }
@ -456,7 +506,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self { fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self {
let (nrows, ncols) = arr[0].data.shape(); let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| { Self::from_fn_generic(nrows, ncols, |i, j| {
[ [
@ -477,7 +527,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self { fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self {
let (nrows, ncols) = arr[0].data.shape(); let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| { Self::from_fn_generic(nrows, ncols, |i, j| {
[ [
@ -500,7 +550,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self { fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self {
let (nrows, ncols) = arr[0].data.shape(); let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| { Self::from_fn_generic(nrows, ncols, |i, j| {
[ [
@ -526,7 +576,7 @@ where
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{ {
fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self { fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self {
let (nrows, ncols) = arr[0].data.shape(); let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| { Self::from_fn_generic(nrows, ncols, |i, j| {
[ [

View File

@ -7,8 +7,8 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut}; use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
use crate::base::Matrix; use crate::base::{Matrix, Scalar};
/* /*
* *
@ -23,7 +23,7 @@ macro_rules! coords_impl(
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
pub struct $T<T> { pub struct $T<T: Scalar> {
$(pub $comps: T),* $(pub $comps: T),*
} }
} }
@ -31,20 +31,22 @@ macro_rules! coords_impl(
macro_rules! deref_impl( macro_rules! deref_impl(
($R: ty, $C: ty; $Target: ident) => { ($R: ty, $C: ty; $Target: ident) => {
impl<T, S> Deref for Matrix<T, $R, $C, S> impl<T: Scalar, S> Deref for Matrix<T, $R, $C, S>
where S: ContiguousStorage<T, $R, $C> { where S: RawStorage<T, $R, $C> + IsContiguous {
type Target = $Target<T>; type Target = $Target<T>;
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
// Safety: this is OK because of the IsContiguous trait.
unsafe { &*(self.data.ptr() as *const Self::Target) } unsafe { &*(self.data.ptr() as *const Self::Target) }
} }
} }
impl<T, S> DerefMut for Matrix<T, $R, $C, S> impl<T: Scalar, S> DerefMut for Matrix<T, $R, $C, S>
where S: ContiguousStorageMut<T, $R, $C> { where S: RawStorageMut<T, $R, $C> + IsContiguous {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: this is OK because of the IsContiguous trait.
unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) } unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) }
} }
} }

View File

@ -4,72 +4,50 @@
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time. //! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
use std::cmp; use std::cmp;
use std::fmt; use std::mem;
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::ptr; use std::ptr;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
use super::Const;
use crate::base::allocator::{Allocator, Reallocator};
use crate::base::array_storage::ArrayStorage;
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic; use crate::base::dimension::Dynamic;
use super::Const;
use crate::base::allocator::{Allocator, InnerAllocator, Reallocator};
use crate::base::array_storage::ArrayStorage;
use crate::base::dimension::{Dim, DimName}; use crate::base::dimension::{Dim, DimName};
use crate::base::storage::{ use crate::base::storage::{RawStorage, RawStorageMut};
ContiguousStorage, ContiguousStorageMut, InnerOwned, Storage, StorageMut, #[cfg(any(feature = "std", feature = "alloc"))]
};
use crate::base::vec_storage::VecStorage; use crate::base::vec_storage::VecStorage;
use crate::U1; use crate::base::Scalar;
use std::mem::{ManuallyDrop, MaybeUninit};
/* /*
* *
* Allocator. * Allocator.
* *
*/ */
/// A helper struct that controls how the storage for a matrix should be allocated.
///
/// This struct is useless on its own. Instead, it's used in trait
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized /// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
/// matrices respectively. /// matrices respectively.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct DefaultAllocator; pub struct DefaultAllocator;
// Static - Static // Static - Static
impl<T, const R: usize, const C: usize> InnerAllocator<T, Const<R>, Const<C>> for DefaultAllocator { impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
for DefaultAllocator
{
type Buffer = ArrayStorage<T, R, C>; type Buffer = ArrayStorage<T, R, C>;
type BufferUninit = ArrayStorage<MaybeUninit<T>, R, C>;
#[inline] #[inline]
fn allocate_from_iterator<I: IntoIterator<Item = T>>( unsafe fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> MaybeUninit<Self::Buffer> {
nrows: Const<R>, mem::MaybeUninit::<Self::Buffer>::uninit()
ncols: Const<C>,
iter: I,
) -> Self::Buffer {
let mut res = Self::allocate_uninitialized(nrows, ncols);
let mut count = 0;
for (res, e) in res.as_mut_slice().iter_mut().zip(iter.into_iter()) {
*res = MaybeUninit::new(e);
count += 1;
} }
assert!(
count == nrows.value() * ncols.value(),
"Matrix init. from iterator: iterator not long enough."
);
// Safety: we have initialized all entries.
unsafe { <Self as Allocator<T, Const<R>, Const<C>>>::assume_init(res) }
}
}
impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for DefaultAllocator {
#[inline] #[inline]
fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> { fn allocate_uninit(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> {
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
let array = unsafe { MaybeUninit::uninit().assume_init() }; let array: [[MaybeUninit<T>; R]; C] = unsafe { MaybeUninit::uninit().assume_init() };
ArrayStorage(array) ArrayStorage(array)
} }
@ -83,41 +61,53 @@ impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for Def
ArrayStorage((&uninit as *const _ as *const [_; C]).read()) ArrayStorage((&uninit as *const _ as *const [_; C]).read())
} }
/// Specifies that a given buffer's entries should be manually dropped.
#[inline] #[inline]
fn manually_drop(buf: ArrayStorage<T, R, C>) -> ArrayStorage<ManuallyDrop<T>, R, C> { fn allocate_from_iterator<I: IntoIterator<Item = T>>(
// SAFETY: nrows: Const<R>,
// * `ManuallyDrop<T>` and T are guaranteed to have the same layout ncols: Const<C>,
// * `ManuallyDrop` does not drop, so there are no double-frees iter: I,
// And thus the conversion is safe ) -> Self::Buffer {
unsafe { ArrayStorage((&ManuallyDrop::new(buf) as *const _ as *const [_; C]).read()) } #[cfg(feature = "no_unsound_assume_init")]
let mut res: Self::Buffer = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols).assume_init() };
let mut count = 0;
// Safety: this is OK because the Buffer is known to be contiguous.
let res_slice = unsafe { res.as_mut_slice_unchecked() };
for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) {
*res = e;
count += 1;
}
assert!(
count == nrows.value() * ncols.value(),
"Matrix init. from iterator: iterator not long enough."
);
res
} }
} }
// Dynamic - Static // Dynamic - Static
// Dynamic - Dynamic // Dynamic - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, C: Dim> InnerAllocator<T, Dynamic, C> for DefaultAllocator { impl<T: Scalar, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
type Buffer = VecStorage<T, Dynamic, C>; type Buffer = VecStorage<T, Dynamic, C>;
type BufferUninit = VecStorage<MaybeUninit<T>, Dynamic, C>;
#[inline] #[inline]
fn allocate_from_iterator<I: IntoIterator<Item = T>>( unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> MaybeUninit<Self::Buffer> {
nrows: Dynamic, let mut res = Vec::new();
ncols: C, let length = nrows.value() * ncols.value();
iter: I, res.reserve_exact(length);
) -> Self::Buffer { res.set_len(length);
let it = iter.into_iter();
let res: Vec<T> = it.collect();
assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
VecStorage::new(nrows, ncols, res) mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
}
} }
impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
#[inline] #[inline]
fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> VecStorage<MaybeUninit<T>, Dynamic, C> { fn allocate_uninit(nrows: Dynamic, ncols: C) -> VecStorage<MaybeUninit<T>, Dynamic, C> {
let mut data = Vec::new(); let mut data = Vec::new();
let length = nrows.value() * ncols.value(); let length = nrows.value() * ncols.value();
data.reserve_exact(length); data.reserve_exact(length);
@ -143,32 +133,10 @@ impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
VecStorage::new(nrows, ncols, new_data) VecStorage::new(nrows, ncols, new_data)
} }
#[inline]
fn manually_drop(buf: VecStorage<T, Dynamic, C>) -> VecStorage<ManuallyDrop<T>, Dynamic, C> {
// Avoids a double-drop.
let (nrows, ncols) = buf.shape();
let vec: Vec<_> = buf.into();
let mut md = ManuallyDrop::new(vec);
// Safety:
// - ManuallyDrop<T> has the same alignment and layout as T.
// - The length and capacity come from a valid vector.
let new_data =
unsafe { Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()) };
VecStorage::new(nrows, ncols, new_data)
}
}
// Static - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T, R: DimName> InnerAllocator<T, R, Dynamic> for DefaultAllocator {
type Buffer = VecStorage<T, R, Dynamic>;
#[inline] #[inline]
fn allocate_from_iterator<I: IntoIterator<Item = T>>( fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: R, nrows: Dynamic,
ncols: Dynamic, ncols: C,
iter: I, iter: I,
) -> Self::Buffer { ) -> Self::Buffer {
let it = iter.into_iter(); let it = iter.into_iter();
@ -180,9 +148,24 @@ impl<T, R: DimName> InnerAllocator<T, R, Dynamic> for DefaultAllocator {
} }
} }
impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator { // Static - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Scalar, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
type Buffer = VecStorage<T, R, Dynamic>;
type BufferUninit = VecStorage<MaybeUninit<T>, R, Dynamic>;
#[inline] #[inline]
fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> VecStorage<MaybeUninit<T>, R, Dynamic> { unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> MaybeUninit<Self::Buffer> {
let mut res = Vec::new();
let length = nrows.value() * ncols.value();
res.reserve_exact(length);
res.set_len(length);
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
}
#[inline]
fn allocate_uninit(nrows: R, ncols: Dynamic) -> VecStorage<MaybeUninit<T>, R, Dynamic> {
let mut data = Vec::new(); let mut data = Vec::new();
let length = nrows.value() * ncols.value(); let length = nrows.value() * ncols.value();
data.reserve_exact(length); data.reserve_exact(length);
@ -209,253 +192,59 @@ impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
} }
#[inline] #[inline]
fn manually_drop(buf: VecStorage<T, R, Dynamic>) -> VecStorage<ManuallyDrop<T>, R, Dynamic> { fn allocate_from_iterator<I: IntoIterator<Item = T>>(
// Avoids a double-drop. nrows: R,
let (nrows, ncols) = buf.shape(); ncols: Dynamic,
let vec: Vec<_> = buf.into(); iter: I,
let mut md = ManuallyDrop::new(vec); ) -> Self::Buffer {
let it = iter.into_iter();
let res: Vec<T> = it.collect();
assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
// Safety: VecStorage::new(nrows, ncols, res)
// - ManuallyDrop<T> has the same alignment and layout as T.
// - The length and capacity come from a valid vector.
let new_data =
unsafe { Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()) };
VecStorage::new(nrows, ncols, new_data)
} }
} }
/// The owned storage type for a matrix.
#[repr(transparent)]
pub struct Owned<T, R: Dim, C: Dim>(pub InnerOwned<T, R, C>)
where
DefaultAllocator: InnerAllocator<T, R, C>;
impl<T: Copy, R: Dim, C: Dim> Copy for Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
InnerOwned<T, R, C>: Copy,
{
}
impl<T: Clone, R: Dim, C: Dim> Clone for Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
{
fn clone(&self) -> Self {
if Self::is_array() {
// We first clone the data.
let slice = unsafe { self.as_slice_unchecked() };
let vec = ManuallyDrop::new(slice.to_owned());
// We then transmute it back into an array and then an Owned.
unsafe { mem::transmute_copy(&*vec.as_ptr()) }
} else {
// We first clone the data.
let clone = ManuallyDrop::new(self.as_vec_storage().clone());
// We then transmute it back into an Owned.
unsafe { mem::transmute_copy(&clone) }
}
// TODO: check that the auxiliary copies are elided.
}
}
impl<T: fmt::Debug, R: Dim, C: Dim> fmt::Debug for Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if Self::is_array() {
let slice = unsafe { self.as_slice_unchecked() };
slice.fmt(f)
} else {
self.as_vec_storage().fmt(f)
}
}
}
impl<T, const R: usize, const C: usize> Owned<T, Const<R>, Const<C>> {
fn new(array: [[T; R]; C]) -> Self {
Self(ArrayStorage(array))
}
}
impl<T, R: Dim, C: Dim> Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
{
/// Returns whether `Self` stores an [`ArrayStorage`]. This is a zero-cost
/// operation.
const fn is_array() -> bool {
R::is_static() && C::is_static()
}
/// Returns whether `Self` stores a [`VecStorage`].
const fn is_vec() -> bool {
!Self::is_array()
}
/// Returns a reference to the underlying [`VecStorage`].
///
/// # Panics
/// This method will panic if `Self` does not contain a [`VecStorage`].
fn as_vec_storage(&self) -> &VecStorage<T, R, C> {
assert!(Self::is_vec());
// Safety: `self` is transparent and must contain a `VecStorage`.
unsafe { &*(self as *const _ as *const _) }
}
/// Returns a mutable reference to the underlying [`VecStorage`].
///
/// # Panics
/// This method will panic if `Self` does not contain a [`VecStorage`].
fn as_vec_storage_mut(&mut self) -> &mut VecStorage<T, R, C> {
assert!(Self::is_vec());
// Safety: `self` is transparent and must contain a `VecStorage`.
unsafe { &mut *(self as *mut _ as *mut _) }
}
}
unsafe impl<T, R: Dim, C: Dim> Storage<T, R, C> for Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
{
type RStride = U1;
type CStride = R;
fn ptr(&self) -> *const T {
if Self::is_array() {
&self as *const _ as *const T
} else {
self.as_vec_storage().as_vec().as_ptr()
}
}
fn shape(&self) -> (R, C) {
if Self::is_array() {
(R::default(), C::default())
} else {
let vec = self.as_vec_storage();
(vec.nrows, vec.ncols)
}
}
fn strides(&self) -> (Self::RStride, Self::CStride) {
if Self::is_array() {
(U1::name(), R::default())
} else {
let vec = self.as_vec_storage();
(U1::name(), vec.nrows)
}
}
#[inline(always)]
fn is_contiguous(&self) -> bool {
true
}
unsafe fn as_slice_unchecked(&self) -> &[T] {
if Self::is_array() {
std::slice::from_raw_parts(
self.ptr(),
R::try_to_usize().unwrap() * C::try_to_usize().unwrap(),
)
} else {
self.as_vec_storage().as_vec().as_ref()
}
}
#[inline(always)]
fn into_owned(self) -> Self {
self
}
#[inline(always)]
fn clone_owned(&self) -> Self
where
T: Clone,
{
self.clone()
}
}
unsafe impl<T, R: Dim, C: Dim> StorageMut<T, R, C> for Owned<T, R, C>
where
DefaultAllocator: InnerAllocator<T, R, C>,
{
fn ptr_mut(&mut self) -> *mut T {
if Self::is_array() {
&mut self as *mut _ as *mut T
} else {
self.as_vec_storage_mut().as_vec().as_ptr()
}
}
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
if Self::is_array() {
std::slice::from_raw_parts(
self.ptr_mut(),
R::try_to_usize().unwrap() * C::try_to_usize().unwrap(),
)
} else {
self.as_vec_storage_mut().as_vec_mut().as_mut()
}
}
}
unsafe impl<T, R: Dim, C: Dim> ContiguousStorage<T, R, C> for Owned<T, R, C> where
DefaultAllocator: InnerAllocator<T, R, C>
{
}
unsafe impl<T, R: Dim, C: Dim> ContiguousStorageMut<T, R, C> for Owned<T, R, C> where
DefaultAllocator: InnerAllocator<T, R, C>
{
}
/* /*
* *
* Reallocator. * Reallocator.
* *
*/ */
// Anything -> Static × Static // Anything -> Static × Static
impl<T, RFrom: Dim, CFrom: Dim, const RTO: usize, const CTO: usize> impl<T: Scalar, RFrom, CFrom, const RTO: usize, const CTO: usize>
Reallocator<T, RFrom, CFrom, Const<RTO>, Const<CTO>> for DefaultAllocator Reallocator<T, RFrom, CFrom, Const<RTO>, Const<CTO>> for DefaultAllocator
where where
RFrom: Dim,
CFrom: Dim,
Self: Allocator<T, RFrom, CFrom>, Self: Allocator<T, RFrom, CFrom>,
{ {
#[inline] #[inline]
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: Const<RTO>, rto: Const<RTO>,
cto: Const<CTO>, cto: Const<CTO>,
buf: InnerOwned<T, RFrom, CFrom>, buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> ArrayStorage<T, RTO, CTO> { ) -> ArrayStorage<T, RTO, CTO> {
#[cfg(feature = "no_unsound_assume_init")]
let mut res: ArrayStorage<T, RTO, CTO> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res = let mut res =
<Self as Allocator<_, Const<RTO>, Const<CTO>>>::allocate_uninitialized(rto, cto); <Self as Allocator<T, Const<RTO>, Const<CTO>>>::allocate_uninitialized(rto, cto)
.assume_init();
let (rfrom, cfrom) = buf.shape(); let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value(); let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value(); let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
// Safety: TODO res
<Self as Allocator<_, Const<RTO>, Const<CTO>>>::assume_init(res)
} }
} }
// Static × Static -> Dynamic × Any // Static × Static -> Dynamic × Any
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, CTo, const RFROM: usize, const CFROM: usize> impl<T: Scalar, CTo, const RFROM: usize, const CFROM: usize>
Reallocator<T, Const<RFROM>, Const<CFROM>, Dynamic, CTo> for DefaultAllocator Reallocator<T, Const<RFROM>, Const<CFROM>, Dynamic, CTo> for DefaultAllocator
where where
CTo: Dim, CTo: Dim,
@ -466,25 +255,25 @@ where
cto: CTo, cto: CTo,
buf: ArrayStorage<T, RFROM, CFROM>, buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<T, Dynamic, CTo> { ) -> VecStorage<T, Dynamic, CTo> {
let mut res = <Self as Allocator<T, Dynamic, CTo>>::allocate_uninitialized(rto, cto); #[cfg(feature = "no_unsound_assume_init")]
let mut res: VecStorage<T, Dynamic, CTo> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res =
<Self as Allocator<T, Dynamic, CTo>>::allocate_uninitialized(rto, cto).assume_init();
let (rfrom, cfrom) = buf.shape(); let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value(); let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value(); let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
<Self as Allocator<T, Dynamic, CTo>>::assume_init(res) res
} }
} }
// Static × Static -> Static × Dynamic // Static × Static -> Static × Dynamic
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, RTo, const RFROM: usize, const CFROM: usize> impl<T: Scalar, RTo, const RFROM: usize, const CFROM: usize>
Reallocator<T, Const<RFROM>, Const<CFROM>, RTo, Dynamic> for DefaultAllocator Reallocator<T, Const<RFROM>, Const<CFROM>, RTo, Dynamic> for DefaultAllocator
where where
RTo: DimName, RTo: DimName,
@ -495,25 +284,27 @@ where
cto: Dynamic, cto: Dynamic,
buf: ArrayStorage<T, RFROM, CFROM>, buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<T, RTo, Dynamic> { ) -> VecStorage<T, RTo, Dynamic> {
let mut res = <Self as Allocator<T, RTo, Dynamic>>::allocate_uninitialized(rto, cto); #[cfg(feature = "no_unsound_assume_init")]
let mut res: VecStorage<T, RTo, Dynamic> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res =
<Self as Allocator<T, RTo, Dynamic>>::allocate_uninitialized(rto, cto).assume_init();
let (rfrom, cfrom) = buf.shape(); let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value(); let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value(); let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
<Self as Allocator<T, RTo, Dynamic>>::assume_init(res) res
} }
} }
// All conversion from a dynamic buffer to a dynamic buffer. // All conversion from a dynamic buffer to a dynamic buffer.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo> for DefaultAllocator { impl<T: Scalar, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo>
for DefaultAllocator
{
#[inline] #[inline]
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: Dynamic, rto: Dynamic,
@ -526,7 +317,7 @@ impl<T, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo> for D
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic> impl<T: Scalar, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
for DefaultAllocator for DefaultAllocator
{ {
#[inline] #[inline]
@ -541,7 +332,7 @@ impl<T, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo> impl<T: Scalar, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
for DefaultAllocator for DefaultAllocator
{ {
#[inline] #[inline]
@ -556,7 +347,7 @@ impl<T, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dynamic, RTo, Dynamic> impl<T: Scalar, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dynamic, RTo, Dynamic>
for DefaultAllocator for DefaultAllocator
{ {
#[inline] #[inline]

View File

@ -2,7 +2,7 @@
//! Traits and tags for identifying the dimension of all algebraic entities. //! Traits and tags for identifying the dimension of all algebraic entities.
use std::any::TypeId; use std::any::{Any, TypeId};
use std::cmp; use std::cmp;
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};
@ -11,8 +11,8 @@ use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned}
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Stores the dimension of dynamically-sized algebraic entities. /// Dim of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug)] #[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Dynamic { pub struct Dynamic {
value: usize, value: usize,
} }
@ -55,7 +55,7 @@ impl IsNotStaticOne for Dynamic {}
/// Trait implemented by any type that can be used as a dimension. This includes type-level /// Trait implemented by any type that can be used as a dimension. This includes type-level
/// integers and `Dynamic` (for dimensions not known at compile-time). /// integers and `Dynamic` (for dimensions not known at compile-time).
pub trait Dim: 'static + Debug + Copy + Default + PartialEq + Send + Sync { pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync {
#[inline(always)] #[inline(always)]
fn is<D: Dim>() -> bool { fn is<D: Dim>() -> bool {
TypeId::of::<Self>() == TypeId::of::<D>() TypeId::of::<Self>() == TypeId::of::<D>()
@ -65,16 +65,6 @@ pub trait Dim: 'static + Debug + Copy + Default + PartialEq + Send + Sync {
/// Dynamic`. /// Dynamic`.
fn try_to_usize() -> Option<usize>; fn try_to_usize() -> Option<usize>;
/// Returns whether `Self` has a known compile-time value.
fn is_static() -> bool {
Self::try_to_usize().is_some()
}
/// Returns whether `Self` does not have a known compile-time value.
fn is_dynamic() -> bool {
Self::try_to_usize().is_none()
}
/// Gets the run-time value of `self`. For type-level integers, this is the same as /// Gets the run-time value of `self`. For type-level integers, this is the same as
/// `Self::try_to_usize().unwrap()`. /// `Self::try_to_usize().unwrap()`.
fn value(&self) -> usize; fn value(&self) -> usize;
@ -206,10 +196,7 @@ dim_ops!(
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
); );
/// A wrapper around const types, which provides the capability of performing #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// type-level arithmetic. This might get removed if const-generics become
/// more powerful in the future.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
pub struct Const<const R: usize>; pub struct Const<const R: usize>;
/// Trait implemented exclusively by type-level integers. /// Trait implemented exclusively by type-level integers.

View File

@ -2,9 +2,6 @@ use num::{One, Zero};
use std::cmp; use std::cmp;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use std::iter::ExactSizeIterator; use std::iter::ExactSizeIterator;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::mem;
use std::mem::MaybeUninit;
use std::ptr; use std::ptr;
use crate::base::allocator::{Allocator, Reallocator}; use crate::base::allocator::{Allocator, Reallocator};
@ -12,8 +9,10 @@ use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, Shap
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::dimension::Dynamic; use crate::base::dimension::Dynamic;
use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1}; use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
use crate::base::storage::{ContiguousStorageMut, ReshapableStorage, Storage, StorageMut}; use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage};
use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector}; use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
use crate::Storage;
use std::mem::MaybeUninit;
/// # Rows and columns extraction /// # Rows and columns extraction
impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
@ -50,11 +49,11 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where where
I: IntoIterator<Item = &'a usize>, I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator + Clone, I::IntoIter: ExactSizeIterator + Clone,
DefaultAllocator: Allocator<T, Dynamic, C>,
{ {
let irows = irows.into_iter(); let irows = irows.into_iter();
let ncols = self.data.shape().1; let ncols = self.shape_generic().1;
let mut res = let mut res = Matrix::uninit(Dynamic::new(irows.len()), ncols);
OMatrix::<T, Dynamic, C>::new_uninitialized_generic(Dynamic::new(irows.len()), ncols);
// First, check that all the indices from irows are valid. // First, check that all the indices from irows are valid.
// This will allow us to use unchecked access in the inner loop. // This will allow us to use unchecked access in the inner loop.
@ -68,13 +67,15 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
let src = self.column(j); let src = self.column(j);
for (destination, source) in irows.clone().enumerate() { for (destination, source) in irows.clone().enumerate() {
// Safety: all indices are in range.
unsafe { unsafe {
*res.vget_unchecked_mut(destination) = *res.vget_unchecked_mut(destination) =
MaybeUninit::new(src.vget_unchecked(*source).clone()); MaybeUninit::new(src.vget_unchecked(*source).inlined_clone());
} }
} }
} }
// Safety: res is now fully initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
@ -88,32 +89,30 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, R, Dynamic>, DefaultAllocator: Allocator<T, R, Dynamic>,
{ {
let icols = icols.into_iter(); let icols = icols.into_iter();
let nrows = self.data.shape().0; let nrows = self.shape_generic().0;
let mut res = Matrix::new_uninitialized_generic(nrows, Dynamic::new(icols.len())); let mut res = Matrix::uninit(nrows, Dynamic::new(icols.len()));
for (destination, source) in icols.enumerate() { for (destination, source) in icols.enumerate() {
for (d, s) in res // NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit.
.column_mut(destination) res.column_mut(destination)
.iter_mut() .zip_apply(&self.column(*source), |out, e| {
.zip(self.column(*source).iter()) *out = MaybeUninit::new(e.inlined_clone())
{ });
*d = MaybeUninit::new(s.clone());
}
} }
// Safety: res is now fully initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
} }
/// # Set rows, columns, and diagonal /// # Set rows, columns, and diagonal
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Fills the diagonal of this matrix with the content of the given vector. /// Fills the diagonal of this matrix with the content of the given vector.
#[inline] #[inline]
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>) pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
where where
T: Clone,
R: DimMin<C>, R: DimMin<C>,
S2: Storage<T, R2>, S2: RawStorage<T, R2>,
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>, ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
{ {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
@ -121,7 +120,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions."); assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
for i in 0..min_nrows_ncols { for i in 0..min_nrows_ncols {
unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone() } unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).inlined_clone() }
} }
} }
@ -144,8 +143,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>) pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
where where
T: Clone, S2: RawStorage<T, U1, C2>,
S2: Storage<T, U1, C2>,
ShapeConstraint: SameNumberOfColumns<C, C2>, ShapeConstraint: SameNumberOfColumns<C, C2>,
{ {
self.row_mut(i).copy_from(row); self.row_mut(i).copy_from(row);
@ -155,8 +153,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>) pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
where where
T: Clone, S2: RawStorage<T, R2, U1>,
S2: Storage<T, R2, U1>,
ShapeConstraint: SameNumberOfRows<R, R2>, ShapeConstraint: SameNumberOfRows<R, R2>,
{ {
self.column_mut(i).copy_from(column); self.column_mut(i).copy_from(column);
@ -164,23 +161,23 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
} }
/// # In-place filling /// # In-place filling
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Sets all the elements of this matrix to the value returned by the closure.
#[inline]
pub fn fill_with(&mut self, val: impl Fn() -> T) {
for e in self.iter_mut() {
*e = val()
}
}
/// Sets all the elements of this matrix to `val`. /// Sets all the elements of this matrix to `val`.
#[inline] #[inline]
pub fn fill(&mut self, val: T) pub fn fill(&mut self, val: T)
where where
T: Clone, T: Scalar,
{ {
for e in self.iter_mut() { for e in self.iter_mut() {
*e = val.clone() *e = val.inlined_clone()
}
}
/// Sets all the elements of this matrix to `f()`.
#[inline]
pub fn fill_fn<F: FnMut() -> T>(&mut self, mut f: F) {
for e in self.iter_mut() {
*e = f();
} }
} }
@ -188,7 +185,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_with_identity(&mut self) pub fn fill_with_identity(&mut self)
where where
T: Zero + One + Scalar, T: Scalar + Zero + One,
{ {
self.fill(T::zero()); self.fill(T::zero());
self.fill_diagonal(T::one()); self.fill_diagonal(T::one());
@ -198,13 +195,13 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_diagonal(&mut self, val: T) pub fn fill_diagonal(&mut self, val: T)
where where
T: Clone, T: Scalar,
{ {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
let n = cmp::min(nrows, ncols); let n = cmp::min(nrows, ncols);
for i in 0..n { for i in 0..n {
unsafe { *self.get_unchecked_mut((i, i)) = val.clone() } unsafe { *self.get_unchecked_mut((i, i)) = val.inlined_clone() }
} }
} }
@ -212,11 +209,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_row(&mut self, i: usize, val: T) pub fn fill_row(&mut self, i: usize, val: T)
where where
T: Clone, T: Scalar,
{ {
assert!(i < self.nrows(), "Row index out of bounds."); assert!(i < self.nrows(), "Row index out of bounds.");
for j in 0..self.ncols() { for j in 0..self.ncols() {
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
} }
} }
@ -224,11 +221,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_column(&mut self, j: usize, val: T) pub fn fill_column(&mut self, j: usize, val: T)
where where
T: Clone, T: Scalar,
{ {
assert!(j < self.ncols(), "Row index out of bounds."); assert!(j < self.ncols(), "Row index out of bounds.");
for i in 0..self.nrows() { for i in 0..self.nrows() {
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
} }
} }
@ -242,11 +239,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_lower_triangle(&mut self, val: T, shift: usize) pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
where where
T: Clone, T: Scalar,
{ {
for j in 0..self.ncols() { for j in 0..self.ncols() {
for i in (j + shift)..self.nrows() { for i in (j + shift)..self.nrows() {
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
} }
} }
} }
@ -261,19 +258,19 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn fill_upper_triangle(&mut self, val: T, shift: usize) pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
where where
T: Clone, T: Scalar,
{ {
for j in shift..self.ncols() { for j in shift..self.ncols() {
// TODO: is there a more efficient way to avoid the min ? // TODO: is there a more efficient way to avoid the min ?
// (necessary for rectangular matrices) // (necessary for rectangular matrices)
for i in 0..cmp::min(j + 1 - shift, self.nrows()) { for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
} }
} }
} }
} }
impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> { impl<T: Scalar, D: Dim, S: RawStorageMut<T, D, D>> Matrix<T, D, D, S> {
/// Copies the upper-triangle of this matrix to its lower-triangular part. /// Copies the upper-triangle of this matrix to its lower-triangular part.
/// ///
/// This makes the matrix symmetric. Panics if the matrix is not square. /// This makes the matrix symmetric. Panics if the matrix is not square.
@ -284,7 +281,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
for j in 0..dim { for j in 0..dim {
for i in j + 1..dim { for i in j + 1..dim {
unsafe { unsafe {
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone(); *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
} }
} }
} }
@ -299,7 +296,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
for j in 1..self.ncols() { for j in 1..self.ncols() {
for i in 0..j { for i in 0..j {
unsafe { unsafe {
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone(); *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
} }
} }
} }
@ -307,7 +304,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
} }
/// # In-place swapping /// # In-place swapping
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Swaps two rows in-place. /// Swaps two rows in-place.
#[inline] #[inline]
pub fn swap_rows(&mut self, irow1: usize, irow2: usize) { pub fn swap_rows(&mut self, irow1: usize, irow2: usize) {
@ -343,7 +340,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
* *
*/ */
/// # Rows and columns removal /// # Rows and columns removal
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/* /*
* *
* Column removal. * Column removal.
@ -367,7 +364,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>, DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
{ {
let mut m = self.into_owned(); let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let mut offset: usize = 0; let mut offset: usize = 0;
let mut target: usize = 0; let mut target: usize = 0;
while offset + target < ncols.value() { while offset + target < ncols.value() {
@ -401,7 +398,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>, DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
{ {
let mut m = self.into_owned(); let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let mut offset: usize = 0; let mut offset: usize = 0;
let mut target: usize = 0; let mut target: usize = 0;
while offset + target < nrows.value() * ncols.value() { while offset + target < nrows.value() * ncols.value() {
@ -464,7 +461,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>, DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>,
{ {
let mut m = self.into_owned(); let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
assert!( assert!(
i + nremove.value() <= ncols.value(), i + nremove.value() <= ncols.value(),
"Column index out of range." "Column index out of range."
@ -543,7 +540,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>, DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>,
{ {
let mut m = self.into_owned(); let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
assert!( assert!(
i + nremove.value() <= nrows.value(), i + nremove.value() <= nrows.value(),
"Row index out of range." "Row index out of range."
@ -552,7 +549,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
if nremove.value() != 0 { if nremove.value() != 0 {
unsafe { unsafe {
compress_rows( compress_rows(
&mut m.data.as_mut_slice(), &mut m.as_mut_slice(),
nrows.value(), nrows.value(),
ncols.value(), ncols.value(),
i, i,
@ -572,7 +569,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
} }
/// # Rows and columns insertion /// # Rows and columns insertion
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/* /*
* *
* Columns insertion. * Columns insertion.
@ -633,7 +630,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>, DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>,
{ {
let m = self.into_owned(); let m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows, nrows,
ncols.add(ninsert), ncols.add(ninsert),
@ -717,7 +714,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>, DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>,
{ {
let m = self.into_owned(); let m = self.into_owned();
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.shape_generic();
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows.add(ninsert), nrows.add(ninsert),
ncols, ncols,
@ -728,7 +725,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
if ninsert.value() != 0 { if ninsert.value() != 0 {
extend_rows( extend_rows(
&mut res.data.as_mut_slice(), &mut res.as_mut_slice(),
nrows.value(), nrows.value(),
ncols.value(), ncols.value(),
i, i,
@ -741,7 +738,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
} }
/// # Resizing and reshaping /// # Resizing and reshaping
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns. /// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns.
/// ///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
@ -763,7 +760,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where where
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>, DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
{ {
let ncols = self.data.shape().1; let ncols = self.shape_generic().1;
self.resize_generic(Dynamic::new(new_nrows), ncols, val) self.resize_generic(Dynamic::new(new_nrows), ncols, val)
} }
@ -776,7 +773,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where where
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>, DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
{ {
let nrows = self.data.shape().0; let nrows = self.shape_generic().0;
self.resize_generic(nrows, Dynamic::new(new_ncols), val) self.resize_generic(nrows, Dynamic::new(new_ncols), val)
} }
@ -809,10 +806,10 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R2, C2>, DefaultAllocator: Reallocator<T, R, C, R2, C2>,
{ {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
let mut data = self.data.into_owned(); let mut data = self.into_owned();
if new_nrows.value() == nrows { if new_nrows.value() == nrows {
let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.0) }; let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.data) };
let mut res = Matrix::from_data(res); let mut res = Matrix::from_data(res);
if new_ncols.value() > ncols { if new_ncols.value() > ncols {
res.columns_range_mut(ncols..).fill(val); res.columns_range_mut(ncols..).fill(val);
@ -832,14 +829,14 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
nrows - new_nrows.value(), nrows - new_nrows.value(),
); );
res = Matrix::from_data(DefaultAllocator::reallocate_copy( res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data.0, new_nrows, new_ncols, data.data,
)); ));
} else { } else {
res = Matrix::from_data(DefaultAllocator::reallocate_copy( res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data.0, new_nrows, new_ncols, data.data,
)); ));
extend_rows( extend_rows(
&mut res.data.as_mut_slice(), &mut res.as_mut_slice(),
nrows, nrows,
new_ncols.value(), new_ncols.value(),
nrows, nrows,
@ -849,7 +846,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
} }
if new_ncols.value() > ncols { if new_ncols.value() > ncols {
res.columns_range_mut(ncols..).fill(val.clone()); res.columns_range_mut(ncols..).fill(val.inlined_clone());
} }
if new_nrows.value() > nrows { if new_nrows.value() > nrows {
@ -931,7 +928,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// # In-place resizing /// # In-place resizing
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Clone> OMatrix<T, Dynamic, Dynamic> { impl<T: Scalar> OMatrix<T, Dynamic, Dynamic> {
/// Resizes this matrix in-place. /// Resizes this matrix in-place.
/// ///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
@ -942,20 +939,13 @@ impl<T: Clone> OMatrix<T, Dynamic, Dynamic> {
where where
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>, DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
{ {
// IMPORTANT TODO: this method is still UB, and we should decide how to // TODO: avoid the clone.
// update the API to take it into account. *self = self.clone().resize(new_nrows, new_ncols, val);
let placeholder = unsafe {
Matrix::new_uninitialized_generic(Dynamic::new(0), Dynamic::new(0)).assume_init()
};
let old = mem::replace(self, placeholder);
let new = old.resize(new_nrows, new_ncols, val);
let _ = mem::replace(self, new);
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Clone, C: Dim> OMatrix<T, Dynamic, C> impl<T: Scalar, C: Dim> OMatrix<T, Dynamic, C>
where where
DefaultAllocator: Allocator<T, Dynamic, C>, DefaultAllocator: Allocator<T, Dynamic, C>,
{ {
@ -970,16 +960,13 @@ where
where where
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>, DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
{ {
let placeholder = // TODO: avoid the clone.
Matrix::from_fn_generic(Dynamic::new(0), self.data.shape().1, |_, _| val.clone()); *self = self.clone().resize_vertically(new_nrows, val);
let old = mem::replace(self, placeholder);
let new = old.resize_vertically(new_nrows, val);
let _ = mem::replace(self, new);
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Clone, R: Dim> OMatrix<T, R, Dynamic> impl<T: Scalar, R: Dim> OMatrix<T, R, Dynamic>
where where
DefaultAllocator: Allocator<T, R, Dynamic>, DefaultAllocator: Allocator<T, R, Dynamic>,
{ {
@ -994,15 +981,18 @@ where
where where
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>, DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
{ {
let placeholder = // TODO: avoid the clone.
Matrix::from_fn_generic(self.data.shape().0, Dynamic::new(0), |_, _| val.clone()); *self = self.clone().resize_horizontally(new_ncols, val);
let old = mem::replace(self, placeholder);
let new = old.resize_horizontally(new_ncols, val);
let _ = mem::replace(self, new);
} }
} }
unsafe fn compress_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, nremove: usize) { unsafe fn compress_rows<T: Scalar>(
data: &mut [T],
nrows: usize,
ncols: usize,
i: usize,
nremove: usize,
) {
let new_nrows = nrows - nremove; let new_nrows = nrows - nremove;
if new_nrows == 0 || ncols == 0 { if new_nrows == 0 || ncols == 0 {
@ -1035,7 +1025,13 @@ unsafe fn compress_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize,
// Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index. // Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index.
// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements. // The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements.
unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, ninsert: usize) { unsafe fn extend_rows<T: Scalar>(
data: &mut [T],
nrows: usize,
ncols: usize,
i: usize,
ninsert: usize,
) {
let new_nrows = nrows + ninsert; let new_nrows = nrows + ninsert;
if new_nrows == 0 || ncols == 0 { if new_nrows == 0 || ncols == 0 {
@ -1065,7 +1061,12 @@ unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, n
/// Extend the number of columns of the `Matrix` with elements from /// Extend the number of columns of the `Matrix` with elements from
/// a given iterator. /// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, R: Dim, S: Extend<T>> Extend<T> for Matrix<T, R, Dynamic, S> { impl<T, R, S> Extend<T> for Matrix<T, R, Dynamic, S>
where
T: Scalar,
R: Dim,
S: Extend<T>,
{
/// Extend the number of columns of the `Matrix` with elements /// Extend the number of columns of the `Matrix` with elements
/// from the given iterator. /// from the given iterator.
/// ///
@ -1110,6 +1111,7 @@ impl<T, R: Dim, S: Extend<T>> Extend<T> for Matrix<T, R, Dynamic, S> {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, S> Extend<T> for Matrix<T, Dynamic, U1, S> impl<T, S> Extend<T> for Matrix<T, Dynamic, U1, S>
where where
T: Scalar,
S: Extend<T>, S: Extend<T>,
{ {
/// Extend the number of rows of a `Vector` with elements /// Extend the number of rows of a `Vector` with elements
@ -1128,10 +1130,13 @@ where
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<T, R: Dim, S, RV: Dim, SV> Extend<Vector<T, RV, SV>> for Matrix<T, R, Dynamic, S> impl<T, R, S, RV, SV> Extend<Vector<T, RV, SV>> for Matrix<T, R, Dynamic, S>
where where
T: Scalar,
R: Dim,
S: Extend<Vector<T, RV, SV>>, S: Extend<Vector<T, RV, SV>>,
SV: Storage<T, RV>, RV: Dim,
SV: RawStorage<T, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>, ShapeConstraint: SameNumberOfRows<R, RV>,
{ {
/// Extends the number of columns of a `Matrix` with `Vector`s /// Extends the number of columns of a `Matrix` with `Vector`s

View File

@ -1,8 +1,8 @@
//! Indexing //! Indexing
use crate::base::storage::{Storage, StorageMut}; use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::{ use crate::base::{
Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, U1, Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1,
}; };
use std::ops; use std::ops;
@ -310,7 +310,7 @@ fn dimrange_rangetoinclusive_usize() {
} }
/// A helper trait used for indexing operations. /// A helper trait used for indexing operations.
pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized { pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>>: Sized {
/// The output type returned by methods. /// The output type returned by methods.
type Output: 'a; type Output: 'a;
@ -345,7 +345,7 @@ pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized {
} }
/// A helper trait used for indexing operations. /// A helper trait used for indexing operations.
pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>>: pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>>:
MatrixIndex<'a, T, R, C, S> MatrixIndex<'a, T, R, C, S>
{ {
/// The output type returned by methods. /// The output type returned by methods.
@ -476,7 +476,7 @@ pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>>:
/// 4, 7, /// 4, 7,
/// 5, 8))); /// 5, 8)));
/// ``` /// ```
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a view of the data at the given index, or /// Produces a view of the data at the given index, or
/// `None` if the index is out of bounds. /// `None` if the index is out of bounds.
#[inline] #[inline]
@ -494,7 +494,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use] #[must_use]
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut> pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
where where
S: StorageMut<T, R, C>, S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>, I: MatrixIndexMut<'a, T, R, C, S>,
{ {
index.get_mut(self) index.get_mut(self)
@ -516,7 +516,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where where
S: StorageMut<T, R, C>, S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>, I: MatrixIndexMut<'a, T, R, C, S>,
{ {
index.index_mut(self) index.index_mut(self)
@ -539,7 +539,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use] #[must_use]
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where where
S: StorageMut<T, R, C>, S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>, I: MatrixIndexMut<'a, T, R, C, S>,
{ {
index.get_unchecked_mut(self) index.get_unchecked_mut(self)
@ -548,9 +548,12 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
// EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS // EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndex<'a, T, R, C, S> for usize impl<'a, T, R, C, S> MatrixIndex<'a, T, R, C, S> for usize
where where
S: Storage<T, R, C>, T: Scalar,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
type Output = &'a T; type Output = &'a T;
@ -567,9 +570,12 @@ where
} }
} }
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndexMut<'a, T, R, C, S> for usize impl<'a, T, R, C, S> MatrixIndexMut<'a, T, R, C, S> for usize
where where
S: StorageMut<T, R, C>, T: Scalar,
R: Dim,
C: Dim,
S: RawStorageMut<T, R, C>,
{ {
type OutputMut = &'a mut T; type OutputMut = &'a mut T;
@ -577,7 +583,7 @@ where
#[inline(always)] #[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where where
S: StorageMut<T, R, C>, S: RawStorageMut<T, R, C>,
{ {
matrix.data.get_unchecked_linear_mut(self) matrix.data.get_unchecked_linear_mut(self)
} }
@ -585,9 +591,11 @@ where
// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES // EXTRACT A SINGLE ELEMENT BY 2D COORDINATES
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndex<'a, T, R, C, S> for (usize, usize) impl<'a, T: 'a, R, C, S> MatrixIndex<'a, T, R, C, S> for (usize, usize)
where where
S: Storage<T, R, C>, R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{ {
type Output = &'a T; type Output = &'a T;
@ -595,7 +603,7 @@ where
#[inline(always)] #[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool { fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool {
let (rows, cols) = self; let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols) DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
} }
@ -607,9 +615,11 @@ where
} }
} }
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize) impl<'a, T: 'a, R, C, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize)
where where
S: StorageMut<T, R, C>, R: Dim,
C: Dim,
S: RawStorageMut<T, R, C>,
{ {
type OutputMut = &'a mut T; type OutputMut = &'a mut T;
@ -617,7 +627,7 @@ where
#[inline(always)] #[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where where
S: StorageMut<T, R, C>, S: RawStorageMut<T, R, C>,
{ {
let (row, col) = self; let (row, col) = self;
matrix.data.get_unchecked_mut(row, col) matrix.data.get_unchecked_mut(row, col)
@ -643,10 +653,12 @@ macro_rules! impl_index_pair {
$(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*] $(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*]
) => ) =>
{ {
impl<'a, T: 'a, $R: Dim, $C: Dim, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
where where
S: Storage<T, R, C>, T: Scalar,
$R: Dim,
$C: Dim,
S: RawStorage<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{ {
@ -656,7 +668,7 @@ macro_rules! impl_index_pair {
#[inline(always)] #[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool { fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool {
let (rows, cols) = self; let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols) DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
} }
@ -666,21 +678,23 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorage; use crate::base::SliceStorage;
let (rows, cols) = self; let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let data = let data =
SliceStorage::new_unchecked(&matrix.data, SliceStorage::new_unchecked(&matrix.data,
(rows.lower(nrows), cols.lower(ncols)), (rows.lower(nrows), cols.lower(ncols)),
(rows.length(nrows), cols.length(ncols))); (rows.length(nrows), cols.length(ncols)));
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
impl<'a, T: 'a, $R: Dim, $C: Dim, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
where where
S: StorageMut<T, R, C>, T: Scalar,
$R: Dim,
$C: Dim,
S: RawStorageMut<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{ {
@ -692,14 +706,14 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorageMut; use crate::base::SliceStorageMut;
let (rows, cols) = self; let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let data = let data =
SliceStorageMut::new_unchecked(&mut matrix.data, SliceStorageMut::new_unchecked(&mut matrix.data,
(rows.lower(nrows), cols.lower(ncols)), (rows.lower(nrows), cols.lower(ncols)),
(rows.length(nrows), cols.length(ncols))); (rows.length(nrows), cols.length(ncols)));
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
} }

View File

@ -5,12 +5,13 @@ use std::marker::PhantomData;
use std::mem; use std::mem;
use crate::base::dimension::{Dim, U1}; use crate::base::dimension::{Dim, U1};
use crate::base::storage::{Storage, StorageMut}; use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut}; use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar};
macro_rules! iterator { macro_rules! iterator {
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
/// An iterator through a dense matrix with arbitrary strides matrix. /// An iterator through a dense matrix with arbitrary strides matrix.
#[derive(Debug)]
pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> { pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
ptr: $Ptr, ptr: $Ptr,
inner_ptr: $Ptr, inner_ptr: $Ptr,
@ -170,8 +171,8 @@ macro_rules! iterator {
}; };
} }
iterator!(struct MatrixIter for Storage.ptr -> *const T, &'a T, &'a S); iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S);
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S); iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
/* /*
* *
@ -180,18 +181,18 @@ iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a
*/ */
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// An iterator through the rows of a matrix. /// An iterator through the rows of a matrix.
pub struct RowIter<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> { pub struct RowIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
mat: &'a Matrix<T, R, C, S>, mat: &'a Matrix<T, R, C, S>,
curr: usize, curr: usize,
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> RowIter<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> RowIter<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self { pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
RowIter { mat, curr: 0 } RowIter { mat, curr: 0 }
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> {
type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>; type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>;
#[inline] #[inline]
@ -219,7 +220,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIter<'a, T
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
for RowIter<'a, T, R, C, S> for RowIter<'a, T, R, C, S>
{ {
#[inline] #[inline]
@ -229,13 +230,14 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
} }
/// An iterator through the mutable rows of a matrix. /// An iterator through the mutable rows of a matrix.
pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> { #[derive(Debug)]
pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
mat: *mut Matrix<T, R, C, S>, mat: *mut Matrix<T, R, C, S>,
curr: usize, curr: usize,
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>, phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self { pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
RowIterMut { RowIterMut {
mat, mat,
@ -249,7 +251,9 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a, T, R, C,
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator for RowIterMut<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
for RowIterMut<'a, T, R, C, S>
{
type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>; type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>;
#[inline] #[inline]
@ -274,7 +278,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator for RowIterMut
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
for RowIterMut<'a, T, R, C, S> for RowIterMut<'a, T, R, C, S>
{ {
#[inline] #[inline]
@ -290,18 +294,18 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
*/ */
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// An iterator through the columns of a matrix. /// An iterator through the columns of a matrix.
pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> { pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
mat: &'a Matrix<T, R, C, S>, mat: &'a Matrix<T, R, C, S>,
curr: usize, curr: usize,
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ColumnIter<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ColumnIter<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self { pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
ColumnIter { mat, curr: 0 } ColumnIter { mat, curr: 0 }
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for ColumnIter<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for ColumnIter<'a, T, R, C, S> {
type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>;
#[inline] #[inline]
@ -329,7 +333,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for ColumnIter<'a
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
for ColumnIter<'a, T, R, C, S> for ColumnIter<'a, T, R, C, S>
{ {
#[inline] #[inline]
@ -339,13 +343,14 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
} }
/// An iterator through the mutable columns of a matrix. /// An iterator through the mutable columns of a matrix.
pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> { #[derive(Debug)]
pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
mat: *mut Matrix<T, R, C, S>, mat: *mut Matrix<T, R, C, S>,
curr: usize, curr: usize,
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>, phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self { pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
ColumnIterMut { ColumnIterMut {
mat, mat,
@ -359,7 +364,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'a, T, R,
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
for ColumnIterMut<'a, T, R, C, S> for ColumnIterMut<'a, T, R, C, S>
{ {
type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>;
@ -386,7 +391,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
} }
} }
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
for ColumnIterMut<'a, T, R, C, S> for ColumnIterMut<'a, T, R, C, S>
{ {
#[inline] #[inline]

File diff suppressed because it is too large Load Diff

View File

@ -9,9 +9,11 @@ use crate::base::{DefaultAllocator, OMatrix, Scalar};
* Simd structures. * Simd structures.
* *
*/ */
impl<T, R: Dim, C: Dim> SimdValue for OMatrix<T, R, C> impl<T, R, C> SimdValue for OMatrix<T, R, C>
where where
T: Scalar + SimdValue, T: Scalar + SimdValue,
R: Dim,
C: Dim,
T::Element: Scalar, T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{ {
@ -42,7 +44,6 @@ where
fn replace(&mut self, i: usize, val: Self::Element) { fn replace(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| { self.zip_apply(&val, |mut a, b| {
a.replace(i, b); a.replace(i, b);
a
}) })
} }
@ -50,7 +51,6 @@ where
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| { self.zip_apply(&val, |mut a, b| {
a.replace_unchecked(i, b); a.replace_unchecked(i, b);
a
}) })
} }

View File

@ -1,14 +1,13 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
use std::slice; use std::slice;
use crate::base::allocator::{Allocator, InnerAllocator}; use crate::base::allocator::Allocator;
use crate::base::default_allocator::DefaultAllocator; use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1}; use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1};
use crate::base::iter::MatrixIter; use crate::base::iter::MatrixIter;
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage};
use crate::base::{Matrix, Owned}; use crate::base::{Matrix, Scalar};
macro_rules! slice_storage_impl( macro_rules! slice_storage_impl(
($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => {
@ -82,7 +81,7 @@ macro_rules! slice_storage_impl(
impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
$T<'a, T, R, C, RStride, CStride> $T<'a, T, R, C, RStride, CStride>
where where
Self: ContiguousStorage<T, R, C> Self: RawStorage<T, R, C> + IsContiguous
{ {
/// Extracts the original slice from this storage /// Extracts the original slice from this storage
pub fn into_slice(self) -> &'a [T] { pub fn into_slice(self) -> &'a [T] {
@ -100,19 +99,19 @@ macro_rules! slice_storage_impl(
slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \ slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \
to another matrix data storage."; to another matrix data storage.";
Storage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T)); RawStorage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T));
slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \ slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \
internal mutable reference to another matrix data storage."; internal mutable reference to another matrix data storage.";
StorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T) RawStorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T)
); );
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
for SliceStorage<'a, T, R, C, RStride, CStride> for SliceStorage<'a, T, R, C, RStride, CStride>
{ {
} }
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
for SliceStorage<'a, T, R, C, RStride, CStride> for SliceStorage<'a, T, R, C, RStride, CStride>
{ {
#[inline] #[inline]
@ -126,10 +125,10 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
} }
} }
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
SliceStorageMut<'a, T, R, C, RStride, CStride> SliceStorageMut<'a, T, R, C, RStride, CStride>
where where
Self: ContiguousStorageMut<T, R, C>, Self: RawStorageMut<T, R, C> + IsContiguous,
{ {
/// Extracts the original slice from this storage /// Extracts the original slice from this storage
pub fn into_slice_mut(self) -> &'a mut [T] { pub fn into_slice_mut(self) -> &'a mut [T] {
@ -145,7 +144,7 @@ where
macro_rules! storage_impl( macro_rules! storage_impl(
($($T: ident),* $(,)*) => {$( ($($T: ident),* $(,)*) => {$(
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C> unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage<T, R, C>
for $T<'a, T, R, C, RStride, CStride> { for $T<'a, T, R, C, RStride, CStride> {
type RStride = RStride; type RStride = RStride;
@ -182,26 +181,6 @@ macro_rules! storage_impl(
} }
} }
#[inline]
fn into_owned(self) -> Owned<T, R, C>
where
T: Clone,
DefaultAllocator: Allocator<T, R, C>
{
self.clone_owned()
}
#[inline]
fn clone_owned(&self) -> Owned<T, R, C>
where
T: Clone,
DefaultAllocator: Allocator<T, R, C>
{
let (nrows, ncols) = self.shape();
let it = MatrixIter::new(self).cloned();
Owned( DefaultAllocator::allocate_from_iterator(nrows, ncols, it))
}
#[inline] #[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
@ -214,39 +193,29 @@ macro_rules! storage_impl(
} }
} }
} }
unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
for $T<'a, T, R, C, RStride, CStride> {
#[inline]
fn into_owned(self) -> Owned<T, R, C>
where DefaultAllocator: Allocator<T, R, C> {
self.clone_owned()
}
#[inline]
fn clone_owned(&self) -> Owned<T, R, C>
where DefaultAllocator: Allocator<T, R, C> {
let (nrows, ncols) = self.shape();
let it = MatrixIter::new(self).cloned();
DefaultAllocator::allocate_from_iterator(nrows, ncols, it)
}
}
)*} )*}
); );
storage_impl!(SliceStorage, SliceStorageMut); storage_impl!(SliceStorage, SliceStorageMut);
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut<T, R, C>
SliceStorage<'a, MaybeUninit<T>, R, C, RStride, CStride>
{
/// Assumes a slice storage's entries to be initialized. This operation
/// should be near zero-cost.
///
/// # Safety
/// All of the slice storage's entries must be initialized, otherwise
/// Undefined Behavior will be triggered.
pub unsafe fn assume_init(self) -> SliceStorage<'a, T, R, C, RStride, CStride> {
SliceStorage::from_raw_parts(self.ptr as *const T, self.shape, self.strides)
}
}
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
SliceStorageMut<'a, MaybeUninit<T>, R, C, RStride, CStride>
{
/// Assumes a slice storage's entries to be initialized. This operation should be near zero-cost.
///
/// # Safety
/// The user must make sure that every single entry of the buffer has been initialized,
/// or Undefined Behavior will immediately occur.
pub unsafe fn assume_init(self) -> SliceStorageMut<'a, T, R, C, RStride, CStride> {
SliceStorageMut::from_raw_parts(self.ptr as *mut T, self.shape, self.strides)
}
}
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<T, R, C>
for SliceStorageMut<'a, T, R, C, RStride, CStride> for SliceStorageMut<'a, T, R, C, RStride, CStride>
{ {
#[inline] #[inline]
@ -266,37 +235,22 @@ unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<T, R,
} }
} }
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1> unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for SliceStorage<'a, T, R, U1, U1, CStride> {}
for SliceStorage<'a, T, R, U1, U1, CStride> unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous
{
}
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1>
for SliceStorageMut<'a, T, R, U1, U1, CStride> for SliceStorageMut<'a, T, R, U1, U1, CStride>
{ {
} }
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorageMut<T, R, U1> unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
for SliceStorageMut<'a, T, R, U1, U1, CStride>
{
}
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
for SliceStorage<'a, T, R, C, U1, R> for SliceStorage<'a, T, R, C, U1, R>
{ {
} }
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
for SliceStorageMut<'a, T, R, C, U1, R> for SliceStorageMut<'a, T, R, C, U1, R>
{ {
} }
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<T, R, C> impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
for SliceStorageMut<'a, T, R, C, U1, R>
{
}
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[inline] #[inline]
fn assert_slice_index( fn assert_slice_index(
&self, &self,
@ -344,7 +298,6 @@ macro_rules! matrix_slice_impl(
$fixed_slice_with_steps: ident, $fixed_slice_with_steps: ident,
$generic_slice: ident, $generic_slice: ident,
$generic_slice_with_steps: ident, $generic_slice_with_steps: ident,
$full_slice: ident,
$rows_range_pair: ident, $rows_range_pair: ident,
$columns_range_pair: ident) => { $columns_range_pair: ident) => {
/* /*
@ -403,14 +356,14 @@ macro_rules! matrix_slice_impl(
pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice) pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice)
-> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> { -> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> {
let my_shape = $me.data.shape(); let my_shape = $me.shape_generic();
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0));
let shape = (nrows, my_shape.1); let shape = (nrows, my_shape.1);
unsafe { unsafe {
let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape); let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
@ -421,7 +374,7 @@ macro_rules! matrix_slice_impl(
-> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride> -> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
where RSlice: Dim { where RSlice: Dim {
let my_shape = $me.data.shape(); let my_shape = $me.shape_generic();
let my_strides = $me.data.strides(); let my_strides = $me.data.strides();
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0));
@ -430,7 +383,7 @@ macro_rules! matrix_slice_impl(
unsafe { unsafe {
let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
@ -491,23 +444,24 @@ macro_rules! matrix_slice_impl(
pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice) pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> { -> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> {
let my_shape = $me.data.shape(); let my_shape = $me.shape_generic();
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0));
let shape = (my_shape.0, ncols); let shape = (my_shape.0, ncols);
unsafe { unsafe {
let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); let data = $SliceStorage::new_unchecked($data, (0, first_col), shape);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
/// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may
/// or may not be values known at compile-time. /// or may not be values known at compile-time.
#[inline] #[inline]
pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize) pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> { -> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> {
let my_shape = $me.data.shape(); let my_shape = $me.shape_generic();
let my_strides = $me.data.strides(); let my_strides = $me.data.strides();
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step));
@ -517,7 +471,7 @@ macro_rules! matrix_slice_impl(
unsafe { unsafe {
let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
@ -537,10 +491,11 @@ macro_rules! matrix_slice_impl(
unsafe { unsafe {
let data = $SliceStorage::new_unchecked($data, start, shape); let data = $SliceStorage::new_unchecked($data, start, shape);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
/// Slices this matrix starting at its component `(start.0, start.1)` and with /// Slices this matrix starting at its component `(start.0, start.1)` and with
/// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is
/// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the
@ -564,7 +519,7 @@ macro_rules! matrix_slice_impl(
unsafe { unsafe {
let data = $SliceStorage::new_unchecked($data, (irow, icol), shape); let data = $SliceStorage::new_unchecked($data, (irow, icol), shape);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
@ -581,14 +536,16 @@ macro_rules! matrix_slice_impl(
/// Creates a slice that may or may not have a fixed size and stride. /// Creates a slice that may or may not have a fixed size and stride.
#[inline] #[inline]
pub fn $generic_slice<RSlice: Dim, CSlice: Dim>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
-> $MatrixSlice<T, RSlice, CSlice, S::RStride, S::CStride> -> $MatrixSlice<'_, T, RSlice, CSlice, S::RStride, S::CStride>
{ where RSlice: Dim,
CSlice: Dim {
$me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0)); $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0));
unsafe { unsafe {
let data = $SliceStorage::new_unchecked($data, start, shape); let data = $SliceStorage::new_unchecked($data, start, shape);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
@ -610,16 +567,10 @@ macro_rules! matrix_slice_impl(
unsafe { unsafe {
let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides); let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides);
Matrix::from_data(data) Matrix::from_data_statically_unchecked(data)
} }
} }
/// Returns a slice containing the entire matrix.
pub fn $full_slice($me: $Me) -> $MatrixSlice<T, R, C, S::RStride, S::CStride> {
let (nrows, ncols) = $me.shape();
$me.$generic_slice((0, 0), (R::from_usize(nrows), C::from_usize(ncols)))
}
/* /*
* *
* Splitting. * Splitting.
@ -633,7 +584,7 @@ macro_rules! matrix_slice_impl(
-> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>, -> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>,
$MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) { $MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) {
let (nrows, ncols) = $me.data.shape(); let (nrows, ncols) = $me.shape_generic();
let strides = $me.data.strides(); let strides = $me.data.strides();
let start1 = r1.begin(nrows); let start1 = r1.begin(nrows);
@ -654,8 +605,8 @@ macro_rules! matrix_slice_impl(
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides);
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides);
let slice1 = Matrix::from_data(data1); let slice1 = Matrix::from_data_statically_unchecked(data1);
let slice2 = Matrix::from_data(data2); let slice2 = Matrix::from_data_statically_unchecked(data2);
(slice1, slice2) (slice1, slice2)
} }
@ -669,7 +620,7 @@ macro_rules! matrix_slice_impl(
-> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>, -> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>,
$MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) { $MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) {
let (nrows, ncols) = $me.data.shape(); let (nrows, ncols) = $me.shape_generic();
let strides = $me.data.strides(); let strides = $me.data.strides();
let start1 = r1.begin(ncols); let start1 = r1.begin(ncols);
@ -690,8 +641,8 @@ macro_rules! matrix_slice_impl(
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides);
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides);
let slice1 = Matrix::from_data(data1); let slice1 = Matrix::from_data_statically_unchecked(data1);
let slice2 = Matrix::from_data(data2); let slice2 = Matrix::from_data_statically_unchecked(data2);
(slice1, slice2) (slice1, slice2)
} }
@ -707,9 +658,9 @@ pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> =
Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>; Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>;
/// # Slicing based on index and length /// # Slicing based on index and length
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
matrix_slice_impl!( matrix_slice_impl!(
self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data; self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data;
row, row,
row_part, row_part,
rows, rows,
@ -732,15 +683,14 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
fixed_slice_with_steps, fixed_slice_with_steps,
generic_slice, generic_slice,
generic_slice_with_steps, generic_slice_with_steps,
full_slice,
rows_range_pair, rows_range_pair,
columns_range_pair); columns_range_pair);
} }
/// # Mutable slicing based on index and length /// # Mutable slicing based on index and length
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
matrix_slice_impl!( matrix_slice_impl!(
self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut.get_address_unchecked_mut(), &mut self.data; self: &mut Self, MatrixSliceMut, SliceStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data;
row_mut, row_mut,
row_part_mut, row_part_mut,
rows_mut, rows_mut,
@ -763,29 +713,10 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
fixed_slice_with_steps_mut, fixed_slice_with_steps_mut,
generic_slice_mut, generic_slice_mut,
generic_slice_with_steps_mut, generic_slice_with_steps_mut,
full_slice_mut,
rows_range_pair_mut, rows_range_pair_mut,
columns_range_pair_mut); columns_range_pair_mut);
} }
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
MatrixSlice<'a, MaybeUninit<T>, R, C, RStride, CStride>
{
/// Assumes a matrix slices's entries to be initialized. This operation should be near zero-cost.
pub unsafe fn slice_assume_init(self) -> MatrixSlice<'a, T, R, C, RStride, CStride> {
Matrix::from_data(self.data.assume_init())
}
}
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
MatrixSliceMut<'a, MaybeUninit<T>, R, C, RStride, CStride>
{
/// Assumes a matrix slices's entries to be initialized. This operation should be near zero-cost.
pub unsafe fn slice_assume_init(self) -> MatrixSliceMut<'a, T, R, C, RStride, CStride> {
Matrix::from_data(self.data.assume_init())
}
}
/// A range with a size that may be known at compile-time. /// A range with a size that may be known at compile-time.
/// ///
/// This may be: /// This may be:
@ -922,7 +853,7 @@ impl<D: Dim> SliceRange<D> for RangeInclusive<usize> {
// TODO: see how much of this overlaps with the general indexing // TODO: see how much of this overlaps with the general indexing
// methods from indexing.rs. // methods from indexing.rs.
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
/// by the range `cols`. /// by the range `cols`.
#[inline] #[inline]
@ -936,7 +867,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
RowRange: SliceRange<R>, RowRange: SliceRange<R>,
ColRange: SliceRange<C>, ColRange: SliceRange<C>,
{ {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.shape_generic();
self.generic_slice( self.generic_slice(
(rows.begin(nrows), cols.begin(ncols)), (rows.begin(nrows), cols.begin(ncols)),
(rows.size(nrows), cols.size(ncols)), (rows.size(nrows), cols.size(ncols)),
@ -966,7 +897,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
// TODO: see how much of this overlaps with the general indexing // TODO: see how much of this overlaps with the general indexing
// methods from indexing.rs. // methods from indexing.rs.
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns
/// indexed by the range `cols`. /// indexed by the range `cols`.
pub fn slice_range_mut<RowRange, ColRange>( pub fn slice_range_mut<RowRange, ColRange>(
@ -978,7 +909,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
RowRange: SliceRange<R>, RowRange: SliceRange<R>,
ColRange: SliceRange<C>, ColRange: SliceRange<C>,
{ {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.shape_generic();
self.generic_slice_mut( self.generic_slice_mut(
(rows.begin(nrows), cols.begin(ncols)), (rows.begin(nrows), cols.begin(ncols)),
(rows.size(nrows), cols.size(ncols)), (rows.size(nrows), cols.size(ncols)),
@ -1004,9 +935,13 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
} }
} }
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T, R, C, RStride, CStride> From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
for MatrixSlice<'a, T, R, C, RStride, CStride> for MatrixSlice<'a, T, R, C, RStride, CStride>
where
R: Dim,
C: Dim,
RStride: Dim,
CStride: Dim,
{ {
fn from(slice_mut: MatrixSliceMut<'a, T, R, C, RStride, CStride>) -> Self { fn from(slice_mut: MatrixSliceMut<'a, T, R, C, RStride, CStride>) -> Self {
let data = SliceStorage { let data = SliceStorage {
@ -1016,6 +951,6 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
_phantoms: PhantomData, _phantoms: PhantomData,
}; };
Matrix::from_data(data) unsafe { Matrix::from_data_statically_unchecked(data) }
} }
} }

View File

@ -1,10 +1,10 @@
use crate::storage::Storage; use crate::storage::RawStorage;
use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector}; use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector};
use num::{Signed, Zero}; use num::{Signed, Zero};
use simba::simd::SimdSigned; use simba::simd::SimdSigned;
/// # Find the min and max components /// # Find the min and max components
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Returns the absolute value of the component with the largest absolute value. /// Returns the absolute value of the component with the largest absolute value.
/// # Example /// # Example
/// ``` /// ```
@ -167,7 +167,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
} }
} }
impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Computes the index of the matrix component with the largest absolute value. /// Computes the index of the matrix component with the largest absolute value.
/// ///
/// # Examples: /// # Examples:
@ -203,7 +203,7 @@ impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matri
// TODO: find a way to avoid code duplication just for complex number support. // TODO: find a way to avoid code duplication just for complex number support.
/// # Find the min and max components (vector-specific methods) /// # Find the min and max components (vector-specific methods)
impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> { impl<T: Scalar, D: Dim, S: RawStorage<T, D>> Vector<T, D, S> {
/// Computes the index of the vector component with the largest complex or real absolute value. /// Computes the index of the vector component with the largest complex or real absolute value.
/// ///
/// # Examples: /// # Examples:

View File

@ -33,10 +33,12 @@ mod unit;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
mod vec_storage; mod vec_storage;
mod blas_uninit;
#[doc(hidden)] #[doc(hidden)]
pub mod helper; pub mod helper;
mod interpolation; mod interpolation;
mod min_max; mod min_max;
pub mod uninit;
pub use self::matrix::*; pub use self::matrix::*;
pub use self::norm::*; pub use self::norm::*;
@ -50,5 +52,6 @@ pub use self::alias::*;
pub use self::alias_slice::*; pub use self::alias_slice::*;
pub use self::array_storage::*; pub use self::array_storage::*;
pub use self::matrix_slice::*; pub use self::matrix_slice::*;
pub use self::storage::*;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub use self::vec_storage::*; pub use self::vec_storage::*;

View File

@ -434,7 +434,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
{ {
let n = self.norm(); let n = self.norm();
let le = n.simd_le(min_norm); let le = n.simd_le(min_norm);
self.apply(|e| e.simd_unscale(n).select(le, e)); self.apply(|e| *e = e.simd_unscale(n).select(le, *e));
SimdOption::new(n, le) SimdOption::new(n, le)
} }
@ -508,13 +508,8 @@ where
/// The i-the canonical basis element. /// The i-the canonical basis element.
#[inline] #[inline]
fn canonical_basis_element(i: usize) -> Self { fn canonical_basis_element(i: usize) -> Self {
assert!(i < D::dim(), "Index out of bound.");
let mut res = Self::zero(); let mut res = Self::zero();
unsafe { res[i] = T::one();
*res.data.get_unchecked_linear_mut(i) = T::one();
}
res res
} }

View File

@ -1,29 +1,31 @@
use num::{One, Zero}; use num::{One, Zero};
use std::iter; use std::iter;
use std::mem::MaybeUninit;
use std::ops::{ use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
}; };
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use crate::base::allocator::{ use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
Allocator, InnerAllocator, SameShapeAllocator, SameShapeC, SameShapeR, use crate::base::blas_uninit::gemm_uninit;
};
use crate::base::constraint::{ use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
}; };
use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic}; use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut}; use crate::base::storage::{Storage, StorageMut};
use crate::base::uninit::Uninit;
use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice}; use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice};
use crate::{MatrixSliceMut, SimdComplexField}; use crate::storage::IsContiguous;
use crate::uninit::{Init, InitStatus};
use crate::{RawStorage, RawStorageMut, SimdComplexField};
use std::mem::MaybeUninit;
/* /*
* *
* Indexing. * Indexing.
* *
*/ */
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
type Output = T; type Output = T;
#[inline] #[inline]
@ -33,10 +35,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T, R, C, S>
} }
} }
impl<T, R: Dim, C: Dim, S> Index<(usize, usize)> for Matrix<T, R, C, S> impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<(usize, usize)> for Matrix<T, R, C, S> {
where
S: Storage<T, R, C>,
{
type Output = T; type Output = T;
#[inline] #[inline]
@ -52,7 +51,7 @@ where
} }
// Mutable versions. // Mutable versions.
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> { impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut T { fn index_mut(&mut self, i: usize) -> &mut T {
let ij = self.vector_to_matrix_index(i); let ij = self.vector_to_matrix_index(i);
@ -60,10 +59,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R,
} }
} }
impl<T, R: Dim, C: Dim, S> IndexMut<(usize, usize)> for Matrix<T, R, C, S> impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<(usize, usize)> for Matrix<T, R, C, S> {
where
S: StorageMut<T, R, C>,
{
#[inline] #[inline]
fn index_mut(&mut self, ij: (usize, usize)) -> &mut T { fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
let shape = self.shape(); let shape = self.shape();
@ -135,25 +131,27 @@ macro_rules! componentwise_binop_impl(
($Trait: ident, $method: ident, $bound: ident; ($Trait: ident, $method: ident, $bound: ident;
$TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident, $TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident,
$method_assign_statically_unchecked_rhs: ident; $method_assign_statically_unchecked_rhs: ident;
$method_to: ident, $method_to_statically_unchecked: ident) => { $method_to: ident, $method_to_statically_unchecked_uninit: ident) => {
impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA> impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
where where T: Scalar + $bound {
T: Scalar + $bound
{
/* /*
* *
* Methods without dimension checking at compile-time. * Methods without dimension checking at compile-time.
* This is useful for code reuse because the sum representative system does not play * This is useful for code reuse because the sum representative system does not plays
* nicely with static checks. * easily with static checks.
* *
*/ */
#[inline] #[inline]
fn $method_to_statically_unchecked<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( fn $method_to_statically_unchecked_uninit<Status, R2: Dim, C2: Dim, SB,
&self, rhs: &Matrix<T, R2, C2, SB>, out: &mut Matrix<MaybeUninit<T>, R3, C3, SC> R3: Dim, C3: Dim, SC>(&self,
) where status: Status,
SB: Storage<T, R2, C2>, rhs: &Matrix<T, R2, C2, SB>,
SC: StorageMut<MaybeUninit<T>, R3, C3> out: &mut Matrix<Status::Value, R3, C3, SC>)
{ where Status: InitStatus<T>,
SB: RawStorage<T, R2, C2>,
SC: RawStorageMut<Status::Value, R3, C3> {
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch."); assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
@ -165,29 +163,26 @@ macro_rules! componentwise_binop_impl(
let arr2 = rhs.data.as_slice_unchecked(); let arr2 = rhs.data.as_slice_unchecked();
let out = out.data.as_mut_slice_unchecked(); let out = out.data.as_mut_slice_unchecked();
for i in 0 .. arr1.len() { for i in 0 .. arr1.len() {
*out.get_unchecked_mut(i) = MaybeUninit::new( Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()));
arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()
));
} }
} else { } else {
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
*out.get_unchecked_mut((i, j)) = MaybeUninit::new( let val = self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone());
self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone()) Status::init(out.get_unchecked_mut((i, j)), val);
);
} }
} }
} }
} }
} }
#[inline] #[inline]
fn $method_assign_statically_unchecked<R2: Dim, C2: Dim, SB>( fn $method_assign_statically_unchecked<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
&mut self, rhs: &Matrix<T, R2, C2, SB> where R2: Dim,
) where C2: Dim,
SA: StorageMut<T, R1, C1>, SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2> SB: Storage<T, R2, C2> {
{
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
// This is the most common case and should be deduced at compile-time. // This is the most common case and should be deduced at compile-time.
@ -210,12 +205,12 @@ macro_rules! componentwise_binop_impl(
} }
} }
#[inline] #[inline]
fn $method_assign_statically_unchecked_rhs<R2: Dim, C2: Dim, SB>( fn $method_assign_statically_unchecked_rhs<R2, C2, SB>(&self, rhs: &mut Matrix<T, R2, C2, SB>)
&self, rhs: &mut Matrix<T, R2, C2, SB> where R2: Dim,
) where C2: Dim,
SB: StorageMut<T, R2, C2> SB: StorageMut<T, R2, C2> {
{
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
// This is the most common case and should be deduced at compile-time. // This is the most common case and should be deduced at compile-time.
@ -250,20 +245,15 @@ macro_rules! componentwise_binop_impl(
*/ */
/// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations. /// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations.
#[inline] #[inline]
pub fn $method_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( pub fn $method_to<R2: Dim, C2: Dim, SB,
&self, R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC> out: &mut Matrix<T, R3, C3, SC>)
) where where SB: Storage<T, R2, C2>,
SB: Storage<T, R2, C2>, SC: StorageMut<T, R3, C3>,
SC: StorageMut<MaybeUninit<T>, R3, C3>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
ShapeConstraint: SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
SameNumberOfRows<R1, R2> + self.$method_to_statically_unchecked_uninit(Init, rhs, out)
SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> +
SameNumberOfColumns<C1, C3>
{
self.$method_to_statically_unchecked(rhs, out)
} }
} }
@ -285,14 +275,13 @@ macro_rules! componentwise_binop_impl(
} }
} }
impl<'a, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA> impl<'a, T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
where where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound, T: Scalar + $bound,
SA: Storage<T, R1, C1>, SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>, DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>,
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> {
{
type Output = MatrixSum<T, R2, C2, R1, C1>; type Output = MatrixSum<T, R2, C2, R1, C1>;
#[inline] #[inline]
@ -304,14 +293,13 @@ macro_rules! componentwise_binop_impl(
} }
} }
impl<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA> impl<T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound, T: Scalar + $bound,
SA: Storage<T, R1, C1>, SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>, DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
{
type Output = MatrixSum<T, R1, C1, R2, C2>; type Output = MatrixSum<T, R1, C1, R2, C2>;
#[inline] #[inline]
@ -320,14 +308,13 @@ macro_rules! componentwise_binop_impl(
} }
} }
impl<'a, 'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA> impl<'a, 'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
where where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound, T: Scalar + $bound,
SA: Storage<T, R1, C1>, SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>, DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
{
type Output = MatrixSum<T, R1, C1, R2, C2>; type Output = MatrixSum<T, R1, C1, R2, C2>;
#[inline] #[inline]
@ -335,33 +322,33 @@ macro_rules! componentwise_binop_impl(
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows); let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols); let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
let mut res = Matrix::new_uninitialized_generic(nrows, ncols); let mut res = Matrix::uninit(nrows, ncols);
self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res);
self.$method_to_statically_unchecked(rhs, &mut res); // SAFETY: the output has been initialized above.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
} }
impl<'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA> impl<'b, T, R1, C1, R2, C2, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound, T: Scalar + $bound,
SA: StorageMut<T, R1, C1>, SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
{
#[inline] #[inline]
fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) { fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) {
self.$method_assign_statically_unchecked(rhs) self.$method_assign_statically_unchecked(rhs)
} }
} }
impl<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA> impl<T, R1, C1, R2, C2, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound, T: Scalar + $bound,
SA: StorageMut<T, R1, C1>, SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
{
#[inline] #[inline]
fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) { fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) {
self.$method_assign(&rhs) self.$method_assign(&rhs)
@ -372,10 +359,10 @@ macro_rules! componentwise_binop_impl(
componentwise_binop_impl!(Add, add, ClosedAdd; componentwise_binop_impl!(Add, add, ClosedAdd;
AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut; AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut;
add_to, add_to_statically_unchecked); add_to, add_to_statically_unchecked_uninit);
componentwise_binop_impl!(Sub, sub, ClosedSub; componentwise_binop_impl!(Sub, sub, ClosedSub;
SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut; SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut;
sub_to, sub_to_statically_unchecked); sub_to, sub_to_statically_unchecked_uninit);
impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C> impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C>
where where
@ -574,9 +561,12 @@ where
#[inline] #[inline]
fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output { fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
let mut res = Matrix::new_uninitialized_generic(self.data.shape().0, rhs.data.shape().1); let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1);
let _ = self.mul_to(rhs, &mut res); unsafe {
unsafe { res.assume_init() } // SAFETY: this is OK because status = Uninit && bevy == 0
gemm_uninit(Uninit, &mut res, T::one(), self, rhs, T::zero());
res.assume_init()
}
} }
} }
@ -634,14 +624,16 @@ where
// TODO: this is too restrictive: // TODO: this is too restrictive:
// we can't use `a *= b` when `a` is a mutable slice. // we can't use `a *= b` when `a` is a mutable slice.
// we can't use `a *= b` when C2 is not equal to C1. // we can't use `a *= b` when C2 is not equal to C1.
impl<T, R1: Dim, C1: Dim, R2: Dim, SA, SB> MulAssign<Matrix<T, R2, C1, SB>> impl<T, R1, C1, R2, SA, SB> MulAssign<Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
for Matrix<T, R1, C1, SA>
where where
R1: Dim,
C1: Dim,
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul, T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<T, R2, C1>, SB: Storage<T, R2, C1>,
SA: ContiguousStorageMut<T, R1, C1>, SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
DefaultAllocator: Allocator<T, R1, C1> + InnerAllocator<T, R1, C1, Buffer = SA>, DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: Matrix<T, R2, C1, SB>) { fn mul_assign(&mut self, rhs: Matrix<T, R2, C1, SB>) {
@ -649,15 +641,17 @@ where
} }
} }
impl<'b, T, R1: Dim, C1: Dim, R2: Dim, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>> impl<'b, T, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
for Matrix<T, R1, C1, SA>
where where
R1: Dim,
C1: Dim,
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul, T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<T, R2, C1>, SB: Storage<T, R2, C1>,
SA: ContiguousStorageMut<T, R1, C1>, SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
// TODO: this is too restrictive. See comments for the non-ref version. // TODO: this is too restrictive. See comments for the non-ref version.
DefaultAllocator: Allocator<T, R1, C1> + InnerAllocator<T, R1, C1, Buffer = SA>, DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) { fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) {
@ -680,8 +674,9 @@ where
DefaultAllocator: Allocator<T, C1, C2>, DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>, ShapeConstraint: SameNumberOfRows<R1, R2>,
{ {
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1); let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
self.tr_mul_to(rhs, &mut res); self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dot(b));
// SAFETY: this is OK because the result is now initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
@ -695,23 +690,26 @@ where
DefaultAllocator: Allocator<T, C1, C2>, DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>, ShapeConstraint: SameNumberOfRows<R1, R2>,
{ {
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1); let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
self.ad_mul_to(rhs, &mut res); self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dotc(b));
// SAFETY: this is OK because the result is now initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
#[inline(always)] #[inline(always)]
fn xx_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( fn xx_mul_to_uninit<Status, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self, &self,
status: Status,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>, out: &mut Matrix<Status::Value, R3, C3, SC>,
dot: impl Fn( dot: impl Fn(
&VectorSlice<'_, T, R1, SA::RStride, SA::CStride>, &VectorSlice<'_, T, R1, SA::RStride, SA::CStride>,
&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, &VectorSlice<'_, T, R2, SB::RStride, SB::CStride>,
) -> T, ) -> T,
) where ) where
SB: Storage<T, R2, C2>, Status: InitStatus<T>,
SC: StorageMut<MaybeUninit<T>, R3, C3>, SB: RawStorage<T, R2, C2>,
SC: RawStorageMut<Status::Value, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>, ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{ {
let (nrows1, ncols1) = self.shape(); let (nrows1, ncols1) = self.shape();
@ -740,9 +738,8 @@ where
for i in 0..ncols1 { for i in 0..ncols1 {
for j in 0..ncols2 { for j in 0..ncols2 {
let dot = dot(&self.column(i), &rhs.column(j)); let dot = dot(&self.column(i), &rhs.column(j));
unsafe { let elt = unsafe { out.get_unchecked_mut((i, j)) };
*out.get_unchecked_mut((i, j)) = MaybeUninit::new(dot); Status::init(elt, dot);
}
} }
} }
} }
@ -753,13 +750,13 @@ where
pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self, &self,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>, out: &mut Matrix<T, R3, C3, SC>,
) where ) where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>, SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>, ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{ {
self.xx_mul_to(rhs, out, |a, b| a.dot(b)) self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dot(b))
} }
/// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid /// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid
@ -768,31 +765,30 @@ where
pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self, &self,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>, out: &mut Matrix<T, R3, C3, SC>,
) where ) where
T: SimdComplexField, T: SimdComplexField,
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>, SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>, ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{ {
self.xx_mul_to(rhs, out, |a, b| a.dotc(b)) self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dotc(b))
} }
/// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations. /// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations.
#[inline] #[inline]
pub fn mul_to<'a, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>( pub fn mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self, &self,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,
out: &'a mut Matrix<MaybeUninit<T>, R3, C3, SC>, out: &mut Matrix<T, R3, C3, SC>,
) -> MatrixSliceMut<'a, T, R3, C3, SC::RStride, SC::CStride> ) where
where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>, SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R3, R1> ShapeConstraint: SameNumberOfRows<R3, R1>
+ SameNumberOfColumns<C3, C2> + SameNumberOfColumns<C3, C2>
+ AreMultipliable<R1, C1, R2, C2>, + AreMultipliable<R1, C1, R2, C2>,
{ {
out.gemm_z(T::one(), self, rhs) out.gemm(T::one(), self, rhs, T::zero());
} }
/// The kronecker product of two matrices (aka. tensor product of the corresponding linear /// The kronecker product of two matrices (aka. tensor product of the corresponding linear
@ -809,34 +805,31 @@ where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>, DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>,
{ {
let (nrows1, ncols1) = self.data.shape(); let (nrows1, ncols1) = self.shape_generic();
let (nrows2, ncols2) = rhs.data.shape(); let (nrows2, ncols2) = rhs.shape_generic();
let mut res = Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2)); let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2));
{
let mut data_res = res.data.ptr_mut(); let mut data_res = res.data.ptr_mut();
unsafe {
for j1 in 0..ncols1.value() { for j1 in 0..ncols1.value() {
for j2 in 0..ncols2.value() { for j2 in 0..ncols2.value() {
for i1 in 0..nrows1.value() { for i1 in 0..nrows1.value() {
unsafe {
let coeff = self.get_unchecked((i1, j1)).inlined_clone(); let coeff = self.get_unchecked((i1, j1)).inlined_clone();
for i2 in 0..nrows2.value() { for i2 in 0..nrows2.value() {
*data_res = MaybeUninit::new( *data_res = MaybeUninit::new(
coeff.inlined_clone() coeff.inlined_clone() * rhs.get_unchecked((i2, j2)).inlined_clone(),
* rhs.get_unchecked((i2, j2)).inlined_clone(),
); );
data_res = data_res.offset(1); data_res = data_res.offset(1);
} }
} }
} }
} }
}
}
unsafe { res.assume_init() } // SAFETY: the result matrix has been initialized by the loop above.
res.assume_init()
}
} }
} }

View File

@ -7,9 +7,10 @@ use simba::scalar::{ClosedAdd, ClosedMul, ComplexField, RealField};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{Dim, DimMin}; use crate::base::dimension::{Dim, DimMin};
use crate::base::storage::Storage; use crate::base::storage::Storage;
use crate::base::{DefaultAllocator, Matrix, SquareMatrix}; use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix};
use crate::RawStorage;
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// The total number of elements of this matrix. /// The total number of elements of this matrix.
/// ///
/// # Examples: /// # Examples:

View File

@ -1,38 +1,27 @@
use std::any::Any;
use std::any::TypeId; use std::any::TypeId;
use std::fmt::Debug; use std::fmt::Debug;
/// The basic scalar trait for all structures of `nalgebra`. /// The basic scalar type for all structures of `nalgebra`.
/// ///
/// This is by design a very loose trait, and does not make any assumption on /// This does not make any assumption on the algebraic properties of `Self`.
/// the algebraic properties of `Self`. It has various purposes and objectives: pub trait Scalar: Clone + PartialEq + Debug + Any {
/// - Enforces simple and future-proof trait bounds.
/// - Enables important optimizations for floating point types via specialization.
/// - Makes debugging generic code possible in most circumstances.
pub trait Scalar: 'static + Clone + Debug {
#[inline] #[inline]
/// Tests whether `Self` is the same as the type `T`. /// Tests if `Self` the same as the type `T`
/// ///
/// Typically used to test of `Self` is an `f32` or an `f64`, which is /// Typically used to test of `Self` is a f32 or a f64 with `T::is::<f32>()`.
/// important as it allows for specialization and certain optimizations to
/// be made.
///
// If the need ever arose to get rid of the `'static` requirement, we could
// merely replace this method by two unsafe associated methods `is_f32` and
// `is_f64`.
fn is<T: Scalar>() -> bool { fn is<T: Scalar>() -> bool {
TypeId::of::<Self>() == TypeId::of::<T>() TypeId::of::<Self>() == TypeId::of::<T>()
} }
/// Performance hack: Clone doesn't get inlined for Copy types in debug #[inline(always)]
/// mode, so make it inline anyway. /// Performance hack: Clone doesn't get inlined for Copy types in debug mode, so make it inline anyway.
fn inlined_clone(&self) -> Self { fn inlined_clone(&self) -> Self {
self.clone() self.clone()
} }
} }
// Unfortunately, this blanket impl leads to many misleading compiler messages impl<T: Copy + PartialEq + Debug + Any> Scalar for T {
// telling you to implement Copy, even though Scalar is what's really needed.
impl<T: 'static + Copy + Debug> Scalar for T {
#[inline(always)] #[inline(always)]
fn inlined_clone(&self) -> T { fn inlined_clone(&self) -> T {
*self *self

View File

@ -1,13 +1,12 @@
use std::mem::MaybeUninit;
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::storage::Storage; use crate::storage::RawStorage;
use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1}; use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1};
use num::Zero; use num::Zero;
use simba::scalar::{ClosedAdd, Field, SupersetOf}; use simba::scalar::{ClosedAdd, Field, SupersetOf};
use std::mem::MaybeUninit;
/// # Folding on columns and rows /// # Folding on columns and rows
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a row vector where each element is the result of the application of `f` on the /// Returns a row vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix. /// corresponding column of the original matrix.
#[inline] #[inline]
@ -19,16 +18,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where where
DefaultAllocator: Allocator<T, U1, C>, DefaultAllocator: Allocator<T, U1, C>,
{ {
let ncols = self.data.shape().1; let ncols = self.shape_generic().1;
let mut res = RowOVector::new_uninitialized_generic(Const::<1>, ncols); let mut res = Matrix::uninit(Const::<1>, ncols);
for i in 0..ncols.value() { for i in 0..ncols.value() {
// TODO: avoid bound checking of column. // TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe { unsafe {
*res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i))); *res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i)));
} }
} }
// Safety: res is now fully initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
@ -45,16 +46,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where where
DefaultAllocator: Allocator<T, C>, DefaultAllocator: Allocator<T, C>,
{ {
let ncols = self.data.shape().1; let ncols = self.shape_generic().1;
let mut res = Matrix::new_uninitialized_generic(ncols, Const::<1>); let mut res = Matrix::uninit(ncols, Const::<1>);
for i in 0..ncols.value() { for i in 0..ncols.value() {
// TODO: avoid bound checking of column. // TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe { unsafe {
*res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i))); *res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i)));
} }
} }
// Safety: res is now fully initialized.
unsafe { res.assume_init() } unsafe { res.assume_init() }
} }
@ -63,22 +66,24 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use] #[must_use]
pub fn compress_columns( pub fn compress_columns(
&self, &self,
mut init: OVector<T, R>, init: OVector<T, R>,
f: impl Fn(&mut OVector<T, R>, VectorSlice<T, R, S::RStride, S::CStride>), f: impl Fn(&mut OVector<T, R>, VectorSlice<'_, T, R, S::RStride, S::CStride>),
) -> OVector<T, R> ) -> OVector<T, R>
where where
DefaultAllocator: Allocator<T, R>, DefaultAllocator: Allocator<T, R>,
{ {
let mut res = init;
for i in 0..self.ncols() { for i in 0..self.ncols() {
f(&mut init, self.column(i)) f(&mut res, self.column(i))
} }
init res
} }
} }
/// # Common statistics operations /// # Common statistics operations
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/* /*
* *
* Sum computation. * Sum computation.
@ -178,7 +183,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: ClosedAdd + Zero, T: ClosedAdd + Zero,
DefaultAllocator: Allocator<T, R>, DefaultAllocator: Allocator<T, R>,
{ {
let nrows = self.data.shape().0; let nrows = self.shape_generic().0;
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| { self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
*out += col; *out += col;
}) })
@ -281,10 +286,10 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
DefaultAllocator: Allocator<T, R>, DefaultAllocator: Allocator<T, R>,
{ {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.shape_generic();
let mut mean = self.column_mean(); let mut mean = self.column_mean();
mean.apply(|e| -(e.inlined_clone() * e)); mean.apply(|e| *e = -(e.inlined_clone() * e.inlined_clone()));
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64); let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
self.compress_columns(mean, |out, col| { self.compress_columns(mean, |out, col| {
@ -389,7 +394,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
DefaultAllocator: Allocator<T, R>, DefaultAllocator: Allocator<T, R>,
{ {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.shape_generic();
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64); let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| { self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
out.axpy(denom.inlined_clone(), &col, T::one()) out.axpy(denom.inlined_clone(), &col, T::one())

View File

@ -2,27 +2,32 @@
use std::ptr; use std::ptr;
use crate::base::allocator::{Allocator, InnerAllocator, SameShapeC, SameShapeR}; use crate::base::allocator::{Allocator, SameShapeC, SameShapeR};
use crate::base::default_allocator::DefaultAllocator; use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Dim, U1}; use crate::base::dimension::{Dim, U1};
use crate::base::Owned; use crate::base::Scalar;
/* /*
* Aliases for allocation results. * Aliases for allocation results.
*/ */
/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`.
pub type SameShapeStorage<T, R1, C1, R2, C2> =
<DefaultAllocator as Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>>::Buffer;
// TODO: better name than Owned ? // TODO: better name than Owned ?
/// The owned data storage that can be allocated from `S`. /// The owned data storage that can be allocated from `S`.
pub type InnerOwned<T, R, C = U1> = <DefaultAllocator as InnerAllocator<T, R, C>>::Buffer; pub type Owned<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::Buffer;
/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`. /// The owned data storage that can be allocated from `S`.
pub type SameShapeStorage<T, R1, C1, R2, C2> = Owned<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>; pub type OwnedUninit<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::BufferUninit;
/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`. /// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type RStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::RStride; pub type RStride<T, R, C = U1> =
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::RStride;
/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`. /// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type CStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::CStride; pub type CStride<T, R, C = U1> =
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::CStride;
/// The trait shared by all matrix data storage. /// The trait shared by all matrix data storage.
/// ///
@ -33,7 +38,7 @@ pub type CStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::CStr
/// should **not** allow the user to modify the size of the underlying buffer with safe methods /// should **not** allow the user to modify the size of the underlying buffer with safe methods
/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the /// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
/// vector's size so that it no longer contains enough elements: this will lead to UB. /// vector's size so that it no longer contains enough elements: this will lead to UB.
pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized { pub unsafe trait RawStorage<T, R: Dim, C: Dim = U1>: Sized {
/// The static stride of this storage's rows. /// The static stride of this storage's rows.
type RStride: Dim; type RStride: Dim;
@ -118,17 +123,17 @@ pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized {
/// ///
/// Call the safe alternative `matrix.as_slice()` instead. /// Call the safe alternative `matrix.as_slice()` instead.
unsafe fn as_slice_unchecked(&self) -> &[T]; unsafe fn as_slice_unchecked(&self) -> &[T];
}
pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
/// Builds a matrix data storage that does not contain any reference. /// Builds a matrix data storage that does not contain any reference.
fn into_owned(self) -> Owned<T, R, C> fn into_owned(self) -> Owned<T, R, C>
where where
T: Clone,
DefaultAllocator: Allocator<T, R, C>; DefaultAllocator: Allocator<T, R, C>;
/// Clones this data storage to one that does not contain any reference. /// Clones this data storage to one that does not contain any reference.
fn clone_owned(&self) -> Owned<T, R, C> fn clone_owned(&self) -> Owned<T, R, C>
where where
T: Clone,
DefaultAllocator: Allocator<T, R, C>; DefaultAllocator: Allocator<T, R, C>;
} }
@ -137,7 +142,7 @@ pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized {
/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable /// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable
/// matrix slice can provide mutable access to its elements even if it does not own its data (it /// matrix slice can provide mutable access to its elements even if it does not own its data (it
/// contains only an internal reference to them). /// contains only an internal reference to them).
pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>: Storage<T, R, C> { pub unsafe trait RawStorageMut<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
/// The matrix mutable data pointer. /// The matrix mutable data pointer.
fn ptr_mut(&mut self) -> *mut T; fn ptr_mut(&mut self) -> *mut T;
@ -212,40 +217,37 @@ pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>: Storage<T, R, C> {
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T]; unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
} }
/// A matrix storage that is stored contiguously in memory. pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>:
/// Storage<T, R, C> + RawStorageMut<T, R, C>
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value {
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
/// failing to comply to this may cause Undefined Behaviors.
pub unsafe trait ContiguousStorage<T, R: Dim, C: Dim = U1>: Storage<T, R, C> {
/// Converts this data storage to a contiguous slice.
fn as_slice(&self) -> &[T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_slice_unchecked() }
}
} }
/// A mutable matrix storage that is stored contiguously in memory. unsafe impl<S, T, R, C> StorageMut<T, R, C> for S
where
R: Dim,
C: Dim,
S: Storage<T, R, C> + RawStorageMut<T, R, C>,
{
}
/// Marker trait indicating that a storage is stored contiguously in memory.
/// ///
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value /// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because /// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
/// failing to comply to this may cause Undefined Behaviors. /// failing to comply to this may cause Undefined Behaviors.
pub unsafe trait ContiguousStorageMut<T, R: Dim, C: Dim = U1>: pub unsafe trait IsContiguous {}
ContiguousStorage<T, R, C> + StorageMut<T, R, C>
{
/// Converts this data storage to a contiguous mutable slice.
fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_mut_slice_unchecked() }
}
}
/// A matrix storage that can be reshaped in-place. /// A matrix storage that can be reshaped in-place.
pub trait ReshapableStorage<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim>: Storage<T, R1, C1> { pub trait ReshapableStorage<T, R1, C1, R2, C2>: RawStorage<T, R1, C1>
where
T: Scalar,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
{
/// The reshaped storage type. /// The reshaped storage type.
type Output: Storage<T, R2, C2>; type Output: RawStorage<T, R2, C2>;
/// Reshapes the storage into the output storage type. /// Reshapes the storage into the output storage type.
fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output; fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;

View File

@ -1,5 +1,5 @@
use crate::base::{DimName, ToTypenum, Vector, Vector2, Vector3}; use crate::base::{DimName, Scalar, ToTypenum, Vector, Vector2, Vector3};
use crate::storage::Storage; use crate::storage::RawStorage;
use typenum::{self, Cmp, Greater}; use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle { macro_rules! impl_swizzle {
@ -11,7 +11,7 @@ macro_rules! impl_swizzle {
#[must_use] #[must_use]
pub fn $name(&self) -> $Result<T> pub fn $name(&self) -> $Result<T>
where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> { where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i].clone()),*) $Result::new($(self[$i].inlined_clone()),*)
} }
)* )*
)* )*
@ -19,7 +19,7 @@ macro_rules! impl_swizzle {
} }
/// # Swizzling /// # Swizzling
impl<T: Clone, D, S: Storage<T, D>> Vector<T, D, S> impl<T: Scalar, D, S: RawStorage<T, D>> Vector<T, D, S>
where where
D: DimName + ToTypenum, D: DimName + ToTypenum,
{ {

76
src/base/uninit.rs Normal file
View File

@ -0,0 +1,76 @@
use std::mem::MaybeUninit;
// # Safety
// This trait must not be implemented outside of this crate.
pub unsafe trait InitStatus<T>: Copy {
type Value;
fn init(out: &mut Self::Value, t: T);
unsafe fn assume_init_ref(t: &Self::Value) -> &T;
unsafe fn assume_init_mut(t: &mut Self::Value) -> &mut T;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Init;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Uninit;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Initialized<Status>(pub Status);
unsafe impl<T> InitStatus<T> for Init {
type Value = T;
#[inline(always)]
fn init(out: &mut T, t: T) {
*out = t;
}
#[inline(always)]
unsafe fn assume_init_ref(t: &T) -> &T {
t
}
#[inline(always)]
unsafe fn assume_init_mut(t: &mut T) -> &mut T {
t
}
}
unsafe impl<T> InitStatus<T> for Uninit {
type Value = MaybeUninit<T>;
#[inline(always)]
fn init(out: &mut MaybeUninit<T>, t: T) {
*out = MaybeUninit::new(t);
}
#[inline(always)]
unsafe fn assume_init_ref(t: &MaybeUninit<T>) -> &T {
std::mem::transmute(t.as_ptr()) // TODO: use t.assume_init_ref()
}
#[inline(always)]
unsafe fn assume_init_mut(t: &mut MaybeUninit<T>) -> &mut T {
std::mem::transmute(t.as_mut_ptr()) // TODO: use t.assume_init_mut()
}
}
unsafe impl<T, Status: InitStatus<T>> InitStatus<T> for Initialized<Status> {
type Value = Status::Value;
#[inline(always)]
fn init(out: &mut Status::Value, t: T) {
unsafe {
*Status::assume_init_mut(out) = t;
}
}
#[inline(always)]
unsafe fn assume_init_ref(t: &Status::Value) -> &T {
Status::assume_init_ref(t)
}
#[inline(always)]
unsafe fn assume_init_mut(t: &mut Status::Value) -> &mut T {
Status::assume_init_mut(t)
}
}

View File

@ -10,7 +10,7 @@ use abomonation::Abomonation;
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::DefaultAllocator; use crate::base::DefaultAllocator;
use crate::storage::{InnerOwned, Storage}; use crate::storage::RawStorage;
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField}; use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
/// A wrapper that ensures the underlying algebraic entity has a unit norm. /// A wrapper that ensures the underlying algebraic entity has a unit norm.
@ -113,10 +113,10 @@ mod rkyv_impl {
impl<T, R, C, S> PartialEq for Unit<Matrix<T, R, C, S>> impl<T, R, C, S> PartialEq for Unit<Matrix<T, R, C, S>>
where where
T: PartialEq, T: Scalar + PartialEq,
R: Dim, R: Dim,
C: Dim, C: Dim,
S: Storage<T, R, C>, S: RawStorage<T, R, C>,
{ {
#[inline] #[inline]
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
@ -126,10 +126,10 @@ where
impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>> impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>>
where where
T: Eq, T: Scalar + Eq,
R: Dim, R: Dim,
C: Dim, C: Dim,
S: Storage<T, R, C>, S: RawStorage<T, R, C>,
{ {
} }
@ -228,7 +228,7 @@ impl<T> Unit<T> {
/// Wraps the given reference, assuming it is already normalized. /// Wraps the given reference, assuming it is already normalized.
#[inline] #[inline]
pub fn from_ref_unchecked(value: &T) -> &Self { pub fn from_ref_unchecked(value: &T) -> &Self {
unsafe { &*(value as *const _ as *const _) } unsafe { &*(value as *const T as *const Self) }
} }
/// Retrieves the underlying value. /// Retrieves the underlying value.
@ -331,7 +331,7 @@ impl<T> Deref for Unit<T> {
#[inline] #[inline]
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { &*(self as *const _ as *const T) } unsafe { &*(self as *const Self as *const T) }
} }
} }
@ -344,7 +344,6 @@ where
T: From<[<T as simba::simd::SimdValue>::Element; 2]>, T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
T::Element: Scalar, T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{ {
#[inline] #[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 2]) -> Self { fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 2]) -> Self {
@ -361,7 +360,6 @@ where
T: From<[<T as simba::simd::SimdValue>::Element; 4]>, T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
T::Element: Scalar, T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{ {
#[inline] #[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 4]) -> Self { fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 4]) -> Self {
@ -380,7 +378,6 @@ where
T: From<[<T as simba::simd::SimdValue>::Element; 8]>, T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
T::Element: Scalar, T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{ {
#[inline] #[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 8]) -> Self { fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 8]) -> Self {
@ -403,7 +400,6 @@ where
T: From<[<T as simba::simd::SimdValue>::Element; 16]>, T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
T::Element: Scalar, T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{ {
#[inline] #[inline]
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 16]) -> Self { fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 16]) -> Self {

View File

@ -4,14 +4,12 @@ use std::io::{Result as IOResult, Write};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::allocator::InnerAllocator; use crate::base::allocator::Allocator;
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::base::default_allocator::DefaultAllocator; use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Dim, DimName, Dynamic, U1}; use crate::base::dimension::{Dim, DimName, Dynamic, U1};
use crate::base::storage::{ use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
ContiguousStorage, ContiguousStorageMut, ReshapableStorage, Storage, StorageMut, use crate::base::{Scalar, Vector};
};
use crate::base::{Owned, Vector};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{ use serde::{
@ -19,20 +17,22 @@ use serde::{
ser::{Serialize, Serializer}, ser::{Serialize, Serializer},
}; };
use crate::Storage;
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
/* /*
* *
* Storage. * RawStorage.
* *
*/ */
/// A Vec-based matrix data storage. It may be dynamically-sized. /// A Vec-based matrix data storage. It may be dynamically-sized.
#[repr(C)]
#[derive(Eq, Debug, Clone, PartialEq)] #[derive(Eq, Debug, Clone, PartialEq)]
pub struct VecStorage<T, R: Dim, C: Dim> { pub struct VecStorage<T, R: Dim, C: Dim> {
data: Vec<T>, data: Vec<T>,
pub(crate) nrows: R, nrows: R,
pub(crate) ncols: C, ncols: C,
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
@ -142,6 +142,18 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
/// A slice containing all the components stored in this storage in column-major order.
#[inline]
pub fn as_slice(&self) -> &[T] {
&self.data[..]
}
/// A mutable slice containing all the components stored in this storage in column-major order.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.data[..]
}
} }
impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> { impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
@ -156,10 +168,7 @@ impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
* Dynamic Dynamic * Dynamic Dynamic
* *
*/ */
unsafe impl<T, C: Dim> Storage<T, Dynamic, C> for VecStorage<T, Dynamic, C> unsafe impl<T, C: Dim> RawStorage<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
where
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
{
type RStride = U1; type RStride = U1;
type CStride = Dynamic; type CStride = Dynamic;
@ -183,29 +192,34 @@ where
true true
} }
#[inline]
fn into_owned(self) -> Owned<T, Dynamic, C> {
Owned(self)
}
#[inline]
fn clone_owned(&self) -> Owned<T, Dynamic, C>
where
T: Clone,
{
Owned(self.clone())
}
#[inline] #[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
&self.data &self.data
} }
} }
unsafe impl<T, R: DimName> Storage<T, R, Dynamic> for VecStorage<T, R, Dynamic> unsafe impl<T: Scalar, C: Dim> Storage<T, Dynamic, C> for VecStorage<T, Dynamic, C>
where where
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>, DefaultAllocator: Allocator<T, Dynamic, C, Buffer = Self>,
{ {
#[inline]
fn into_owned(self) -> Owned<T, Dynamic, C>
where
DefaultAllocator: Allocator<T, Dynamic, C>,
{
self
}
#[inline]
fn clone_owned(&self) -> Owned<T, Dynamic, C>
where
DefaultAllocator: Allocator<T, Dynamic, C>,
{
self.clone()
}
}
unsafe impl<T, R: DimName> RawStorage<T, R, Dynamic> for VecStorage<T, R, Dynamic> {
type RStride = U1; type RStride = U1;
type CStride = R; type CStride = R;
@ -229,34 +243,39 @@ where
true true
} }
#[inline]
fn into_owned(self) -> Owned<T, R, Dynamic> {
Owned(self)
}
#[inline]
fn clone_owned(&self) -> Owned<T, R, Dynamic>
where
T: Clone,
{
Owned(self.clone())
}
#[inline] #[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
&self.data &self.data
} }
} }
unsafe impl<T: Scalar, R: DimName> Storage<T, R, Dynamic> for VecStorage<T, R, Dynamic>
where
DefaultAllocator: Allocator<T, R, Dynamic, Buffer = Self>,
{
#[inline]
fn into_owned(self) -> Owned<T, R, Dynamic>
where
DefaultAllocator: Allocator<T, R, Dynamic>,
{
self
}
#[inline]
fn clone_owned(&self) -> Owned<T, R, Dynamic>
where
DefaultAllocator: Allocator<T, R, Dynamic>,
{
self.clone()
}
}
/* /*
* *
* StorageMut, ContiguousStorage. * RawStorageMut, ContiguousStorage.
* *
*/ */
unsafe impl<T, C: Dim> StorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> unsafe impl<T, C: Dim> RawStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
where
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
{
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut T { fn ptr_mut(&mut self) -> *mut T {
self.data.as_mut_ptr() self.data.as_mut_ptr()
@ -268,18 +287,13 @@ where
} }
} }
unsafe impl<T, C: Dim> ContiguousStorage<T, Dynamic, C> for VecStorage<T, Dynamic, C> where unsafe impl<T, R: Dim, C: Dim> IsContiguous for VecStorage<T, R, C> {}
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>
{
}
unsafe impl<T, C: Dim> ContiguousStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> where impl<T, C1, C2> ReshapableStorage<T, Dynamic, C1, Dynamic, C2> for VecStorage<T, Dynamic, C1>
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self> where
{ T: Scalar,
} C1: Dim,
C2: Dim,
impl<T, C1: Dim, C2: Dim> ReshapableStorage<T, Dynamic, C1, Dynamic, C2>
for VecStorage<T, Dynamic, C1>
{ {
type Output = VecStorage<T, Dynamic, C2>; type Output = VecStorage<T, Dynamic, C2>;
@ -293,8 +307,11 @@ impl<T, C1: Dim, C2: Dim> ReshapableStorage<T, Dynamic, C1, Dynamic, C2>
} }
} }
impl<T, C1: Dim, R2: DimName> ReshapableStorage<T, Dynamic, C1, R2, Dynamic> impl<T, C1, R2> ReshapableStorage<T, Dynamic, C1, R2, Dynamic> for VecStorage<T, Dynamic, C1>
for VecStorage<T, Dynamic, C1> where
T: Scalar,
C1: Dim,
R2: DimName,
{ {
type Output = VecStorage<T, R2, Dynamic>; type Output = VecStorage<T, R2, Dynamic>;
@ -308,10 +325,7 @@ impl<T, C1: Dim, R2: DimName> ReshapableStorage<T, Dynamic, C1, R2, Dynamic>
} }
} }
unsafe impl<T, R: DimName> StorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> unsafe impl<T, R: DimName> RawStorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> {
where
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>,
{
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut T { fn ptr_mut(&mut self) -> *mut T {
self.data.as_mut_ptr() self.data.as_mut_ptr()
@ -323,8 +337,11 @@ where
} }
} }
impl<T, R1: DimName, C2: Dim> ReshapableStorage<T, R1, Dynamic, Dynamic, C2> impl<T, R1, C2> ReshapableStorage<T, R1, Dynamic, Dynamic, C2> for VecStorage<T, R1, Dynamic>
for VecStorage<T, R1, Dynamic> where
T: Scalar,
R1: DimName,
C2: Dim,
{ {
type Output = VecStorage<T, Dynamic, C2>; type Output = VecStorage<T, Dynamic, C2>;
@ -338,8 +355,11 @@ impl<T, R1: DimName, C2: Dim> ReshapableStorage<T, R1, Dynamic, Dynamic, C2>
} }
} }
impl<T, R1: DimName, R2: DimName> ReshapableStorage<T, R1, Dynamic, R2, Dynamic> impl<T, R1, R2> ReshapableStorage<T, R1, Dynamic, R2, Dynamic> for VecStorage<T, R1, Dynamic>
for VecStorage<T, R1, Dynamic> where
T: Scalar,
R1: DimName,
R2: DimName,
{ {
type Output = VecStorage<T, R2, Dynamic>; type Output = VecStorage<T, R2, Dynamic>;
@ -368,16 +388,6 @@ impl<T: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<T, R, C> {
} }
} }
unsafe impl<T, R: DimName> ContiguousStorage<T, R, Dynamic> for VecStorage<T, R, Dynamic> where
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>
{
}
unsafe impl<T, R: DimName> ContiguousStorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> where
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>
{
}
impl<T, R: Dim> Extend<T> for VecStorage<T, R, Dynamic> { impl<T, R: Dim> Extend<T> for VecStorage<T, R, Dynamic> {
/// Extends the number of columns of the `VecStorage` with elements /// Extends the number of columns of the `VecStorage` with elements
/// from the given iterator. /// from the given iterator.
@ -407,9 +417,12 @@ impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage<T, R, Dynamic> {
} }
} }
impl<T: Clone, R: Dim, RV: Dim, SV> Extend<Vector<T, RV, SV>> for VecStorage<T, R, Dynamic> impl<T, R, RV, SV> Extend<Vector<T, RV, SV>> for VecStorage<T, R, Dynamic>
where where
SV: Storage<T, RV>, T: Scalar,
R: Dim,
RV: Dim,
SV: RawStorage<T, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>, ShapeConstraint: SameNumberOfRows<R, RV>,
{ {
/// Extends the number of columns of the `VecStorage` with vectors /// Extends the number of columns of the `VecStorage` with vectors

View File

@ -1,52 +1,24 @@
use std::fmt; #[cfg(feature = "arbitrary")]
use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{Dim, DimName, Dynamic}; use crate::base::dimension::{Dim, Dynamic};
use crate::base::Scalar;
use crate::base::{DefaultAllocator, OMatrix}; use crate::base::{DefaultAllocator, OMatrix};
use crate::linalg::givens::GivensRotation; use crate::linalg::givens::GivensRotation;
use crate::storage::Owned;
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
/// A random orthogonal matrix. /// A random orthogonal matrix.
pub struct RandomOrthogonal<T, D: Dim = Dynamic> #[derive(Clone, Debug)]
pub struct RandomOrthogonal<T: Scalar, D: Dim = Dynamic>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
m: OMatrix<T, D, D>, m: OMatrix<T, D, D>,
} }
impl<T: Copy, D: DimName> Copy for RandomOrthogonal<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: Copy,
{
}
impl<T: Clone, D: Dim> Clone for RandomOrthogonal<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: Clone,
{
fn clone(&self) -> Self {
Self { m: self.m.clone() }
}
}
impl<T: fmt::Debug, D: Dim> fmt::Debug for RandomOrthogonal<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RandomOrthogonal")
.field("m", &self.m)
.finish()
}
}
impl<T: ComplexField, D: Dim> RandomOrthogonal<T, D> impl<T: ComplexField, D: Dim> RandomOrthogonal<T, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,

View File

@ -1,50 +1,25 @@
use std::fmt; #[cfg(feature = "arbitrary")]
use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{Dim, Dynamic}; use crate::base::dimension::{Dim, Dynamic};
use crate::base::{DefaultAllocator, OMatrix, Owned}; use crate::base::Scalar;
use crate::base::{DefaultAllocator, OMatrix};
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::debug::RandomOrthogonal; use crate::debug::RandomOrthogonal;
/// A random, well-conditioned, symmetric definite-positive matrix. /// A random, well-conditioned, symmetric definite-positive matrix.
pub struct RandomSDP<T, D: Dim = Dynamic> #[derive(Clone, Debug)]
pub struct RandomSDP<T: Scalar, D: Dim = Dynamic>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
m: OMatrix<T, D, D>, m: OMatrix<T, D, D>,
} }
impl<T: Copy, D: Dim> Copy for RandomSDP<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: Copy,
{
}
impl<T: Clone, D: Dim> Clone for RandomSDP<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: Clone,
{
fn clone(&self) -> Self {
Self { m: self.m.clone() }
}
}
impl<T: fmt::Debug, D: Dim> fmt::Debug for RandomSDP<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
Owned<T, D, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RandomSDP").field("m", &self.m).finish()
}
}
impl<T: ComplexField, D: Dim> RandomSDP<T, D> impl<T: ComplexField, D: Dim> RandomSDP<T, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,

View File

@ -2,15 +2,15 @@
#![allow(clippy::op_ref)] #![allow(clippy::op_ref)]
use crate::{ use crate::{
Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, SimdRealField, Translation3, Unit, Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3,
UnitQuaternion, Vector3, Zero, U8, Unit, UnitQuaternion, Vector3, Zero, U8,
}; };
use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use approx::{AbsDiffEq, RelativeEq, UlpsEq};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt; use std::fmt;
use simba::scalar::RealField; use simba::scalar::{ClosedNeg, RealField};
/// A dual quaternion. /// A dual quaternion.
/// ///
@ -46,16 +46,16 @@ pub struct DualQuaternion<T> {
pub dual: Quaternion<T>, pub dual: Quaternion<T>,
} }
impl<T: Eq> Eq for DualQuaternion<T> {} impl<T: Scalar + Eq> Eq for DualQuaternion<T> {}
impl<T: PartialEq> PartialEq for DualQuaternion<T> { impl<T: Scalar> PartialEq for DualQuaternion<T> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.real == right.real && self.dual == right.dual self.real == right.real && self.dual == right.dual
} }
} }
impl<T: Zero + Clone> Default for DualQuaternion<T> { impl<T: Scalar + Zero> Default for DualQuaternion<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
real: Quaternion::default(), real: Quaternion::default(),
@ -267,7 +267,10 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T: Serialize> Serialize for DualQuaternion<T> { impl<T: SimdRealField> Serialize for DualQuaternion<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where where
S: Serializer, S: Serializer,
@ -277,7 +280,10 @@ impl<T: Serialize> Serialize for DualQuaternion<T> {
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: Deserialize<'a>> Deserialize<'a> for DualQuaternion<T> { impl<'a, T: SimdRealField> Deserialize<'a> for DualQuaternion<T>
where
T: Deserialize<'a>,
{
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
Des: Deserializer<'a>, Des: Deserializer<'a>,
@ -293,14 +299,9 @@ impl<'a, T: Deserialize<'a>> Deserialize<'a> for DualQuaternion<T> {
} }
} }
impl<T> DualQuaternion<T> { impl<T: RealField> DualQuaternion<T> {
// TODO: Cloning shouldn't be necessary. fn to_vector(self) -> OVector<T, U8> {
// TODO: rename into `into_vector` to appease clippy. (*self.as_ref()).into()
fn to_vector(self) -> OVector<T, U8>
where
T: Clone,
{
(self.as_ref().clone()).into()
} }
} }
@ -356,14 +357,14 @@ impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for DualQuaternion<T> {
/// A unit quaternions. May be used to represent a rotation followed by a translation. /// A unit quaternions. May be used to represent a rotation followed by a translation.
pub type UnitDualQuaternion<T> = Unit<DualQuaternion<T>>; pub type UnitDualQuaternion<T> = Unit<DualQuaternion<T>>;
impl<T: PartialEq> PartialEq for UnitDualQuaternion<T> { impl<T: Scalar + ClosedNeg + PartialEq + SimdRealField> PartialEq for UnitDualQuaternion<T> {
#[inline] #[inline]
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
self.as_ref().eq(rhs.as_ref()) self.as_ref().eq(rhs.as_ref())
} }
} }
impl<T: Eq> Eq for UnitDualQuaternion<T> {} impl<T: Scalar + ClosedNeg + Eq + SimdRealField> Eq for UnitDualQuaternion<T> {}
impl<T: SimdRealField> Normed for DualQuaternion<T> { impl<T: SimdRealField> Normed for DualQuaternion<T> {
type Norm = T::SimdRealField; type Norm = T::SimdRealField;
@ -391,7 +392,10 @@ impl<T: SimdRealField> Normed for DualQuaternion<T> {
} }
} }
impl<T> UnitDualQuaternion<T> { impl<T: SimdRealField> UnitDualQuaternion<T>
where
T::Element: SimdRealField,
{
/// The underlying dual quaternion. /// The underlying dual quaternion.
/// ///
/// Same as `self.as_ref()`. /// Same as `self.as_ref()`.
@ -410,12 +414,7 @@ impl<T> UnitDualQuaternion<T> {
pub fn dual_quaternion(&self) -> &DualQuaternion<T> { pub fn dual_quaternion(&self) -> &DualQuaternion<T> {
self.as_ref() self.as_ref()
} }
}
impl<T: SimdRealField> UnitDualQuaternion<T>
where
T::Element: SimdRealField,
{
/// Compute the conjugate of this unit quaternion. /// Compute the conjugate of this unit quaternion.
/// ///
/// # Example /// # Example
@ -617,7 +616,7 @@ where
#[must_use] #[must_use]
pub fn sclerp(&self, other: &Self, t: T) -> Self pub fn sclerp(&self, other: &Self, t: T) -> Self
where where
T: RealField + RelativeEq<Epsilon = T>, T: RealField,
{ {
self.try_sclerp(other, t, T::default_epsilon()) self.try_sclerp(other, t, T::default_epsilon())
.expect("DualQuaternion sclerp: ambiguous configuration.") .expect("DualQuaternion sclerp: ambiguous configuration.")
@ -637,7 +636,7 @@ where
#[must_use] #[must_use]
pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField + RelativeEq<Epsilon = T>, T: RealField,
{ {
let two = T::one() + T::one(); let two = T::one() + T::one();
let half = T::one() / two; let half = T::one() / two;

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
DualQuaternion, Isometry3, Quaternion, SimdRealField, Translation3, UnitDualQuaternion, DualQuaternion, Isometry3, Quaternion, Scalar, SimdRealField, Translation3, UnitDualQuaternion,
UnitQuaternion, UnitQuaternion,
}; };
use num::{One, Zero}; use num::{One, Zero};
@ -7,7 +7,7 @@ use num::{One, Zero};
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use simba::scalar::SupersetOf; use simba::scalar::SupersetOf;
impl<T> DualQuaternion<T> { impl<T: Scalar> DualQuaternion<T> {
/// Creates a dual quaternion from its rotation and translation components. /// Creates a dual quaternion from its rotation and translation components.
/// ///
/// # Example /// # Example
@ -60,7 +60,7 @@ impl<T> DualQuaternion<T> {
/// let q2 = q.cast::<f32>(); /// let q2 = q.cast::<f32>();
/// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0))); /// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0)));
/// ``` /// ```
pub fn cast<To>(self) -> DualQuaternion<To> pub fn cast<To: Scalar>(self) -> DualQuaternion<To>
where where
DualQuaternion<To>: SupersetOf<Self>, DualQuaternion<To>: SupersetOf<Self>,
{ {
@ -156,7 +156,7 @@ impl<T: SimdRealField> UnitDualQuaternion<T> {
/// let q2 = q.cast::<f32>(); /// let q2 = q.cast::<f32>();
/// assert_eq!(q2, UnitDualQuaternion::<f32>::identity()); /// assert_eq!(q2, UnitDualQuaternion::<f32>::identity());
/// ``` /// ```
pub fn cast<To>(self) -> UnitDualQuaternion<To> pub fn cast<To: Scalar>(self) -> UnitDualQuaternion<To>
where where
UnitDualQuaternion<To>: SupersetOf<Self>, UnitDualQuaternion<To>: SupersetOf<Self>,
{ {

View File

@ -24,7 +24,8 @@ use crate::geometry::{
impl<T1, T2> SubsetOf<DualQuaternion<T2>> for DualQuaternion<T1> impl<T1, T2> SubsetOf<DualQuaternion<T2>> for DualQuaternion<T1>
where where
T2: SupersetOf<T1>, T1: SimdRealField,
T2: SimdRealField + SupersetOf<T1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> DualQuaternion<T2> { fn to_superset(&self) -> DualQuaternion<T2> {
@ -48,7 +49,8 @@ where
impl<T1, T2> SubsetOf<UnitDualQuaternion<T2>> for UnitDualQuaternion<T1> impl<T1, T2> SubsetOf<UnitDualQuaternion<T2>> for UnitDualQuaternion<T1>
where where
T2: SupersetOf<T1>, T1: SimdRealField,
T2: SimdRealField + SupersetOf<T1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> UnitDualQuaternion<T2> { fn to_superset(&self) -> UnitDualQuaternion<T2> {

View File

@ -56,21 +56,21 @@ use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
}; };
impl<T> AsRef<[T; 8]> for DualQuaternion<T> { impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> {
#[inline] #[inline]
fn as_ref(&self) -> &[T; 8] { fn as_ref(&self) -> &[T; 8] {
unsafe { &*(self as *const _ as *const _) } unsafe { &*(self as *const Self as *const [T; 8]) }
} }
} }
impl<T> AsMut<[T; 8]> for DualQuaternion<T> { impl<T: SimdRealField> AsMut<[T; 8]> for DualQuaternion<T> {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [T; 8] { fn as_mut(&mut self) -> &mut [T; 8] {
unsafe { &mut *(self as *mut _ as *mut _) } unsafe { &mut *(self as *mut Self as *mut [T; 8]) }
} }
} }
impl<T> Index<usize> for DualQuaternion<T> { impl<T: SimdRealField> Index<usize> for DualQuaternion<T> {
type Output = T; type Output = T;
#[inline] #[inline]
@ -79,7 +79,7 @@ impl<T> Index<usize> for DualQuaternion<T> {
} }
} }
impl<T> IndexMut<usize> for DualQuaternion<T> { impl<T: SimdRealField> IndexMut<usize> for DualQuaternion<T> {
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut T { fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.as_mut()[i] &mut self.as_mut()[i]

View File

@ -15,7 +15,7 @@ use simba::simd::SimdRealField;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit}; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit};
use crate::geometry::{AbstractRotation, Point, Translation}; use crate::geometry::{AbstractRotation, Point, Translation};
@ -53,6 +53,7 @@ use crate::geometry::{AbstractRotation, Point, Translation};
/// # Conversion to a matrix /// # Conversion to a matrix
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix) /// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
/// ///
#[repr(C)]
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
@ -79,6 +80,7 @@ pub struct Isometry<T, R, const D: usize> {
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, R, const D: usize> Abomonation for Isometry<T, R, D> impl<T, R, const D: usize> Abomonation for Isometry<T, R, D>
where where
T: SimdRealField,
R: Abomonation, R: Abomonation,
Translation<T, D>: Abomonation, Translation<T, D>: Abomonation,
{ {
@ -104,7 +106,10 @@ mod rkyv_impl {
use crate::{base::Scalar, geometry::Translation}; use crate::{base::Scalar, geometry::Translation};
use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
impl<T: Archive, R: Archive, const D: usize> Archive for Isometry<T, R, D> { impl<T: Scalar + Archive, R: Archive, const D: usize> Archive for Isometry<T, R, D>
where
T::Archived: Scalar,
{
type Archived = Isometry<T::Archived, R::Archived, D>; type Archived = Isometry<T::Archived, R::Archived, D>;
type Resolver = (R::Resolver, <Translation<T, D> as Archive>::Resolver); type Resolver = (R::Resolver, <Translation<T, D> as Archive>::Resolver);
@ -127,8 +132,8 @@ mod rkyv_impl {
} }
} }
impl<T: Serialize<S>, R: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S> impl<T: Scalar + Serialize<S>, R: Serialize<S>, S: Fallible + ?Sized, const D: usize>
for Isometry<T, R, D> Serialize<S> for Isometry<T, R, D>
where where
T::Archived: Scalar, T::Archived: Scalar,
{ {
@ -140,7 +145,7 @@ mod rkyv_impl {
} }
} }
impl<T: Archive, R: Archive, _D: Fallible + ?Sized, const D: usize> impl<T: Scalar + Archive, R: Archive, _D: Fallible + ?Sized, const D: usize>
Deserialize<Isometry<T, R, D>, _D> for Isometry<T::Archived, R::Archived, D> Deserialize<Isometry<T, R, D>, _D> for Isometry<T::Archived, R::Archived, D>
where where
T::Archived: Scalar + Deserialize<T, _D>, T::Archived: Scalar + Deserialize<T, _D>,
@ -155,9 +160,9 @@ mod rkyv_impl {
} }
} }
impl<T: hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Isometry<T, R, D> impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Isometry<T, R, D>
where where
InnerOwned<T, Const<D>>: hash::Hash, Owned<T, Const<D>>: hash::Hash,
{ {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.translation.hash(state); self.translation.hash(state);
@ -165,9 +170,12 @@ where
} }
} }
impl<T: Copy, R: Copy, const D: usize> Copy for Isometry<T, R, D> where InnerOwned<T, Const<D>>: Copy {} impl<T: Scalar + Copy, R: Copy, const D: usize> Copy for Isometry<T, R, D> where
Owned<T, Const<D>>: Copy
{
}
impl<T: Clone, R: Clone, const D: usize> Clone for Isometry<T, R, D> { impl<T: Scalar, R: Clone, const D: usize> Clone for Isometry<T, R, D> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@ -630,7 +638,7 @@ where
* Display * Display
* *
*/ */
impl<T: Scalar + fmt::Display, R, const D: usize> fmt::Display for Isometry<T, R, D> impl<T: RealField + fmt::Display, R, const D: usize> fmt::Display for Isometry<T, R, D>
where where
R: fmt::Display, R: fmt::Display,
{ {

View File

@ -1,5 +1,5 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -97,7 +97,7 @@ where
T: SimdRealField + Arbitrary + Send, T: SimdRealField + Arbitrary + Send,
T::Element: SimdRealField, T::Element: SimdRealField,
R: AbstractRotation<T, D> + Arbitrary + Send, R: AbstractRotation<T, D> + Arbitrary + Send,
InnerOwned<T, crate::Const<D>>: Send, Owned<T, crate::Const<D>>: Send,
{ {
#[inline] #[inline]
fn arbitrary(rng: &mut Gen) -> Self { fn arbitrary(rng: &mut Gen) -> Self {

View File

@ -18,29 +18,27 @@ use crate::base::{Matrix4, Vector, Vector3};
use crate::geometry::{Point3, Projective3}; use crate::geometry::{Point3, Projective3};
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix. /// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
#[repr(transparent)] #[repr(C)]
pub struct Orthographic3<T> { pub struct Orthographic3<T> {
matrix: Matrix4<T>, matrix: Matrix4<T>,
} }
impl<T: Copy> Copy for Orthographic3<T> {} impl<T: RealField> Copy for Orthographic3<T> {}
impl<T: Clone> Clone for Orthographic3<T> { impl<T: RealField> Clone for Orthographic3<T> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self::from_matrix_unchecked(self.matrix)
matrix: self.matrix.clone(),
}
} }
} }
impl<T: fmt::Debug> fmt::Debug for Orthographic3<T> { impl<T: RealField> fmt::Debug for Orthographic3<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.matrix.fmt(f) self.matrix.fmt(f)
} }
} }
impl<T: PartialEq> PartialEq for Orthographic3<T> { impl<T: RealField> PartialEq for Orthographic3<T> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
@ -64,7 +62,7 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T: Serialize> Serialize for Orthographic3<T> { impl<T: RealField + Serialize> Serialize for Orthographic3<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
@ -74,7 +72,7 @@ impl<T: Serialize> Serialize for Orthographic3<T> {
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: Deserialize<'a>> Deserialize<'a> for Orthographic3<T> { impl<'a, T: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
Des: Deserializer<'a>, Des: Deserializer<'a>,
@ -85,8 +83,31 @@ impl<'a, T: Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
} }
} }
/// # Basic methods and casts.
impl<T> Orthographic3<T> { impl<T> Orthographic3<T> {
/// Wraps the given matrix to interpret it as a 3D orthographic matrix.
///
/// It is not checked whether or not the given matrix actually represents an orthographic
/// projection.
///
/// # Example
/// ```
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let mat = Matrix4::new(
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0
/// );
/// let proj = Orthographic3::from_matrix_unchecked(mat);
/// assert_eq!(proj, Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0));
/// ```
#[inline]
pub const fn from_matrix_unchecked(matrix: Matrix4<T>) -> Self {
Self { matrix }
}
}
impl<T: RealField> Orthographic3<T> {
/// Creates a new orthographic projection matrix. /// Creates a new orthographic projection matrix.
/// ///
/// This follows the OpenGL convention, so this will flip the `z` axis. /// This follows the OpenGL convention, so this will flip the `z` axis.
@ -130,11 +151,8 @@ impl<T> Orthographic3<T> {
/// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0)); /// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0));
/// ``` /// ```
#[inline] #[inline]
pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
where let matrix = Matrix4::<T>::identity();
T: RealField,
{
let matrix = Matrix4::identity();
let mut res = Self::from_matrix_unchecked(matrix); let mut res = Self::from_matrix_unchecked(matrix);
res.set_left_and_right(left, right); res.set_left_and_right(left, right);
@ -146,10 +164,7 @@ impl<T> Orthographic3<T> {
/// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view. /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
#[inline] #[inline]
pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self {
where
T: RealField,
{
assert!( assert!(
znear != zfar, znear != zfar,
"The far plane must not be equal to the near plane." "The far plane must not be equal to the near plane."
@ -192,10 +207,7 @@ impl<T> Orthographic3<T> {
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
pub fn inverse(&self) -> Matrix4<T> pub fn inverse(&self) -> Matrix4<T> {
where
T: RealField,
{
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
let inv_m11 = T::one() / self.matrix[(0, 0)]; let inv_m11 = T::one() / self.matrix[(0, 0)];
@ -229,7 +241,6 @@ impl<T> Orthographic3<T> {
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
// TODO: rename into `into_homogeneous` to appease clippy.
pub fn to_homogeneous(self) -> Matrix4<T> { pub fn to_homogeneous(self) -> Matrix4<T> {
self.matrix self.matrix
} }
@ -265,8 +276,7 @@ impl<T> Orthographic3<T> {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn as_projective(&self) -> &Projective3<T> { pub fn as_projective(&self) -> &Projective3<T> {
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix. unsafe { &*(self as *const Orthographic3<T> as *const Projective3<T>) }
unsafe { &*(self as *const _ as *const _) }
} }
/// This transformation seen as a `Projective3`. /// This transformation seen as a `Projective3`.
@ -279,7 +289,6 @@ impl<T> Orthographic3<T> {
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
// TODO: rename into `into_projective` to appease clippy.
pub fn to_projective(self) -> Projective3<T> { pub fn to_projective(self) -> Projective3<T> {
Projective3::from_matrix_unchecked(self.matrix) Projective3::from_matrix_unchecked(self.matrix)
} }
@ -311,10 +320,7 @@ impl<T> Orthographic3<T> {
pub fn unwrap(self) -> Matrix4<T> { pub fn unwrap(self) -> Matrix4<T> {
self.matrix self.matrix
} }
}
/// # Mathematical methods.
impl<T: RealField> Orthographic3<T> {
/// The left offset of the view cuboid. /// The left offset of the view cuboid.
/// ///
/// ``` /// ```

View File

@ -34,7 +34,7 @@ impl<T: RealField> Clone for Perspective3<T> {
} }
impl<T: RealField> fmt::Debug for Perspective3<T> { impl<T: RealField> fmt::Debug for Perspective3<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.matrix.fmt(f) self.matrix.fmt(f)
} }
} }
@ -158,8 +158,7 @@ impl<T: RealField> Perspective3<T> {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn as_projective(&self) -> &Projective3<T> { pub fn as_projective(&self) -> &Projective3<T> {
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix. unsafe { &*(self as *const Perspective3<T> as *const Projective3<T>) }
unsafe { &*(self as *const _ as *const _) }
} }
/// This transformation seen as a `Projective3`. /// This transformation seen as a `Projective3`.

View File

@ -5,7 +5,6 @@ use std::fmt;
use std::hash; use std::hash;
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
use std::mem::{ManuallyDrop, MaybeUninit};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -15,13 +14,11 @@ use abomonation::Abomonation;
use simba::simd::SimdPartialOrd; use simba::simd::SimdPartialOrd;
use crate::allocator::InnerAllocator;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::{Const, DefaultAllocator, OVector}; use crate::base::{Const, DefaultAllocator, OVector, Scalar};
use crate::storage::InnerOwned; use std::mem::MaybeUninit;
use crate::Scalar;
/// A point in an euclidean space. /// A point in an euclidean space.
/// ///
@ -42,16 +39,17 @@ use crate::Scalar;
/// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation /// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation /// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
/// of said transformations for details. /// of said transformations for details.
#[repr(transparent)] #[repr(C)]
pub struct OPoint<T, D: DimName> #[derive(Debug, Clone)]
pub struct OPoint<T: Scalar, D: DimName>
where where
DefaultAllocator: InnerAllocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
/// The coordinates of this point, i.e., the shift from the origin. /// The coordinates of this point, i.e., the shift from the origin.
pub coords: OVector<T, D>, pub coords: OVector<T, D>,
} }
impl<T: hash::Hash, D: DimName> hash::Hash for OPoint<T, D> impl<T: Scalar + hash::Hash, D: DimName> hash::Hash for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -60,37 +58,15 @@ where
} }
} }
impl<T: Copy, D: DimName> Copy for OPoint<T, D> impl<T: Scalar + Copy, D: DimName> Copy for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
OVector<T, D>: Copy, OVector<T, D>: Copy,
{ {
} }
impl<T: Clone, D: DimName> Clone for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
OVector<T, D>: Clone,
{
fn clone(&self) -> Self {
Self::from(self.coords.clone())
}
}
impl<T: fmt::Debug, D: DimName> fmt::Debug for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
OVector<T, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("OPoint")
.field("coords", &self.coords)
.finish()
}
}
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T, D: DimName> bytemuck::Zeroable for OPoint<T, D> unsafe impl<T: Scalar, D: DimName> bytemuck::Zeroable for OPoint<T, D>
where where
OVector<T, D>: bytemuck::Zeroable, OVector<T, D>: bytemuck::Zeroable,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -98,7 +74,7 @@ where
} }
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T, D: DimName> bytemuck::Pod for OPoint<T, D> unsafe impl<T: Scalar, D: DimName> bytemuck::Pod for OPoint<T, D>
where where
T: Copy, T: Copy,
OVector<T, D>: bytemuck::Pod, OVector<T, D>: bytemuck::Pod,
@ -107,10 +83,10 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T: Serialize, D: DimName> Serialize for OPoint<T, D> impl<T: Scalar, D: DimName> Serialize for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
<DefaultAllocator as InnerAllocator<T, D>>::Buffer: Serialize, <DefaultAllocator as Allocator<T, D>>::Buffer: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -121,10 +97,10 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: Deserialize<'a>, D: DimName> Deserialize<'a> for OPoint<T, D> impl<'a, T: Scalar, D: DimName> Deserialize<'a> for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
<DefaultAllocator as InnerAllocator<T, D>>::Buffer: Deserialize<'a>, <DefaultAllocator as Allocator<T, D>>::Buffer: Deserialize<'a>,
{ {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
@ -139,6 +115,7 @@ where
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, D: DimName> Abomonation for OPoint<T, D> impl<T, D: DimName> Abomonation for OPoint<T, D>
where where
T: Scalar,
OVector<T, D>: Abomonation, OVector<T, D>: Abomonation,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -155,7 +132,7 @@ where
} }
} }
impl<T, D: DimName> OPoint<T, D> impl<T: Scalar, D: DimName> OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -173,9 +150,8 @@ where
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
pub fn map<T2, F: FnMut(T) -> T2>(&self, f: F) -> OPoint<T2, D> pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, f: F) -> OPoint<T2, D>
where where
T: Clone,
DefaultAllocator: Allocator<T2, D>, DefaultAllocator: Allocator<T2, D>,
{ {
self.coords.map(f).into() self.coords.map(f).into()
@ -187,19 +163,16 @@ where
/// ``` /// ```
/// # use nalgebra::{Point2, Point3}; /// # use nalgebra::{Point2, Point3};
/// let mut p = Point2::new(1.0, 2.0); /// let mut p = Point2::new(1.0, 2.0);
/// p.apply(|e| e * 10.0); /// p.apply(|e| *e = *e * 10.0);
/// assert_eq!(p, Point2::new(10.0, 20.0)); /// assert_eq!(p, Point2::new(10.0, 20.0));
/// ///
/// // This works in any dimension. /// // This works in any dimension.
/// let mut p = Point3::new(1.0, 2.0, 3.0); /// let mut p = Point3::new(1.0, 2.0, 3.0);
/// p.apply(|e| e * 10.0); /// p.apply(|e| *e = *e * 10.0);
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0)); /// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
/// ``` /// ```
#[inline] #[inline]
pub fn apply<F: FnMut(T) -> T>(&mut self, f: F) pub fn apply<F: FnMut(&mut T)>(&mut self, f: F) {
where
T: Clone,
{
self.coords.apply(f) self.coords.apply(f)
} }
@ -221,45 +194,25 @@ where
#[inline] #[inline]
#[must_use] #[must_use]
pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<D, U1>> pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<D, U1>>
where
T: One + Clone,
D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
{
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
for i in 0..D::dim() {
unsafe {
*res.get_unchecked_mut(i) = MaybeUninit::new(self.coords[i].clone());
}
}
res[(D::dim(), 0)] = MaybeUninit::new(T::one());
unsafe { res.assume_init() }
}
/// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the
/// end of it. Unlike [`to_homogeneous`], this method does not require `T: Clone`.
pub fn into_homogeneous(self) -> OVector<T, DimNameSum<D, U1>>
where where
T: One, T: One,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>, DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
{ {
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized(); // TODO: this is mostly a copy-past from Vector::push.
let mut md = self.manually_drop(); // But we cant use Vector::push because of the DimAdd bound
// (which we dont use because we use DimNameAdd).
// We should find a way to re-use Vector::push.
let len = self.len();
let mut res = crate::Matrix::uninit(DimNameSum::<D, U1>::name(), Const::<1>);
// This is basically a copy_from except that we warp the copied
// values into MaybeUninit.
res.generic_slice_mut((0, 0), self.coords.shape_generic())
.zip_apply(&self.coords, |out, e| *out = MaybeUninit::new(e));
res[(len, 0)] = MaybeUninit::new(T::one());
for i in 0..D::dim() { // Safety: res has been fully initialized.
unsafe { unsafe { res.assume_init() }
*res.get_unchecked_mut(i) =
MaybeUninit::new(ManuallyDrop::take(md.coords.get_unchecked_mut(i)));
}
}
unsafe {
*res.get_unchecked_mut(D::dim()) = MaybeUninit::new(T::one());
res.assume_init()
}
} }
/// Creates a new point with the given coordinates. /// Creates a new point with the given coordinates.
@ -322,7 +275,9 @@ where
/// assert_eq!(it.next(), Some(3.0)); /// assert_eq!(it.next(), Some(3.0));
/// assert_eq!(it.next(), None); /// assert_eq!(it.next(), None);
#[inline] #[inline]
pub fn iter(&self) -> MatrixIter<T, D, Const<1>, InnerOwned<T, D>> { pub fn iter(
&self,
) -> MatrixIter<'_, T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
self.coords.iter() self.coords.iter()
} }
@ -346,7 +301,9 @@ where
/// ///
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0)); /// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
#[inline] #[inline]
pub fn iter_mut(&mut self) -> MatrixIterMut<T, D, Const<1>, InnerOwned<T, D>> { pub fn iter_mut(
&mut self,
) -> MatrixIterMut<'_, T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
self.coords.iter_mut() self.coords.iter_mut()
} }
@ -364,7 +321,7 @@ where
} }
} }
impl<T: AbsDiffEq, D: DimName> AbsDiffEq for OPoint<T, D> impl<T: Scalar + AbsDiffEq, D: DimName> AbsDiffEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -382,7 +339,7 @@ where
} }
} }
impl<T: RelativeEq, D: DimName> RelativeEq for OPoint<T, D> impl<T: Scalar + RelativeEq, D: DimName> RelativeEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -404,7 +361,7 @@ where
} }
} }
impl<T: UlpsEq, D: DimName> UlpsEq for OPoint<T, D> impl<T: Scalar + UlpsEq, D: DimName> UlpsEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -420,9 +377,9 @@ where
} }
} }
impl<T: Eq, D: DimName> Eq for OPoint<T, D> where DefaultAllocator: Allocator<T, D> {} impl<T: Scalar + Eq, D: DimName> Eq for OPoint<T, D> where DefaultAllocator: Allocator<T, D> {}
impl<T: PartialEq, D: DimName> PartialEq for OPoint<T, D> impl<T: Scalar, D: DimName> PartialEq for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -432,7 +389,7 @@ where
} }
} }
impl<T: PartialOrd, D: DimName> PartialOrd for OPoint<T, D> impl<T: Scalar + PartialOrd, D: DimName> PartialOrd for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -497,7 +454,7 @@ where
* Display * Display
* *
*/ */
impl<T: fmt::Display, D: DimName> fmt::Display for OPoint<T, D> impl<T: Scalar + fmt::Display, D: DimName> fmt::Display for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {

View File

@ -1,5 +1,3 @@
use std::mem::{ManuallyDrop, MaybeUninit};
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -22,23 +20,10 @@ use simba::scalar::{ClosedDiv, SupersetOf};
use crate::geometry::Point; use crate::geometry::Point;
/// # Other construction methods /// # Other construction methods
impl<T, D: DimName> OPoint<T, D> impl<T: Scalar, D: DimName> OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
/// Creates a new point with uninitialized coordinates.
#[inline]
pub fn new_uninitialized() -> OPoint<MaybeUninit<T>, D> {
OPoint::from(OVector::new_uninitialized_generic(D::name(), Const::<1>))
}
/// Converts `self` into a point whose coordinates must be manually dropped.
/// This should be zero-cost.
#[inline]
pub fn manually_drop(self) -> OPoint<ManuallyDrop<T>, D> {
OPoint::from(self.coords.manually_drop())
}
/// Creates a new point with all coordinates equal to zero. /// Creates a new point with all coordinates equal to zero.
/// ///
/// # Example /// # Example
@ -57,9 +42,9 @@ where
#[inline] #[inline]
pub fn origin() -> Self pub fn origin() -> Self
where where
T: Zero + Clone, T: Zero,
{ {
Self::from(OVector::<_, D>::zeros()) Self::from(OVector::from_element(T::zero()))
} }
/// Creates a new point from a slice. /// Creates a new point from a slice.
@ -77,11 +62,8 @@ where
/// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0)); /// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0));
/// ``` /// ```
#[inline] #[inline]
pub fn from_slice(components: &[T]) -> Self pub fn from_slice(components: &[T]) -> Self {
where Self::from(OVector::from_row_slice(components))
T: Clone,
{
Self::from(OVector::<_, D>::from_row_slice(components))
} }
/// Creates a new point from its homogeneous vector representation. /// Creates a new point from its homogeneous vector representation.
@ -139,7 +121,7 @@ where
/// let pt2 = pt.cast::<f32>(); /// let pt2 = pt.cast::<f32>();
/// assert_eq!(pt2, Point2::new(1.0f32, 2.0)); /// assert_eq!(pt2, Point2::new(1.0f32, 2.0));
/// ``` /// ```
pub fn cast<To>(self) -> OPoint<To, D> pub fn cast<To: Scalar>(self) -> OPoint<To, D>
where where
OPoint<To, D>: SupersetOf<Self>, OPoint<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D>, DefaultAllocator: Allocator<To, D>,
@ -169,7 +151,7 @@ where
} }
#[cfg(feature = "rand-no-std")] #[cfg(feature = "rand-no-std")]
impl<T, D: DimName> Distribution<OPoint<T, D>> for Standard impl<T: Scalar, D: DimName> Distribution<OPoint<T, D>> for Standard
where where
Standard: Distribution<T>, Standard: Distribution<T>,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -182,10 +164,10 @@ where
} }
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T: Arbitrary + Send, D: DimName> Arbitrary for OPoint<T, D> impl<T: Scalar + Arbitrary + Send, D: DimName> Arbitrary for OPoint<T, D>
where where
<DefaultAllocator as Allocator<T, D>>::Buffer: Send,
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
crate::base::storage::InnerOwned<T, D>: Clone + Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
@ -201,7 +183,7 @@ where
// NOTE: the impl for Point1 is not with the others so that we // NOTE: the impl for Point1 is not with the others so that we
// can add a section with the impl block comment. // can add a section with the impl block comment.
/// # Construction from individual components /// # Construction from individual components
impl<T> Point1<T> { impl<T: Scalar> Point1<T> {
/// Initializes this point from its components. /// Initializes this point from its components.
/// ///
/// # Example /// # Example
@ -220,7 +202,7 @@ impl<T> Point1<T> {
} }
macro_rules! componentwise_constructors_impl( macro_rules! componentwise_constructors_impl(
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$( ($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<T> $Point<T> { impl<T: Scalar> $Point<T> {
#[doc = "Initializes this point from its components."] #[doc = "Initializes this point from its components."]
#[doc = "# Example\n```"] #[doc = "# Example\n```"]
#[doc = $doc] #[doc = $doc]

View File

@ -2,7 +2,7 @@ use num::{One, Zero};
use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf}; use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf};
use simba::simd::PrimitiveSimdValue; use simba::simd::PrimitiveSimdValue;
use crate::base::allocator::{Allocator, InnerAllocator}; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar}; use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar};
@ -19,7 +19,8 @@ use crate::{DimName, OPoint};
impl<T1, T2, D: DimName> SubsetOf<OPoint<T2, D>> for OPoint<T1, D> impl<T1, T2, D: DimName> SubsetOf<OPoint<T2, D>> for OPoint<T1, D>
where where
T2: SupersetOf<T1>, T1: Scalar,
T2: Scalar + SupersetOf<T1>,
DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>, DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>,
{ {
#[inline] #[inline]
@ -43,6 +44,7 @@ where
impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D> impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D>
where where
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
T1: Scalar,
T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>, T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>,
DefaultAllocator: Allocator<T1, D> DefaultAllocator: Allocator<T1, D>
+ Allocator<T2, D> + Allocator<T2, D>
@ -54,7 +56,7 @@ where
#[inline] #[inline]
fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> { fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> {
let p: OPoint<T2, D> = self.to_superset(); let p: OPoint<T2, D> = self.to_superset();
p.into_homogeneous() p.to_homogeneous()
} }
#[inline] #[inline]
@ -64,25 +66,25 @@ where
#[inline] #[inline]
fn from_superset_unchecked(v: &OVector<T2, DimNameSum<D, U1>>) -> Self { fn from_superset_unchecked(v: &OVector<T2, DimNameSum<D, U1>>) -> Self {
let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone();
Self { Self {
coords: crate::convert_unchecked(coords), coords: crate::convert_unchecked(coords),
} }
} }
} }
impl<T: Zero + One, D: DimName> From<OPoint<T, D>> for OVector<T, DimNameSum<D, U1>> impl<T: Scalar + Zero + One, D: DimName> From<OPoint<T, D>> for OVector<T, DimNameSum<D, U1>>
where where
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>, DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>,
{ {
#[inline] #[inline]
fn from(t: OPoint<T, D>) -> Self { fn from(t: OPoint<T, D>) -> Self {
t.into_homogeneous() t.to_homogeneous()
} }
} }
impl<T, const D: usize> From<[T; D]> for Point<T, D> { impl<T: Scalar, const D: usize> From<[T; D]> for Point<T, D> {
#[inline] #[inline]
fn from(coords: [T; D]) -> Self { fn from(coords: [T; D]) -> Self {
Point { Point {
@ -91,19 +93,16 @@ impl<T, const D: usize> From<[T; D]> for Point<T, D> {
} }
} }
impl<T, const D: usize> From<Point<T, D>> for [T; D] impl<T: Scalar, const D: usize> From<Point<T, D>> for [T; D] {
where
T: Clone,
{
#[inline] #[inline]
fn from(p: Point<T, D>) -> Self { fn from(p: Point<T, D>) -> Self {
p.coords.into() p.coords.into()
} }
} }
impl<T, D: DimName> From<OVector<T, D>> for OPoint<T, D> impl<T: Scalar, D: DimName> From<OVector<T, D>> for OPoint<T, D>
where where
DefaultAllocator: InnerAllocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
#[inline] #[inline]
fn from(coords: OVector<T, D>) -> Self { fn from(coords: OVector<T, D>) -> Self {
@ -111,81 +110,85 @@ where
} }
} }
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 2]> for Point<T, D> impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 2]>
for Point<T, D>
where where
T: From<[<T as simba::simd::SimdValue>::Element; 2]>, T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
T::Element: Scalar, T::Element: Scalar + Copy,
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
{ {
#[inline] #[inline]
fn from(arr: [Point<T::Element, D>; 2]) -> Self { fn from(arr: [Point<T::Element, D>; 2]) -> Self {
Self::from(OVector::from([ Self::from(OVector::from([arr[0].coords, arr[1].coords]))
arr[0].coords.clone(),
arr[1].coords.clone(),
]))
} }
} }
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 4]> for Point<T, D> impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 4]>
for Point<T, D>
where where
T: From<[<T as simba::simd::SimdValue>::Element; 4]>, T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
T::Element: Scalar, T::Element: Scalar + Copy,
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
{ {
#[inline] #[inline]
fn from(arr: [Point<T::Element, D>; 4]) -> Self { fn from(arr: [Point<T::Element, D>; 4]) -> Self {
Self::from(OVector::from([ Self::from(OVector::from([
arr[0].coords.clone(), arr[0].coords,
arr[1].coords.clone(), arr[1].coords,
arr[2].coords.clone(), arr[2].coords,
arr[3].coords.clone(), arr[3].coords,
])) ]))
} }
} }
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 8]> for Point<T, D> impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 8]>
for Point<T, D>
where where
T: From<[<T as simba::simd::SimdValue>::Element; 8]>, T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
T::Element: Scalar, T::Element: Scalar + Copy,
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
{ {
#[inline] #[inline]
fn from(arr: [Point<T::Element, D>; 8]) -> Self { fn from(arr: [Point<T::Element, D>; 8]) -> Self {
Self::from(OVector::from([ Self::from(OVector::from([
arr[0].coords.clone(), arr[0].coords,
arr[1].coords.clone(), arr[1].coords,
arr[2].coords.clone(), arr[2].coords,
arr[3].coords.clone(), arr[3].coords,
arr[4].coords.clone(), arr[4].coords,
arr[5].coords.clone(), arr[5].coords,
arr[6].coords.clone(), arr[6].coords,
arr[7].coords.clone(), arr[7].coords,
])) ]))
} }
} }
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 16]> impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 16]>
for Point<T, D> for Point<T, D>
where where
T: From<[<T as simba::simd::SimdValue>::Element; 16]>, T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
T::Element: Scalar, T::Element: Scalar + Copy,
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
{ {
#[inline] #[inline]
fn from(arr: [Point<T::Element, D>; 16]) -> Self { fn from(arr: [Point<T::Element, D>; 16]) -> Self {
Self::from(OVector::from([ Self::from(OVector::from([
arr[0].coords.clone(), arr[0].coords,
arr[1].coords.clone(), arr[1].coords,
arr[2].coords.clone(), arr[2].coords,
arr[3].coords.clone(), arr[3].coords,
arr[4].coords.clone(), arr[4].coords,
arr[5].coords.clone(), arr[5].coords,
arr[6].coords.clone(), arr[6].coords,
arr[7].coords.clone(), arr[7].coords,
arr[8].coords.clone(), arr[8].coords,
arr[9].coords.clone(), arr[9].coords,
arr[10].coords.clone(), arr[10].coords,
arr[11].coords.clone(), arr[11].coords,
arr[12].coords.clone(), arr[12].coords,
arr[13].coords.clone(), arr[13].coords,
arr[14].coords.clone(), arr[14].coords,
arr[15].coords.clone(), arr[15].coords,
])) ]))
} }
} }

View File

@ -1,7 +1,7 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
use crate::base::{U1, U2, U3, U4, U5, U6}; use crate::base::{Scalar, U1, U2, U3, U4, U5, U6};
use crate::geometry::OPoint; use crate::geometry::OPoint;
@ -13,7 +13,7 @@ use crate::geometry::OPoint;
macro_rules! deref_impl( macro_rules! deref_impl(
($D: ty, $Target: ident $(, $comps: ident)*) => { ($D: ty, $Target: ident $(, $comps: ident)*) => {
impl<T> Deref for OPoint<T, $D> impl<T: Scalar> Deref for OPoint<T, $D>
{ {
type Target = $Target<T>; type Target = $Target<T>;
@ -23,7 +23,7 @@ macro_rules! deref_impl(
} }
} }
impl<T> DerefMut for OPoint<T, $D> impl<T: Scalar> DerefMut for OPoint<T, $D>
{ {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {

View File

@ -21,7 +21,7 @@ use crate::DefaultAllocator;
* Indexing. * Indexing.
* *
*/ */
impl<T, D: DimName> Index<usize> for OPoint<T, D> impl<T: Scalar, D: DimName> Index<usize> for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
@ -33,7 +33,7 @@ where
} }
} }
impl<T, D: DimName> IndexMut<usize> for OPoint<T, D> impl<T: Scalar, D: DimName> IndexMut<usize> for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {

View File

@ -1,8 +1,8 @@
use simba::simd::SimdValue; use simba::simd::SimdValue;
use crate::base::OVector; use crate::base::{OVector, Scalar};
use crate::geometry::Point; use crate::geometry::Point;
use crate::Scalar;
impl<T: Scalar + SimdValue, const D: usize> SimdValue for Point<T, D> impl<T: Scalar + SimdValue, const D: usize> SimdValue for Point<T, D>
where where

View File

@ -6,7 +6,7 @@ use std::hash::{Hash, Hasher};
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -26,29 +26,29 @@ use crate::geometry::{Point3, Rotation};
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion /// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
/// that may be used as a rotation. /// that may be used as a rotation.
#[repr(transparent)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Quaternion<T> { pub struct Quaternion<T> {
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
pub coords: Vector4<T>, pub coords: Vector4<T>,
} }
impl<T: Hash> Hash for Quaternion<T> { impl<T: Scalar + Hash> Hash for Quaternion<T> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.coords.hash(state) self.coords.hash(state)
} }
} }
impl<T: Eq> Eq for Quaternion<T> {} impl<T: Scalar + Eq> Eq for Quaternion<T> {}
impl<T: PartialEq> PartialEq for Quaternion<T> { impl<T: Scalar> PartialEq for Quaternion<T> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.coords == right.coords self.coords == right.coords
} }
} }
impl<T: Zero + Clone> Default for Quaternion<T> { impl<T: Scalar + Zero> Default for Quaternion<T> {
fn default() -> Self { fn default() -> Self {
Quaternion { Quaternion {
coords: Vector4::zeros(), coords: Vector4::zeros(),
@ -57,10 +57,10 @@ impl<T: Zero + Clone> Default for Quaternion<T> {
} }
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::Zeroable for Quaternion<T> where Vector4<T>: bytemuck::Zeroable {} unsafe impl<T: Scalar> bytemuck::Zeroable for Quaternion<T> where Vector4<T>: bytemuck::Zeroable {}
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::Pod for Quaternion<T> unsafe impl<T: Scalar> bytemuck::Pod for Quaternion<T>
where where
Vector4<T>: bytemuck::Pod, Vector4<T>: bytemuck::Pod,
T: Copy, T: Copy,
@ -68,7 +68,7 @@ where
} }
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T> Abomonation for Quaternion<T> impl<T: Scalar> Abomonation for Quaternion<T>
where where
Vector4<T>: Abomonation, Vector4<T>: Abomonation,
{ {
@ -86,7 +86,7 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T> Serialize for Quaternion<T> impl<T: Scalar> Serialize for Quaternion<T>
where where
Owned<T, U4>: Serialize, Owned<T, U4>: Serialize,
{ {
@ -99,7 +99,7 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T> Deserialize<'a> for Quaternion<T> impl<'a, T: Scalar> Deserialize<'a> for Quaternion<T>
where where
Owned<T, U4>: Deserialize<'a>, Owned<T, U4>: Deserialize<'a>,
{ {
@ -1045,8 +1045,8 @@ impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for Quaternion<T> {
} }
} }
impl<T: fmt::Display> fmt::Display for Quaternion<T> { impl<T: RealField + fmt::Display> fmt::Display for Quaternion<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"Quaternion {} ({}, {}, {})", "Quaternion {} ({}, {}, {})",
@ -1097,7 +1097,7 @@ impl<T: SimdRealField> UnitQuaternion<T>
where where
T::Element: SimdRealField, T::Element: SimdRealField,
{ {
/// The rotation angle in \[0; pi\] of this unit quaternion. /// The rotation angle in [0; pi] of this unit quaternion.
/// ///
/// # Example /// # Example
/// ``` /// ```

View File

@ -1,7 +1,7 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::dimension::U4; use crate::base::dimension::U4;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -179,7 +179,7 @@ where
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T: SimdRealField + Arbitrary> Arbitrary for Quaternion<T> impl<T: SimdRealField + Arbitrary> Arbitrary for Quaternion<T>
where where
InnerOwned<T, U4>: Send, Owned<T, U4>: Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
@ -881,8 +881,8 @@ where
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T: RealField + Arbitrary> Arbitrary for UnitQuaternion<T> impl<T: RealField + Arbitrary> Arbitrary for UnitQuaternion<T>
where where
InnerOwned<T, U4>: Send, Owned<T, U4>: Send,
InnerOwned<T, U3>: Send, Owned<T, U3>: Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {

View File

@ -28,7 +28,8 @@ use crate::geometry::{
impl<T1, T2> SubsetOf<Quaternion<T2>> for Quaternion<T1> impl<T1, T2> SubsetOf<Quaternion<T2>> for Quaternion<T1>
where where
T2: SupersetOf<T1>, T1: Scalar,
T2: Scalar + SupersetOf<T1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Quaternion<T2> { fn to_superset(&self) -> Quaternion<T2> {
@ -50,7 +51,8 @@ where
impl<T1, T2> SubsetOf<UnitQuaternion<T2>> for UnitQuaternion<T1> impl<T1, T2> SubsetOf<UnitQuaternion<T2>> for UnitQuaternion<T1>
where where
T2: SupersetOf<T1>, T1: Scalar,
T2: Scalar + SupersetOf<T1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> UnitQuaternion<T2> { fn to_superset(&self) -> UnitQuaternion<T2> {
@ -237,14 +239,14 @@ where
} }
} }
impl<T> From<Vector4<T>> for Quaternion<T> { impl<T: Scalar> From<Vector4<T>> for Quaternion<T> {
#[inline] #[inline]
fn from(coords: Vector4<T>) -> Self { fn from(coords: Vector4<T>) -> Self {
Self { coords } Self { coords }
} }
} }
impl<T> From<[T; 4]> for Quaternion<T> { impl<T: Scalar> From<[T; 4]> for Quaternion<T> {
#[inline] #[inline]
fn from(coords: [T; 4]) -> Self { fn from(coords: [T; 4]) -> Self {
Self { Self {

View File

@ -12,14 +12,13 @@ impl<T: Scalar + SimdValue> Deref for Quaternion<T> {
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
// Safety: Self and IJKW are both stored as contiguous coordinates. unsafe { &*(self as *const Self as *const Self::Target) }
unsafe { &*(self as *const _ as *const _) }
} }
} }
impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> { impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self as *mut _ as *mut _) } unsafe { &mut *(self as *mut Self as *mut Self::Target) }
} }
} }

View File

@ -59,12 +59,12 @@ use std::ops::{
use crate::base::dimension::U3; use crate::base::dimension::U3;
use crate::base::storage::Storage; use crate::base::storage::Storage;
use crate::base::{Const, Unit, Vector, Vector3}; use crate::base::{Const, Scalar, Unit, Vector, Vector3};
use crate::SimdRealField; use crate::SimdRealField;
use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion}; use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
impl<T> Index<usize> for Quaternion<T> { impl<T: Scalar> Index<usize> for Quaternion<T> {
type Output = T; type Output = T;
#[inline] #[inline]
@ -73,7 +73,7 @@ impl<T> Index<usize> for Quaternion<T> {
} }
} }
impl<T> IndexMut<usize> for Quaternion<T> { impl<T: Scalar> IndexMut<usize> for Quaternion<T> {
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut T { fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.coords[i] &mut self.coords[i]

View File

@ -1,5 +1,3 @@
use std::mem::MaybeUninit;
use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
use crate::base::{Const, Matrix, Unit, Vector}; use crate::base::{Const, Matrix, Unit, Vector};
use crate::dimension::{Dim, U1}; use crate::dimension::{Dim, U1};
@ -9,7 +7,7 @@ use simba::scalar::ComplexField;
use crate::geometry::Point; use crate::geometry::Point;
/// A reflection wrt. a plane. /// A reflection wrt. a plane.
pub struct Reflection<T, D: Dim, S> { pub struct Reflection<T, D, S> {
axis: Vector<T, D, S>, axis: Vector<T, D, S>,
bias: T, bias: T,
} }
@ -88,40 +86,40 @@ impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
pub fn reflect_rows<R2: Dim, C2: Dim, S2, S3>( pub fn reflect_rows<R2: Dim, C2: Dim, S2, S3>(
&self, &self,
lhs: &mut Matrix<T, R2, C2, S2>, lhs: &mut Matrix<T, R2, C2, S2>,
work: &mut Vector<MaybeUninit<T>, R2, S3>, work: &mut Vector<T, R2, S3>,
) where ) where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
S3: StorageMut<MaybeUninit<T>, R2>, S3: StorageMut<T, R2>,
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>, ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
{ {
let mut work = lhs.mul_to(&self.axis, work); lhs.mul_to(&self.axis, work);
if !self.bias.is_zero() { if !self.bias.is_zero() {
work.add_scalar_mut(-self.bias); work.add_scalar_mut(-self.bias);
} }
let m_two: T = crate::convert(-2.0f64); let m_two: T = crate::convert(-2.0f64);
lhs.gerc(m_two, &work, &self.axis, T::one()); lhs.gerc(m_two, work, &self.axis, T::one());
} }
/// Applies the reflection to the rows of `lhs`. /// Applies the reflection to the rows of `lhs`.
pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>( pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>(
&self, &self,
lhs: &mut Matrix<T, R2, C2, S2>, lhs: &mut Matrix<T, R2, C2, S2>,
work: &mut Vector<MaybeUninit<T>, R2, S3>, work: &mut Vector<T, R2, S3>,
sign: T, sign: T,
) where ) where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
S3: StorageMut<MaybeUninit<T>, R2>, S3: StorageMut<T, R2>,
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>, ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
{ {
let mut work = lhs.mul_to(&self.axis, work); lhs.mul_to(&self.axis, work);
if !self.bias.is_zero() { if !self.bias.is_zero() {
work.add_scalar_mut(-self.bias); work.add_scalar_mut(-self.bias);
} }
let m_two = sign.scale(crate::convert(-2.0f64)); let m_two = sign.scale(crate::convert(-2.0f64));
lhs.gerc(m_two, &work, &self.axis, sign); lhs.gerc(m_two, work, &self.axis, sign);
} }
} }

View File

@ -9,8 +9,7 @@ use std::io::{Result as IOResult, Write};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
use crate::storage::InnerOwned;
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
@ -54,26 +53,29 @@ use crate::geometry::Point;
/// # Conversion /// # Conversion
/// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix) /// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
/// ///
#[repr(transparent)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct Rotation<T, const D: usize> { pub struct Rotation<T, const D: usize> {
matrix: SMatrix<T, D, D>, matrix: SMatrix<T, D, D>,
} }
impl<T: hash::Hash, const D: usize> hash::Hash for Rotation<T, D> impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Rotation<T, D>
where where
InnerOwned<T, Const<D>, Const<D>>: hash::Hash, <DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: hash::Hash,
{ {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.matrix.hash(state) self.matrix.hash(state)
} }
} }
impl<T: Copy, const D: usize> Copy for Rotation<T, D> where InnerOwned<T, Const<D>, Const<D>>: Copy {} impl<T: Scalar + Copy, const D: usize> Copy for Rotation<T, D> where
<DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: Copy
{
}
impl<T: Clone, const D: usize> Clone for Rotation<T, D> impl<T: Scalar, const D: usize> Clone for Rotation<T, D>
where where
InnerOwned<T, Const<D>, Const<D>>: Clone, <DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: Clone,
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -100,6 +102,7 @@ where
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, const D: usize> Abomonation for Rotation<T, D> impl<T, const D: usize> Abomonation for Rotation<T, D>
where where
T: Scalar,
SMatrix<T, D, D>: Abomonation, SMatrix<T, D, D>: Abomonation,
{ {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> { unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
@ -118,7 +121,7 @@ where
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T: Scalar, const D: usize> Serialize for Rotation<T, D> impl<T: Scalar, const D: usize> Serialize for Rotation<T, D>
where where
InnerOwned<T, Const<D>, Const<D>>: Serialize, Owned<T, Const<D>, Const<D>>: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -129,9 +132,9 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T, const D: usize> Deserialize<'a> for Rotation<T, D> impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Rotation<T, D>
where where
InnerOwned<T, Const<D>, Const<D>>: Deserialize<'a>, Owned<T, Const<D>, Const<D>>: Deserialize<'a>,
{ {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
@ -173,7 +176,7 @@ impl<T, const D: usize> Rotation<T, D> {
} }
/// # Conversion to a matrix /// # Conversion to a matrix
impl<T, const D: usize> Rotation<T, D> { impl<T: Scalar, const D: usize> Rotation<T, D> {
/// A reference to the underlying matrix representation of this rotation. /// A reference to the underlying matrix representation of this rotation.
/// ///
/// # Example /// # Example
@ -201,7 +204,7 @@ impl<T, const D: usize> Rotation<T, D> {
/// A mutable reference to the underlying matrix representation of this rotation. /// A mutable reference to the underlying matrix representation of this rotation.
#[inline] #[inline]
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")] #[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
pub fn matrix_mut(&mut self) -> &mut SMatrix<T, D, D> { pub unsafe fn matrix_mut(&mut self) -> &mut SMatrix<T, D, D> {
&mut self.matrix &mut self.matrix
} }
@ -274,7 +277,7 @@ impl<T, const D: usize> Rotation<T, D> {
#[must_use] #[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
T: Zero + One + Scalar, T: Zero + One,
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
{ {

View File

@ -1,5 +1,5 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -284,7 +284,7 @@ where
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation2<T> impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation2<T>
where where
T::Element: SimdRealField, T::Element: SimdRealField,
InnerOwned<T, U2, U2>: Send, Owned<T, U2, U2>: Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
@ -976,8 +976,8 @@ where
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation3<T> impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation3<T>
where where
T::Element: SimdRealField, T::Element: SimdRealField,
InnerOwned<T, U3, U3>: Send, Owned<T, U3, U3>: Send,
InnerOwned<T, U3>: Send, Owned<T, U3>: Send,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {

View File

@ -17,11 +17,12 @@ use simba::simd::SimdRealField;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
#[repr(C)]
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
@ -64,7 +65,7 @@ where
impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Similarity<T, R, D> impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Similarity<T, R, D>
where where
InnerOwned<T, Const<D>>: hash::Hash, Owned<T, Const<D>>: hash::Hash,
{ {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.isometry.hash(state); self.isometry.hash(state);
@ -75,7 +76,7 @@ where
impl<T: Scalar + Copy + Zero, R: AbstractRotation<T, D> + Copy, const D: usize> Copy impl<T: Scalar + Copy + Zero, R: AbstractRotation<T, D> + Copy, const D: usize> Copy
for Similarity<T, R, D> for Similarity<T, R, D>
where where
InnerOwned<T, Const<D>>: Copy, Owned<T, Const<D>>: Copy,
{ {
} }

View File

@ -1,5 +1,5 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -109,7 +109,7 @@ where
T: crate::RealField + Arbitrary + Send, T: crate::RealField + Arbitrary + Send,
T::Element: crate::RealField, T::Element: crate::RealField,
R: AbstractRotation<T, D> + Arbitrary + Send, R: AbstractRotation<T, D> + Arbitrary + Send,
InnerOwned<T, crate::Const<D>>: Send, Owned<T, crate::Const<D>>: Send,
{ {
#[inline] #[inline]
fn arbitrary(rng: &mut Gen) -> Self { fn arbitrary(rng: &mut Gen) -> Self {

View File

@ -1,6 +1,5 @@
use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::Any; use std::any::Any;
use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash; use std::hash;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -8,11 +7,11 @@ use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use simba::scalar::{ComplexField, RealField}; use simba::scalar::RealField;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector}; use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector};
use crate::geometry::Point; use crate::geometry::Point;
@ -120,7 +119,7 @@ macro_rules! category_mul_impl(
)*} )*}
); );
// We require stability upon multiplication. // We require stability uppon multiplication.
impl<T: TCategory> TCategoryMul<T> for T { impl<T: TCategory> TCategoryMul<T> for T {
type Representative = T; type Representative = T;
} }
@ -157,8 +156,9 @@ super_tcategory_impl!(
/// ///
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a /// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
/// 3D transformation. /// 3D transformation.
#[repr(transparent)] #[repr(C)]
pub struct Transform<T, C: TCategory, const D: usize> #[derive(Debug)]
pub struct Transform<T: RealField, C: TCategory, const D: usize>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
@ -167,32 +167,29 @@ where
_phantom: PhantomData<C>, _phantom: PhantomData<C>,
} }
impl<T: hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D> impl<T: RealField + hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash, Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash,
{ {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.matrix.hash(state); self.matrix.hash(state);
} }
} }
/* impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D>
impl<T: Copy, C: TCategory, const D: usize> Copy for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy, Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
{ {
} }
*/
impl<T: Clone, C: TCategory, const D: usize> Clone for Transform<T, C, D> impl<T: RealField, C: TCategory, const D: usize> Clone for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -200,25 +197,33 @@ where
} }
} }
impl<T: Debug, C: TCategory, const D: usize> Debug for Transform<T, C, D> #[cfg(feature = "bytemuck")]
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Zeroable for Transform<T, C, D>
where where
T: RealField + bytemuck::Zeroable,
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Debug, OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Zeroable,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Transform")
.field("matrix", &self.matrix)
.finish()
} }
#[cfg(feature = "bytemuck")]
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Pod for Transform<T, C, D>
where
T: RealField + bytemuck::Pod,
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Pod,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
{
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T, C: TCategory, const D: usize> Serialize for Transform<T, C, D> impl<T: RealField, C: TCategory, const D: usize> Serialize for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Serialize, Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -229,11 +234,11 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T, C: TCategory, const D: usize> Deserialize<'a> for Transform<T, C, D> impl<'a, T: RealField, C: TCategory, const D: usize> Deserialize<'a> for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Deserialize<'a>, Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Deserialize<'a>,
{ {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
@ -247,14 +252,14 @@ where
} }
} }
impl<T: Eq, C: TCategory, const D: usize> Eq for Transform<T, C, D> impl<T: RealField + Eq, C: TCategory, const D: usize> Eq for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
{ {
} }
impl<T: PartialEq, C: TCategory, const D: usize> PartialEq for Transform<T, C, D> impl<T: RealField, C: TCategory, const D: usize> PartialEq for Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
@ -265,7 +270,7 @@ where
} }
} }
impl<T, C: TCategory, const D: usize> Transform<T, C, D> impl<T: RealField, C: TCategory, const D: usize> Transform<T, C, D>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
@ -370,10 +375,7 @@ where
#[deprecated( #[deprecated(
note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release." note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release."
)] )]
pub fn clone_owned(&self) -> Transform<T, C, D> pub fn clone_owned(&self) -> Transform<T, C, D> {
where
T: Clone,
{
Transform::from_matrix_unchecked(self.matrix.clone_owned()) Transform::from_matrix_unchecked(self.matrix.clone_owned())
} }
@ -391,10 +393,7 @@ where
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
where
T: Clone,
{
self.matrix().clone_owned() self.matrix().clone_owned()
} }
@ -423,10 +422,7 @@ where
/// ``` /// ```
#[inline] #[inline]
#[must_use = "Did you mean to use try_inverse_mut()?"] #[must_use = "Did you mean to use try_inverse_mut()?"]
pub fn try_inverse(self) -> Option<Transform<T, C, D>> pub fn try_inverse(self) -> Option<Transform<T, C, D>> {
where
T: ComplexField,
{
self.matrix self.matrix
.try_inverse() .try_inverse()
.map(Transform::from_matrix_unchecked) .map(Transform::from_matrix_unchecked)
@ -452,7 +448,6 @@ where
#[must_use = "Did you mean to use inverse_mut()?"] #[must_use = "Did you mean to use inverse_mut()?"]
pub fn inverse(self) -> Transform<T, C, D> pub fn inverse(self) -> Transform<T, C, D>
where where
T: ComplexField,
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
{ {
// TODO: specialize for TAffine? // TODO: specialize for TAffine?
@ -484,10 +479,7 @@ where
/// assert!(!t.try_inverse_mut()); /// assert!(!t.try_inverse_mut());
/// ``` /// ```
#[inline] #[inline]
pub fn try_inverse_mut(&mut self) -> bool pub fn try_inverse_mut(&mut self) -> bool {
where
T: ComplexField,
{
self.matrix.try_inverse_mut() self.matrix.try_inverse_mut()
} }
@ -511,7 +503,6 @@ where
#[inline] #[inline]
pub fn inverse_mut(&mut self) pub fn inverse_mut(&mut self)
where where
T: ComplexField,
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
{ {
let _ = self.matrix.try_inverse_mut(); let _ = self.matrix.try_inverse_mut();
@ -552,8 +543,8 @@ where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
+ Allocator<T, DimNameSum<Const<D>, U1>>, + Allocator<T, DimNameSum<Const<D>, U1>>, // + Allocator<T, D, D>
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone, // + Allocator<T, D>
{ {
/// Transform the given point by the inverse of this transformation. /// Transform the given point by the inverse of this transformation.
/// This may be cheaper than inverting the transformation and transforming /// This may be cheaper than inverting the transformation and transforming

View File

@ -9,7 +9,6 @@ use simba::scalar::{ClosedAdd, ClosedMul, RealField, SubsetOf};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::storage::InnerOwned;
use crate::geometry::{ use crate::geometry::{
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory, Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
@ -373,8 +372,7 @@ md_impl_all!(
const D; const D;
for CA, CB; for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>, where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
Transform<T, CB, D>: Clone; // There's probably a better bound here.
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>; self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
@ -628,8 +626,7 @@ md_assign_impl_all!(
const D; const D;
for CA, CB; for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>, where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>; self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() }; [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() };

View File

@ -15,13 +15,13 @@ use simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::geometry::Point; use crate::geometry::Point;
/// A translation. /// A translation.
#[repr(transparent)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct Translation<T, const D: usize> { pub struct Translation<T, const D: usize> {
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// The translation coordinates, i.e., how much is added to a point's coordinates when it is
@ -29,20 +29,20 @@ pub struct Translation<T, const D: usize> {
pub vector: SVector<T, D>, pub vector: SVector<T, D>,
} }
impl<T: hash::Hash, const D: usize> hash::Hash for Translation<T, D> impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D>
where where
InnerOwned<T, Const<D>>: hash::Hash, Owned<T, Const<D>>: hash::Hash,
{ {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.vector.hash(state) self.vector.hash(state)
} }
} }
impl<T: Copy, const D: usize> Copy for Translation<T, D> {} impl<T: Scalar + Copy, const D: usize> Copy for Translation<T, D> {}
impl<T: Clone, const D: usize> Clone for Translation<T, D> impl<T: Scalar, const D: usize> Clone for Translation<T, D>
where where
InnerOwned<T, Const<D>>: Clone, Owned<T, Const<D>>: Clone,
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -69,6 +69,7 @@ where
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, const D: usize> Abomonation for Translation<T, D> impl<T, const D: usize> Abomonation for Translation<T, D>
where where
T: Scalar,
SVector<T, D>: Abomonation, SVector<T, D>: Abomonation,
{ {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> { unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
@ -85,9 +86,9 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T, const D: usize> Serialize for Translation<T, D> impl<T: Scalar, const D: usize> Serialize for Translation<T, D>
where where
InnerOwned<T, Const<D>>: Serialize, Owned<T, Const<D>>: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -98,9 +99,9 @@ where
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T, const D: usize> Deserialize<'a> for Translation<T, D> impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation<T, D>
where where
InnerOwned<T, Const<D>>: Deserialize<'a>, Owned<T, Const<D>>: Deserialize<'a>,
{ {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
@ -155,7 +156,7 @@ mod rkyv_impl {
} }
} }
impl<T, const D: usize> Translation<T, D> { impl<T: Scalar, const D: usize> Translation<T, D> {
/// Creates a new translation from the given vector. /// Creates a new translation from the given vector.
#[inline] #[inline]
#[deprecated(note = "Use `::from` instead.")] #[deprecated(note = "Use `::from` instead.")]
@ -181,7 +182,7 @@ impl<T, const D: usize> Translation<T, D> {
#[must_use = "Did you mean to use inverse_mut()?"] #[must_use = "Did you mean to use inverse_mut()?"]
pub fn inverse(&self) -> Translation<T, D> pub fn inverse(&self) -> Translation<T, D>
where where
T: ClosedNeg + Scalar, T: ClosedNeg,
{ {
Translation::from(-&self.vector) Translation::from(-&self.vector)
} }
@ -208,7 +209,7 @@ impl<T, const D: usize> Translation<T, D> {
#[must_use] #[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
T: Zero + One + Scalar, T: Zero + One,
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
{ {
@ -239,7 +240,7 @@ impl<T, const D: usize> Translation<T, D> {
#[inline] #[inline]
pub fn inverse_mut(&mut self) pub fn inverse_mut(&mut self)
where where
T: ClosedNeg + Scalar, T: ClosedNeg,
{ {
self.vector.neg_mut() self.vector.neg_mut()
} }
@ -279,16 +280,16 @@ impl<T: Scalar + ClosedSub, const D: usize> Translation<T, D> {
} }
} }
impl<T: Eq, const D: usize> Eq for Translation<T, D> {} impl<T: Scalar + Eq, const D: usize> Eq for Translation<T, D> {}
impl<T: PartialEq, const D: usize> PartialEq for Translation<T, D> { impl<T: Scalar + PartialEq, const D: usize> PartialEq for Translation<T, D> {
#[inline] #[inline]
fn eq(&self, right: &Translation<T, D>) -> bool { fn eq(&self, right: &Translation<T, D>) -> bool {
self.vector == right.vector self.vector == right.vector
} }
} }
impl<T: AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D> impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
{ {
@ -305,7 +306,7 @@ where
} }
} }
impl<T: RelativeEq, const D: usize> RelativeEq for Translation<T, D> impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Translation<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
{ {
@ -326,7 +327,7 @@ where
} }
} }
impl<T: UlpsEq, const D: usize> UlpsEq for Translation<T, D> impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Translation<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
{ {

View File

@ -1,5 +1,5 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned; use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -77,7 +77,7 @@ where
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Translation<T, D> impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Translation<T, D>
where where
InnerOwned<T, crate::Const<D>>: Send, Owned<T, crate::Const<D>>: Send,
{ {
#[inline] #[inline]
fn arbitrary(rng: &mut Gen) -> Self { fn arbitrary(rng: &mut Gen) -> Self {

View File

@ -27,7 +27,8 @@ use crate::Point;
impl<T1, T2, const D: usize> SubsetOf<Translation<T2, D>> for Translation<T1, D> impl<T1, T2, const D: usize> SubsetOf<Translation<T2, D>> for Translation<T1, D>
where where
T2: SupersetOf<T1>, T1: Scalar,
T2: Scalar + SupersetOf<T1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Translation<T2, D> { fn to_superset(&self) -> Translation<T2, D> {
@ -192,14 +193,14 @@ where
} }
} }
impl<T, const D: usize> From<OVector<T, Const<D>>> for Translation<T, D> { impl<T: Scalar, const D: usize> From<OVector<T, Const<D>>> for Translation<T, D> {
#[inline] #[inline]
fn from(vector: OVector<T, Const<D>>) -> Self { fn from(vector: OVector<T, Const<D>>) -> Self {
Translation { vector } Translation { vector }
} }
} }
impl<T, const D: usize> From<[T; D]> for Translation<T, D> { impl<T: Scalar, const D: usize> From<[T; D]> for Translation<T, D> {
#[inline] #[inline]
fn from(coords: [T; D]) -> Self { fn from(coords: [T; D]) -> Self {
Translation { Translation {
@ -208,17 +209,14 @@ impl<T, const D: usize> From<[T; D]> for Translation<T, D> {
} }
} }
impl<T, const D: usize> From<Point<T, D>> for Translation<T, D> { impl<T: Scalar, const D: usize> From<Point<T, D>> for Translation<T, D> {
#[inline] #[inline]
fn from(pt: Point<T, D>) -> Self { fn from(pt: Point<T, D>) -> Self {
Translation { vector: pt.coords } Translation { vector: pt.coords }
} }
} }
impl<T, const D: usize> From<Translation<T, D>> for [T; D] impl<T: Scalar, const D: usize> From<Translation<T, D>> for [T; D] {
where
T: Clone,
{
#[inline] #[inline]
fn from(t: Translation<T, D>) -> Self { fn from(t: Translation<T, D>) -> Self {
t.vector.into() t.vector.into()

View File

@ -18,14 +18,14 @@ macro_rules! deref_impl(
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const _ as *const _) } unsafe { &*(self as *const Translation<T, $D> as *const Self::Target) }
} }
} }
impl<T: Scalar> DerefMut for Translation<T, $D> { impl<T: Scalar> DerefMut for Translation<T, $D> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self as *mut _ as *mut _) } unsafe { &mut *(self as *mut Translation<T, $D> as *mut Self::Target) }
} }
} }
} }

View File

@ -77,12 +77,12 @@ an optimized set of tools for computer graphics and physics. Those features incl
unused_parens, unused_parens,
unused_qualifications, unused_qualifications,
unused_results, unused_results,
missing_docs,
rust_2018_idioms, rust_2018_idioms,
rust_2018_compatibility, rust_2018_compatibility,
future_incompatible, future_incompatible,
missing_copy_implementations missing_copy_implementations
)] )]
// #![deny(missing_docs)] // XXX: deny that
#![doc( #![doc(
html_favicon_url = "https://nalgebra.org/img/favicon.ico", html_favicon_url = "https://nalgebra.org/img/favicon.ico",
html_root_url = "https://docs.rs/nalgebra/0.25.0" html_root_url = "https://docs.rs/nalgebra/0.25.0"

View File

@ -5,7 +5,6 @@ use std::ops::{DivAssign, MulAssign};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::dimension::Dim; use crate::base::dimension::Dim;
use crate::base::storage::Storage;
use crate::base::{Const, DefaultAllocator, OMatrix, OVector}; use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
/// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns /// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns
@ -18,7 +17,7 @@ where
{ {
assert!(matrix.is_square(), "Unable to balance a non-square matrix."); assert!(matrix.is_square(), "Unable to balance a non-square matrix.");
let dim = matrix.data.shape().0; let dim = matrix.shape_generic().0;
let radix: T = crate::convert(2.0f64); let radix: T = crate::convert(2.0f64);
let mut d = OVector::from_element_generic(dim, Const::<1>, T::one()); let mut d = OVector::from_element_generic(dim, Const::<1>, T::one());

View File

@ -1,17 +1,14 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit}; use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1}; use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::Dynamic;
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::geometry::Reflection; use crate::geometry::Reflection;
use crate::linalg::householder; use crate::linalg::householder;
use std::mem::MaybeUninit;
/// The bidiagonalization of a general matrix. /// The bidiagonalization of a general matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -35,6 +32,7 @@ use crate::linalg::householder;
OVector<T, DimMinimum<R, C>>: Deserialize<'de>, OVector<T, DimMinimum<R, C>>: Deserialize<'de>,
OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Deserialize<'de>")) OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct Bidiagonal<T: ComplexField, R: DimMin<C>, C: Dim> pub struct Bidiagonal<T: ComplexField, R: DimMin<C>, C: Dim>
where where
DimMinimum<R, C>: DimSub<U1>, DimMinimum<R, C>: DimSub<U1>,
@ -52,59 +50,17 @@ where
upper_diagonal: bool, upper_diagonal: bool,
} }
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for Bidiagonal<T, R, C>
where
DimMinimum<R, C>: DimSub<U1>,
DefaultAllocator: Allocator<T, R, C>
+ Allocator<T, DimMinimum<R, C>>
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
InnerOwned<T, R, C>: Clone,
InnerOwned<T, DimMinimum<R, C>>: Clone,
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: Clone,
{
fn clone(&self) -> Self {
Self {
uv: self.uv.clone(),
diagonal: self.diagonal.clone(),
off_diagonal: self.off_diagonal.clone(),
upper_diagonal: self.upper_diagonal,
}
}
}
/*
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for Bidiagonal<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for Bidiagonal<T, R, C>
where where
DimMinimum<R, C>: DimSub<U1>, DimMinimum<R, C>: DimSub<U1>,
DefaultAllocator: Allocator<T, R, C> DefaultAllocator: Allocator<T, R, C>
+ Allocator<T, DimMinimum<R, C>> + Allocator<T, DimMinimum<R, C>>
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>, + Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
InnerOwned<T, R, C>: Copy, OMatrix<T, R, C>: Copy,
InnerOwned<T, DimMinimum<R, C>>: Copy, OVector<T, DimMinimum<R, C>>: Copy,
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: Copy, OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Copy,
{ {
} }
*/
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for Bidiagonal<T, R, C>
where
DimMinimum<R, C>: DimSub<U1>,
DefaultAllocator: Allocator<T, R, C>
+ Allocator<T, DimMinimum<R, C>>
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
InnerOwned<T, R, C>: fmt::Debug,
InnerOwned<T, DimMinimum<R, C>>: fmt::Debug,
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Bidiagonal")
.field("uv", &self.uv)
.field("diagonal", &self.diagonal)
.field("off_diagonal", &self.off_diagonal)
.field("upper_diagonal", &self.upper_diagonal)
.finish()
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> Bidiagonal<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> Bidiagonal<T, R, C>
where where
@ -117,7 +73,7 @@ where
{ {
/// Computes the Bidiagonal decomposition using householder reflections. /// Computes the Bidiagonal decomposition using householder reflections.
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self { pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let dim = min_nrows_ncols.value(); let dim = min_nrows_ncols.value();
assert!( assert!(
@ -125,82 +81,72 @@ where
"Cannot compute the bidiagonalization of an empty matrix." "Cannot compute the bidiagonalization of an empty matrix."
); );
let mut diagonal = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>); let mut diagonal = Matrix::uninit(min_nrows_ncols, Const::<1>);
let mut off_diagonal = let mut off_diagonal = Matrix::uninit(min_nrows_ncols.sub(Const::<1>), Const::<1>);
Matrix::new_uninitialized_generic(min_nrows_ncols.sub(Const::<1>), Const::<1>); let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>); let mut work = Matrix::zeros_generic(nrows, Const::<1>);
let mut work = Matrix::new_uninitialized_generic(nrows, Const::<1>);
let upper_diagonal = nrows.value() >= ncols.value(); let upper_diagonal = nrows.value() >= ncols.value();
// Safety: all pointers involved are valid for writes, aligned, and uninitialized.
unsafe {
if upper_diagonal { if upper_diagonal {
for ite in 0..dim - 1 { for ite in 0..dim - 1 {
householder::clear_column_unchecked( diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix, &mut matrix,
diagonal[ite].as_mut_ptr(),
ite, ite,
0, 0,
None, None,
); ));
householder::clear_row_unchecked( off_diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix, &mut matrix,
off_diagonal[ite].as_mut_ptr(),
&mut axis_packed, &mut axis_packed,
&mut work, &mut work,
ite, ite,
1, 1,
); ));
} }
householder::clear_column_unchecked( diagonal[dim - 1] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix, &mut matrix,
diagonal[dim - 1].as_mut_ptr(),
dim - 1, dim - 1,
0, 0,
None, None,
); ));
} else { } else {
for ite in 0..dim - 1 { for ite in 0..dim - 1 {
householder::clear_row_unchecked( diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix, &mut matrix,
diagonal[ite].as_mut_ptr(),
&mut axis_packed, &mut axis_packed,
&mut work, &mut work,
ite, ite,
0, 0,
); ));
householder::clear_column_unchecked( off_diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix, &mut matrix,
off_diagonal[ite].as_mut_ptr(),
ite, ite,
1, 1,
None, None,
); ));
} }
householder::clear_row_unchecked( diagonal[dim - 1] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix, &mut matrix,
diagonal[dim - 1].as_mut_ptr(),
&mut axis_packed, &mut axis_packed,
&mut work, &mut work,
dim - 1, dim - 1,
0, 0,
); ));
}
} }
// Safety: all values have been initialized. // Safety: diagonal and off_diagonal have been fully initialized.
unsafe { let (diagonal, off_diagonal) =
unsafe { (diagonal.assume_init(), off_diagonal.assume_init()) };
Bidiagonal { Bidiagonal {
uv: matrix, uv: matrix,
diagonal: diagonal.assume_init(), diagonal,
off_diagonal: off_diagonal.assume_init(), off_diagonal,
upper_diagonal, upper_diagonal,
} }
} }
}
/// Indicates whether this decomposition contains an upper-diagonal matrix. /// Indicates whether this decomposition contains an upper-diagonal matrix.
#[inline] #[inline]
@ -245,7 +191,7 @@ where
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.uv.data.shape(); let (nrows, ncols) = self.uv.shape_generic();
let d = nrows.min(ncols); let d = nrows.min(ncols);
let mut res = OMatrix::identity_generic(d, d); let mut res = OMatrix::identity_generic(d, d);
@ -265,7 +211,7 @@ where
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.uv.data.shape(); let (nrows, ncols) = self.uv.shape_generic();
let mut res = Matrix::identity_generic(nrows, nrows.min(ncols)); let mut res = Matrix::identity_generic(nrows, nrows.min(ncols));
let dim = self.diagonal.len(); let dim = self.diagonal.len();
@ -294,23 +240,21 @@ where
#[must_use] #[must_use]
pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C> pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C>
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C> + Allocator<T, Dynamic, U1>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.uv.data.shape(); let (nrows, ncols) = self.uv.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut res = Matrix::identity_generic(min_nrows_ncols, ncols); let mut res = Matrix::identity_generic(min_nrows_ncols, ncols);
let mut work = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>); let mut work = Matrix::zeros_generic(min_nrows_ncols, Const::<1>);
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>); let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
let shift = self.axis_shift().1; let shift = self.axis_shift().1;
for i in (0..min_nrows_ncols.value() - shift).rev() { for i in (0..min_nrows_ncols.value() - shift).rev() {
let axis = self.uv.slice_range(i, i + shift..); let axis = self.uv.slice_range(i, i + shift..);
let mut axis_packed = axis_packed.rows_range_mut(i + shift..); let mut axis_packed = axis_packed.rows_range_mut(i + shift..);
axis_packed.tr_copy_init_from(&axis); axis_packed.tr_copy_from(&axis);
let axis_packed = unsafe { axis_packed.slice_assume_init() };
// TODO: sometimes, the axis might have a zero magnitude. // TODO: sometimes, the axis might have a zero magnitude.
let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero()); let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero());
@ -404,7 +348,7 @@ where
// assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix."); // assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix.");
// //
// // TODO: is there a less naive method ? // // TODO: is there a less naive method ?
// let (nrows, ncols) = self.uv.data.shape(); // let (nrows, ncols) = self.uv.shape_generic();
// let mut res = OMatrix::identity_generic(nrows, ncols); // let mut res = OMatrix::identity_generic(nrows, ncols);
// self.solve_mut(&mut res); // self.solve_mut(&mut res);
// res // res

View File

@ -1,6 +1,3 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -12,7 +9,7 @@ use crate::allocator::Allocator;
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector}; use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector};
use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1}; use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1};
use crate::storage::{InnerOwned, Storage, StorageMut}; use crate::storage::{Storage, StorageMut};
/// The Cholesky decomposition of a symmetric-definite-positive matrix. /// The Cholesky decomposition of a symmetric-definite-positive matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -26,6 +23,7 @@ use crate::storage::{InnerOwned, Storage, StorageMut};
serde(bound(deserialize = "DefaultAllocator: Allocator<T, D>, serde(bound(deserialize = "DefaultAllocator: Allocator<T, D>,
OMatrix<T, D, D>: Deserialize<'de>")) OMatrix<T, D, D>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct Cholesky<T: SimdComplexField, D: Dim> pub struct Cholesky<T: SimdComplexField, D: Dim>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
@ -33,38 +31,12 @@ where
chol: OMatrix<T, D, D>, chol: OMatrix<T, D, D>,
} }
/*
impl<T: SimdComplexField, D: Dim> Copy for Cholesky<T, D> impl<T: SimdComplexField, D: Dim> Copy for Cholesky<T, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
{ {
} }
*/
impl<T: SimdComplexField, D: Dim> Clone for Cholesky<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
InnerOwned<T, D, D>: Clone,
{
fn clone(&self) -> Self {
Self {
chol: self.chol.clone(),
}
}
}
impl<T: SimdComplexField, D: Dim> fmt::Debug for Cholesky<T, D>
where
DefaultAllocator: Allocator<T, D, D>,
InnerOwned<T, D, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Cholesky")
.field("chol", &self.chol)
.finish()
}
}
impl<T: SimdComplexField, D: Dim> Cholesky<T, D> impl<T: SimdComplexField, D: Dim> Cholesky<T, D>
where where
@ -164,7 +136,7 @@ where
/// Computes the inverse of the decomposed matrix. /// Computes the inverse of the decomposed matrix.
#[must_use] #[must_use]
pub fn inverse(&self) -> OMatrix<T, D, D> { pub fn inverse(&self) -> OMatrix<T, D, D> {
let shape = self.chol.data.shape(); let shape = self.chol.shape_generic();
let mut res = OMatrix::identity_generic(shape.0, shape.1); let mut res = OMatrix::identity_generic(shape.0, shape.1);
self.solve_mut(&mut res); self.solve_mut(&mut res);
@ -254,8 +226,6 @@ where
DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>> + Allocator<T, R2>, DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>> + Allocator<T, R2>,
ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>, ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
{ {
// TODO: check that MaybeUninit manipulations are sound!
let mut col = col.into_owned(); let mut col = col.into_owned();
// for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition // for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
let n = col.nrows(); let n = col.nrows();
@ -267,20 +237,19 @@ where
assert!(j < n, "j needs to be within the bound of the new matrix."); assert!(j < n, "j needs to be within the bound of the new matrix.");
// loads the data into a new matrix with an additional jth row/column // loads the data into a new matrix with an additional jth row/column
let mut chol = Matrix::new_uninitialized_generic( // TODO: would it be worth it to avoid the zero-initialization?
self.chol.data.shape().0.add(Const::<1>), let mut chol = Matrix::zeros_generic(
self.chol.data.shape().1.add(Const::<1>), self.chol.shape_generic().0.add(Const::<1>),
self.chol.shape_generic().1.add(Const::<1>),
); );
// TODO: checked that every entry is initialized EXACTLY once.
chol.slice_range_mut(..j, ..j) chol.slice_range_mut(..j, ..j)
.copy_init_from(&self.chol.slice_range(..j, ..j)); .copy_from(&self.chol.slice_range(..j, ..j));
chol.slice_range_mut(..j, j + 1..) chol.slice_range_mut(..j, j + 1..)
.copy_init_from(&self.chol.slice_range(..j, j..)); .copy_from(&self.chol.slice_range(..j, j..));
chol.slice_range_mut(j + 1.., ..j) chol.slice_range_mut(j + 1.., ..j)
.copy_init_from(&self.chol.slice_range(j.., ..j)); .copy_from(&self.chol.slice_range(j.., ..j));
chol.slice_range_mut(j + 1.., j + 1..) chol.slice_range_mut(j + 1.., j + 1..)
.copy_init_from(&self.chol.slice_range(j.., j..)); .copy_from(&self.chol.slice_range(j.., j..));
// update the jth row // update the jth row
let top_left_corner = self.chol.slice_range(..j, ..j); let top_left_corner = self.chol.slice_range(..j, ..j);
@ -296,7 +265,7 @@ where
// update the center element // update the center element
let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared())); let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared()));
chol[(j, j)] = MaybeUninit::new(center_element); chol[(j, j)] = center_element;
// update the jth column // update the jth column
let bottom_left_corner = self.chol.slice_range(j.., ..j); let bottom_left_corner = self.chol.slice_range(j.., ..j);
@ -307,9 +276,7 @@ where
&new_rowj_adjoint, &new_rowj_adjoint,
T::one() / center_element, T::one() / center_element,
); );
chol.slice_range_mut(j + 1.., j).copy_init_from(&new_colj); chol.slice_range_mut(j + 1.., j).copy_from(&new_colj);
let mut chol = unsafe { chol.assume_init() };
// update the bottom right corner // update the bottom right corner
let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..); let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..);
@ -330,27 +297,24 @@ where
D: DimSub<U1>, D: DimSub<U1>,
DefaultAllocator: Allocator<T, DimDiff<D, U1>, DimDiff<D, U1>> + Allocator<T, D>, DefaultAllocator: Allocator<T, DimDiff<D, U1>, DimDiff<D, U1>> + Allocator<T, D>,
{ {
// TODO: check that MaybeUninit manipulations are sound!
let n = self.chol.nrows(); let n = self.chol.nrows();
assert!(n > 0, "The matrix needs at least one column."); assert!(n > 0, "The matrix needs at least one column.");
assert!(j < n, "j needs to be within the bound of the matrix."); assert!(j < n, "j needs to be within the bound of the matrix.");
// loads the data into a new matrix except for the jth row/column // loads the data into a new matrix except for the jth row/column
let mut chol = Matrix::new_uninitialized_generic( // TODO: would it be worth it to avoid this zero initialization?
self.chol.data.shape().0.sub(Const::<1>), let mut chol = Matrix::zeros_generic(
self.chol.data.shape().1.sub(Const::<1>), self.chol.shape_generic().0.sub(Const::<1>),
self.chol.shape_generic().1.sub(Const::<1>),
); );
chol.slice_range_mut(..j, ..j) chol.slice_range_mut(..j, ..j)
.copy_init_from(&self.chol.slice_range(..j, ..j)); .copy_from(&self.chol.slice_range(..j, ..j));
chol.slice_range_mut(..j, j..) chol.slice_range_mut(..j, j..)
.copy_init_from(&self.chol.slice_range(..j, j + 1..)); .copy_from(&self.chol.slice_range(..j, j + 1..));
chol.slice_range_mut(j.., ..j) chol.slice_range_mut(j.., ..j)
.copy_init_from(&self.chol.slice_range(j + 1.., ..j)); .copy_from(&self.chol.slice_range(j + 1.., ..j));
chol.slice_range_mut(j.., j..) chol.slice_range_mut(j.., j..)
.copy_init_from(&self.chol.slice_range(j + 1.., j + 1..)); .copy_from(&self.chol.slice_range(j + 1.., j + 1..));
let mut chol = unsafe { chol.assume_init() };
// updates the bottom right corner // updates the bottom right corner
let mut bottom_right_corner = chol.slice_range_mut(j.., j..); let mut bottom_right_corner = chol.slice_range_mut(j.., j..);
@ -366,12 +330,14 @@ where
/// ///
/// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column` /// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column`
/// where it is used on a square slice of the decomposition /// where it is used on a square slice of the decomposition
fn xx_rank_one_update<Dm: Dim, Sm, Rx: Dim, Sx>( fn xx_rank_one_update<Dm, Sm, Rx, Sx>(
chol: &mut Matrix<T, Dm, Dm, Sm>, chol: &mut Matrix<T, Dm, Dm, Sm>,
x: &mut Vector<T, Rx, Sx>, x: &mut Vector<T, Rx, Sx>,
sigma: T::RealField, sigma: T::RealField,
) where ) where
//T: ComplexField, //T: ComplexField,
Dm: Dim,
Rx: Dim,
Sm: StorageMut<T, Dm, Dm>, Sm: StorageMut<T, Dm, Dm>,
Sx: StorageMut<T, Rx, U1>, Sx: StorageMut<T, Rx, U1>,
{ {

View File

@ -6,11 +6,12 @@ use crate::allocator::{Allocator, Reallocator};
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, OVector, Unit}; use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, OVector, Unit};
use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum}; use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{Storage, StorageMut}; use crate::storage::StorageMut;
use crate::ComplexField; use crate::ComplexField;
use crate::geometry::Reflection; use crate::geometry::Reflection;
use crate::linalg::{householder, PermutationSequence}; use crate::linalg::{householder, PermutationSequence};
use std::mem::MaybeUninit;
/// The QR decomposition (with column pivoting) of a general matrix. /// The QR decomposition (with column pivoting) of a general matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -30,6 +31,7 @@ use crate::linalg::{householder, PermutationSequence};
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>, PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>,
OVector<T, DimMinimum<R, C>>: Deserialize<'de>")) OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct ColPivQR<T: ComplexField, R: DimMin<C>, C: Dim> pub struct ColPivQR<T: ComplexField, R: DimMin<C>, C: Dim>
where where
DefaultAllocator: Allocator<T, R, C> DefaultAllocator: Allocator<T, R, C>
@ -52,24 +54,6 @@ where
{ {
} }
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for ColPivQR<T, R, C>
where
DefaultAllocator: Allocator<T, R, C>
+ Allocator<T, DimMinimum<R, C>>
+ Allocator<(usize, usize), DimMinimum<R, C>>,
OMatrix<T, R, C>: Clone,
PermutationSequence<DimMinimum<R, C>>: Clone,
OVector<T, DimMinimum<R, C>>: Clone,
{
fn clone(&self) -> Self {
Self {
col_piv_qr: self.col_piv_qr.clone(),
p: self.p.clone(),
diag: self.diag.clone(),
}
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> ColPivQR<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> ColPivQR<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C> DefaultAllocator: Allocator<T, R, C>
@ -79,42 +63,37 @@ where
{ {
/// Computes the `ColPivQR` decomposition using householder reflections. /// Computes the `ColPivQR` decomposition using householder reflections.
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self { pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut p = PermutationSequence::identity_generic(min_nrows_ncols); let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
let mut diag = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
if min_nrows_ncols.value() == 0 { if min_nrows_ncols.value() == 0 {
// Safety: there's no (uninitialized) values.
unsafe {
return ColPivQR { return ColPivQR {
col_piv_qr: matrix, col_piv_qr: matrix,
p, p,
diag: diag.assume_init(), diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>),
};
}; };
} }
let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>);
for i in 0..min_nrows_ncols.value() { for i in 0..min_nrows_ncols.value() {
let piv = matrix.slice_range(i.., i..).icamax_full(); let piv = matrix.slice_range(i.., i..).icamax_full();
let col_piv = piv.1 + i; let col_piv = piv.1 + i;
matrix.swap_columns(i, col_piv); matrix.swap_columns(i, col_piv);
p.append_permutation(i, col_piv); p.append_permutation(i, col_piv);
// Safety: the pointer is valid for writes, aligned, and uninitialized. diag[i] =
unsafe { MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None));
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
}
} }
// Safety: all values have been initialized. // Safety: diag is now fully initialized.
unsafe { let diag = unsafe { diag.assume_init() };
ColPivQR { ColPivQR {
col_piv_qr: matrix, col_piv_qr: matrix,
p, p,
diag: diag.assume_init(), diag,
}
} }
} }
@ -125,7 +104,7 @@ where
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.col_piv_qr.data.shape(); let (nrows, ncols) = self.col_piv_qr.shape_generic();
let mut res = self let mut res = self
.col_piv_qr .col_piv_qr
.rows_generic(0, nrows.min(ncols)) .rows_generic(0, nrows.min(ncols))
@ -142,7 +121,7 @@ where
where where
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>, DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.col_piv_qr.data.shape(); let (nrows, ncols) = self.col_piv_qr.shape_generic();
let mut res = self let mut res = self
.col_piv_qr .col_piv_qr
.resize_generic(nrows.min(ncols), ncols, T::zero()); .resize_generic(nrows.min(ncols), ncols, T::zero());
@ -157,7 +136,7 @@ where
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.col_piv_qr.data.shape(); let (nrows, ncols) = self.col_piv_qr.shape_generic();
// NOTE: we could build the identity matrix and call q_mul on it. // NOTE: we could build the identity matrix and call q_mul on it.
// Instead we don't so that we take in account the matrix sparseness. // Instead we don't so that we take in account the matrix sparseness.
@ -320,7 +299,7 @@ where
); );
// TODO: is there a less naive method ? // TODO: is there a less naive method ?
let (nrows, ncols) = self.col_piv_qr.data.shape(); let (nrows, ncols) = self.col_piv_qr.shape_generic();
let mut res = OMatrix::identity_generic(nrows, ncols); let mut res = OMatrix::identity_generic(nrows, ncols);
if self.solve_mut(&mut res) { if self.solve_mut(&mut res) {

View File

@ -38,7 +38,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
.data .data
.shape() .shape()
.0 .0
.add(kernel.data.shape().0) .add(kernel.shape_generic().0)
.sub(Const::<1>); .sub(Const::<1>);
let mut conv = OVector::zeros_generic(result_len, Const::<1>); let mut conv = OVector::zeros_generic(result_len, Const::<1>);
@ -92,7 +92,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
.shape() .shape()
.0 .0
.add(Const::<1>) .add(Const::<1>)
.sub(kernel.data.shape().0); .sub(kernel.shape_generic().0);
let mut conv = OVector::zeros_generic(result_len, Const::<1>); let mut conv = OVector::zeros_generic(result_len, Const::<1>);
for i in 0..(vec - ker + 1) { for i in 0..(vec - ker + 1) {
@ -126,7 +126,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
} }
let mut conv = OVector::zeros_generic(self.data.shape().0, Const::<1>); let mut conv = OVector::zeros_generic(self.shape_generic().0, Const::<1>);
for i in 0..vec { for i in 0..vec {
for j in 0..ker { for j in 0..ker {

View File

@ -4,12 +4,9 @@ use crate::{
base::{ base::{
allocator::Allocator, allocator::Allocator,
dimension::{Const, Dim, DimMin, DimMinimum}, dimension::{Const, Dim, DimMin, DimMinimum},
storage::Storage,
DefaultAllocator, DefaultAllocator,
}, },
convert, convert, try_convert, ComplexField, OMatrix, RealField,
storage::InnerOwned,
try_convert, ComplexField, OMatrix, RealField,
}; };
use crate::num::Zero; use crate::num::Zero;
@ -49,7 +46,7 @@ where
DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), DimMinimum<D, D>>, DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), DimMinimum<D, D>>,
{ {
fn new(a: OMatrix<T, D, D>, use_exact_norm: bool) -> Self { fn new(a: OMatrix<T, D, D>, use_exact_norm: bool) -> Self {
let (nrows, ncols) = a.data.shape(); let (nrows, ncols) = a.shape_generic();
ExpmPadeHelper { ExpmPadeHelper {
use_exact_norm, use_exact_norm,
ident: OMatrix::<T, D, D>::identity_generic(nrows, ncols), ident: OMatrix::<T, D, D>::identity_generic(nrows, ncols),
@ -350,7 +347,7 @@ where
D: Dim, D: Dim,
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
{ {
let nrows = a.data.shape().0; let nrows = a.shape_generic().0;
let mut v = crate::OVector::<T, D>::repeat_generic(nrows, Const::<1>, convert(1.0)); let mut v = crate::OVector::<T, D>::repeat_generic(nrows, Const::<1>, convert(1.0));
let m = a.transpose(); let m = a.transpose();
@ -435,7 +432,6 @@ where
+ Allocator<T, D> + Allocator<T, D>
+ Allocator<T::RealField, D> + Allocator<T::RealField, D>
+ Allocator<T::RealField, D, D>, + Allocator<T::RealField, D, D>,
InnerOwned<T, D, D>: Clone,
{ {
/// Computes exponential of this matrix /// Computes exponential of this matrix
#[must_use] #[must_use]

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
OMatrix<T, R, C>: Deserialize<'de>, OMatrix<T, R, C>: Deserialize<'de>,
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>")) PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
)] )]
pub struct FullPivLU<T, R: DimMin<C>, C: Dim> #[derive(Clone, Debug)]
pub struct FullPivLU<T: ComplexField, R: DimMin<C>, C: Dim>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
{ {
@ -41,41 +40,11 @@ where
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<R, C>>: Copy,
OMatrix<T, R, C>: Copy, OMatrix<T, R, C>: Copy,
PermutationSequence<DimMinimum<R, C>>: Copy,
{ {
} }
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for FullPivLU<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<R, C>>: Clone,
OMatrix<T, R, C>: Clone,
{
fn clone(&self) -> Self {
Self {
lu: self.lu.clone(),
p: self.p.clone(),
q: self.q.clone(),
}
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for FullPivLU<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<R, C>>: fmt::Debug,
OMatrix<T, R, C>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FullPivLU")
.field("lu", &self.lu)
.field("p", &self.p)
.field("q", &self.q)
.finish()
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
@ -84,7 +53,7 @@ where
/// ///
/// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`. /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self { pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut p = PermutationSequence::identity_generic(min_nrows_ncols); let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
@ -132,7 +101,7 @@ where
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
m.fill_upper_triangle(T::zero(), 1); m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one()); m.fill_diagonal(T::one());
@ -146,7 +115,7 @@ where
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
} }
@ -253,7 +222,7 @@ where
"FullPivLU inverse: unable to compute the inverse of a non-square matrix." "FullPivLU inverse: unable to compute the inverse of a non-square matrix."
); );
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut res = OMatrix::identity_generic(nrows, ncols); let mut res = OMatrix::identity_generic(nrows, ncols);
if self.solve_mut(&mut res) { if self.solve_mut(&mut res) {

View File

@ -1,17 +1,14 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector}; use crate::base::{DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Const, DimDiff, DimSub, U1}; use crate::dimension::{Const, DimDiff, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::Matrix;
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::linalg::householder; use crate::linalg::householder;
use crate::Matrix;
use std::mem::MaybeUninit;
/// Hessenberg decomposition of a general matrix. /// Hessenberg decomposition of a general matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -29,6 +26,7 @@ use crate::linalg::householder;
OMatrix<T, D, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>,
OVector<T, DimDiff<D, U1>>: Deserialize<'de>")) OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct Hessenberg<T: ComplexField, D: DimSub<U1>> pub struct Hessenberg<T: ComplexField, D: DimSub<U1>>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
@ -37,43 +35,13 @@ where
subdiag: OVector<T, DimDiff<D, U1>>, subdiag: OVector<T, DimDiff<D, U1>>,
} }
/*
impl<T: ComplexField, D: DimSub<U1>> Copy for Hessenberg<T, D> impl<T: ComplexField, D: DimSub<U1>> Copy for Hessenberg<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
InnerOwned<T, DimDiff<D, U1>>: Copy, OVector<T, DimDiff<D, U1>>: Copy,
{ {
} }
*/
impl<T: ComplexField, D: DimSub<U1>> Clone for Hessenberg<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Clone,
InnerOwned<T, DimDiff<D, U1>>: Clone,
{
fn clone(&self) -> Self {
Self {
hess: self.hess.clone(),
subdiag: self.subdiag.clone(),
}
}
}
impl<T: ComplexField, D: DimSub<U1>> fmt::Debug for Hessenberg<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: fmt::Debug,
InnerOwned<T, DimDiff<D, U1>>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Hessenberg")
.field("hess", &self.hess)
.field("subdiag", &self.subdiag)
.finish()
}
}
impl<T: ComplexField, D: DimSub<U1>> Hessenberg<T, D> impl<T: ComplexField, D: DimSub<U1>> Hessenberg<T, D>
where where
@ -81,7 +49,7 @@ where
{ {
/// Computes the Hessenberg decomposition using householder reflections. /// Computes the Hessenberg decomposition using householder reflections.
pub fn new(hess: OMatrix<T, D, D>) -> Self { pub fn new(hess: OMatrix<T, D, D>) -> Self {
let mut work = OVector::new_uninitialized_generic(hess.data.shape().0, Const::<1>); let mut work = Matrix::zeros_generic(hess.shape_generic().0, Const::<1>);
Self::new_with_workspace(hess, &mut work) Self::new_with_workspace(hess, &mut work)
} }
@ -89,16 +57,13 @@ where
/// ///
/// The workspace containing `D` elements must be provided but its content does not have to be /// The workspace containing `D` elements must be provided but its content does not have to be
/// initialized. /// initialized.
pub fn new_with_workspace( pub fn new_with_workspace(mut hess: OMatrix<T, D, D>, work: &mut OVector<T, D>) -> Self {
mut hess: OMatrix<T, D, D>,
work: &mut OVector<MaybeUninit<T>, D>,
) -> Self {
assert!( assert!(
hess.is_square(), hess.is_square(),
"Cannot compute the hessenberg decomposition of a non-square matrix." "Cannot compute the hessenberg decomposition of a non-square matrix."
); );
let dim = hess.data.shape().0; let dim = hess.shape_generic().0;
assert!( assert!(
dim.value() != 0, dim.value() != 0,
@ -110,38 +75,27 @@ where
"Hessenberg: invalid workspace size." "Hessenberg: invalid workspace size."
); );
let mut subdiag = Matrix::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
if dim.value() == 0 { if dim.value() == 0 {
// Safety: there's no (uninitialized) values. return Hessenberg {
unsafe {
return Self {
hess, hess,
subdiag: subdiag.assume_init(), subdiag: Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>),
}; };
} }
}
let mut subdiag = Matrix::uninit(dim.sub(Const::<1>), Const::<1>);
for ite in 0..dim.value() - 1 { for ite in 0..dim.value() - 1 {
// Safety: the pointer is valid for writes, aligned, and uninitialized. subdiag[ite] = MaybeUninit::new(householder::clear_column_unchecked(
unsafe {
householder::clear_column_unchecked(
&mut hess, &mut hess,
subdiag[ite].as_mut_ptr(),
ite, ite,
1, 1,
Some(work), Some(work),
); ));
}
} }
// Safety: all values have been initialized. // Safety: subdiag is now fully initialized.
unsafe { let subdiag = unsafe { subdiag.assume_init() };
Self { Hessenberg { hess, subdiag }
hess,
subdiag: subdiag.assume_init(),
}
}
} }
/// Retrieves `(q, h)` with `q` the orthogonal matrix of this decomposition and `h` the /// Retrieves `(q, h)` with `q` the orthogonal matrix of this decomposition and `h` the
@ -170,10 +124,7 @@ where
/// This is less efficient than `.unpack_h()` as it allocates a new matrix. /// This is less efficient than `.unpack_h()` as it allocates a new matrix.
#[inline] #[inline]
#[must_use] #[must_use]
pub fn h(&self) -> OMatrix<T, D, D> pub fn h(&self) -> OMatrix<T, D, D> {
where
InnerOwned<T, D, D>: Clone,
{
let dim = self.hess.nrows(); let dim = self.hess.nrows();
let mut res = self.hess.clone(); let mut res = self.hess.clone();
res.fill_lower_triangle(T::zero(), 2); res.fill_lower_triangle(T::zero(), 2);

View File

@ -1,11 +1,9 @@
//! Construction of householder elementary reflections. //! Construction of householder elementary reflections.
use std::mem::MaybeUninit;
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector}; use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector};
use crate::dimension::Dim; use crate::dimension::Dim;
use crate::storage::{Storage, StorageMut}; use crate::storage::StorageMut;
use num::Zero; use num::Zero;
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
@ -46,29 +44,22 @@ pub fn reflection_axis_mut<T: ComplexField, D: Dim, S: StorageMut<T, D>>(
/// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th /// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th
/// subdiagonal element. /// subdiagonal element.
/// ///
/// # Safety /// Returns the signed norm of the column.
/// Behavior is undefined if any of the following conditions are violated:
///
/// - `diag_elt` must be valid for writes.
/// - `diag_elt` must be properly aligned.
///
/// Furthermore, if `diag_elt` was previously initialized, this method will leak
/// its data.
#[doc(hidden)] #[doc(hidden)]
pub unsafe fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>( #[must_use]
pub fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>(
matrix: &mut OMatrix<T, R, C>, matrix: &mut OMatrix<T, R, C>,
diag_elt: *mut T,
icol: usize, icol: usize,
shift: usize, shift: usize,
bilateral: Option<&mut OVector<MaybeUninit<T>, R>>, bilateral: Option<&mut OVector<T, R>>,
) where ) -> T
where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R>, DefaultAllocator: Allocator<T, R, C> + Allocator<T, R>,
{ {
let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..); let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..);
let mut axis = left.rows_range_mut(icol + shift..); let mut axis = left.rows_range_mut(icol + shift..);
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis); let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
diag_elt.write(reflection_norm);
if not_zero { if not_zero {
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
@ -78,38 +69,32 @@ pub unsafe fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>(
} }
refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate()); refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate());
} }
reflection_norm
} }
/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th /// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th
/// superdiagonal element. /// superdiagonal element.
/// ///
/// # Safety /// Returns the signed norm of the column.
/// Behavior is undefined if any of the following conditions are violated:
///
/// - `diag_elt` must be valid for writes.
/// - `diag_elt` must be properly aligned.
///
/// Furthermore, if `diag_elt` was previously initialized, this method will leak
/// its data.
#[doc(hidden)] #[doc(hidden)]
pub unsafe fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>( #[must_use]
pub fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>(
matrix: &mut OMatrix<T, R, C>, matrix: &mut OMatrix<T, R, C>,
diag_elt: *mut T, axis_packed: &mut OVector<T, C>,
axis_packed: &mut OVector<MaybeUninit<T>, C>, work: &mut OVector<T, R>,
work: &mut OVector<MaybeUninit<T>, R>,
irow: usize, irow: usize,
shift: usize, shift: usize,
) where ) -> T
where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, C>, DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, C>,
{ {
let (mut top, mut bottom) = matrix.rows_range_pair_mut(irow, irow + 1..); let (mut top, mut bottom) = matrix.rows_range_pair_mut(irow, irow + 1..);
let mut axis = axis_packed.rows_range_mut(irow + shift..); let mut axis = axis_packed.rows_range_mut(irow + shift..);
axis.tr_copy_init_from(&top.columns_range(irow + shift..)); axis.tr_copy_from(&top.columns_range(irow + shift..));
let mut axis = axis.assume_init_mut();
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis); let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
axis.conjugate_mut(); // So that reflect_rows actually cancels the first row. axis.conjugate_mut(); // So that reflect_rows actually cancels the first row.
diag_elt.write(reflection_norm);
if not_zero { if not_zero {
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
@ -123,6 +108,8 @@ pub unsafe fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>(
} else { } else {
top.columns_range_mut(irow + shift..).tr_copy_from(&axis); top.columns_range_mut(irow + shift..).tr_copy_from(&axis);
} }
reflection_norm
} }
/// Computes the orthogonal transformation described by the elementary reflector axii stored on /// Computes the orthogonal transformation described by the elementary reflector axii stored on
@ -134,7 +121,7 @@ where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
assert!(m.is_square()); assert!(m.is_square());
let dim = m.data.shape().0; let dim = m.shape_generic().0;
// NOTE: we could build the identity matrix and call p_mult on it. // NOTE: we could build the identity matrix and call p_mult on it.
// Instead we don't so that we take in account the matrix sparseness. // Instead we don't so that we take in account the matrix sparseness.

View File

@ -1,6 +1,3 @@
use std::fmt;
use std::mem;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,8 +5,9 @@ use crate::allocator::{Allocator, Reallocator};
use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar}; use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar};
use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum}; use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{InnerOwned, Storage, StorageMut}; use crate::storage::{Storage, StorageMut};
use simba::scalar::{ComplexField, Field}; use simba::scalar::{ComplexField, Field};
use std::mem;
use crate::linalg::PermutationSequence; use crate::linalg::PermutationSequence;
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
OMatrix<T, R, C>: Deserialize<'de>, OMatrix<T, R, C>: Deserialize<'de>,
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>")) PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
)] )]
pub struct LU<T, R: DimMin<C>, C: Dim> #[derive(Clone, Debug)]
pub struct LU<T: ComplexField, R: DimMin<C>, C: Dim>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
{ {
@ -37,43 +36,13 @@ where
p: PermutationSequence<DimMinimum<R, C>>, p: PermutationSequence<DimMinimum<R, C>>,
} }
/* impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
impl<T: Copy, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
OMatrix<T, R, C>: Copy,
PermutationSequence<DimMinimum<R, C>>: Copy, PermutationSequence<DimMinimum<R, C>>: Copy,
InnerOwned<T, R, C>: Copy,
{ {
} }
*/
impl<T: Clone, R: DimMin<C>, C: Dim> Clone for LU<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<R, C>>: Clone,
InnerOwned<T, R, C>: Clone,
{
fn clone(&self) -> Self {
Self {
lu: self.lu.clone(),
p: self.p.clone(),
}
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for LU<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<R, C>>: fmt::Debug,
InnerOwned<T, R, C>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("LU")
.field("lu", &self.lu)
.field("p", &self.p)
.finish()
}
}
/// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`. /// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`.
/// ///
@ -121,7 +90,7 @@ where
{ {
/// Computes the LU decomposition with partial (row) pivoting of `matrix`. /// Computes the LU decomposition with partial (row) pivoting of `matrix`.
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self { pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut p = PermutationSequence::identity_generic(min_nrows_ncols); let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
@ -163,7 +132,7 @@ where
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
m.fill_upper_triangle(T::zero(), 1); m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one()); m.fill_diagonal(T::one());
@ -180,7 +149,7 @@ where
where where
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>, DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero()); let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
m.fill_upper_triangle(T::zero(), 1); m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one()); m.fill_diagonal(T::one());
@ -193,7 +162,7 @@ where
where where
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>, DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero()); let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
m.fill_upper_triangle(T::zero(), 1); m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one()); m.fill_diagonal(T::one());
@ -207,7 +176,7 @@ where
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
} }
@ -299,7 +268,7 @@ where
"LU inverse: unable to compute the inverse of a non-square matrix." "LU inverse: unable to compute the inverse of a non-square matrix."
); );
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.shape_generic();
let mut res = OMatrix::identity_generic(nrows, ncols); let mut res = OMatrix::identity_generic(nrows, ncols);
if self.try_inverse_to(&mut res) { if self.try_inverse_to(&mut res) {
Some(res) Some(res)

View File

@ -1,6 +1,3 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -11,10 +8,8 @@ use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, OVector, Scalar}; use crate::base::{DefaultAllocator, Matrix, OVector, Scalar};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use crate::dimension::Dynamic; use crate::dimension::Dynamic;
use crate::dimension::{Dim, DimName}; use crate::dimension::{Const, Dim, DimName};
use crate::iter::MatrixIter; use crate::storage::StorageMut;
use crate::storage::{InnerOwned, StorageMut};
use crate::{Const, U1};
/// A sequence of row or column permutations. /// A sequence of row or column permutations.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -28,47 +23,22 @@ use crate::{Const, U1};
serde(bound(deserialize = "DefaultAllocator: Allocator<(usize, usize), D>, serde(bound(deserialize = "DefaultAllocator: Allocator<(usize, usize), D>,
OVector<(usize, usize), D>: Deserialize<'de>")) OVector<(usize, usize), D>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct PermutationSequence<D: Dim> pub struct PermutationSequence<D: Dim>
where where
DefaultAllocator: Allocator<(usize, usize), D>, DefaultAllocator: Allocator<(usize, usize), D>,
{ {
len: usize, len: usize,
ipiv: OVector<MaybeUninit<(usize, usize)>, D>, ipiv: OVector<(usize, usize), D>,
} }
impl<D: Dim> Copy for PermutationSequence<D> impl<D: Dim> Copy for PermutationSequence<D>
where where
DefaultAllocator: Allocator<(usize, usize), D>, DefaultAllocator: Allocator<(usize, usize), D>,
OVector<MaybeUninit<(usize, usize)>, D>: Copy, OVector<(usize, usize), D>: Copy,
{ {
} }
impl<D: Dim> Clone for PermutationSequence<D>
where
DefaultAllocator: Allocator<(usize, usize), D>,
OVector<MaybeUninit<(usize, usize)>, D>: Clone,
{
fn clone(&self) -> Self {
Self {
len: self.len,
ipiv: self.ipiv.clone(),
}
}
}
impl<D: Dim> fmt::Debug for PermutationSequence<D>
where
DefaultAllocator: Allocator<(usize, usize), D>,
OVector<MaybeUninit<(usize, usize)>, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PermutationSequence")
.field("len", &self.len)
.field("ipiv", &self.ipiv)
.finish()
}
}
impl<D: DimName> PermutationSequence<D> impl<D: DimName> PermutationSequence<D>
where where
DefaultAllocator: Allocator<(usize, usize), D>, DefaultAllocator: Allocator<(usize, usize), D>,
@ -101,7 +71,9 @@ where
pub fn identity_generic(dim: D) -> Self { pub fn identity_generic(dim: D) -> Self {
Self { Self {
len: 0, len: 0,
ipiv: OVector::new_uninitialized_generic(dim, Const::<1>), // TODO: using a uninitialized matrix would save some computation, but
// that loos difficult to setup with MaybeUninit.
ipiv: Matrix::repeat_generic(dim, Const::<1>, (0, 0)),
} }
} }
@ -114,7 +86,7 @@ where
self.len < self.ipiv.len(), self.len < self.ipiv.len(),
"Maximum number of permutations exceeded." "Maximum number of permutations exceeded."
); );
self.ipiv[self.len] = MaybeUninit::new((i, i2)); self.ipiv[self.len] = (i, i2);
self.len += 1; self.len += 1;
} }
} }
@ -125,8 +97,8 @@ where
where where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
{ {
for perm in self.iter() { for i in self.ipiv.rows_range(..self.len).iter() {
rhs.swap_rows(perm.0, perm.1) rhs.swap_rows(i.0, i.1)
} }
} }
@ -136,8 +108,8 @@ where
where where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
{ {
for perm in self.iter().rev() { for i in 0..self.len {
let (i1, i2) = perm; let (i1, i2) = self.ipiv[self.len - i - 1];
rhs.swap_rows(i1, i2) rhs.swap_rows(i1, i2)
} }
} }
@ -148,8 +120,8 @@ where
where where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
{ {
for perm in self.iter() { for i in self.ipiv.rows_range(..self.len).iter() {
rhs.swap_columns(perm.0, perm.1) rhs.swap_columns(i.0, i.1)
} }
} }
@ -161,8 +133,8 @@ where
) where ) where
S2: StorageMut<T, R2, C2>, S2: StorageMut<T, R2, C2>,
{ {
for perm in self.iter().rev() { for i in 0..self.len {
let (i1, i2) = perm; let (i1, i2) = self.ipiv[self.len - i - 1];
rhs.swap_columns(i1, i2) rhs.swap_columns(i1, i2)
} }
} }
@ -189,27 +161,4 @@ where
-T::one() -T::one()
} }
} }
/// Iterates over the permutations that have been initialized.
pub fn iter(
&self,
) -> std::iter::Map<
std::iter::Copied<
std::iter::Take<
MatrixIter<
MaybeUninit<(usize, usize)>,
D,
U1,
InnerOwned<MaybeUninit<(usize, usize)>, D, U1>,
>,
>,
>,
impl FnMut(MaybeUninit<(usize, usize)>) -> (usize, usize),
> {
self.ipiv
.iter()
.take(self.len)
.copied()
.map(|e| unsafe { e.assume_init() })
}
} }

View File

@ -40,31 +40,19 @@ where
// We use the buffer to hold the result of multiplier ^ 2, thus avoiding // We use the buffer to hold the result of multiplier ^ 2, thus avoiding
// extra allocations. // extra allocations.
let (nrows, ncols) = self.data.shape();
let mut multiplier = self.clone_owned(); let mut multiplier = self.clone_owned();
let mut buf = Matrix::new_uninitialized_generic(nrows, ncols); let mut buf = self.clone_owned();
// Exponentiation by squares. // Exponentiation by squares.
loop { loop {
if e % two == one { if e % two == one {
let init_buf = self.mul_to(&multiplier, &mut buf); self.mul_to(&multiplier, &mut buf);
self.copy_from(&init_buf); self.copy_from(&buf);
// Safety: `mul_to` leaves `buf` completely initialized.
unsafe {
buf.reinitialize();
}
} }
e /= two; e /= two;
multiplier.mul_to(&multiplier, &mut buf);
let init_buf = multiplier.mul_to(&multiplier, &mut buf); multiplier.copy_from(&buf);
multiplier.copy_from(&init_buf);
// Safety: `mul_to` leaves `buf` completely initialized.
unsafe {
buf.reinitialize();
}
if e == zero { if e == zero {
return true; return true;

View File

@ -1,5 +1,3 @@
use std::fmt;
use num::Zero; use num::Zero;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,11 +6,12 @@ use crate::allocator::{Allocator, Reallocator};
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit}; use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Const, Dim, DimMin, DimMinimum}; use crate::dimension::{Const, Dim, DimMin, DimMinimum};
use crate::storage::{InnerOwned, Storage, StorageMut}; use crate::storage::{Storage, StorageMut};
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::geometry::Reflection; use crate::geometry::Reflection;
use crate::linalg::householder; use crate::linalg::householder;
use std::mem::MaybeUninit;
/// The QR decomposition of a general matrix. /// The QR decomposition of a general matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -30,8 +29,8 @@ use crate::linalg::householder;
OMatrix<T, R, C>: Deserialize<'de>, OMatrix<T, R, C>: Deserialize<'de>,
OVector<T, DimMinimum<R, C>>: Deserialize<'de>")) OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct QR<T, R: DimMin<C>, C: Dim> pub struct QR<T: ComplexField, R: DimMin<C>, C: Dim>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
{ {
@ -39,43 +38,13 @@ where
diag: OVector<T, DimMinimum<R, C>>, diag: OVector<T, DimMinimum<R, C>>,
} }
/* impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for QR<T, R, C>
impl<T: Copy, R: DimMin<C>, C: Dim> Copy for QR<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
InnerOwned<T, R, C>: Copy, OMatrix<T, R, C>: Copy,
InnerOwned<T, DimMinimum<R, C>>: Copy, OVector<T, DimMinimum<R, C>>: Copy,
{ {
} }
*/
impl<T: Clone, R: DimMin<C>, C: Dim> Clone for QR<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
InnerOwned<T, R, C>: Clone,
InnerOwned<T, DimMinimum<R, C>>: Clone,
{
fn clone(&self) -> Self {
Self {
qr: self.qr.clone(),
diag: self.diag.clone(),
}
}
}
impl<T: fmt::Debug, R: DimMin<C>, C: Dim> fmt::Debug for QR<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
InnerOwned<T, R, C>: fmt::Debug,
InnerOwned<T, DimMinimum<R, C>>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("QR")
.field("qr", &self.qr)
.field("diag", &self.diag)
.finish()
}
}
impl<T: ComplexField, R: DimMin<C>, C: Dim> QR<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> QR<T, R, C>
where where
@ -83,32 +52,26 @@ where
{ {
/// Computes the QR decomposition using householder reflections. /// Computes the QR decomposition using householder reflections.
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self { pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let mut diag = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
if min_nrows_ncols.value() == 0 { if min_nrows_ncols.value() == 0 {
return Self { return QR {
qr: matrix, qr: matrix,
diag: unsafe { diag.assume_init() }, diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>),
}; };
} }
let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>);
for i in 0..min_nrows_ncols.value() { for i in 0..min_nrows_ncols.value() {
// Safety: the pointer is valid for writes, aligned, and uninitialized. diag[i] =
unsafe { MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None));
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
}
} }
// Safety: all values have been initialized. // Safety: diag is now fully initialized.
unsafe { let diag = unsafe { diag.assume_init() };
Self { QR { qr: matrix, diag }
qr: matrix,
diag: diag.assume_init(),
}
}
} }
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition. /// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
@ -118,7 +81,7 @@ where
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle(); let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle();
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus()))); res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
res res
@ -132,7 +95,7 @@ where
where where
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>, DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
{ {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, T::zero()); let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, T::zero());
res.fill_lower_triangle(T::zero(), 1); res.fill_lower_triangle(T::zero(), 1);
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus()))); res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
@ -145,7 +108,7 @@ where
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
{ {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
// NOTE: we could build the identity matrix and call q_mul on it. // NOTE: we could build the identity matrix and call q_mul on it.
// Instead we don't so that we take in account the matrix sparseness. // Instead we don't so that we take in account the matrix sparseness.
@ -297,7 +260,7 @@ where
); );
// TODO: is there a less naive method ? // TODO: is there a less naive method ?
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.shape_generic();
let mut res = OMatrix::identity_generic(nrows, ncols); let mut res = OMatrix::identity_generic(nrows, ncols);
if self.solve_mut(&mut res) { if self.solve_mut(&mut res) {

View File

@ -1,25 +1,23 @@
#![allow(clippy::suspicious_operation_groupings)] #![allow(clippy::suspicious_operation_groupings)]
use std::cmp;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use approx::AbsDiffEq; use approx::AbsDiffEq;
use num_complex::Complex as NumComplex; use num_complex::Complex as NumComplex;
use simba::scalar::{ComplexField, RealField}; use simba::scalar::{ComplexField, RealField};
use std::cmp;
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dynamic, U1, U2}; use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dynamic, U1, U2};
use crate::base::storage::{InnerOwned, Storage}; use crate::base::storage::Storage;
use crate::base::{ use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3};
DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3,
};
use crate::geometry::Reflection; use crate::geometry::Reflection;
use crate::linalg::givens::GivensRotation; use crate::linalg::givens::GivensRotation;
use crate::linalg::householder; use crate::linalg::householder;
use crate::linalg::Hessenberg; use crate::linalg::Hessenberg;
use crate::{Matrix, UninitVector};
use std::mem::MaybeUninit;
/// Schur decomposition of a square matrix. /// Schur decomposition of a square matrix.
/// ///
@ -36,7 +34,7 @@ use crate::linalg::Hessenberg;
OMatrix<T, D, D>: Deserialize<'de>")) OMatrix<T, D, D>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Schur<T, D: Dim> pub struct Schur<T: ComplexField, D: Dim>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
@ -44,10 +42,10 @@ where
t: OMatrix<T, D, D>, t: OMatrix<T, D, D>,
} }
impl<T: Copy, D: Dim> Copy for Schur<T, D> impl<T: ComplexField, D: Dim> Copy for Schur<T, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
{ {
} }
@ -76,7 +74,7 @@ where
/// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm
/// continues indefinitely until convergence. /// continues indefinitely until convergence.
pub fn try_new(m: OMatrix<T, D, D>, eps: T::RealField, max_niter: usize) -> Option<Self> { pub fn try_new(m: OMatrix<T, D, D>, eps: T::RealField, max_niter: usize) -> Option<Self> {
let mut work = OVector::new_uninitialized_generic(m.data.shape().0, Const::<1>); let mut work = Matrix::zeros_generic(m.shape_generic().0, Const::<1>);
Self::do_decompose(m, &mut work, eps, max_niter, true) Self::do_decompose(m, &mut work, eps, max_niter, true)
.map(|(q, t)| Schur { q: q.unwrap(), t }) .map(|(q, t)| Schur { q: q.unwrap(), t })
@ -84,7 +82,7 @@ where
fn do_decompose( fn do_decompose(
mut m: OMatrix<T, D, D>, mut m: OMatrix<T, D, D>,
work: &mut OVector<MaybeUninit<T>, D>, work: &mut OVector<T, D>,
eps: T::RealField, eps: T::RealField,
max_niter: usize, max_niter: usize,
compute_q: bool, compute_q: bool,
@ -94,7 +92,7 @@ where
"Unable to compute the eigenvectors and eigenvalues of a non-square matrix." "Unable to compute the eigenvectors and eigenvalues of a non-square matrix."
); );
let dim = m.data.shape().0; let dim = m.shape_generic().0;
// Specialization would make this easier. // Specialization would make this easier.
if dim.value() == 0 { if dim.value() == 0 {
@ -273,9 +271,7 @@ where
} }
/// Computes the eigenvalues of the decomposed matrix. /// Computes the eigenvalues of the decomposed matrix.
fn do_eigenvalues(t: &OMatrix<T, D, D>, out: &mut OVector<MaybeUninit<T>, D>) -> bool { fn do_eigenvalues(t: &OMatrix<T, D, D>, out: &mut OVector<T, D>) -> bool {
// TODO: check dropping stuff.
let dim = t.nrows(); let dim = t.nrows();
let mut m = 0; let mut m = 0;
@ -283,7 +279,7 @@ where
let n = m + 1; let n = m + 1;
if t[(n, m)].is_zero() { if t[(n, m)].is_zero() {
out[m] = MaybeUninit::new(t[(m, m)]); out[m] = t[(m, m)];
m += 1; m += 1;
} else { } else {
// Complex eigenvalue. // Complex eigenvalue.
@ -292,22 +288,18 @@ where
} }
if m == dim - 1 { if m == dim - 1 {
out[m] = MaybeUninit::new(t[(m, m)]); out[m] = t[(m, m)];
} }
true true
} }
/// Computes the complex eigenvalues of the decomposed matrix. /// Computes the complex eigenvalues of the decomposed matrix.
fn do_complex_eigenvalues( fn do_complex_eigenvalues(t: &OMatrix<T, D, D>, out: &mut UninitVector<NumComplex<T>, D>)
t: &OMatrix<T, D, D>, where
out: &mut OVector<MaybeUninit<NumComplex<T>>, D>,
) where
T: RealField, T: RealField,
DefaultAllocator: Allocator<NumComplex<T>, D>, DefaultAllocator: Allocator<NumComplex<T>, D>,
{ {
// TODO: check for dropping behavior.
let dim = t.nrows(); let dim = t.nrows();
let mut m = 0; let mut m = 0;
@ -397,9 +389,9 @@ where
/// Return `None` if some eigenvalues are complex. /// Return `None` if some eigenvalues are complex.
#[must_use] #[must_use]
pub fn eigenvalues(&self) -> Option<OVector<T, D>> { pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>); let mut out = Matrix::zeros_generic(self.t.shape_generic().0, Const::<1>);
if Self::do_eigenvalues(&self.t, &mut out) { if Self::do_eigenvalues(&self.t, &mut out) {
Some(unsafe { out.assume_init() }) Some(out)
} else { } else {
None None
} }
@ -412,8 +404,9 @@ where
T: RealField, T: RealField,
DefaultAllocator: Allocator<NumComplex<T>, D>, DefaultAllocator: Allocator<NumComplex<T>, D>,
{ {
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>); let mut out = Matrix::uninit(self.t.shape_generic().0, Const::<1>);
Self::do_complex_eigenvalues(&self.t, &mut out); Self::do_complex_eigenvalues(&self.t, &mut out);
// Safety: out has been fully initialized by do_complex_eigenvalues.
unsafe { out.assume_init() } unsafe { out.assume_init() }
} }
} }
@ -425,7 +418,7 @@ fn decompose_2x2<T: ComplexField, D: Dim>(
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
{ {
let dim = m.data.shape().0; let dim = m.shape_generic().0;
let mut q = None; let mut q = None;
match compute_2x2_basis(&m.fixed_slice::<2, 2>(0, 0)) { match compute_2x2_basis(&m.fixed_slice::<2, 2>(0, 0)) {
Some(rot) => { Some(rot) => {
@ -519,14 +512,12 @@ where
/// Computes the eigenvalues of this matrix. /// Computes the eigenvalues of this matrix.
#[must_use] #[must_use]
pub fn eigenvalues(&self) -> Option<OVector<T, D>> { pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
// TODO: check drop stuff.
assert!( assert!(
self.is_square(), self.is_square(),
"Unable to compute eigenvalues of a non-square matrix." "Unable to compute eigenvalues of a non-square matrix."
); );
let mut work = OVector::new_uninitialized_generic(self.data.shape().0, Const::<1>); let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
// Special case for 2x2 matrices. // Special case for 2x2 matrices.
if self.nrows() == 2 { if self.nrows() == 2 {
@ -535,9 +526,9 @@ where
let me = self.fixed_slice::<2, 2>(0, 0); let me = self.fixed_slice::<2, 2>(0, 0);
return match compute_2x2_eigvals(&me) { return match compute_2x2_eigvals(&me) {
Some((a, b)) => { Some((a, b)) => {
work[0] = MaybeUninit::new(a); work[0] = a;
work[1] = MaybeUninit::new(b); work[1] = b;
Some(unsafe { work.assume_init() }) Some(work)
} }
None => None, None => None,
}; };
@ -552,8 +543,9 @@ where
false, false,
) )
.unwrap(); .unwrap();
if Schur::do_eigenvalues(&schur.1, &mut work) { if Schur::do_eigenvalues(&schur.1, &mut work) {
Some(unsafe { work.assume_init() }) Some(work)
} else { } else {
None None
} }
@ -567,8 +559,8 @@ where
T: RealField, T: RealField,
DefaultAllocator: Allocator<NumComplex<T>, D>, DefaultAllocator: Allocator<NumComplex<T>, D>,
{ {
let dim = self.data.shape().0; let dim = self.shape_generic().0;
let mut work = OVector::new_uninitialized_generic(dim, Const::<1>); let mut work = Matrix::zeros_generic(dim, Const::<1>);
let schur = Schur::do_decompose( let schur = Schur::do_decompose(
self.clone_owned(), self.clone_owned(),
@ -578,8 +570,9 @@ where
false, false,
) )
.unwrap(); .unwrap();
let mut eig = OVector::new_uninitialized_generic(dim, Const::<1>); let mut eig = Matrix::uninit(dim, Const::<1>);
Schur::do_complex_eigenvalues(&schur.1, &mut eig); Schur::do_complex_eigenvalues(&schur.1, &mut eig);
// Safety: eig has been fully initialized by do_complex_eigenvalues.
unsafe { eig.assume_init() } unsafe { eig.assume_init() }
} }
} }

View File

@ -7,8 +7,8 @@ use num::{One, Zero};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2}; use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2};
use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimName, DimSub, U1}; use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
use crate::storage::{InnerOwned, Storage}; use crate::storage::Storage;
use simba::scalar::{ComplexField, RealField}; use simba::scalar::{ComplexField, RealField};
use crate::linalg::givens::GivensRotation; use crate::linalg::givens::GivensRotation;
@ -54,14 +54,14 @@ where
pub singular_values: OVector<T::RealField, DimMinimum<R, C>>, pub singular_values: OVector<T::RealField, DimMinimum<R, C>>,
} }
impl<T: ComplexField + Copy, R: DimName + DimMin<C>, C: DimName> Copy for SVD<T, R, C> impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for SVD<T, R, C>
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C> DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
+ Allocator<T, R, DimMinimum<R, C>> + Allocator<T, R, DimMinimum<R, C>>
+ Allocator<T::RealField, DimMinimum<R, C>>, + Allocator<T::RealField, DimMinimum<R, C>>,
InnerOwned<T, R, DimMinimum<R, C>>: Copy, OMatrix<T, R, DimMinimum<R, C>>: Copy,
InnerOwned<T, DimMinimum<R, C>, C>: Copy, OMatrix<T, DimMinimum<R, C>, C>: Copy,
InnerOwned<T::RealField, DimMinimum<R, C>>: Copy, OVector<T::RealField, DimMinimum<R, C>>: Copy,
{ {
} }
@ -111,7 +111,7 @@ where
!matrix.is_empty(), !matrix.is_empty(),
"Cannot compute the SVD of an empty matrix." "Cannot compute the SVD of an empty matrix."
); );
let (nrows, ncols) = matrix.data.shape(); let (nrows, ncols) = matrix.shape_generic();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);
let dim = min_nrows_ncols.value(); let dim = min_nrows_ncols.value();

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,8 +6,8 @@ use num::Zero;
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2}; use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2};
use crate::dimension::{Dim, DimDiff, DimName, DimSub, U1}; use crate::dimension::{Dim, DimDiff, DimSub, U1};
use crate::storage::{InnerOwned, Storage}; use crate::storage::Storage;
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::linalg::givens::GivensRotation; use crate::linalg::givens::GivensRotation;
@ -31,6 +29,7 @@ use crate::linalg::SymmetricTridiagonal;
OVector<T::RealField, D>: Deserialize<'de>, OVector<T::RealField, D>: Deserialize<'de>,
OMatrix<T, D, D>: Deserialize<'de>")) OMatrix<T, D, D>: Deserialize<'de>"))
)] )]
#[derive(Clone, Debug)]
pub struct SymmetricEigen<T: ComplexField, D: Dim> pub struct SymmetricEigen<T: ComplexField, D: Dim>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
@ -42,42 +41,14 @@ where
pub eigenvalues: OVector<T::RealField, D>, pub eigenvalues: OVector<T::RealField, D>,
} }
impl<T: ComplexField, D: DimName> Copy for SymmetricEigen<T, D> impl<T: ComplexField, D: Dim> Copy for SymmetricEigen<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
InnerOwned<T::RealField, D>: Copy, OVector<T::RealField, D>: Copy,
{ {
} }
impl<T: ComplexField, D: Dim> Clone for SymmetricEigen<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
InnerOwned<T, D, D>: Clone,
InnerOwned<T::RealField, D>: Clone,
{
fn clone(&self) -> Self {
Self {
eigenvectors: self.eigenvectors.clone(),
eigenvalues: self.eigenvalues.clone(),
}
}
}
impl<T: ComplexField, D: Dim> fmt::Debug for SymmetricEigen<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
InnerOwned<T, D, D>: fmt::Debug,
InnerOwned<T::RealField, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SymmetricEigen")
.field("eigenvectors", &self.eigenvectors)
.field("eigenvalues", &self.eigenvalues)
.finish()
}
}
impl<T: ComplexField, D: Dim> SymmetricEigen<T, D> impl<T: ComplexField, D: Dim> SymmetricEigen<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
@ -299,10 +270,7 @@ where
/// ///
/// This is useful if some of the eigenvalues have been manually modified. /// This is useful if some of the eigenvalues have been manually modified.
#[must_use] #[must_use]
pub fn recompose(&self) -> OMatrix<T, D, D> pub fn recompose(&self) -> OMatrix<T, D, D> {
where
InnerOwned<T, D, D>: Clone,
{
let mut u_t = self.eigenvectors.clone(); let mut u_t = self.eigenvectors.clone();
for i in 0..self.eigenvalues.len() { for i in 0..self.eigenvalues.len() {
let val = self.eigenvalues[i]; let val = self.eigenvalues[i];

View File

@ -1,16 +1,14 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector}; use crate::base::{DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Const, DimDiff, DimName, DimSub, U1}; use crate::dimension::{Const, DimDiff, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
use crate::linalg::householder; use crate::linalg::householder;
use crate::Matrix;
use std::mem::MaybeUninit;
/// Tridiagonalization of a symmetric matrix. /// Tridiagonalization of a symmetric matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -28,7 +26,8 @@ use crate::linalg::householder;
OMatrix<T, D, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>,
OVector<T, DimDiff<D, U1>>: Deserialize<'de>")) OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
)] )]
pub struct SymmetricTridiagonal<T, D: DimSub<U1>> #[derive(Clone, Debug)]
pub struct SymmetricTridiagonal<T: ComplexField, D: DimSub<U1>>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
{ {
@ -36,42 +35,14 @@ where
off_diagonal: OVector<T, DimDiff<D, U1>>, off_diagonal: OVector<T, DimDiff<D, U1>>,
} }
impl<T: Copy, D: DimSub<U1> + DimName> Copy for SymmetricTridiagonal<T, D> impl<T: ComplexField, D: DimSub<U1>> Copy for SymmetricTridiagonal<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
InnerOwned<T, DimDiff<D, U1>>: Copy, OVector<T, DimDiff<D, U1>>: Copy,
{ {
} }
impl<T: Clone, D: DimSub<U1>> Clone for SymmetricTridiagonal<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Clone,
InnerOwned<T, DimDiff<D, U1>>: Clone,
{
fn clone(&self) -> Self {
Self {
tri: self.tri.clone(),
off_diagonal: self.off_diagonal.clone(),
}
}
}
impl<T: fmt::Debug, D: DimSub<U1>> fmt::Debug for SymmetricTridiagonal<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: fmt::Debug,
InnerOwned<T, DimDiff<D, U1>>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SymmetricTridiagonal")
.field("tri", &self.tri)
.field("off_diagonal", &self.off_diagonal)
.finish()
}
}
impl<T: ComplexField, D: DimSub<U1>> SymmetricTridiagonal<T, D> impl<T: ComplexField, D: DimSub<U1>> SymmetricTridiagonal<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
@ -80,7 +51,7 @@ where
/// ///
/// Only the lower-triangular part (including the diagonal) of `m` is read. /// Only the lower-triangular part (including the diagonal) of `m` is read.
pub fn new(mut m: OMatrix<T, D, D>) -> Self { pub fn new(mut m: OMatrix<T, D, D>) -> Self {
let dim = m.data.shape().0; let dim = m.shape_generic().0;
assert!( assert!(
m.is_square(), m.is_square(),
@ -91,8 +62,8 @@ where
"Unable to compute the symmetric tridiagonal decomposition of an empty matrix." "Unable to compute the symmetric tridiagonal decomposition of an empty matrix."
); );
let mut off_diagonal = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>); let mut off_diagonal = Matrix::uninit(dim.sub(Const::<1>), Const::<1>);
let mut p = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>); let mut p = Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>);
for i in 0..dim.value() - 1 { for i in 0..dim.value() - 1 {
let mut m = m.rows_range_mut(i + 1..); let mut m = m.rows_range_mut(i + 1..);
@ -104,8 +75,7 @@ where
if not_zero { if not_zero {
let mut p = p.rows_range_mut(i..); let mut p = p.rows_range_mut(i..);
p.hegemv_z(crate::convert(2.0), &m, &axis); p.hegemv(crate::convert(2.0), &m, &axis, T::zero());
let p = unsafe { p.slice_assume_init() };
let dot = axis.dotc(&p); let dot = axis.dotc(&p);
m.hegerc(-T::one(), &p, &axis, T::one()); m.hegerc(-T::one(), &p, &axis, T::one());
@ -114,9 +84,11 @@ where
} }
} }
// Safety: off_diagonal has been fully initialized.
let off_diagonal = unsafe { off_diagonal.assume_init() };
Self { Self {
tri: m, tri: m,
off_diagonal: unsafe { off_diagonal.assume_init() }, off_diagonal,
} }
} }

View File

@ -1,12 +1,9 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::allocator::Allocator; use crate::allocator::Allocator;
use crate::base::{Const, DefaultAllocator, OMatrix, OVector}; use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Dim, DimName}; use crate::dimension::Dim;
use crate::storage::{InnerOwned, Storage};
use simba::scalar::RealField; use simba::scalar::RealField;
/// UDU factorization. /// UDU factorization.
@ -21,7 +18,8 @@ use simba::scalar::RealField;
deserialize = "OVector<T, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>" deserialize = "OVector<T, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>"
)) ))
)] )]
pub struct UDU<T, D: Dim> #[derive(Clone, Debug)]
pub struct UDU<T: RealField, D: Dim>
where where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>, DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
{ {
@ -31,42 +29,14 @@ where
pub d: OVector<T, D>, pub d: OVector<T, D>,
} }
impl<T: Copy, D: DimName> Copy for UDU<T, D> impl<T: RealField, D: Dim> Copy for UDU<T, D>
where where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>, DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
InnerOwned<T, D>: Copy, OVector<T, D>: Copy,
InnerOwned<T, D, D>: Copy, OMatrix<T, D, D>: Copy,
{ {
} }
impl<T: Clone, D: Dim> Clone for UDU<T, D>
where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
InnerOwned<T, D>: Clone,
InnerOwned<T, D, D>: Clone,
{
fn clone(&self) -> Self {
Self {
u: self.u.clone(),
d: self.d.clone(),
}
}
}
impl<T: fmt::Debug, D: Dim> fmt::Debug for UDU<T, D>
where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
InnerOwned<T, D>: fmt::Debug,
InnerOwned<T, D, D>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("UDU")
.field("u", &self.u)
.field("d", &self.d)
.finish()
}
}
impl<T: RealField, D: Dim> UDU<T, D> impl<T: RealField, D: Dim> UDU<T, D>
where where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>, DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
@ -79,7 +49,7 @@ where
/// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360 /// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360
pub fn new(p: OMatrix<T, D, D>) -> Option<Self> { pub fn new(p: OMatrix<T, D, D>) -> Option<Self> {
let n = p.ncols(); let n = p.ncols();
let n_dim = p.data.shape().1; let n_dim = p.shape_generic().1;
let mut d = OVector::zeros_generic(n_dim, Const::<1>); let mut d = OVector::zeros_generic(n_dim, Const::<1>);
let mut u = OMatrix::zeros_generic(n_dim, n_dim); let mut u = OMatrix::zeros_generic(n_dim, n_dim);

View File

@ -263,7 +263,7 @@ where
} }
/// Same as `matrix`, but without the additional anonymous generic types /// Same as `matrix`, but without the additional anonymous generic types
fn matrix_<R: Dim, C: Dim, ScalarStrategy>( fn matrix_<R, C, ScalarStrategy>(
value_strategy: ScalarStrategy, value_strategy: ScalarStrategy,
rows: DimRange<R>, rows: DimRange<R>,
cols: DimRange<C>, cols: DimRange<C>,
@ -271,6 +271,8 @@ fn matrix_<R: Dim, C: Dim, ScalarStrategy>(
where where
ScalarStrategy: Strategy + Clone + 'static, ScalarStrategy: Strategy + Clone + 'static,
ScalarStrategy::Value: Scalar, ScalarStrategy::Value: Scalar,
R: Dim,
C: Dim,
DefaultAllocator: Allocator<ScalarStrategy::Value, R, C>, DefaultAllocator: Allocator<ScalarStrategy::Value, R, C>,
{ {
let nrows = rows.lower_bound().value()..=rows.upper_bound().value(); let nrows = rows.lower_bound().value()..=rows.upper_bound().value();
@ -330,7 +332,12 @@ where
matrix_(value_strategy, length.into(), Const::<1>.into()) matrix_(value_strategy, length.into(), Const::<1>.into())
} }
impl<NParameters: Default, R: DimName, C: DimName> Default for MatrixParameters<NParameters, R, C> { impl<NParameters, R, C> Default for MatrixParameters<NParameters, R, C>
where
NParameters: Default,
R: DimName,
C: DimName,
{
fn default() -> Self { fn default() -> Self {
Self { Self {
rows: DimRange::from(R::name()), rows: DimRange::from(R::name()),

Some files were not shown because too many files have changed in this diff Show More