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/).
## [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]
### Added
- Implement `Hash` for `Transform`.

View File

@ -1,7 +1,4 @@
use na::{
Const, DMatrix, DVector, Dynamic, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3,
Vector4, U10,
};
use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3, Vector4, U10};
use rand::Rng;
use rand_isaac::IsaacRng;
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) {
let a = DMatrix::<f64>::new_random(1000, 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)));
}
@ -197,7 +194,7 @@ fn tr_mul_to(bench: &mut criterion::Criterion) {
fn mat_mul_mat(bench: &mut criterion::Criterion) {
let a = 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| {
bh.iter(|| {

View File

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

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};
@ -11,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -34,7 +32,8 @@ use lapack;
OMatrix<T, D, D>: Deserialize<'de>")
)
)]
pub struct Eigen<T, D: Dim>
#[derive(Clone, Debug)]
pub struct Eigen<T: Scalar, D: Dim>
where
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
{
@ -46,7 +45,7 @@ where
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
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
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>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
@ -104,13 +73,11 @@ where
let ljob = if left_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 lda = n as i32;
// IMPORTANT TODO: this is still UB.
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
// TODO: Tap into the workspace.
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."
);
let nrows = m.data.shape().0;
let nrows = m.shape_generic().0;
let n = nrows.value();
let lda = n as i32;

View File

@ -4,7 +4,7 @@ use num_complex::Complex;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, DimDiff, DimSub, U1};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -48,7 +48,7 @@ where
{
/// Computes the hessenberg decomposition of the matrix `m`.
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;
assert!(
@ -60,7 +60,6 @@ where
"Unable to compute the hessenberg decomposition of an empty matrix."
);
// IMPORTANT TODO: this is still UB.
let mut tau = unsafe {
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> {
let mut res = Vec::new();
res.reserve_exact(n);

View File

@ -4,7 +4,7 @@ use num_complex::Complex;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -61,7 +61,7 @@ where
{
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
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 nrows = nrows.value() as i32;
let ncols = ncols.value() as i32;
@ -87,7 +87,7 @@ where
#[inline]
#[must_use]
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();
res.fill_upper_triangle(Zero::zero(), 1);
@ -100,7 +100,7 @@ where
#[inline]
#[must_use]
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();
res.fill_lower_triangle(Zero::zero(), 1);
@ -115,7 +115,7 @@ where
#[inline]
#[must_use]
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);
self.permute(&mut id);
@ -191,7 +191,7 @@ where
b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>>
where
S2: Storage<T, R2, C2>,
S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{
let mut res = b.clone_owned();
@ -209,7 +209,7 @@ where
b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>>
where
S2: Storage<T, R2, C2>,
S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{
let mut res = b.clone_owned();
@ -227,7 +227,7 @@ where
b: &Matrix<T, R2, C2, S2>,
) -> Option<OMatrix<T, R2, C2>>
where
S2: Storage<T, R2, C2>,
S2: RawStorage<T, R2, C2>,
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
{
let mut res = b.clone_owned();

View File

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

View File

@ -9,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -71,7 +71,7 @@ where
"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 lda = n as i32;
@ -153,15 +153,15 @@ where
where
DefaultAllocator: Allocator<Complex<T>, D>,
{
let mut out =
unsafe { OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>) };
let mut out = unsafe {
OVector::new_uninitialized_generic(self.t.shape_generic().0, Const::<1>).assume_init()
};
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.
unsafe { out.assume_init() }
out
}
}

View File

@ -6,7 +6,7 @@ use std::cmp;
use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum, U1};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -89,7 +89,7 @@ macro_rules! svd_impl(
Allocator<$t, DimMinimum<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 {
return None;
@ -99,7 +99,6 @@ macro_rules! svd_impl(
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 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() };
@ -152,8 +151,8 @@ macro_rules! svd_impl(
/// been manually changed by the user.
#[inline]
pub fn recompose(self) -> OMatrix<$t, R, C> {
let nrows = self.u.data.shape().0;
let ncols = self.vt.data.shape().1;
let nrows = self.u.shape_generic().0;
let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols);
let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols);
@ -178,8 +177,8 @@ macro_rules! svd_impl(
#[inline]
#[must_use]
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
let nrows = self.u.data.shape().0;
let ncols = self.vt.data.shape().1;
let nrows = self.u.shape_generic().0;
let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols);
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>, C, 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 {
return None;

View File

@ -9,7 +9,7 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::storage::RawStorage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -89,12 +89,11 @@ where
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 lda = n as i32;
// IMPORTANT TODO: this is still UB.
let mut values =
unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut info = 0;

View File

@ -2,14 +2,16 @@ use crate::convert::serial::*;
use crate::coo::CooMatrix;
use crate::csc::CscMatrix;
use crate::csr::CsrMatrix;
use nalgebra::storage::Storage;
use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
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
T: Scalar + Zero + PartialEq,
S: Storage<T, R, C>,
T: Scalar + Zero,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
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
T: Scalar + Zero + PartialEq,
S: Storage<T, R, C>,
T: Scalar + Zero,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
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
T: Scalar + Zero + PartialEq,
S: Storage<T, R, C>,
T: Scalar + Zero,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_csc(matrix)

View File

@ -7,7 +7,7 @@ use std::ops::Add;
use num_traits::Zero;
use nalgebra::storage::Storage;
use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
use crate::coo::CooMatrix;
@ -16,10 +16,12 @@ use crate::csc::CscMatrix;
use crate::csr::CsrMatrix;
/// 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
T: Scalar + Zero + PartialEq,
S: Storage<T, R, C>,
T: Scalar + Zero,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
@ -91,10 +93,10 @@ where
/// Converts a dense matrix to a [`CsrMatrix`].
pub fn convert_dense_csr<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CsrMatrix<T>
where
T: Scalar + Zero + PartialEq,
T: Scalar + Zero,
R: 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 col_idx = Vec::new();
@ -168,10 +170,10 @@ where
/// Converts a dense matrix to a [`CscMatrix`].
pub fn convert_dense_csc<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CscMatrix<T>
where
T: Scalar + Zero + PartialEq,
T: Scalar + Zero,
R: 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 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
/// when inserted at `(r, c)`.
#[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,
r: 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,
};
use crate::ops::Op;
use nalgebra::allocator::{Allocator, InnerAllocator};
use nalgebra::base::storage::Storage;
use nalgebra::allocator::Allocator;
use nalgebra::base::storage::RawStorage;
use nalgebra::constraint::{DimEq, ShapeConstraint};
use nalgebra::{
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.
// Sub to SpAdd with negative coefficients. This is not well-defined for
// 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;
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) => {
// Implement ref-ref
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 mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols);
$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,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
DefaultAllocator: Allocator<T, Dynamic, C>,
// TODO: Is it possible to simplify these bounds?
ShapeConstraint:
// 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<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
+ DimEq<U1, S::RStride>
+ DimEq<R, Dynamic>

View File

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

View File

@ -55,7 +55,7 @@ pub fn spadd_csc_prealloc<T>(
a: Op<&CscMatrix<T>>,
) -> Result<(), OperationError>
where
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq,
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{
assert_compatible_spadd_dims!(c, a);
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>>,
) -> Result<(), OperationError>
where
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq,
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{
assert_compatible_spadd_dims!(c, a);
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SparsityPatternFormatError::InvalidOffsetArrayLength => {
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"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
use crate::base::storage::Owned;
#[cfg(any(feature = "std", feature = "alloc"))]
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.**
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.
///
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
#[deprecated(
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.
///
@ -277,6 +283,9 @@ pub type OVector<T, D> = Matrix<T, D, U1, Owned<T, D, U1>>;
/// 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>>;
/// 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.
///
/// **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.
use std::mem::{ManuallyDrop, MaybeUninit};
use std::any::Any;
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::{Dim, U1};
use crate::base::storage::ContiguousStorageMut;
use crate::base::DefaultAllocator;
use crate::base::{DefaultAllocator, Scalar};
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()`
/// 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
/// same `Buffer` type.
///
/// 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 {
pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
/// 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.
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;
}
/// Same as the [`InnerAllocator`] trait, but also provides methods to build uninitialized buffers,
/// or buffers whose entries must be manually dropped.
pub trait Allocator<T, R: Dim, C: Dim = U1>:
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>:
/// 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: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo>
{
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
/// `buf`. Data stored by `buf` are linearly copied to the output:
///
/// # Safety
/// **NO! THIS IS STILL UB!**
/// * 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 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(
nrows: RTo,
ncols: CTo,
buf: <Self as InnerAllocator<T, RFrom, CFrom>>::Buffer,
) -> <Self as InnerAllocator<T, RTo, CTo>>::Buffer;
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> <Self as Allocator<T, RTo, CTo>>::Buffer;
}
/// 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.
/// 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>>
where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
}
impl<T, R1: Dim, R2: Dim, C1: Dim, C2: Dim> SameShapeAllocator<T, R1, C1, R2, C2>
for DefaultAllocator
impl<T, R1, R2, C1, C2> SameShapeAllocator<T, R1, C1, R2, C2> for DefaultAllocator
where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
@ -106,15 +97,19 @@ where
// XXX: Bad name.
/// 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>
where
R1: Dim,
R2: Dim,
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
R1: Dim,
R2: Dim,
DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{

View File

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

View File

@ -1,21 +1,9 @@
//! Implements a subset of the Basic Linear Algebra Subprograms (BLAS), a
//! 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 crate::{RawStorage, SimdComplexField};
use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul};
#[cfg(feature = "std")]
use std::mem;
use std::mem::MaybeUninit;
use crate::base::allocator::Allocator;
use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit};
use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
};
@ -24,9 +12,10 @@ use crate::base::storage::{Storage, StorageMut};
use crate::base::{
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice,
};
use crate::core::uninit::Init;
/// # 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
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
@ -37,7 +26,7 @@ where
conjugate: impl Fn(T) -> T,
) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
assert!(
@ -205,7 +194,7 @@ where
#[must_use]
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
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
where
T: SimdComplexField,
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
self.dotx(rhs, T::simd_conjugate)
@ -262,7 +251,7 @@ where
#[must_use]
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,
{
let (nrows, ncols) = self.shape();
@ -293,10 +282,7 @@ where
T: Scalar + Zero + ClosedAdd + ClosedMul,
S: StorageMut<T, D>,
{
/// Computes `self = a * x * c + b * self`, where `a`, `b`, `c` are scalars,
/// and `x` is a vector of the same size as `self`.
///
/// For commutative scalars, this is equivalent to an [`axpy`] call.
/// Computes `self = a * x * c + b * self`.
///
/// If `b` is zero, `self` is never read from.
///
@ -316,34 +302,7 @@ where
SB: Storage<T, D2>,
ShapeConstraint: DimEq<D, D2>,
{
assert_eq!(self.nrows(), x.nrows(), "Axcpy: mismatched vector shapes.");
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();
}
}
}
unsafe { axcpy_uninit(Init, self, a, x, c, b) };
}
/// Computes `self = a * x + b * self`.
@ -399,38 +358,8 @@ where
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 {
// 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());
}
// Safety: this is safe because we are passing Status == Init.
unsafe { gemv_uninit(Init, self, alpha, a, x, beta) }
}
#[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
/// 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>
where
T: Scalar + Zero + ClosedAdd + ClosedMul,
@ -1170,122 +755,9 @@ where
+ 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 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(),
);
}
// SAFETY: this is valid because our matrices are initialized and
// we are using status = Init.
unsafe { gemm_uninit(Init, self, alpha, a, b, beta) }
}
/// 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,
/// 0.5, 0.6, 0.7,
/// 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;
///
/// 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);
/// 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,
alpha: T,
lhs: &Matrix<T, R3, C3, S3>,
mid: &SquareMatrix<T, D4, S4>,
beta: T,
) where
R3: Dim,
C3: Dim,
D4: Dim,
S3: Storage<T, R3, C3>,
S4: Storage<T, D4, D4>,
ShapeConstraint: DimEq<D1, R3> + DimEq<C3, D4>,
DefaultAllocator: Allocator<T, R3>,
ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>,
DefaultAllocator: Allocator<T, D1>,
{
let mut work =
Matrix::new_uninitialized_generic(R3::from_usize(self.shape().0), Const::<1>);
let mut work = work.gemv_z(T::one(), lhs, &mid.column(0));
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());
}
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta)
}
/// 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,
/// 0.5, 0.6, 0.7,
/// 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;
///
/// 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);
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,
work: &mut Vector<T, D2, S2>,
alpha: T,
mid: &SquareMatrix<T, D3, S3>,
rhs: &Matrix<T, R4, C4, S4>,
beta: T,
) where
D2: Dim,
D3: Dim,
R4: Dim,
C4: Dim,
S2: StorageMut<T, D2>,
S3: Storage<T, D3, D3>,
S4: Storage<T, R4, C4>,
ShapeConstraint: DimEq<D3, R4> + DimEq<R4, D3> + DimEq<D1, C4>,
DefaultAllocator: Allocator<T, D3>,
ShapeConstraint:
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.
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));
work.gemv(T::one(), mid, &rhs.column(0), T::zero());
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() {
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)
.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")))]
use alloc::vec::Vec;
#[cfg(feature = "arbitrary")]
use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen};
@ -11,17 +13,49 @@ use rand::{
Rng,
};
use std::{iter, mem::MaybeUninit};
use std::iter;
use typenum::{self, Cmp, Greater};
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::storage::Storage;
use crate::base::storage::RawStorage;
use crate::base::{
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
/// This set of matrix and vector construction functions are all generic
@ -29,16 +63,23 @@ use crate::base::{
/// the dimension as inputs.
///
/// 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
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`.
#[inline]
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self
where
T: Clone,
{
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self {
let len = nrows.value() * ncols.value();
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
}
@ -47,10 +88,7 @@ where
///
/// Same as `from_element_generic`.
#[inline]
pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self
where
T: Clone,
{
pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self {
let len = nrows.value() * ncols.value();
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
}
@ -59,7 +97,7 @@ where
#[inline]
pub fn zeros_generic(nrows: R, ncols: C) -> Self
where
T: Zero + Clone,
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.,
/// row-by-row.
#[inline]
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self
where
T: Clone,
{
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
assert!(
slice.len() == nrows.value() * ncols.value(),
"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();
for i in 0..nrows.value() {
for j in 0..ncols.value() {
unsafe {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone());
unsafe {
for i in 0..nrows.value() {
for j in 0..ncols.value() {
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(iter.next().unwrap().inlined_clone())
}
}
}
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
// SAFETY: the result has been fully initialized above.
res.assume_init()
}
}
/// 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).
#[inline]
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self
where
T: Clone,
{
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
Self::from_iterator_generic(nrows, ncols, slice.iter().cloned())
}
@ -120,18 +153,18 @@ where
where
F: FnMut(usize, usize) -> T,
{
let mut res = Self::new_uninitialized_generic(nrows, ncols);
let mut res = Matrix::uninit(nrows, ncols);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
unsafe {
for j in 0..ncols.value() {
for i in 0..nrows.value() {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
}
}
}
// Safety: all entries have been initialized.
unsafe { res.assume_init() }
// SAFETY: the result has been fully initialized above.
res.assume_init()
}
}
/// Creates a new identity matrix.
@ -141,7 +174,7 @@ where
#[inline]
pub fn identity_generic(nrows: R, ncols: C) -> Self
where
T: Zero + One + Scalar,
T: Zero + One,
{
Self::from_diagonal_element_generic(nrows, ncols, T::one())
}
@ -153,7 +186,7 @@ where
#[inline]
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self
where
T: Zero + One + Scalar,
T: Zero + One,
{
let mut res = Self::zeros_generic(nrows, ncols);
@ -171,7 +204,7 @@ where
#[inline]
pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self
where
T: Zero + Clone,
T: Zero,
{
let mut res = Self::zeros_generic(nrows, ncols);
assert!(
@ -180,7 +213,7 @@ where
);
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
@ -205,8 +238,7 @@ where
#[inline]
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
where
T: Clone,
SB: Storage<T, Const<1>, C>,
SB: RawStorage<T, Const<1>, C>,
{
assert!(!rows.is_empty(), "At least one row must be given.");
let nrows = R::try_to_usize().unwrap_or_else(|| rows.len());
@ -225,7 +257,7 @@ where
// TODO: optimize that.
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]
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
where
T: Clone,
SB: Storage<T, R>,
SB: RawStorage<T, R>,
{
assert!(!columns.is_empty(), "At least one column must be given.");
let ncols = C::try_to_usize().unwrap_or_else(|| columns.len());
@ -268,7 +299,7 @@ where
// TODO: optimize that.
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>
where
T: Scalar,
DefaultAllocator: Allocator<T, D, D>,
{
/// 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);
/// ```
#[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
T: Zero + Scalar,
T: Zero,
{
let (dim, _) = diag.data.shape();
let (dim, _) = diag.shape_generic();
let mut res = Self::zeros_generic(dim, dim);
for i in 0..diag.len() {
@ -366,6 +398,12 @@ where
*/
macro_rules! impl_constructors(
($($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`.
///
/// # Example
@ -387,10 +425,7 @@ macro_rules! impl_constructors(
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
/// ```
#[inline]
pub fn from_element($($args: usize,)* elem: T) -> Self
where
T: Clone
{
pub fn from_element($($args: usize,)* elem: T) -> Self {
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);
/// ```
#[inline]
pub fn repeat($($args: usize,)* elem: T) -> Self
where
T: Clone
{
pub fn repeat($($args: usize,)* elem: T) -> Self {
Self::repeat_generic($($gargs, )* elem)
}
@ -446,9 +478,7 @@ macro_rules! impl_constructors(
/// ```
#[inline]
pub fn zeros($($args: usize),*) -> Self
where
T: Zero + Clone
{
where T: Zero {
Self::zeros_generic($($gargs),*)
}
@ -504,7 +534,8 @@ macro_rules! impl_constructors(
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[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)
}
@ -528,9 +559,7 @@ macro_rules! impl_constructors(
/// ```
#[inline]
pub fn identity($($args: usize,)*) -> Self
where
T: Zero + One + Scalar
{
where T: Zero + One {
Self::identity_generic($($gargs),* )
}
@ -553,9 +582,7 @@ macro_rules! impl_constructors(
/// ```
#[inline]
pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self
where
T: Zero + One + Scalar
{
where T: Zero + One {
Self::from_diagonal_element_generic($($gargs, )* elt)
}
@ -582,9 +609,7 @@ macro_rules! impl_constructors(
/// ```
#[inline]
pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self
where
T: Zero + Scalar
{
where T: Zero {
Self::from_partial_diagonal_generic($($gargs, )* elts)
}
@ -603,16 +628,14 @@ macro_rules! impl_constructors(
#[inline]
#[cfg(feature = "rand")]
pub fn new_random($($args: usize),*) -> Self
where
Standard: Distribution<T>
{
where Standard: Distribution<T> {
Self::new_random_generic($($gargs),*)
}
}
);
/// # 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
DefaultAllocator: Allocator<T, R, C>,
{
@ -623,19 +646,8 @@ where
); // 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
impl<T, R: DimName> OMatrix<T, R, Dynamic>
impl<T: Scalar, R: DimName> OMatrix<T, R, Dynamic>
where
DefaultAllocator: Allocator<T, R, Dynamic>,
{
@ -645,19 +657,8 @@ where
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
impl<T, C: DimName> OMatrix<T, Dynamic, C>
impl<T: Scalar, C: DimName> OMatrix<T, Dynamic, C>
where
DefaultAllocator: Allocator<T, Dynamic, C>,
{
@ -667,19 +668,8 @@ where
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
impl<T> OMatrix<T, Dynamic, Dynamic>
impl<T: Scalar> OMatrix<T, Dynamic, Dynamic>
where
DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
{
@ -689,20 +679,6 @@ where
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
@ -711,10 +687,8 @@ where
*/
macro_rules! impl_constructors_from_data(
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<T, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*>
where
DefaultAllocator: Allocator<T $(, $Dims)*>
{
impl<T: Scalar, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*>
where DefaultAllocator: Allocator<T $(, $Dims)*> {
/// Creates a matrix with its elements filled with the components provided by a slice
/// 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);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self
where
T: Clone
{
pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self {
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);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self
where
T: Clone
{
pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self {
Self::from_column_slice_generic($($gargs, )* $data)
}
@ -877,7 +845,7 @@ where
}
#[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
DefaultAllocator: Allocator<T, R, C>,
Standard: Distribution<T>,
@ -892,10 +860,13 @@ where
}
#[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
T: Arbitrary + Send,
R: Dim,
C: Dim,
T: Scalar + Arbitrary + Send,
DefaultAllocator: Allocator<T, R, C>,
Owned<T, R, C>: Clone + Send,
{
#[inline]
fn arbitrary(g: &mut Gen) -> Self {

View File

@ -1,11 +1,13 @@
use crate::base::dimension::{Const, Dim, DimName, Dynamic};
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
use crate::base::{MatrixSlice, MatrixSliceMutMN};
use crate::base::{MatrixSlice, MatrixSliceMutMN, Scalar};
use num_rational::Ratio;
/// # 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.
///
/// # 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.
///
/// # Safety
@ -85,7 +87,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
macro_rules! impl_constructors(
($($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.
///
/// 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.
///
/// Panics if `data` does not contain enough elements.
@ -141,7 +143,7 @@ impl_constructors!(Dynamic, Dynamic;
nrows, ncols);
/// # 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>
{
/// 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.
///
/// # Safety
@ -245,7 +247,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
macro_rules! impl_constructors_mut(
($($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.
///
/// 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.
///
/// 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")))]
use alloc::vec::Vec;
use simba::scalar::{SubsetOf, SupersetOf};
use std::borrow::{Borrow, BorrowMut};
use std::convert::{AsMut, AsRef, From, Into};
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,
};
use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
use crate::base::{
ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
MatrixSliceMut, OMatrix, Scalar,
@ -26,12 +24,17 @@ use crate::base::{DVector, VecStorage};
use crate::base::{SliceStorage, SliceStorageMut};
use crate::constraint::DimEq;
use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector};
use std::mem::MaybeUninit;
// 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>>
for OMatrix<T1, R1, C1>
impl<T1, T2, R1, C1, R2, C2> SubsetOf<OMatrix<T2, R2, C2>> for OMatrix<T1, R1, C1>
where
T2: SupersetOf<T1>,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
T1: Scalar,
T2: Scalar + SupersetOf<T1>,
DefaultAllocator:
Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
@ -41,11 +44,11 @@ where
let (nrows, ncols) = self.shape();
let nrows2 = R2::from_usize(nrows);
let ncols2 = C2::from_usize(ncols);
let mut res = Matrix::new_uninitialized_generic(nrows2, ncols2);
let mut res = Matrix::uninit(nrows2, ncols2);
for i in 0..nrows {
for j in 0..ncols {
// Safety: all indices are in range.
unsafe {
*res.get_unchecked_mut((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() }
}
@ -67,23 +70,25 @@ where
let (nrows2, ncols2) = m.shape();
let nrows = R1::from_usize(nrows2);
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 j in 0..ncols2 {
// Safety: all indices are in range.
unsafe {
*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() }
}
}
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 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 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]
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]
fn from(vec: SVector<T, D>) -> Self {
let data = ManuallyDrop::new(vec.data.0);
// Safety: [[T; D]; 1] always has the same data layout as [T; D].
let res = unsafe { (data.as_ptr() as *const [_; D]).read() };
mem::forget(data);
res
// TODO: unfortunately, we must clone because we can move out of an array.
vec.data.0[0].clone()
}
}
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
Const<D>: IsNotStaticOne,
{
#[inline]
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
Const<D>: IsNotStaticOne,
{
@ -144,10 +148,11 @@ where
macro_rules! impl_from_into_asref_1D(
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
where
S: ContiguousStorage<T, $NRows, $NCols> {
where T: Scalar,
S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn as_ref(&self) -> &[T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe {
&*(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>
where
S: ContiguousStorageMut<T, $NRows, $NCols> {
where T: Scalar,
S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn as_mut(&mut self) -> &mut [T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe {
&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;
);
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]
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]
fn from(vec: SMatrix<T, R, C>) -> Self {
vec.data.0
@ -203,20 +209,22 @@ macro_rules! impl_from_into_asref_borrow_2D(
($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
) => {
impl<T, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorage<T, $NRows, $NCols> {
impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe {
&*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
}
}
}
impl<T, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorageMut<T, $NRows, $NCols> {
impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe {
&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);
);
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>>
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 {
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"))]
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
impl<'a, T, C, RStride, CStride> From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
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 {
matrix_slice.into_owned()
@ -264,18 +280,26 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim>
From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
impl<'a, T, R, RStride, CStride> From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
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 {
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>>
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 {
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"))]
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
impl<'a, T, C, RStride, CStride> From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
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 {
matrix_slice.into_owned()
@ -293,26 +321,37 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim>
From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
impl<'a, T, R, RStride, CStride> From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
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 {
matrix_slice.into_owned()
}
}
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
From<&'a Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix<T, R, C, S>>
for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
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>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
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 col_slice = CSlice::from_usize(col.value());
@ -327,23 +366,29 @@ where
(row_slice, col_slice),
(rstride_slice, cstride_slice),
);
Self::from_data(data)
Matrix::from_data_statically_unchecked(data)
}
}
}
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
From<&'a mut Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
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>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
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 col_slice = CSlice::from_usize(col.value());
@ -358,23 +403,29 @@ where
(row_slice, col_slice),
(rstride_slice, cstride_slice),
);
Matrix::from_data(data)
Matrix::from_data_statically_unchecked(data)
}
}
}
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
From<&'a mut Matrix<T, R, C, S>> for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
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>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
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 col_slice = CSlice::from_usize(col.value());
@ -389,22 +440,21 @@ where
(row_slice, col_slice),
(rstride_slice, cstride_slice),
);
Matrix::from_data(data)
Matrix::from_data_statically_unchecked(data)
}
}
}
#[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]
fn from(vec: Vec<T>) -> Self {
Self::from_vec(vec)
}
}
impl<'a, T, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> From<&'a Matrix<T, R, C, S>>
for &'a [T]
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage<T, R, C> + IsContiguous>
From<&'a Matrix<T, R, C, S>> for &'a [T]
{
#[inline]
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>>
for &'a mut [T]
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut<T, R, C> + IsContiguous>
From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
{
#[inline]
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]
fn from(slice: &'a [T]) -> Self {
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] {
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]
fn from(slice: &'a mut [T]) -> Self {
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] {
vec.data.into_slice_mut()
}
@ -456,7 +506,7 @@ where
{
#[inline]
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| {
[
@ -477,7 +527,7 @@ where
{
#[inline]
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| {
[
@ -500,7 +550,7 @@ where
{
#[inline]
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| {
[
@ -526,7 +576,7 @@ where
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
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| {
[

View File

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

View File

@ -4,72 +4,50 @@
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
use std::cmp;
use std::fmt;
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::mem;
use std::ptr;
#[cfg(all(feature = "alloc", not(feature = "std")))]
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"))]
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::storage::{
ContiguousStorage, ContiguousStorageMut, InnerOwned, Storage, StorageMut,
};
use crate::base::storage::{RawStorage, RawStorageMut};
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage;
use crate::U1;
use crate::base::Scalar;
use std::mem::{ManuallyDrop, MaybeUninit};
/*
*
* 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
/// matrices respectively.
#[derive(Copy, Clone, Debug)]
pub struct DefaultAllocator;
// 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 BufferUninit = ArrayStorage<MaybeUninit<T>, R, C>;
#[inline]
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: Const<R>,
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) }
unsafe fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> MaybeUninit<Self::Buffer> {
mem::MaybeUninit::<Self::Buffer>::uninit()
}
}
impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for DefaultAllocator {
#[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.
let array = unsafe { MaybeUninit::uninit().assume_init() };
let array: [[MaybeUninit<T>; R]; C] = unsafe { MaybeUninit::uninit().assume_init() };
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())
}
/// Specifies that a given buffer's entries should be manually dropped.
#[inline]
fn manually_drop(buf: ArrayStorage<T, R, C>) -> ArrayStorage<ManuallyDrop<T>, R, C> {
// SAFETY:
// * `ManuallyDrop<T>` and T are guaranteed to have the same layout
// * `ManuallyDrop` does not drop, so there are no double-frees
// And thus the conversion is safe
unsafe { ArrayStorage((&ManuallyDrop::new(buf) as *const _ as *const [_; C]).read()) }
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: Const<R>,
ncols: Const<C>,
iter: I,
) -> Self::Buffer {
#[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 - Dynamic
#[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 BufferUninit = VecStorage<MaybeUninit<T>, Dynamic, C>;
#[inline]
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: Dynamic,
ncols: C,
iter: I,
) -> 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.");
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> MaybeUninit<Self::Buffer> {
let mut res = Vec::new();
let length = nrows.value() * ncols.value();
res.reserve_exact(length);
res.set_len(length);
VecStorage::new(nrows, ncols, res)
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
}
}
impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
#[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 length = nrows.value() * ncols.value();
data.reserve_exact(length);
@ -143,32 +133,10 @@ impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
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]
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: R,
ncols: Dynamic,
nrows: Dynamic,
ncols: C,
iter: I,
) -> Self::Buffer {
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]
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 length = nrows.value() * ncols.value();
data.reserve_exact(length);
@ -209,253 +192,59 @@ impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
}
#[inline]
fn manually_drop(buf: VecStorage<T, R, Dynamic>) -> VecStorage<ManuallyDrop<T>, R, Dynamic> {
// Avoids a double-drop.
let (nrows, ncols) = buf.shape();
let vec: Vec<_> = buf.into();
let mut md = ManuallyDrop::new(vec);
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: R,
ncols: Dynamic,
iter: I,
) -> 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:
// - 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)
VecStorage::new(nrows, ncols, res)
}
}
/// 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.
*
*/
// 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
where
RFrom: Dim,
CFrom: Dim,
Self: Allocator<T, RFrom, CFrom>,
{
#[inline]
unsafe fn reallocate_copy(
rto: Const<RTO>,
cto: Const<CTO>,
buf: InnerOwned<T, RFrom, CFrom>,
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> 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 =
<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 len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
// Safety: TODO
<Self as Allocator<_, Const<RTO>, Const<CTO>>>::assume_init(res)
res
}
}
// Static × Static -> Dynamic × Any
#[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
where
CTo: Dim,
@ -466,25 +255,25 @@ where
cto: CTo,
buf: ArrayStorage<T, RFROM, CFROM>,
) -> 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 len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
<Self as Allocator<T, Dynamic, CTo>>::assume_init(res)
res
}
}
// Static × Static -> Static × Dynamic
#[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
where
RTo: DimName,
@ -495,25 +284,27 @@ where
cto: Dynamic,
buf: ArrayStorage<T, RFROM, CFROM>,
) -> 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 len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(
buf.ptr(),
res.ptr_mut() as *mut T,
cmp::min(len_from, len_to),
);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), 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.
#[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]
unsafe fn reallocate_copy(
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"))]
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
{
#[inline]
@ -541,7 +332,7 @@ impl<T, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
}
#[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
{
#[inline]
@ -556,7 +347,7 @@ impl<T, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
}
#[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
{
#[inline]

View File

@ -2,7 +2,7 @@
//! 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::fmt::Debug;
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")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Stores the dimension of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug)]
/// Dim of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Dynamic {
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
/// 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)]
fn is<D: Dim>() -> bool {
TypeId::of::<Self>() == TypeId::of::<D>()
@ -65,16 +65,6 @@ pub trait Dim: 'static + Debug + Copy + Default + PartialEq + Send + Sync {
/// Dynamic`.
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
/// `Self::try_to_usize().unwrap()`.
fn value(&self) -> usize;
@ -206,10 +196,7 @@ dim_ops!(
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
);
/// A wrapper around const types, which provides the capability of performing
/// type-level arithmetic. This might get removed if const-generics become
/// more powerful in the future.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Const<const R: usize>;
/// Trait implemented exclusively by type-level integers.

View File

@ -2,9 +2,6 @@ use num::{One, Zero};
use std::cmp;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::iter::ExactSizeIterator;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::mem;
use std::mem::MaybeUninit;
use std::ptr;
use crate::base::allocator::{Allocator, Reallocator};
@ -12,8 +9,10 @@ use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, Shap
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::dimension::Dynamic;
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::Storage;
use std::mem::MaybeUninit;
/// # Rows and columns extraction
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
I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator + Clone,
DefaultAllocator: Allocator<T, Dynamic, C>,
{
let irows = irows.into_iter();
let ncols = self.data.shape().1;
let mut res =
OMatrix::<T, Dynamic, C>::new_uninitialized_generic(Dynamic::new(irows.len()), ncols);
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(Dynamic::new(irows.len()), ncols);
// First, check that all the indices from irows are valid.
// 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);
for (destination, source) in irows.clone().enumerate() {
// Safety: all indices are in range.
unsafe {
*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() }
}
@ -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>,
{
let icols = icols.into_iter();
let nrows = self.data.shape().0;
let mut res = Matrix::new_uninitialized_generic(nrows, Dynamic::new(icols.len()));
let nrows = self.shape_generic().0;
let mut res = Matrix::uninit(nrows, Dynamic::new(icols.len()));
for (destination, source) in icols.enumerate() {
for (d, s) in res
.column_mut(destination)
.iter_mut()
.zip(self.column(*source).iter())
{
*d = MaybeUninit::new(s.clone());
}
// NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit.
res.column_mut(destination)
.zip_apply(&self.column(*source), |out, e| {
*out = MaybeUninit::new(e.inlined_clone())
});
}
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
}
/// # 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.
#[inline]
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
where
T: Clone,
R: DimMin<C>,
S2: Storage<T, R2>,
S2: RawStorage<T, R2>,
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
{
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.");
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]
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
where
T: Clone,
S2: Storage<T, U1, C2>,
S2: RawStorage<T, U1, C2>,
ShapeConstraint: SameNumberOfColumns<C, C2>,
{
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]
pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
where
T: Clone,
S2: Storage<T, R2, U1>,
S2: RawStorage<T, R2, U1>,
ShapeConstraint: SameNumberOfRows<R, R2>,
{
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
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`.
#[inline]
pub fn fill(&mut self, val: T)
where
T: Clone,
T: Scalar,
{
for e in self.iter_mut() {
*e = val.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();
*e = val.inlined_clone()
}
}
@ -188,7 +185,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline]
pub fn fill_with_identity(&mut self)
where
T: Zero + One + Scalar,
T: Scalar + Zero + One,
{
self.fill(T::zero());
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]
pub fn fill_diagonal(&mut self, val: T)
where
T: Clone,
T: Scalar,
{
let (nrows, ncols) = self.shape();
let n = cmp::min(nrows, ncols);
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]
pub fn fill_row(&mut self, i: usize, val: T)
where
T: Clone,
T: Scalar,
{
assert!(i < self.nrows(), "Row index out of bounds.");
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]
pub fn fill_column(&mut self, j: usize, val: T)
where
T: Clone,
T: Scalar,
{
assert!(j < self.ncols(), "Row index out of bounds.");
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]
pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
where
T: Clone,
T: Scalar,
{
for j in 0..self.ncols() {
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]
pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
where
T: Clone,
T: Scalar,
{
for j in shift..self.ncols() {
// TODO: is there a more efficient way to avoid the min ?
// (necessary for rectangular matrices)
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.
///
/// 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 i in j + 1..dim {
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 i in 0..j {
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
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.
#[inline]
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
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.
@ -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>,
{
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 target: usize = 0;
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>,
{
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 target: usize = 0;
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>>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
assert!(
i + nremove.value() <= ncols.value(),
"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>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
assert!(
i + nremove.value() <= nrows.value(),
"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 {
unsafe {
compress_rows(
&mut m.data.as_mut_slice(),
&mut m.as_mut_slice(),
nrows.value(),
ncols.value(),
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
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.
@ -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>>,
{
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(
nrows,
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>,
{
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(
nrows.add(ninsert),
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 {
extend_rows(
&mut res.data.as_mut_slice(),
&mut res.as_mut_slice(),
nrows.value(),
ncols.value(),
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
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.
///
/// 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
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)
}
@ -776,7 +773,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where
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)
}
@ -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>,
{
let (nrows, ncols) = self.shape();
let mut data = self.data.into_owned();
let mut data = self.into_owned();
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);
if new_ncols.value() > ncols {
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(),
);
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data.0,
new_nrows, new_ncols, data.data,
));
} else {
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data.0,
new_nrows, new_ncols, data.data,
));
extend_rows(
&mut res.data.as_mut_slice(),
&mut res.as_mut_slice(),
nrows,
new_ncols.value(),
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 {
res.columns_range_mut(ncols..).fill(val.clone());
res.columns_range_mut(ncols..).fill(val.inlined_clone());
}
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
#[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.
///
/// 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
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
{
// IMPORTANT TODO: this method is still UB, and we should decide how to
// update the API to take it into account.
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);
// TODO: avoid the clone.
*self = self.clone().resize(new_nrows, new_ncols, val);
}
}
#[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
DefaultAllocator: Allocator<T, Dynamic, C>,
{
@ -970,16 +960,13 @@ where
where
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
{
let placeholder =
Matrix::from_fn_generic(Dynamic::new(0), self.data.shape().1, |_, _| val.clone());
let old = mem::replace(self, placeholder);
let new = old.resize_vertically(new_nrows, val);
let _ = mem::replace(self, new);
// TODO: avoid the clone.
*self = self.clone().resize_vertically(new_nrows, val);
}
}
#[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
DefaultAllocator: Allocator<T, R, Dynamic>,
{
@ -994,15 +981,18 @@ where
where
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
{
let placeholder =
Matrix::from_fn_generic(self.data.shape().0, Dynamic::new(0), |_, _| val.clone());
let old = mem::replace(self, placeholder);
let new = old.resize_horizontally(new_ncols, val);
let _ = mem::replace(self, new);
// TODO: avoid the clone.
*self = self.clone().resize_horizontally(new_ncols, val);
}
}
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;
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.
// 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;
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
/// a given iterator.
#[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
/// 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"))]
impl<T, S> Extend<T> for Matrix<T, Dynamic, U1, S>
where
T: Scalar,
S: Extend<T>,
{
/// Extend the number of rows of a `Vector` with elements
@ -1128,10 +1130,13 @@ where
}
#[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
T: Scalar,
R: Dim,
S: Extend<Vector<T, RV, SV>>,
SV: Storage<T, RV>,
RV: Dim,
SV: RawStorage<T, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>,
{
/// Extends the number of columns of a `Matrix` with `Vector`s

View File

@ -1,8 +1,8 @@
//! Indexing
use crate::base::storage::{Storage, StorageMut};
use crate::base::storage::{RawStorage, RawStorageMut};
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;
@ -310,7 +310,7 @@ fn dimrange_rangetoinclusive_usize() {
}
/// 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.
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.
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>
{
/// 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,
/// 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
/// `None` if the index is out of bounds.
#[inline]
@ -494,7 +494,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use]
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
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]
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
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]
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
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
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
S: Storage<T, R, C>,
T: Scalar,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
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
S: StorageMut<T, R, C>,
T: Scalar,
R: Dim,
C: Dim,
S: RawStorageMut<T, R, C>,
{
type OutputMut = &'a mut T;
@ -577,7 +583,7 @@ where
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
matrix.data.get_unchecked_linear_mut(self)
}
@ -585,9 +591,11 @@ where
// 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
S: Storage<T, R, C>,
R: Dim,
C: Dim,
S: RawStorage<T, R, C>,
{
type Output = &'a T;
@ -595,7 +603,7 @@ where
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool {
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)
}
@ -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
S: StorageMut<T, R, C>,
R: Dim,
C: Dim,
S: RawStorageMut<T, R, C>,
{
type OutputMut = &'a mut T;
@ -617,7 +627,7 @@ where
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
let (row, col) = self;
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 )*),*>)* )*]
) =>
{
impl<'a, T: 'a, $R: Dim, $C: Dim, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*>
MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
where
S: Storage<T, R, C>,
T: Scalar,
$R: Dim,
$C: Dim,
S: RawStorage<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
@ -656,7 +668,7 @@ macro_rules! impl_index_pair {
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool {
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)
}
@ -666,21 +678,23 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorage;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
let data =
SliceStorage::new_unchecked(&matrix.data,
(rows.lower(nrows), cols.lower(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),*>
MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
where
S: StorageMut<T, R, C>,
T: Scalar,
$R: Dim,
$C: Dim,
S: RawStorageMut<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
@ -692,14 +706,14 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorageMut;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
let data =
SliceStorageMut::new_unchecked(&mut matrix.data,
(rows.lower(nrows), cols.lower(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 crate::base::dimension::{Dim, U1};
use crate::base::storage::{Storage, StorageMut};
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut};
use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar};
macro_rules! iterator {
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
/// 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>> {
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 MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a 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)]
/// 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>,
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 {
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>;
#[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>
{
#[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.
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>,
curr: usize,
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 {
RowIterMut {
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>;
#[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>
{
#[inline]
@ -290,18 +294,18 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
*/
#[derive(Clone, Debug)]
/// 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>,
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 {
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>;
#[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>
{
#[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.
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>,
curr: usize,
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 {
ColumnIterMut {
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>
{
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>
{
#[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.
*
*/
impl<T, R: Dim, C: Dim> SimdValue for OMatrix<T, R, C>
impl<T, R, C> SimdValue for OMatrix<T, R, C>
where
T: Scalar + SimdValue,
R: Dim,
C: Dim,
T::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
@ -42,7 +44,6 @@ where
fn replace(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| {
a.replace(i, b);
a
})
}
@ -50,7 +51,6 @@ where
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| {
a.replace_unchecked(i, b);
a
})
}

View File

@ -1,14 +1,13 @@
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
use std::slice;
use crate::base::allocator::{Allocator, InnerAllocator};
use crate::base::allocator::Allocator;
use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1};
use crate::base::iter::MatrixIter;
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
use crate::base::{Matrix, Owned};
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage};
use crate::base::{Matrix, Scalar};
macro_rules! slice_storage_impl(
($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>
$T<'a, T, R, C, RStride, CStride>
where
Self: ContiguousStorage<T, R, C>
Self: RawStorage<T, R, C> + IsContiguous
{
/// Extracts the original slice from this storage
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 \
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 \
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>
{
}
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>
{
#[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>
where
Self: ContiguousStorageMut<T, R, C>,
Self: RawStorageMut<T, R, C> + IsContiguous,
{
/// Extracts the original slice from this storage
pub fn into_slice_mut(self) -> &'a mut [T] {
@ -145,7 +144,7 @@ where
macro_rules! storage_impl(
($($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> {
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]
unsafe fn as_slice_unchecked(&self) -> &[T] {
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);
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
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>
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut<T, R, C>
for SliceStorageMut<'a, T, R, C, RStride, CStride>
{
#[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>
for SliceStorage<'a, T, R, U1, U1, CStride>
{
}
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> {}
unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous
for SliceStorageMut<'a, T, R, U1, U1, CStride>
{
}
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorageMut<T, R, U1>
for SliceStorageMut<'a, T, R, U1, U1, CStride>
{
}
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
for SliceStorage<'a, T, R, C, U1, R>
{
}
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
for SliceStorageMut<'a, T, R, C, U1, R>
{
}
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<T, R, C>
for SliceStorageMut<'a, T, R, C, U1, R>
{
}
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> {
#[inline]
fn assert_slice_index(
&self,
@ -344,7 +298,6 @@ macro_rules! matrix_slice_impl(
$fixed_slice_with_steps: ident,
$generic_slice: ident,
$generic_slice_with_steps: ident,
$full_slice: ident,
$rows_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)
-> $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));
let shape = (nrows, my_shape.1);
unsafe {
let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape);
Matrix::from_data(data)
Matrix::from_data_statically_unchecked(data)
}
}
@ -421,16 +374,16 @@ macro_rules! matrix_slice_impl(
-> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
where RSlice: Dim {
let my_shape = $me.data.shape();
let my_shape = $me.shape_generic();
let my_strides = $me.data.strides();
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0));
let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1);
let shape = (nrows, my_shape.1);
let shape = (nrows, my_shape.1);
unsafe {
let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides);
Matrix::from_data(data)
Matrix::from_data_statically_unchecked(data)
}
}
@ -491,33 +444,34 @@ macro_rules! matrix_slice_impl(
pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
-> $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));
let shape = (my_shape.0, ncols);
unsafe {
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
/// or may not be values known at compile-time.
#[inline]
pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
-> $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();
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step));
let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value()));
let shape = (my_shape.0, ncols);
let shape = (my_shape.0, ncols);
unsafe {
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 {
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
/// `(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
@ -564,7 +519,7 @@ macro_rules! matrix_slice_impl(
unsafe {
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.
#[inline]
pub fn $generic_slice<RSlice: Dim, CSlice: Dim>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
-> $MatrixSlice<T, RSlice, CSlice, S::RStride, S::CStride>
{
pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
-> $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));
unsafe {
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 {
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.
@ -633,7 +584,7 @@ macro_rules! matrix_slice_impl(
-> ($MatrixSlice<'_, T, Range1::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 start1 = r1.begin(nrows);
@ -654,8 +605,8 @@ macro_rules! matrix_slice_impl(
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides);
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides);
let slice1 = Matrix::from_data(data1);
let slice2 = Matrix::from_data(data2);
let slice1 = Matrix::from_data_statically_unchecked(data1);
let slice2 = Matrix::from_data_statically_unchecked(data2);
(slice1, slice2)
}
@ -669,7 +620,7 @@ macro_rules! matrix_slice_impl(
-> ($MatrixSlice<'_, T, R, Range1::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 start1 = r1.begin(ncols);
@ -690,8 +641,8 @@ macro_rules! matrix_slice_impl(
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides);
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides);
let slice1 = Matrix::from_data(data1);
let slice2 = Matrix::from_data(data2);
let slice1 = Matrix::from_data_statically_unchecked(data1);
let slice2 = Matrix::from_data_statically_unchecked(data2);
(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>>;
/// # 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!(
self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data;
self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data;
row,
row_part,
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,
generic_slice,
generic_slice_with_steps,
full_slice,
rows_range_pair,
columns_range_pair);
}
/// # 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!(
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_part_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,
generic_slice_mut,
generic_slice_with_steps_mut,
full_slice_mut,
rows_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.
///
/// 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
// 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
/// by the range `cols`.
#[inline]
@ -936,7 +867,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
RowRange: SliceRange<R>,
ColRange: SliceRange<C>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
self.generic_slice(
(rows.begin(nrows), cols.begin(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
// 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
/// indexed by the range `cols`.
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>,
ColRange: SliceRange<C>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
self.generic_slice_mut(
(rows.begin(nrows), cols.begin(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>
From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
impl<'a, T, R, C, RStride, CStride> From<MatrixSliceMut<'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 {
let data = SliceStorage {
@ -1016,6 +951,6 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
_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 num::{Signed, Zero};
use simba::simd::SimdSigned;
/// # 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.
/// # 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.
///
/// # 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.
/// # 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.
///
/// # Examples:

View File

@ -33,10 +33,12 @@ mod unit;
#[cfg(any(feature = "std", feature = "alloc"))]
mod vec_storage;
mod blas_uninit;
#[doc(hidden)]
pub mod helper;
mod interpolation;
mod min_max;
pub mod uninit;
pub use self::matrix::*;
pub use self::norm::*;
@ -50,5 +52,6 @@ pub use self::alias::*;
pub use self::alias_slice::*;
pub use self::array_storage::*;
pub use self::matrix_slice::*;
pub use self::storage::*;
#[cfg(any(feature = "std", feature = "alloc"))]
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 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)
}
@ -508,13 +508,8 @@ where
/// The i-the canonical basis element.
#[inline]
fn canonical_basis_element(i: usize) -> Self {
assert!(i < D::dim(), "Index out of bound.");
let mut res = Self::zero();
unsafe {
*res.data.get_unchecked_linear_mut(i) = T::one();
}
res[i] = T::one();
res
}

View File

@ -1,29 +1,31 @@
use num::{One, Zero};
use std::iter;
use std::mem::MaybeUninit;
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use crate::base::allocator::{
Allocator, InnerAllocator, SameShapeAllocator, SameShapeC, SameShapeR,
};
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use crate::base::blas_uninit::gemm_uninit;
use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
};
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::{MatrixSliceMut, SimdComplexField};
use crate::storage::IsContiguous;
use crate::uninit::{Init, InitStatus};
use crate::{RawStorage, RawStorageMut, SimdComplexField};
use std::mem::MaybeUninit;
/*
*
* 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;
#[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>
where
S: Storage<T, R, C>,
{
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<(usize, usize)> for Matrix<T, R, C, S> {
type Output = T;
#[inline]
@ -52,7 +51,7 @@ where
}
// 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]
fn index_mut(&mut self, i: usize) -> &mut T {
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>
where
S: StorageMut<T, R, C>,
{
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<(usize, usize)> for Matrix<T, R, C, S> {
#[inline]
fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
let shape = self.shape();
@ -135,25 +131,27 @@ macro_rules! componentwise_binop_impl(
($Trait: ident, $method: ident, $bound: ident;
$TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: 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>
where
T: Scalar + $bound
{
where T: Scalar + $bound {
/*
*
* Methods without dimension checking at compile-time.
* This is useful for code reuse because the sum representative system does not play
* nicely with static checks.
* This is useful for code reuse because the sum representative system does not plays
* easily with static checks.
*
*/
#[inline]
fn $method_to_statically_unchecked<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self, rhs: &Matrix<T, R2, C2, SB>, out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>
) where
SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>
{
fn $method_to_statically_unchecked_uninit<Status, R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
status: Status,
rhs: &Matrix<T, R2, C2, SB>,
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(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
@ -163,31 +161,28 @@ macro_rules! componentwise_binop_impl(
if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() {
let arr1 = self.data.as_slice_unchecked();
let arr2 = rhs.data.as_slice_unchecked();
let out = out.data.as_mut_slice_unchecked();
for i in 0..arr1.len() {
*out.get_unchecked_mut(i) = MaybeUninit::new(
arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()
));
let out = out.data.as_mut_slice_unchecked();
for i in 0 .. arr1.len() {
Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()));
}
} else {
for j in 0..self.ncols() {
for i in 0..self.nrows() {
*out.get_unchecked_mut((i, j)) = MaybeUninit::new(
self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone())
);
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
let val = 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]
fn $method_assign_statically_unchecked<R2: Dim, C2: Dim, SB>(
&mut self, rhs: &Matrix<T, R2, C2, SB>
) where
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>
{
fn $method_assign_statically_unchecked<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
where R2: Dim,
C2: Dim,
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2> {
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
// This is the most common case and should be deduced at compile-time.
@ -210,12 +205,12 @@ macro_rules! componentwise_binop_impl(
}
}
#[inline]
fn $method_assign_statically_unchecked_rhs<R2: Dim, C2: Dim, SB>(
&self, rhs: &mut Matrix<T, R2, C2, SB>
) where
SB: StorageMut<T, R2, C2>
{
fn $method_assign_statically_unchecked_rhs<R2, C2, SB>(&self, rhs: &mut Matrix<T, R2, C2, SB>)
where R2: Dim,
C2: Dim,
SB: StorageMut<T, R2, C2> {
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
// 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.
#[inline]
pub fn $method_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>
) where
SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>,
ShapeConstraint:
SameNumberOfRows<R1, R2> +
SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> +
SameNumberOfColumns<C1, C3>
{
self.$method_to_statically_unchecked(rhs, out)
pub fn $method_to<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<T, R3, C3, SC>)
where SB: Storage<T, R2, C2>,
SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
self.$method_to_statically_unchecked_uninit(Init, 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>
where
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>,
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1>
{
impl<'a, T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>,
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> {
type Output = MatrixSum<T, R2, C2, R1, C1>;
#[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>
where
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
{
impl<T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
type Output = MatrixSum<T, R1, C1, R2, C2>;
#[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>
where
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
{
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 R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound,
SA: Storage<T, R1, C1>,
SB: Storage<T, R2, C2>,
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
type Output = MatrixSum<T, R1, C1, R2, C2>;
#[inline]
@ -335,33 +322,33 @@ macro_rules! componentwise_binop_impl(
let (nrows, ncols) = self.shape();
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
self.$method_to_statically_unchecked(rhs, &mut res);
let mut res = Matrix::uninit(nrows, ncols);
self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res);
// SAFETY: the output has been initialized above.
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>
where
T: Scalar + $bound,
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
{
impl<'b, T, R1, C1, R2, C2, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound,
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
#[inline]
fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) {
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>
where
T: Scalar + $bound,
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
{
impl<T, R1, C1, R2, C2, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
T: Scalar + $bound,
SA: StorageMut<T, R1, C1>,
SB: Storage<T, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
#[inline]
fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) {
self.$method_assign(&rhs)
@ -372,10 +359,10 @@ macro_rules! componentwise_binop_impl(
componentwise_binop_impl!(Add, add, ClosedAdd;
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;
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>
where
@ -574,9 +561,12 @@ where
#[inline]
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 _ = self.mul_to(rhs, &mut res);
unsafe { res.assume_init() }
let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1);
unsafe {
// 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:
// 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.
impl<T, R1: Dim, C1: Dim, R2: Dim, SA, SB> MulAssign<Matrix<T, R2, C1, SB>>
for Matrix<T, R1, C1, SA>
impl<T, R1, C1, R2, SA, SB> MulAssign<Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
where
R1: Dim,
C1: Dim,
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
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>,
DefaultAllocator: Allocator<T, R1, C1> + InnerAllocator<T, R1, C1, Buffer = SA>,
DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
{
#[inline]
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>>
for Matrix<T, R1, C1, SA>
impl<'b, T, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
where
R1: Dim,
C1: Dim,
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
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>,
// 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]
fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) {
@ -680,8 +674,9 @@ where
DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1);
self.tr_mul_to(rhs, &mut res);
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
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() }
}
@ -695,23 +690,26 @@ where
DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1);
self.ad_mul_to(rhs, &mut res);
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
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() }
}
#[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,
status: Status,
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(
&VectorSlice<'_, T, R1, SA::RStride, SA::CStride>,
&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>,
) -> T,
) where
SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>,
Status: InitStatus<T>,
SB: RawStorage<T, R2, C2>,
SC: RawStorageMut<Status::Value, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{
let (nrows1, ncols1) = self.shape();
@ -740,9 +738,8 @@ where
for i in 0..ncols1 {
for j in 0..ncols2 {
let dot = dot(&self.column(i), &rhs.column(j));
unsafe {
*out.get_unchecked_mut((i, j)) = MaybeUninit::new(dot);
}
let elt = unsafe { out.get_unchecked_mut((i, j)) };
Status::init(elt, dot);
}
}
}
@ -753,13 +750,13 @@ where
pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>,
out: &mut Matrix<T, R3, C3, SC>,
) where
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>,
{
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
@ -768,31 +765,30 @@ where
pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>,
out: &mut Matrix<T, R3, C3, SC>,
) where
T: SimdComplexField,
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>,
{
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.
#[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,
rhs: &Matrix<T, R2, C2, SB>,
out: &'a mut Matrix<MaybeUninit<T>, R3, C3, SC>,
) -> MatrixSliceMut<'a, T, R3, C3, SC::RStride, SC::CStride>
where
out: &mut Matrix<T, R3, C3, SC>,
) where
SB: Storage<T, R2, C2>,
SC: StorageMut<MaybeUninit<T>, R3, C3>,
SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R3, R1>
+ SameNumberOfColumns<C3, 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
@ -809,34 +805,31 @@ where
SB: Storage<T, R2, C2>,
DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>,
{
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
let (nrows1, ncols1) = self.shape_generic();
let (nrows2, ncols2) = rhs.shape_generic();
let mut res = Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2));
{
let mut data_res = res.data.ptr_mut();
let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2));
let mut data_res = res.data.ptr_mut();
unsafe {
for j1 in 0..ncols1.value() {
for j2 in 0..ncols2.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() {
*data_res = MaybeUninit::new(
coeff.inlined_clone()
* rhs.get_unchecked((i2, j2)).inlined_clone(),
);
data_res = data_res.offset(1);
}
for i2 in 0..nrows2.value() {
*data_res = MaybeUninit::new(
coeff.inlined_clone() * rhs.get_unchecked((i2, j2)).inlined_clone(),
);
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::dimension::{Dim, DimMin};
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.
///
/// # Examples:

View File

@ -1,38 +1,27 @@
use std::any::Any;
use std::any::TypeId;
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
/// the algebraic properties of `Self`. It has various purposes and objectives:
/// - 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 {
/// This does not make any assumption on the algebraic properties of `Self`.
pub trait Scalar: Clone + PartialEq + Debug + Any {
#[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
/// 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`.
/// Typically used to test of `Self` is a f32 or a f64 with `T::is::<f32>()`.
fn is<T: Scalar>() -> bool {
TypeId::of::<Self>() == TypeId::of::<T>()
}
/// Performance hack: Clone doesn't get inlined for Copy types in debug
/// mode, so make it inline anyway.
#[inline(always)]
/// Performance hack: Clone doesn't get inlined for Copy types in debug mode, so make it inline anyway.
fn inlined_clone(&self) -> Self {
self.clone()
}
}
// Unfortunately, this blanket impl leads to many misleading compiler messages
// telling you to implement Copy, even though Scalar is what's really needed.
impl<T: 'static + Copy + Debug> Scalar for T {
impl<T: Copy + PartialEq + Debug + Any> Scalar for T {
#[inline(always)]
fn inlined_clone(&self) -> T {
*self

View File

@ -1,13 +1,12 @@
use std::mem::MaybeUninit;
use crate::allocator::Allocator;
use crate::storage::Storage;
use crate::storage::RawStorage;
use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1};
use num::Zero;
use simba::scalar::{ClosedAdd, Field, SupersetOf};
use std::mem::MaybeUninit;
/// # 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
/// corresponding column of the original matrix.
#[inline]
@ -19,16 +18,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where
DefaultAllocator: Allocator<T, U1, C>,
{
let ncols = self.data.shape().1;
let mut res = RowOVector::new_uninitialized_generic(Const::<1>, ncols);
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(Const::<1>, ncols);
for i in 0..ncols.value() {
// TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe {
*res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i)));
}
}
// Safety: res is now fully initialized.
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
DefaultAllocator: Allocator<T, C>,
{
let ncols = self.data.shape().1;
let mut res = Matrix::new_uninitialized_generic(ncols, Const::<1>);
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(ncols, Const::<1>);
for i in 0..ncols.value() {
// TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe {
*res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i)));
}
}
// Safety: res is now fully initialized.
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]
pub fn compress_columns(
&self,
mut init: OVector<T, R>,
f: impl Fn(&mut OVector<T, R>, VectorSlice<T, R, S::RStride, S::CStride>),
init: OVector<T, R>,
f: impl Fn(&mut OVector<T, R>, VectorSlice<'_, T, R, S::RStride, S::CStride>),
) -> OVector<T, R>
where
DefaultAllocator: Allocator<T, R>,
{
let mut res = init;
for i in 0..self.ncols() {
f(&mut init, self.column(i))
f(&mut res, self.column(i))
}
init
res
}
}
/// # 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.
@ -178,7 +183,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: ClosedAdd + Zero,
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| {
*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>,
DefaultAllocator: Allocator<T, R>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
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);
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>,
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);
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
out.axpy(denom.inlined_clone(), &col, T::one())

View File

@ -2,27 +2,32 @@
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::dimension::{Dim, U1};
use crate::base::Owned;
use crate::base::Scalar;
/*
* 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 ?
/// 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)`.
pub type SameShapeStorage<T, R1, C1, R2, C2> = Owned<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>;
/// The owned data storage that can be allocated from `S`.
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)`.
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)`.
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.
///
@ -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
/// (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.
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.
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.
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.
fn into_owned(self) -> Owned<T, R, C>
where
T: Clone,
DefaultAllocator: Allocator<T, R, C>;
/// Clones this data storage to one that does not contain any reference.
fn clone_owned(&self) -> Owned<T, R, C>
where
T: Clone,
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
/// 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).
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.
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];
}
/// A matrix storage that is stored contiguously in memory.
///
/// 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() }
}
pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>:
Storage<T, R, C> + RawStorageMut<T, R, C>
{
}
/// 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
/// `.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 ContiguousStorageMut<T, R: Dim, C: Dim = U1>:
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() }
}
}
pub unsafe trait IsContiguous {}
/// 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.
type Output: Storage<T, R2, C2>;
type Output: RawStorage<T, R2, C2>;
/// Reshapes the storage into the output storage type.
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::storage::Storage;
use crate::base::{DimName, Scalar, ToTypenum, Vector, Vector2, Vector3};
use crate::storage::RawStorage;
use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle {
@ -11,7 +11,7 @@ macro_rules! impl_swizzle {
#[must_use]
pub fn $name(&self) -> $Result<T>
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
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
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::base::DefaultAllocator;
use crate::storage::{InnerOwned, Storage};
use crate::storage::RawStorage;
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
/// 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>>
where
T: PartialEq,
T: Scalar + PartialEq,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
#[inline]
fn eq(&self, rhs: &Self) -> bool {
@ -126,10 +126,10 @@ where
impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>>
where
T: Eq,
T: Scalar + Eq,
R: 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.
#[inline]
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.
@ -331,7 +331,7 @@ impl<T> Deref for Unit<T> {
#[inline]
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::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{
#[inline]
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::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{
#[inline]
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::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{
#[inline]
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::Element: Scalar,
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
InnerOwned<T::Element, R, C>: Clone,
{
#[inline]
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")))]
use alloc::vec::Vec;
use crate::allocator::InnerAllocator;
use crate::base::allocator::Allocator;
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Dim, DimName, Dynamic, U1};
use crate::base::storage::{
ContiguousStorage, ContiguousStorageMut, ReshapableStorage, Storage, StorageMut,
};
use crate::base::{Owned, Vector};
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
use crate::base::{Scalar, Vector};
#[cfg(feature = "serde-serialize-no-std")]
use serde::{
@ -19,20 +17,22 @@ use serde::{
ser::{Serialize, Serializer},
};
use crate::Storage;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
/*
*
* Storage.
* RawStorage.
*
*/
/// A Vec-based matrix data storage. It may be dynamically-sized.
#[repr(C)]
#[derive(Eq, Debug, Clone, PartialEq)]
pub struct VecStorage<T, R: Dim, C: Dim> {
data: Vec<T>,
pub(crate) nrows: R,
pub(crate) ncols: C,
nrows: R,
ncols: C,
}
#[cfg(feature = "serde-serialize")]
@ -142,6 +142,18 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
pub fn is_empty(&self) -> bool {
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> {
@ -156,10 +168,7 @@ impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
* Dynamic Dynamic
*
*/
unsafe impl<T, C: Dim> Storage<T, Dynamic, C> for VecStorage<T, Dynamic, C>
where
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
{
unsafe impl<T, C: Dim> RawStorage<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
type RStride = U1;
type CStride = Dynamic;
@ -183,29 +192,34 @@ where
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]
unsafe fn as_slice_unchecked(&self) -> &[T] {
&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
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 CStride = R;
@ -229,34 +243,39 @@ where
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]
unsafe fn as_slice_unchecked(&self) -> &[T] {
&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>
where
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
{
unsafe impl<T, C: Dim> RawStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
#[inline]
fn ptr_mut(&mut self) -> *mut T {
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
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>
{
}
unsafe impl<T, R: Dim, C: Dim> IsContiguous for VecStorage<T, R, C> {}
unsafe impl<T, C: Dim> ContiguousStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> where
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>
{
}
impl<T, C1: Dim, C2: Dim> ReshapableStorage<T, Dynamic, C1, Dynamic, C2>
for VecStorage<T, Dynamic, C1>
impl<T, C1, C2> ReshapableStorage<T, Dynamic, C1, Dynamic, C2> for VecStorage<T, Dynamic, C1>
where
T: Scalar,
C1: Dim,
C2: Dim,
{
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>
for VecStorage<T, Dynamic, C1>
impl<T, C1, R2> ReshapableStorage<T, Dynamic, C1, R2, Dynamic> for VecStorage<T, Dynamic, C1>
where
T: Scalar,
C1: Dim,
R2: DimName,
{
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>
where
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>,
{
unsafe impl<T, R: DimName> RawStorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> {
#[inline]
fn ptr_mut(&mut self) -> *mut T {
self.data.as_mut_ptr()
@ -323,8 +337,11 @@ where
}
}
impl<T, R1: DimName, C2: Dim> ReshapableStorage<T, R1, Dynamic, Dynamic, C2>
for VecStorage<T, R1, Dynamic>
impl<T, R1, C2> ReshapableStorage<T, R1, Dynamic, Dynamic, C2> for VecStorage<T, R1, Dynamic>
where
T: Scalar,
R1: DimName,
C2: Dim,
{
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>
for VecStorage<T, R1, Dynamic>
impl<T, R1, R2> ReshapableStorage<T, R1, Dynamic, R2, Dynamic> for VecStorage<T, R1, Dynamic>
where
T: Scalar,
R1: DimName,
R2: DimName,
{
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> {
/// Extends the number of columns of the `VecStorage` with elements
/// 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
SV: Storage<T, RV>,
T: Scalar,
R: Dim,
RV: Dim,
SV: RawStorage<T, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>,
{
/// 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")]
use quickcheck::{Arbitrary, Gen};
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::linalg::givens::GivensRotation;
use crate::storage::Owned;
use simba::scalar::ComplexField;
/// A random orthogonal matrix.
pub struct RandomOrthogonal<T, D: Dim = Dynamic>
#[derive(Clone, Debug)]
pub struct RandomOrthogonal<T: Scalar, D: Dim = Dynamic>
where
DefaultAllocator: Allocator<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>
where
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")]
use quickcheck::{Arbitrary, Gen};
use crate::base::allocator::Allocator;
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 crate::debug::RandomOrthogonal;
/// 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
DefaultAllocator: Allocator<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>
where
DefaultAllocator: Allocator<T, D, D>,

View File

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

View File

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

View File

@ -24,7 +24,8 @@ use crate::geometry::{
impl<T1, T2> SubsetOf<DualQuaternion<T2>> for DualQuaternion<T1>
where
T2: SupersetOf<T1>,
T1: SimdRealField,
T2: SimdRealField + SupersetOf<T1>,
{
#[inline]
fn to_superset(&self) -> DualQuaternion<T2> {
@ -48,7 +49,8 @@ where
impl<T1, T2> SubsetOf<UnitDualQuaternion<T2>> for UnitDualQuaternion<T1>
where
T2: SupersetOf<T1>,
T1: SimdRealField,
T2: SimdRealField + SupersetOf<T1>,
{
#[inline]
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,
};
impl<T> AsRef<[T; 8]> for DualQuaternion<T> {
impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> {
#[inline]
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]
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;
#[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]
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.as_mut()[i]

View File

@ -15,7 +15,7 @@ use simba::simd::SimdRealField;
use crate::base::allocator::Allocator;
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::geometry::{AbstractRotation, Point, Translation};
@ -53,6 +53,7 @@ use crate::geometry::{AbstractRotation, Point, Translation};
/// # Conversion to a matrix
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
///
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
#[cfg_attr(
@ -79,6 +80,7 @@ pub struct Isometry<T, R, const D: usize> {
#[cfg(feature = "abomonation-serialize")]
impl<T, R, const D: usize> Abomonation for Isometry<T, R, D>
where
T: SimdRealField,
R: Abomonation,
Translation<T, D>: Abomonation,
{
@ -104,7 +106,10 @@ mod rkyv_impl {
use crate::{base::Scalar, geometry::Translation};
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 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>
for Isometry<T, R, D>
impl<T: Scalar + Serialize<S>, R: Serialize<S>, S: Fallible + ?Sized, const D: usize>
Serialize<S> for Isometry<T, R, D>
where
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>
where
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
InnerOwned<T, Const<D>>: hash::Hash,
Owned<T, Const<D>>: hash::Hash,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
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]
fn clone(&self) -> Self {
Self {
@ -630,7 +638,7 @@ where
* 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
R: fmt::Display,
{

View File

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

View File

@ -18,29 +18,27 @@ use crate::base::{Matrix4, Vector, Vector3};
use crate::geometry::{Point3, Projective3};
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
#[repr(transparent)]
#[repr(C)]
pub struct Orthographic3<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]
fn clone(&self) -> Self {
Self {
matrix: self.matrix.clone(),
}
Self::from_matrix_unchecked(self.matrix)
}
}
impl<T: fmt::Debug> fmt::Debug for Orthographic3<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl<T: RealField> fmt::Debug for Orthographic3<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.matrix.fmt(f)
}
}
impl<T: PartialEq> PartialEq for Orthographic3<T> {
impl<T: RealField> PartialEq for Orthographic3<T> {
#[inline]
fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix
@ -64,7 +62,7 @@ where
}
#[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>
where
S: Serializer,
@ -74,7 +72,7 @@ impl<T: Serialize> Serialize for Orthographic3<T> {
}
#[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>
where
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> {
/// 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.
///
/// 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));
/// ```
#[inline]
pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self
where
T: RealField,
{
let matrix = Matrix4::identity();
pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
let matrix = Matrix4::<T>::identity();
let mut res = Self::from_matrix_unchecked(matrix);
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.
#[inline]
pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self
where
T: RealField,
{
pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self {
assert!(
znear != zfar,
"The far plane must not be equal to the near plane."
@ -192,10 +207,7 @@ impl<T> Orthographic3<T> {
/// ```
#[inline]
#[must_use]
pub fn inverse(&self) -> Matrix4<T>
where
T: RealField,
{
pub fn inverse(&self) -> Matrix4<T> {
let mut res = self.to_homogeneous();
let inv_m11 = T::one() / self.matrix[(0, 0)];
@ -229,7 +241,6 @@ impl<T> Orthographic3<T> {
/// ```
#[inline]
#[must_use]
// TODO: rename into `into_homogeneous` to appease clippy.
pub fn to_homogeneous(self) -> Matrix4<T> {
self.matrix
}
@ -265,8 +276,7 @@ impl<T> Orthographic3<T> {
#[inline]
#[must_use]
pub fn as_projective(&self) -> &Projective3<T> {
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix.
unsafe { &*(self as *const _ as *const _) }
unsafe { &*(self as *const Orthographic3<T> as *const Projective3<T>) }
}
/// This transformation seen as a `Projective3`.
@ -279,7 +289,6 @@ impl<T> Orthographic3<T> {
/// ```
#[inline]
#[must_use]
// TODO: rename into `into_projective` to appease clippy.
pub fn to_projective(self) -> Projective3<T> {
Projective3::from_matrix_unchecked(self.matrix)
}
@ -311,10 +320,7 @@ impl<T> Orthographic3<T> {
pub fn unwrap(self) -> Matrix4<T> {
self.matrix
}
}
/// # Mathematical methods.
impl<T: RealField> Orthographic3<T> {
/// 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> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.matrix.fmt(f)
}
}
@ -158,8 +158,7 @@ impl<T: RealField> Perspective3<T> {
#[inline]
#[must_use]
pub fn as_projective(&self) -> &Projective3<T> {
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix.
unsafe { &*(self as *const _ as *const _) }
unsafe { &*(self as *const Perspective3<T> as *const Projective3<T>) }
}
/// This transformation seen as a `Projective3`.

View File

@ -5,7 +5,6 @@ use std::fmt;
use std::hash;
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::mem::{ManuallyDrop, MaybeUninit};
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -15,13 +14,11 @@ use abomonation::Abomonation;
use simba::simd::SimdPartialOrd;
use crate::allocator::InnerAllocator;
use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::{Const, DefaultAllocator, OVector};
use crate::storage::InnerOwned;
use crate::Scalar;
use crate::base::{Const, DefaultAllocator, OVector, Scalar};
use std::mem::MaybeUninit;
/// 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
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
/// of said transformations for details.
#[repr(transparent)]
pub struct OPoint<T, D: DimName>
#[repr(C)]
#[derive(Debug, Clone)]
pub struct OPoint<T: Scalar, D: DimName>
where
DefaultAllocator: InnerAllocator<T, D>,
DefaultAllocator: Allocator<T, D>,
{
/// The coordinates of this point, i.e., the shift from the origin.
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
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
DefaultAllocator: Allocator<T, D>,
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")]
unsafe impl<T, D: DimName> bytemuck::Zeroable for OPoint<T, D>
unsafe impl<T: Scalar, D: DimName> bytemuck::Zeroable for OPoint<T, D>
where
OVector<T, D>: bytemuck::Zeroable,
DefaultAllocator: Allocator<T, D>,
@ -98,7 +74,7 @@ where
}
#[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
T: Copy,
OVector<T, D>: bytemuck::Pod,
@ -107,10 +83,10 @@ where
}
#[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
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>
where
@ -121,10 +97,10 @@ where
}
#[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
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>
where
@ -139,6 +115,7 @@ where
#[cfg(feature = "abomonation-serialize")]
impl<T, D: DimName> Abomonation for OPoint<T, D>
where
T: Scalar,
OVector<T, D>: Abomonation,
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
DefaultAllocator: Allocator<T, D>,
{
@ -173,9 +150,8 @@ where
/// ```
#[inline]
#[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
T: Clone,
DefaultAllocator: Allocator<T2, D>,
{
self.coords.map(f).into()
@ -187,19 +163,16 @@ where
/// ```
/// # use nalgebra::{Point2, Point3};
/// 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));
///
/// // This works in any dimension.
/// 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));
/// ```
#[inline]
pub fn apply<F: FnMut(T) -> T>(&mut self, f: F)
where
T: Clone,
{
pub fn apply<F: FnMut(&mut T)>(&mut self, f: F) {
self.coords.apply(f)
}
@ -221,45 +194,25 @@ where
#[inline]
#[must_use]
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
T: One,
D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
{
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
let mut md = self.manually_drop();
// TODO: this is mostly a copy-past from Vector::push.
// 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() {
unsafe {
*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()
}
// Safety: res has been fully initialized.
unsafe { res.assume_init() }
}
/// Creates a new point with the given coordinates.
@ -322,7 +275,9 @@ where
/// assert_eq!(it.next(), Some(3.0));
/// assert_eq!(it.next(), None);
#[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()
}
@ -346,7 +301,9 @@ where
///
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
#[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()
}
@ -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
T::Epsilon: Copy,
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
T::Epsilon: Copy,
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
T::Epsilon: Copy,
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
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
DefaultAllocator: Allocator<T, D>,
{
@ -497,7 +454,7 @@ where
* 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
DefaultAllocator: Allocator<T, D>,
{

View File

@ -1,5 +1,3 @@
use std::mem::{ManuallyDrop, MaybeUninit};
#[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen};
@ -22,23 +20,10 @@ use simba::scalar::{ClosedDiv, SupersetOf};
use crate::geometry::Point;
/// # Other construction methods
impl<T, D: DimName> OPoint<T, D>
impl<T: Scalar, D: DimName> OPoint<T, D>
where
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.
///
/// # Example
@ -57,9 +42,9 @@ where
#[inline]
pub fn origin() -> Self
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.
@ -77,11 +62,8 @@ where
/// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0));
/// ```
#[inline]
pub fn from_slice(components: &[T]) -> Self
where
T: Clone,
{
Self::from(OVector::<_, D>::from_row_slice(components))
pub fn from_slice(components: &[T]) -> Self {
Self::from(OVector::from_row_slice(components))
}
/// Creates a new point from its homogeneous vector representation.
@ -139,7 +121,7 @@ where
/// let pt2 = pt.cast::<f32>();
/// 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
OPoint<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D>,
@ -169,7 +151,7 @@ where
}
#[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
Standard: Distribution<T>,
DefaultAllocator: Allocator<T, D>,
@ -182,10 +164,10 @@ where
}
#[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
<DefaultAllocator as Allocator<T, D>>::Buffer: Send,
DefaultAllocator: Allocator<T, D>,
crate::base::storage::InnerOwned<T, D>: Clone + Send,
{
#[inline]
fn arbitrary(g: &mut Gen) -> Self {
@ -201,7 +183,7 @@ where
// NOTE: the impl for Point1 is not with the others so that we
// can add a section with the impl block comment.
/// # Construction from individual components
impl<T> Point1<T> {
impl<T: Scalar> Point1<T> {
/// Initializes this point from its components.
///
/// # Example
@ -220,7 +202,7 @@ impl<T> Point1<T> {
}
macro_rules! componentwise_constructors_impl(
($($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 = "# Example\n```"]
#[doc = $doc]

View File

@ -2,7 +2,7 @@ use num::{One, Zero};
use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf};
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::{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>
where
T2: SupersetOf<T1>,
T1: Scalar,
T2: Scalar + SupersetOf<T1>,
DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>,
{
#[inline]
@ -43,6 +44,7 @@ where
impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D>
where
D: DimNameAdd<U1>,
T1: Scalar,
T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>,
DefaultAllocator: Allocator<T1, D>
+ Allocator<T2, D>
@ -54,7 +56,7 @@ where
#[inline]
fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> {
let p: OPoint<T2, D> = self.to_superset();
p.into_homogeneous()
p.to_homogeneous()
}
#[inline]
@ -64,25 +66,25 @@ where
#[inline]
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 {
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
D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>,
{
#[inline]
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]
fn from(coords: [T; D]) -> Self {
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]
where
T: Clone,
{
impl<T: Scalar, const D: usize> From<Point<T, D>> for [T; D] {
#[inline]
fn from(p: Point<T, D>) -> Self {
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
DefaultAllocator: InnerAllocator<T, D>,
DefaultAllocator: Allocator<T, D>,
{
#[inline]
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
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]
fn from(arr: [Point<T::Element, D>; 2]) -> Self {
Self::from(OVector::from([
arr[0].coords.clone(),
arr[1].coords.clone(),
]))
Self::from(OVector::from([arr[0].coords, arr[1].coords]))
}
}
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
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]
fn from(arr: [Point<T::Element, D>; 4]) -> Self {
Self::from(OVector::from([
arr[0].coords.clone(),
arr[1].coords.clone(),
arr[2].coords.clone(),
arr[3].coords.clone(),
arr[0].coords,
arr[1].coords,
arr[2].coords,
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
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]
fn from(arr: [Point<T::Element, D>; 8]) -> Self {
Self::from(OVector::from([
arr[0].coords.clone(),
arr[1].coords.clone(),
arr[2].coords.clone(),
arr[3].coords.clone(),
arr[4].coords.clone(),
arr[5].coords.clone(),
arr[6].coords.clone(),
arr[7].coords.clone(),
arr[0].coords,
arr[1].coords,
arr[2].coords,
arr[3].coords,
arr[4].coords,
arr[5].coords,
arr[6].coords,
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>
where
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]
fn from(arr: [Point<T::Element, D>; 16]) -> Self {
Self::from(OVector::from([
arr[0].coords.clone(),
arr[1].coords.clone(),
arr[2].coords.clone(),
arr[3].coords.clone(),
arr[4].coords.clone(),
arr[5].coords.clone(),
arr[6].coords.clone(),
arr[7].coords.clone(),
arr[8].coords.clone(),
arr[9].coords.clone(),
arr[10].coords.clone(),
arr[11].coords.clone(),
arr[12].coords.clone(),
arr[13].coords.clone(),
arr[14].coords.clone(),
arr[15].coords.clone(),
arr[0].coords,
arr[1].coords,
arr[2].coords,
arr[3].coords,
arr[4].coords,
arr[5].coords,
arr[6].coords,
arr[7].coords,
arr[8].coords,
arr[9].coords,
arr[10].coords,
arr[11].coords,
arr[12].coords,
arr[13].coords,
arr[14].coords,
arr[15].coords,
]))
}
}

View File

@ -1,7 +1,7 @@
use std::ops::{Deref, DerefMut};
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;
@ -13,7 +13,7 @@ use crate::geometry::OPoint;
macro_rules! deref_impl(
($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>;
@ -23,7 +23,7 @@ macro_rules! deref_impl(
}
}
impl<T> DerefMut for OPoint<T, $D>
impl<T: Scalar> DerefMut for OPoint<T, $D>
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,14 +12,13 @@ impl<T: Scalar + SimdValue> Deref for Quaternion<T> {
#[inline]
fn deref(&self) -> &Self::Target {
// Safety: Self and IJKW are both stored as contiguous coordinates.
unsafe { &*(self as *const _ as *const _) }
unsafe { &*(self as *const Self as *const Self::Target) }
}
}
impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> {
#[inline]
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::storage::Storage;
use crate::base::{Const, Unit, Vector, Vector3};
use crate::base::{Const, Scalar, Unit, Vector, Vector3};
use crate::SimdRealField;
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;
#[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]
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.coords[i]
@ -371,12 +371,12 @@ quaternion_op_impl!(
;
self: Rotation<T, 3>, rhs: UnitQuaternion<T>,
Output = UnitQuaternion<T>;
UnitQuaternion::<T>::from_rotation_matrix(&self) / rhs;);
UnitQuaternion::<T>::from_rotation_matrix(&self) / rhs; );
// UnitQuaternion × Vector
quaternion_op_impl!(
Mul, mul;
SB: Storage<T, Const<3>>;
SB: Storage<T, Const<3>> ;
self: &'a UnitQuaternion<T>, rhs: &'b Vector<T, Const<3>, SB>,
Output = Vector3<T>;
{

View File

@ -1,5 +1,3 @@
use std::mem::MaybeUninit;
use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
use crate::base::{Const, Matrix, Unit, Vector};
use crate::dimension::{Dim, U1};
@ -9,7 +7,7 @@ use simba::scalar::ComplexField;
use crate::geometry::Point;
/// A reflection wrt. a plane.
pub struct Reflection<T, D: Dim, S> {
pub struct Reflection<T, D, S> {
axis: Vector<T, D, S>,
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>(
&self,
lhs: &mut Matrix<T, R2, C2, S2>,
work: &mut Vector<MaybeUninit<T>, R2, S3>,
work: &mut Vector<T, R2, S3>,
) where
S2: StorageMut<T, R2, C2>,
S3: StorageMut<MaybeUninit<T>, R2>,
S3: StorageMut<T, R2>,
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() {
work.add_scalar_mut(-self.bias);
}
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`.
pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>(
&self,
lhs: &mut Matrix<T, R2, C2, S2>,
work: &mut Vector<MaybeUninit<T>, R2, S3>,
work: &mut Vector<T, R2, S3>,
sign: T,
) where
S2: StorageMut<T, R2, C2>,
S3: StorageMut<MaybeUninit<T>, R2>,
S3: StorageMut<T, R2>,
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() {
work.add_scalar_mut(-self.bias);
}
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};
#[cfg(feature = "serde-serialize-no-std")]
use crate::base::storage::InnerOwned;
use crate::storage::InnerOwned;
use crate::base::storage::Owned;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
@ -54,26 +53,29 @@ use crate::geometry::Point;
/// # Conversion
/// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
///
#[repr(transparent)]
#[repr(C)]
#[derive(Debug)]
pub struct Rotation<T, const D: usize> {
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
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) {
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
InnerOwned<T, Const<D>, Const<D>>: Clone,
<DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: Clone,
{
#[inline]
fn clone(&self) -> Self {
@ -100,6 +102,7 @@ where
#[cfg(feature = "abomonation-serialize")]
impl<T, const D: usize> Abomonation for Rotation<T, D>
where
T: Scalar,
SMatrix<T, D, D>: Abomonation,
{
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
@ -118,7 +121,7 @@ where
#[cfg(feature = "serde-serialize-no-std")]
impl<T: Scalar, const D: usize> Serialize for Rotation<T, D>
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>
where
@ -129,9 +132,9 @@ where
}
#[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
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>
where
@ -173,7 +176,7 @@ impl<T, const D: usize> Rotation<T, D> {
}
/// # 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.
///
/// # Example
@ -201,7 +204,7 @@ impl<T, const D: usize> Rotation<T, D> {
/// A mutable reference to the underlying matrix representation of this rotation.
#[inline]
#[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
}
@ -274,7 +277,7 @@ impl<T, const D: usize> Rotation<T, D> {
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where
T: Zero + One + Scalar,
T: Zero + One,
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
{

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::Any;
use std::fmt;
use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;
@ -8,11 +7,11 @@ use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use simba::scalar::{ComplexField, RealField};
use simba::scalar::RealField;
use crate::base::allocator::Allocator;
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::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 {
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
/// 3D transformation.
#[repr(transparent)]
pub struct Transform<T, C: TCategory, const D: usize>
#[repr(C)]
#[derive(Debug)]
pub struct Transform<T: RealField, C: TCategory, const D: usize>
where
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
@ -167,32 +167,29 @@ where
_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
Const<D>: DimNameAdd<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) {
self.matrix.hash(state);
}
}
/*
impl<T: Copy, C: TCategory, const D: usize> Copy for Transform<T, C, D>
impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D>
where
Const<D>: DimNameAdd<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
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
{
#[inline]
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
T: RealField + bytemuck::Zeroable,
Const<D>: DimNameAdd<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,
{
}
#[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,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Transform")
.field("matrix", &self.matrix)
.finish()
}
}
#[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
Const<D>: DimNameAdd<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>
where
@ -229,11 +234,11 @@ where
}
#[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
Const<D>: DimNameAdd<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>
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
Const<D>: DimNameAdd<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
Const<D>: DimNameAdd<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
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
@ -370,10 +375,7 @@ where
#[deprecated(
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>
where
T: Clone,
{
pub fn clone_owned(&self) -> Transform<T, C, D> {
Transform::from_matrix_unchecked(self.matrix.clone_owned())
}
@ -391,10 +393,7 @@ where
/// ```
#[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where
T: Clone,
{
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix().clone_owned()
}
@ -423,10 +422,7 @@ where
/// ```
#[inline]
#[must_use = "Did you mean to use try_inverse_mut()?"]
pub fn try_inverse(self) -> Option<Transform<T, C, D>>
where
T: ComplexField,
{
pub fn try_inverse(self) -> Option<Transform<T, C, D>> {
self.matrix
.try_inverse()
.map(Transform::from_matrix_unchecked)
@ -452,7 +448,6 @@ where
#[must_use = "Did you mean to use inverse_mut()?"]
pub fn inverse(self) -> Transform<T, C, D>
where
T: ComplexField,
C: SubTCategoryOf<TProjective>,
{
// TODO: specialize for TAffine?
@ -484,10 +479,7 @@ where
/// assert!(!t.try_inverse_mut());
/// ```
#[inline]
pub fn try_inverse_mut(&mut self) -> bool
where
T: ComplexField,
{
pub fn try_inverse_mut(&mut self) -> bool {
self.matrix.try_inverse_mut()
}
@ -511,7 +503,6 @@ where
#[inline]
pub fn inverse_mut(&mut self)
where
T: ComplexField,
C: SubTCategoryOf<TProjective>,
{
let _ = self.matrix.try_inverse_mut();
@ -552,8 +543,8 @@ where
Const<D>: DimNameAdd<U1>,
C: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
+ Allocator<T, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
+ Allocator<T, DimNameSum<Const<D>, U1>>, // + Allocator<T, D, D>
// + Allocator<T, D>
{
/// Transform the given point by the inverse of this transformation.
/// 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::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::storage::InnerOwned;
use crate::geometry::{
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
@ -373,8 +372,7 @@ md_impl_all!(
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
Transform<T, CB, D>: Clone; // There's probably a better bound here.
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
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() };
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
@ -628,8 +626,7 @@ md_assign_impl_all!(
const D;
for CA, CB;
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone;
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.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::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::InnerOwned;
use crate::base::storage::Owned;
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
use crate::geometry::Point;
/// A translation.
#[repr(transparent)]
#[repr(C)]
#[derive(Debug)]
pub struct Translation<T, const D: usize> {
/// 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>,
}
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
InnerOwned<T, Const<D>>: hash::Hash,
Owned<T, Const<D>>: hash::Hash,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
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
InnerOwned<T, Const<D>>: Clone,
Owned<T, Const<D>>: Clone,
{
#[inline]
fn clone(&self) -> Self {
@ -69,6 +69,7 @@ where
#[cfg(feature = "abomonation-serialize")]
impl<T, const D: usize> Abomonation for Translation<T, D>
where
T: Scalar,
SVector<T, D>: Abomonation,
{
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
@ -85,9 +86,9 @@ where
}
#[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
InnerOwned<T, Const<D>>: Serialize,
Owned<T, Const<D>>: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -98,9 +99,9 @@ where
}
#[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
InnerOwned<T, Const<D>>: Deserialize<'a>,
Owned<T, Const<D>>: Deserialize<'a>,
{
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
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.
#[inline]
#[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()?"]
pub fn inverse(&self) -> Translation<T, D>
where
T: ClosedNeg + Scalar,
T: ClosedNeg,
{
Translation::from(-&self.vector)
}
@ -208,7 +209,7 @@ impl<T, const D: usize> Translation<T, D> {
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where
T: Zero + One + Scalar,
T: Zero + One,
Const<D>: DimNameAdd<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]
pub fn inverse_mut(&mut self)
where
T: ClosedNeg + Scalar,
T: ClosedNeg,
{
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]
fn eq(&self, right: &Translation<T, D>) -> bool {
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
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
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
T::Epsilon: Copy,
{

View File

@ -1,5 +1,5 @@
#[cfg(feature = "arbitrary")]
use crate::base::storage::InnerOwned;
use crate::base::storage::Owned;
#[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen};
@ -77,7 +77,7 @@ where
#[cfg(feature = "arbitrary")]
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Translation<T, D>
where
InnerOwned<T, crate::Const<D>>: Send,
Owned<T, crate::Const<D>>: Send,
{
#[inline]
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>
where
T2: SupersetOf<T1>,
T1: Scalar,
T2: Scalar + SupersetOf<T1>,
{
#[inline]
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]
fn from(vector: OVector<T, Const<D>>) -> Self {
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]
fn from(coords: [T; D]) -> Self {
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]
fn from(pt: Point<T, D>) -> Self {
Translation { vector: pt.coords }
}
}
impl<T, const D: usize> From<Translation<T, D>> for [T; D]
where
T: Clone,
{
impl<T: Scalar, const D: usize> From<Translation<T, D>> for [T; D] {
#[inline]
fn from(t: Translation<T, D>) -> Self {
t.vector.into()

View File

@ -18,14 +18,14 @@ macro_rules! deref_impl(
#[inline]
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> {
#[inline]
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_qualifications,
unused_results,
missing_docs,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
missing_copy_implementations
)]
// #![deny(missing_docs)] // XXX: deny that
#![doc(
html_favicon_url = "https://nalgebra.org/img/favicon.ico",
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::base::dimension::Dim;
use crate::base::storage::Storage;
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
@ -18,7 +17,7 @@ where
{
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 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")]
use serde::{Deserialize, Serialize};
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::Dynamic;
use simba::scalar::ComplexField;
use crate::geometry::Reflection;
use crate::linalg::householder;
use std::mem::MaybeUninit;
/// The bidiagonalization of a general matrix.
#[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, DimDiff<DimMinimum<R, C>, U1>>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct Bidiagonal<T: ComplexField, R: DimMin<C>, C: Dim>
where
DimMinimum<R, C>: DimSub<U1>,
@ -52,59 +50,17 @@ where
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>
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>: Copy,
InnerOwned<T, DimMinimum<R, C>>: Copy,
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: Copy,
OMatrix<T, R, C>: Copy,
OVector<T, DimMinimum<R, C>>: 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>
where
@ -117,7 +73,7 @@ where
{
/// Computes the Bidiagonal decomposition using householder reflections.
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 dim = min_nrows_ncols.value();
assert!(
@ -125,80 +81,70 @@ where
"Cannot compute the bidiagonalization of an empty matrix."
);
let mut diagonal = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
let mut off_diagonal =
Matrix::new_uninitialized_generic(min_nrows_ncols.sub(Const::<1>), Const::<1>);
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>);
let mut work = Matrix::new_uninitialized_generic(nrows, Const::<1>);
let mut diagonal = Matrix::uninit(min_nrows_ncols, Const::<1>);
let mut off_diagonal = Matrix::uninit(min_nrows_ncols.sub(Const::<1>), Const::<1>);
let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
let mut work = Matrix::zeros_generic(nrows, Const::<1>);
let upper_diagonal = nrows.value() >= ncols.value();
// Safety: all pointers involved are valid for writes, aligned, and uninitialized.
unsafe {
if upper_diagonal {
for ite in 0..dim - 1 {
householder::clear_column_unchecked(
&mut matrix,
diagonal[ite].as_mut_ptr(),
ite,
0,
None,
);
householder::clear_row_unchecked(
&mut matrix,
off_diagonal[ite].as_mut_ptr(),
&mut axis_packed,
&mut work,
ite,
1,
);
}
householder::clear_column_unchecked(
if upper_diagonal {
for ite in 0..dim - 1 {
diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix,
diagonal[dim - 1].as_mut_ptr(),
dim - 1,
ite,
0,
None,
);
} else {
for ite in 0..dim - 1 {
householder::clear_row_unchecked(
&mut matrix,
diagonal[ite].as_mut_ptr(),
&mut axis_packed,
&mut work,
ite,
0,
);
householder::clear_column_unchecked(
&mut matrix,
off_diagonal[ite].as_mut_ptr(),
ite,
1,
None,
);
}
householder::clear_row_unchecked(
));
off_diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix,
diagonal[dim - 1].as_mut_ptr(),
&mut axis_packed,
&mut work,
dim - 1,
0,
);
ite,
1,
));
}
diagonal[dim - 1] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix,
dim - 1,
0,
None,
));
} else {
for ite in 0..dim - 1 {
diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix,
&mut axis_packed,
&mut work,
ite,
0,
));
off_diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
&mut matrix,
ite,
1,
None,
));
}
diagonal[dim - 1] = MaybeUninit::new(householder::clear_row_unchecked(
&mut matrix,
&mut axis_packed,
&mut work,
dim - 1,
0,
));
}
// Safety: all values have been initialized.
unsafe {
Bidiagonal {
uv: matrix,
diagonal: diagonal.assume_init(),
off_diagonal: off_diagonal.assume_init(),
upper_diagonal,
}
// Safety: diagonal and off_diagonal have been fully initialized.
let (diagonal, off_diagonal) =
unsafe { (diagonal.assume_init(), off_diagonal.assume_init()) };
Bidiagonal {
uv: matrix,
diagonal,
off_diagonal,
upper_diagonal,
}
}
@ -245,7 +191,7 @@ where
where
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 mut res = OMatrix::identity_generic(d, d);
@ -265,7 +211,7 @@ where
where
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 dim = self.diagonal.len();
@ -294,23 +240,21 @@ where
#[must_use]
pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C>
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 mut res = Matrix::identity_generic(min_nrows_ncols, ncols);
let mut work = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>);
let mut work = Matrix::zeros_generic(min_nrows_ncols, Const::<1>);
let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
let shift = self.axis_shift().1;
for i in (0..min_nrows_ncols.value() - shift).rev() {
let axis = self.uv.slice_range(i, i + shift..);
let mut axis_packed = axis_packed.rows_range_mut(i + shift..);
axis_packed.tr_copy_init_from(&axis);
let axis_packed = unsafe { axis_packed.slice_assume_init() };
axis_packed.tr_copy_from(&axis);
// TODO: sometimes, the axis might have a zero magnitude.
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.");
//
// // 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);
// self.solve_mut(&mut res);
// res

View File

@ -1,6 +1,3 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize};
@ -12,7 +9,7 @@ use crate::allocator::Allocator;
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
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.
#[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>,
OMatrix<T, D, D>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct Cholesky<T: SimdComplexField, D: Dim>
where
DefaultAllocator: Allocator<T, D, D>,
@ -33,38 +31,12 @@ where
chol: OMatrix<T, D, D>,
}
/*
impl<T: SimdComplexField, D: Dim> Copy for Cholesky<T, D>
where
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>
where
@ -164,7 +136,7 @@ where
/// Computes the inverse of the decomposed matrix.
#[must_use]
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);
self.solve_mut(&mut res);
@ -254,8 +226,6 @@ where
DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>> + Allocator<T, R2>,
ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
{
// TODO: check that MaybeUninit manipulations are sound!
let mut col = col.into_owned();
// for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
let n = col.nrows();
@ -267,20 +237,19 @@ where
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
let mut chol = Matrix::new_uninitialized_generic(
self.chol.data.shape().0.add(Const::<1>),
self.chol.data.shape().1.add(Const::<1>),
// TODO: would it be worth it to avoid the zero-initialization?
let mut chol = Matrix::zeros_generic(
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)
.copy_init_from(&self.chol.slice_range(..j, ..j));
.copy_from(&self.chol.slice_range(..j, ..j));
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)
.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..)
.copy_init_from(&self.chol.slice_range(j.., j..));
.copy_from(&self.chol.slice_range(j.., j..));
// update the jth row
let top_left_corner = self.chol.slice_range(..j, ..j);
@ -296,7 +265,7 @@ where
// update the center element
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
let bottom_left_corner = self.chol.slice_range(j.., ..j);
@ -307,9 +276,7 @@ where
&new_rowj_adjoint,
T::one() / center_element,
);
chol.slice_range_mut(j + 1.., j).copy_init_from(&new_colj);
let mut chol = unsafe { chol.assume_init() };
chol.slice_range_mut(j + 1.., j).copy_from(&new_colj);
// update the bottom right corner
let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..);
@ -330,27 +297,24 @@ where
D: DimSub<U1>,
DefaultAllocator: Allocator<T, DimDiff<D, U1>, DimDiff<D, U1>> + Allocator<T, D>,
{
// TODO: check that MaybeUninit manipulations are sound!
let n = self.chol.nrows();
assert!(n > 0, "The matrix needs at least one column.");
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
let mut chol = Matrix::new_uninitialized_generic(
self.chol.data.shape().0.sub(Const::<1>),
self.chol.data.shape().1.sub(Const::<1>),
// TODO: would it be worth it to avoid this zero initialization?
let mut chol = Matrix::zeros_generic(
self.chol.shape_generic().0.sub(Const::<1>),
self.chol.shape_generic().1.sub(Const::<1>),
);
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..)
.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)
.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..)
.copy_init_from(&self.chol.slice_range(j + 1.., j + 1..));
let mut chol = unsafe { chol.assume_init() };
.copy_from(&self.chol.slice_range(j + 1.., j + 1..));
// updates the bottom right corner
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`
/// 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>,
x: &mut Vector<T, Rx, Sx>,
sigma: T::RealField,
) where
//T: ComplexField,
Dm: Dim,
Rx: Dim,
Sm: StorageMut<T, Dm, Dm>,
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::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{Storage, StorageMut};
use crate::storage::StorageMut;
use crate::ComplexField;
use crate::geometry::Reflection;
use crate::linalg::{householder, PermutationSequence};
use std::mem::MaybeUninit;
/// The QR decomposition (with column pivoting) of a general matrix.
#[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>,
OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct ColPivQR<T: ComplexField, R: DimMin<C>, C: Dim>
where
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>
where
DefaultAllocator: Allocator<T, R, C>
@ -79,42 +63,37 @@ where
{
/// Computes the `ColPivQR` decomposition using householder reflections.
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 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 {
// Safety: there's no (uninitialized) values.
unsafe {
return ColPivQR {
col_piv_qr: matrix,
p,
diag: diag.assume_init(),
};
return ColPivQR {
col_piv_qr: matrix,
p,
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() {
let piv = matrix.slice_range(i.., i..).icamax_full();
let col_piv = piv.1 + i;
matrix.swap_columns(i, col_piv);
p.append_permutation(i, col_piv);
// Safety: the pointer is valid for writes, aligned, and uninitialized.
unsafe {
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
}
diag[i] =
MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None));
}
// Safety: all values have been initialized.
unsafe {
ColPivQR {
col_piv_qr: matrix,
p,
diag: diag.assume_init(),
}
// Safety: diag is now fully initialized.
let diag = unsafe { diag.assume_init() };
ColPivQR {
col_piv_qr: matrix,
p,
diag,
}
}
@ -125,7 +104,7 @@ where
where
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
.col_piv_qr
.rows_generic(0, nrows.min(ncols))
@ -142,7 +121,7 @@ where
where
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
.col_piv_qr
.resize_generic(nrows.min(ncols), ncols, T::zero());
@ -157,7 +136,7 @@ where
where
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.
// 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 ?
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);
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
.shape()
.0
.add(kernel.data.shape().0)
.add(kernel.shape_generic().0)
.sub(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()
.0
.add(Const::<1>)
.sub(kernel.data.shape().0);
.sub(kernel.shape_generic().0);
let mut conv = OVector::zeros_generic(result_len, Const::<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);
}
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 j in 0..ker {

View File

@ -4,12 +4,9 @@ use crate::{
base::{
allocator::Allocator,
dimension::{Const, Dim, DimMin, DimMinimum},
storage::Storage,
DefaultAllocator,
},
convert,
storage::InnerOwned,
try_convert, ComplexField, OMatrix, RealField,
convert, try_convert, ComplexField, OMatrix, RealField,
};
use crate::num::Zero;
@ -49,7 +46,7 @@ where
DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), DimMinimum<D, D>>,
{
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 {
use_exact_norm,
ident: OMatrix::<T, D, D>::identity_generic(nrows, ncols),
@ -350,7 +347,7 @@ where
D: Dim,
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 m = a.transpose();
@ -435,7 +432,6 @@ where
+ Allocator<T, D>
+ Allocator<T::RealField, D>
+ Allocator<T::RealField, D, D>,
InnerOwned<T, D, D>: Clone,
{
/// Computes exponential of this matrix
#[must_use]

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize};
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
OMatrix<T, 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
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>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
PermutationSequence<DimMinimum<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>
where
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`.
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 mut p = PermutationSequence::identity_generic(min_nrows_ncols);
@ -132,7 +101,7 @@ where
where
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();
m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one());
@ -146,7 +115,7 @@ where
where
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()
}
@ -253,7 +222,7 @@ where
"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);
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")]
use serde::{Deserialize, Serialize};
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Const, DimDiff, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::Matrix;
use simba::scalar::ComplexField;
use crate::linalg::householder;
use crate::Matrix;
use std::mem::MaybeUninit;
/// Hessenberg decomposition of a general matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -29,6 +26,7 @@ use crate::linalg::householder;
OMatrix<T, D, D>: Deserialize<'de>,
OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct Hessenberg<T: ComplexField, D: DimSub<U1>>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
@ -37,43 +35,13 @@ where
subdiag: OVector<T, DimDiff<D, U1>>,
}
/*
impl<T: ComplexField, D: DimSub<U1>> Copy for Hessenberg<T, D>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Copy,
InnerOwned<T, DimDiff<D, U1>>: Copy,
OMatrix<T, D, D>: 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>
where
@ -81,7 +49,7 @@ where
{
/// Computes the Hessenberg decomposition using householder reflections.
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)
}
@ -89,16 +57,13 @@ where
///
/// The workspace containing `D` elements must be provided but its content does not have to be
/// initialized.
pub fn new_with_workspace(
mut hess: OMatrix<T, D, D>,
work: &mut OVector<MaybeUninit<T>, D>,
) -> Self {
pub fn new_with_workspace(mut hess: OMatrix<T, D, D>, work: &mut OVector<T, D>) -> Self {
assert!(
hess.is_square(),
"Cannot compute the hessenberg decomposition of a non-square matrix."
);
let dim = hess.data.shape().0;
let dim = hess.shape_generic().0;
assert!(
dim.value() != 0,
@ -110,38 +75,27 @@ where
"Hessenberg: invalid workspace size."
);
let mut subdiag = Matrix::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
if dim.value() == 0 {
// Safety: there's no (uninitialized) values.
unsafe {
return Self {
hess,
subdiag: subdiag.assume_init(),
};
}
return Hessenberg {
hess,
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 {
// Safety: the pointer is valid for writes, aligned, and uninitialized.
unsafe {
householder::clear_column_unchecked(
&mut hess,
subdiag[ite].as_mut_ptr(),
ite,
1,
Some(work),
);
}
subdiag[ite] = MaybeUninit::new(householder::clear_column_unchecked(
&mut hess,
ite,
1,
Some(work),
));
}
// Safety: all values have been initialized.
unsafe {
Self {
hess,
subdiag: subdiag.assume_init(),
}
}
// Safety: subdiag is now fully initialized.
let subdiag = unsafe { subdiag.assume_init() };
Hessenberg { hess, subdiag }
}
/// 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.
#[inline]
#[must_use]
pub fn h(&self) -> OMatrix<T, D, D>
where
InnerOwned<T, D, D>: Clone,
{
pub fn h(&self) -> OMatrix<T, D, D> {
let dim = self.hess.nrows();
let mut res = self.hess.clone();
res.fill_lower_triangle(T::zero(), 2);

View File

@ -1,11 +1,9 @@
//! Construction of householder elementary reflections.
use std::mem::MaybeUninit;
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector};
use crate::dimension::Dim;
use crate::storage::{Storage, StorageMut};
use crate::storage::StorageMut;
use num::Zero;
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
/// subdiagonal element.
///
/// # Safety
/// 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.
/// Returns the signed norm of the column.
#[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>,
diag_elt: *mut T,
icol: usize,
shift: usize,
bilateral: Option<&mut OVector<MaybeUninit<T>, R>>,
) where
bilateral: Option<&mut OVector<T, R>>,
) -> T
where
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R>,
{
let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..);
let mut axis = left.rows_range_mut(icol + shift..);
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
diag_elt.write(reflection_norm);
if not_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());
}
reflection_norm
}
/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th
/// superdiagonal element.
///
/// # Safety
/// 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.
/// Returns the signed norm of the column.
#[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>,
diag_elt: *mut T,
axis_packed: &mut OVector<MaybeUninit<T>, C>,
work: &mut OVector<MaybeUninit<T>, R>,
axis_packed: &mut OVector<T, C>,
work: &mut OVector<T, R>,
irow: usize,
shift: usize,
) where
) -> T
where
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 axis = axis_packed.rows_range_mut(irow + shift..);
axis.tr_copy_init_from(&top.columns_range(irow + shift..));
let mut axis = axis.assume_init_mut();
axis.tr_copy_from(&top.columns_range(irow + shift..));
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
axis.conjugate_mut(); // So that reflect_rows actually cancels the first row.
diag_elt.write(reflection_norm);
if not_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 {
top.columns_range_mut(irow + shift..).tr_copy_from(&axis);
}
reflection_norm
}
/// Computes the orthogonal transformation described by the elementary reflector axii stored on
@ -134,7 +121,7 @@ where
DefaultAllocator: Allocator<T, D, D>,
{
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.
// 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")]
use serde::{Deserialize, Serialize};
@ -8,8 +5,9 @@ use crate::allocator::{Allocator, Reallocator};
use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimMin, DimMinimum};
use crate::storage::{InnerOwned, Storage, StorageMut};
use crate::storage::{Storage, StorageMut};
use simba::scalar::{ComplexField, Field};
use std::mem;
use crate::linalg::PermutationSequence;
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
OMatrix<T, 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
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
{
@ -37,43 +36,13 @@ where
p: PermutationSequence<DimMinimum<R, C>>,
}
/*
impl<T: Copy, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
where
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
OMatrix<T, 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`.
///
@ -121,7 +90,7 @@ where
{
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
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 mut p = PermutationSequence::identity_generic(min_nrows_ncols);
@ -163,7 +132,7 @@ where
where
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();
m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one());
@ -180,7 +149,7 @@ where
where
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());
m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one());
@ -193,7 +162,7 @@ where
where
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());
m.fill_upper_triangle(T::zero(), 1);
m.fill_diagonal(T::one());
@ -207,7 +176,7 @@ where
where
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()
}
@ -299,7 +268,7 @@ where
"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);
if self.try_inverse_to(&mut res) {
Some(res)

View File

@ -1,6 +1,3 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize};
@ -11,10 +8,8 @@ use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, OVector, Scalar};
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::dimension::Dynamic;
use crate::dimension::{Dim, DimName};
use crate::iter::MatrixIter;
use crate::storage::{InnerOwned, StorageMut};
use crate::{Const, U1};
use crate::dimension::{Const, Dim, DimName};
use crate::storage::StorageMut;
/// A sequence of row or column permutations.
#[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>,
OVector<(usize, usize), D>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct PermutationSequence<D: Dim>
where
DefaultAllocator: Allocator<(usize, usize), D>,
{
len: usize,
ipiv: OVector<MaybeUninit<(usize, usize)>, D>,
ipiv: OVector<(usize, usize), D>,
}
impl<D: Dim> Copy for PermutationSequence<D>
where
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>
where
DefaultAllocator: Allocator<(usize, usize), D>,
@ -101,7 +71,9 @@ where
pub fn identity_generic(dim: D) -> Self {
Self {
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(),
"Maximum number of permutations exceeded."
);
self.ipiv[self.len] = MaybeUninit::new((i, i2));
self.ipiv[self.len] = (i, i2);
self.len += 1;
}
}
@ -125,8 +97,8 @@ where
where
S2: StorageMut<T, R2, C2>,
{
for perm in self.iter() {
rhs.swap_rows(perm.0, perm.1)
for i in self.ipiv.rows_range(..self.len).iter() {
rhs.swap_rows(i.0, i.1)
}
}
@ -136,8 +108,8 @@ where
where
S2: StorageMut<T, R2, C2>,
{
for perm in self.iter().rev() {
let (i1, i2) = perm;
for i in 0..self.len {
let (i1, i2) = self.ipiv[self.len - i - 1];
rhs.swap_rows(i1, i2)
}
}
@ -148,8 +120,8 @@ where
where
S2: StorageMut<T, R2, C2>,
{
for perm in self.iter() {
rhs.swap_columns(perm.0, perm.1)
for i in self.ipiv.rows_range(..self.len).iter() {
rhs.swap_columns(i.0, i.1)
}
}
@ -161,8 +133,8 @@ where
) where
S2: StorageMut<T, R2, C2>,
{
for perm in self.iter().rev() {
let (i1, i2) = perm;
for i in 0..self.len {
let (i1, i2) = self.ipiv[self.len - i - 1];
rhs.swap_columns(i1, i2)
}
}
@ -189,27 +161,4 @@ where
-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
// extra allocations.
let (nrows, ncols) = self.data.shape();
let mut multiplier = self.clone_owned();
let mut buf = Matrix::new_uninitialized_generic(nrows, ncols);
let mut buf = self.clone_owned();
// Exponentiation by squares.
loop {
if e % two == one {
let init_buf = self.mul_to(&multiplier, &mut buf);
self.copy_from(&init_buf);
// Safety: `mul_to` leaves `buf` completely initialized.
unsafe {
buf.reinitialize();
}
self.mul_to(&multiplier, &mut buf);
self.copy_from(&buf);
}
e /= two;
let init_buf = multiplier.mul_to(&multiplier, &mut buf);
multiplier.copy_from(&init_buf);
// Safety: `mul_to` leaves `buf` completely initialized.
unsafe {
buf.reinitialize();
}
multiplier.mul_to(&multiplier, &mut buf);
multiplier.copy_from(&buf);
if e == zero {
return true;

View File

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

View File

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

View File

@ -7,8 +7,8 @@ use num::{One, Zero};
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2};
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimName, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
use crate::storage::Storage;
use simba::scalar::{ComplexField, RealField};
use crate::linalg::givens::GivensRotation;
@ -54,14 +54,14 @@ where
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
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
+ Allocator<T, R, DimMinimum<R, C>>
+ Allocator<T::RealField, DimMinimum<R, C>>,
InnerOwned<T, R, DimMinimum<R, C>>: Copy,
InnerOwned<T, DimMinimum<R, C>, C>: Copy,
InnerOwned<T::RealField, DimMinimum<R, C>>: Copy,
OMatrix<T, R, DimMinimum<R, C>>: Copy,
OMatrix<T, DimMinimum<R, C>, C>: Copy,
OVector<T::RealField, DimMinimum<R, C>>: Copy,
{
}
@ -111,7 +111,7 @@ where
!matrix.is_empty(),
"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 dim = min_nrows_ncols.value();

View File

@ -1,5 +1,3 @@
use std::fmt;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize};
@ -8,8 +6,8 @@ use num::Zero;
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2};
use crate::dimension::{Dim, DimDiff, DimName, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::dimension::{Dim, DimDiff, DimSub, U1};
use crate::storage::Storage;
use simba::scalar::ComplexField;
use crate::linalg::givens::GivensRotation;
@ -31,6 +29,7 @@ use crate::linalg::SymmetricTridiagonal;
OVector<T::RealField, D>: Deserialize<'de>,
OMatrix<T, D, D>: Deserialize<'de>"))
)]
#[derive(Clone, Debug)]
pub struct SymmetricEigen<T: ComplexField, D: Dim>
where
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
@ -42,42 +41,14 @@ where
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
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
InnerOwned<T, D, D>: Copy,
InnerOwned<T::RealField, D>: Copy,
OMatrix<T, D, 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>
where
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.
#[must_use]
pub fn recompose(&self) -> OMatrix<T, D, D>
where
InnerOwned<T, D, D>: Clone,
{
pub fn recompose(&self) -> OMatrix<T, D, D> {
let mut u_t = self.eigenvectors.clone();
for i in 0..self.eigenvalues.len() {
let val = self.eigenvalues[i];

View File

@ -1,16 +1,14 @@
use std::fmt;
use std::mem::MaybeUninit;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Serialize};
use crate::allocator::Allocator;
use crate::base::{DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Const, DimDiff, DimName, DimSub, U1};
use crate::storage::{InnerOwned, Storage};
use crate::dimension::{Const, DimDiff, DimSub, U1};
use simba::scalar::ComplexField;
use crate::linalg::householder;
use crate::Matrix;
use std::mem::MaybeUninit;
/// Tridiagonalization of a symmetric matrix.
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
@ -28,7 +26,8 @@ use crate::linalg::householder;
OMatrix<T, D, D>: 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
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
{
@ -36,42 +35,14 @@ where
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
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
InnerOwned<T, D, D>: Copy,
InnerOwned<T, DimDiff<D, U1>>: Copy,
OMatrix<T, D, D>: 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>
where
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.
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
let dim = m.data.shape().0;
let dim = m.shape_generic().0;
assert!(
m.is_square(),
@ -91,8 +62,8 @@ where
"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 p = 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 = Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>);
for i in 0..dim.value() - 1 {
let mut m = m.rows_range_mut(i + 1..);
@ -104,8 +75,7 @@ where
if not_zero {
let mut p = p.rows_range_mut(i..);
p.hegemv_z(crate::convert(2.0), &m, &axis);
let p = unsafe { p.slice_assume_init() };
p.hegemv(crate::convert(2.0), &m, &axis, T::zero());
let dot = axis.dotc(&p);
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 {
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")]
use serde::{Deserialize, Serialize};
use crate::allocator::Allocator;
use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
use crate::dimension::{Dim, DimName};
use crate::storage::{InnerOwned, Storage};
use crate::dimension::Dim;
use simba::scalar::RealField;
/// UDU factorization.
@ -21,7 +18,8 @@ use simba::scalar::RealField;
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
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
{
@ -31,42 +29,14 @@ where
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
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
InnerOwned<T, D>: Copy,
InnerOwned<T, D, D>: Copy,
OVector<T, 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>
where
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
pub fn new(p: OMatrix<T, D, D>) -> Option<Self> {
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 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
fn matrix_<R: Dim, C: Dim, ScalarStrategy>(
fn matrix_<R, C, ScalarStrategy>(
value_strategy: ScalarStrategy,
rows: DimRange<R>,
cols: DimRange<C>,
@ -271,6 +271,8 @@ fn matrix_<R: Dim, C: Dim, ScalarStrategy>(
where
ScalarStrategy: Strategy + Clone + 'static,
ScalarStrategy::Value: Scalar,
R: Dim,
C: Dim,
DefaultAllocator: Allocator<ScalarStrategy::Value, R, C>,
{
let nrows = rows.lower_bound().value()..=rows.upper_bound().value();
@ -330,7 +332,12 @@ where
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 {
Self {
rows: DimRange::from(R::name()),

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