forked from M-Labs/nalgebra
Implement the single-allocator-trait approach.
This commit is contained in:
parent
d34fed45bc
commit
8c6ebf2757
@ -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`.
|
||||
|
@ -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(|| {
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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) => {
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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).")
|
||||
|
@ -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.**
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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() {
|
||||
|
700
src/base/blas.rs
700
src/base/blas.rs
@ -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
359
src/base/blas_uninit.rs
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
unsafe {
|
||||
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());
|
||||
}
|
||||
*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);
|
||||
|
||||
unsafe {
|
||||
for j in 0..ncols.value() {
|
||||
for i in 0..nrows.value() {
|
||||
unsafe {
|
||||
*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 {
|
||||
|
@ -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.
|
||||
|
@ -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| {
|
||||
[
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
unsafe fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> MaybeUninit<Self::Buffer> {
|
||||
mem::MaybeUninit::<Self::Buffer>::uninit()
|
||||
}
|
||||
|
||||
assert!(
|
||||
count == nrows.value() * ncols.value(),
|
||||
"Matrix init. from iterator: iterator not long enough."
|
||||
);
|
||||
|
||||
// Safety: we have initialized all entries.
|
||||
unsafe { <Self as Allocator<T, Const<R>, Const<C>>>::assume_init(res) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for DefaultAllocator {
|
||||
#[inline]
|
||||
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]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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,7 +374,7 @@ 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));
|
||||
|
||||
@ -430,7 +383,7 @@ macro_rules! matrix_slice_impl(
|
||||
|
||||
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,23 +444,24 @@ 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));
|
||||
@ -517,7 +471,7 @@ macro_rules! matrix_slice_impl(
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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::*;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
247
src/base/ops.rs
247
src/base/ops.rs
@ -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.");
|
||||
|
||||
@ -165,29 +163,26 @@ macro_rules! componentwise_binop_impl(
|
||||
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()
|
||||
));
|
||||
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())
|
||||
);
|
||||
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
|
||||
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>
|
||||
{
|
||||
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,
|
||||
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)
|
||||
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
|
||||
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>
|
||||
{
|
||||
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
|
||||
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>
|
||||
{
|
||||
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
|
||||
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>
|
||||
{
|
||||
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
|
||||
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>
|
||||
{
|
||||
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
|
||||
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>
|
||||
{
|
||||
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 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();
|
||||
|
||||
for i2 in 0..nrows2.value() {
|
||||
*data_res = MaybeUninit::new(
|
||||
coeff.inlined_clone()
|
||||
* rhs.get_unchecked((i2, j2)).inlined_clone(),
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
@ -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
76
src/base/uninit.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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>,
|
||||
|
@ -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;
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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> {
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
///
|
||||
/// ```
|
||||
|
@ -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`.
|
||||
|
@ -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 can’t use Vector::push because of the DimAdd bound
|
||||
// (which we don’t 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>,
|
||||
{
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
/// ```
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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>>,
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Transform")
|
||||
.field("matrix", &self.matrix)
|
||||
.finish()
|
||||
}
|
||||
|
||||
#[cfg(feature = "bytemuck")]
|
||||
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Pod for Transform<T, C, D>
|
||||
where
|
||||
T: RealField + bytemuck::Pod,
|
||||
Const<D>: DimNameAdd<U1>,
|
||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Pod,
|
||||
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
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
|
||||
|
@ -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() };
|
||||
|
@ -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,
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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,82 +81,72 @@ 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(
|
||||
diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||
&mut matrix,
|
||||
diagonal[ite].as_mut_ptr(),
|
||||
ite,
|
||||
0,
|
||||
None,
|
||||
);
|
||||
householder::clear_row_unchecked(
|
||||
));
|
||||
off_diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||
&mut matrix,
|
||||
off_diagonal[ite].as_mut_ptr(),
|
||||
&mut axis_packed,
|
||||
&mut work,
|
||||
ite,
|
||||
1,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
householder::clear_column_unchecked(
|
||||
diagonal[dim - 1] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||
&mut matrix,
|
||||
diagonal[dim - 1].as_mut_ptr(),
|
||||
dim - 1,
|
||||
0,
|
||||
None,
|
||||
);
|
||||
));
|
||||
} else {
|
||||
for ite in 0..dim - 1 {
|
||||
householder::clear_row_unchecked(
|
||||
diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||
&mut matrix,
|
||||
diagonal[ite].as_mut_ptr(),
|
||||
&mut axis_packed,
|
||||
&mut work,
|
||||
ite,
|
||||
0,
|
||||
);
|
||||
householder::clear_column_unchecked(
|
||||
));
|
||||
off_diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||
&mut matrix,
|
||||
off_diagonal[ite].as_mut_ptr(),
|
||||
ite,
|
||||
1,
|
||||
None,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
householder::clear_row_unchecked(
|
||||
diagonal[dim - 1] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||
&mut matrix,
|
||||
diagonal[dim - 1].as_mut_ptr(),
|
||||
&mut axis_packed,
|
||||
&mut work,
|
||||
dim - 1,
|
||||
0,
|
||||
);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
// Safety: all values have been initialized.
|
||||
unsafe {
|
||||
// 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: diagonal.assume_init(),
|
||||
off_diagonal: off_diagonal.assume_init(),
|
||||
diagonal,
|
||||
off_diagonal,
|
||||
upper_diagonal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates whether this decomposition contains an upper-diagonal matrix.
|
||||
#[inline]
|
||||
@ -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
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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(),
|
||||
};
|
||||
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 {
|
||||
// Safety: diag is now fully initialized.
|
||||
let diag = unsafe { diag.assume_init() };
|
||||
|
||||
ColPivQR {
|
||||
col_piv_qr: matrix,
|
||||
p,
|
||||
diag: diag.assume_init(),
|
||||
}
|
||||
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) {
|
||||
|
@ -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 {
|
||||
|
@ -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]
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
return Hessenberg {
|
||||
hess,
|
||||
subdiag: subdiag.assume_init(),
|
||||
subdiag: Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let mut subdiag = Matrix::uninit(dim.sub(Const::<1>), Const::<1>);
|
||||
|
||||
for ite in 0..dim.value() - 1 {
|
||||
// Safety: the pointer is valid for writes, aligned, and uninitialized.
|
||||
unsafe {
|
||||
householder::clear_column_unchecked(
|
||||
subdiag[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||
&mut hess,
|
||||
subdiag[ite].as_mut_ptr(),
|
||||
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);
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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() })
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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::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() }
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user