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/).
|
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||||
|
|
||||||
|
## [0.29.0]
|
||||||
|
### Modified
|
||||||
|
- The closure given to `apply`, `zip_apply`, `zip_zip_apply` must now modify the
|
||||||
|
first argument inplace, instead of returning a new value. This makes these
|
||||||
|
methods more versatile, and avoid useless clones when using non-Copy scalar
|
||||||
|
types.
|
||||||
|
|
||||||
## [0.28.0]
|
## [0.28.0]
|
||||||
### Added
|
### Added
|
||||||
- Implement `Hash` for `Transform`.
|
- Implement `Hash` for `Transform`.
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use na::{
|
use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3, Vector4, U10};
|
||||||
Const, DMatrix, DVector, Dynamic, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3,
|
|
||||||
Vector4, U10,
|
|
||||||
};
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand_isaac::IsaacRng;
|
use rand_isaac::IsaacRng;
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
use std::ops::{Add, Div, Mul, Sub};
|
||||||
|
@ -189,7 +186,7 @@ fn axpy(bench: &mut criterion::Criterion) {
|
||||||
fn tr_mul_to(bench: &mut criterion::Criterion) {
|
fn tr_mul_to(bench: &mut criterion::Criterion) {
|
||||||
let a = DMatrix::<f64>::new_random(1000, 1000);
|
let a = DMatrix::<f64>::new_random(1000, 1000);
|
||||||
let b = DVector::<f64>::new_random(1000);
|
let b = DVector::<f64>::new_random(1000);
|
||||||
let mut c = DVector::new_uninitialized_generic(Dynamic::new(1000), Const::<1>);
|
let mut c = DVector::from_element(1000, 0.0);
|
||||||
|
|
||||||
bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c)));
|
bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c)));
|
||||||
}
|
}
|
||||||
|
@ -197,7 +194,7 @@ fn tr_mul_to(bench: &mut criterion::Criterion) {
|
||||||
fn mat_mul_mat(bench: &mut criterion::Criterion) {
|
fn mat_mul_mat(bench: &mut criterion::Criterion) {
|
||||||
let a = DMatrix::<f64>::new_random(100, 100);
|
let a = DMatrix::<f64>::new_random(100, 100);
|
||||||
let b = DMatrix::<f64>::new_random(100, 100);
|
let b = DMatrix::<f64>::new_random(100, 100);
|
||||||
let mut ab = DMatrix::new_uninitialized_generic(Dynamic::new(100), Dynamic::new(100));
|
let mut ab = DMatrix::<f64>::from_element(100, 100, 0.0);
|
||||||
|
|
||||||
bench.bench_function("mat_mul_mat", move |bh| {
|
bench.bench_function("mat_mul_mat", move |bh| {
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use num_complex::Complex;
|
||||||
|
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::Dim;
|
use na::dimension::Dim;
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -24,17 +24,17 @@ use lapack;
|
||||||
OMatrix<T, D, D>: Deserialize<'de>"))
|
OMatrix<T, D, D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cholesky<T, D: Dim>
|
pub struct Cholesky<T: Scalar, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
l: OMatrix<T, D, D>,
|
l: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: Dim> Copy for Cholesky<T, D>
|
impl<T: Scalar + Copy, D: Dim> Copy for Cholesky<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
Owned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ where
|
||||||
b: &Matrix<T, R2, C2, S2>,
|
b: &Matrix<T, R2, C2, S2>,
|
||||||
) -> Option<OMatrix<T, R2, C2>>
|
) -> Option<OMatrix<T, R2, C2>>
|
||||||
where
|
where
|
||||||
S2: Storage<T, R2, C2>,
|
S2: RawStorage<T, R2, C2>,
|
||||||
DefaultAllocator: Allocator<T, R2, C2>,
|
DefaultAllocator: Allocator<T, R2, C2>,
|
||||||
{
|
{
|
||||||
let mut res = b.clone_owned();
|
let mut res = b.clone_owned();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -11,7 +9,7 @@ use simba::scalar::RealField;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim};
|
use na::dimension::{Const, Dim};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -34,7 +32,8 @@ use lapack;
|
||||||
OMatrix<T, D, D>: Deserialize<'de>")
|
OMatrix<T, D, D>: Deserialize<'de>")
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub struct Eigen<T, D: Dim>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Eigen<T: Scalar, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
|
@ -46,7 +45,7 @@ where
|
||||||
pub left_eigenvectors: Option<OMatrix<T, D, D>>,
|
pub left_eigenvectors: Option<OMatrix<T, D, D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: Dim> Copy for Eigen<T, D>
|
impl<T: Scalar + Copy, D: Dim> Copy for Eigen<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
OVector<T, D>: Copy,
|
OVector<T, D>: Copy,
|
||||||
|
@ -54,36 +53,6 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, D: Dim> Clone for Eigen<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
|
||||||
OVector<T, D>: Clone,
|
|
||||||
OMatrix<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
eigenvalues: self.eigenvalues.clone(),
|
|
||||||
eigenvectors: self.eigenvectors.clone(),
|
|
||||||
left_eigenvectors: self.left_eigenvectors.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: Dim> fmt::Debug for Eigen<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
|
||||||
OVector<T, D>: fmt::Debug,
|
|
||||||
OMatrix<T, D, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Eigen")
|
|
||||||
.field("eigenvalues", &self.eigenvalues)
|
|
||||||
.field("eigenvectors", &self.eigenvectors)
|
|
||||||
.field("left_eigenvectors", &self.left_eigenvectors)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: EigenScalar + RealField, D: Dim> Eigen<T, D>
|
impl<T: EigenScalar + RealField, D: Dim> Eigen<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
|
||||||
|
@ -104,13 +73,11 @@ where
|
||||||
let ljob = if left_eigenvectors { b'V' } else { b'T' };
|
let ljob = if left_eigenvectors { b'V' } else { b'T' };
|
||||||
let rjob = if eigenvectors { b'V' } else { b'T' };
|
let rjob = if eigenvectors { b'V' } else { b'T' };
|
||||||
|
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let n = nrows.value();
|
let n = nrows.value();
|
||||||
|
|
||||||
let lda = n as i32;
|
let lda = n as i32;
|
||||||
|
|
||||||
// IMPORTANT TODO: this is still UB.
|
|
||||||
|
|
||||||
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
||||||
// TODO: Tap into the workspace.
|
// TODO: Tap into the workspace.
|
||||||
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
||||||
|
@ -275,7 +242,7 @@ where
|
||||||
"Unable to compute the eigenvalue decomposition of a non-square matrix."
|
"Unable to compute the eigenvalue decomposition of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let nrows = m.data.shape().0;
|
let nrows = m.shape_generic().0;
|
||||||
let n = nrows.value();
|
let n = nrows.value();
|
||||||
|
|
||||||
let lda = n as i32;
|
let lda = n as i32;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use num_complex::Complex;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, DimDiff, DimSub, U1};
|
use na::dimension::{Const, DimDiff, DimSub, U1};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -48,7 +48,7 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the hessenberg decomposition of the matrix `m`.
|
/// Computes the hessenberg decomposition of the matrix `m`.
|
||||||
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
|
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
|
||||||
let nrows = m.data.shape().0;
|
let nrows = m.shape_generic().0;
|
||||||
let n = nrows.value() as i32;
|
let n = nrows.value() as i32;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -60,7 +60,6 @@ where
|
||||||
"Unable to compute the hessenberg decomposition of an empty matrix."
|
"Unable to compute the hessenberg decomposition of an empty matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
// IMPORTANT TODO: this is still UB.
|
|
||||||
let mut tau = unsafe {
|
let mut tau = unsafe {
|
||||||
Matrix::new_uninitialized_generic(nrows.sub(Const::<1>), Const::<1>).assume_init()
|
Matrix::new_uninitialized_generic(nrows.sub(Const::<1>), Const::<1>).assume_init()
|
||||||
};
|
};
|
||||||
|
|
|
@ -140,7 +140,6 @@ impl ComplexHelper for Complex<f64> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is UB.
|
|
||||||
unsafe fn uninitialized_vec<T: Copy>(n: usize) -> Vec<T> {
|
unsafe fn uninitialized_vec<T: Copy>(n: usize) -> Vec<T> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
res.reserve_exact(n);
|
res.reserve_exact(n);
|
||||||
|
|
|
@ -4,7 +4,7 @@ use num_complex::Complex;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim, DimMin, DimMinimum};
|
use na::dimension::{Const, Dim, DimMin, DimMinimum};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -61,7 +61,7 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
|
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
|
||||||
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
let nrows = nrows.value() as i32;
|
let nrows = nrows.value() as i32;
|
||||||
let ncols = ncols.value() as i32;
|
let ncols = ncols.value() as i32;
|
||||||
|
@ -87,7 +87,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
|
pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
||||||
|
|
||||||
res.fill_upper_triangle(Zero::zero(), 1);
|
res.fill_upper_triangle(Zero::zero(), 1);
|
||||||
|
@ -100,7 +100,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
|
pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned();
|
let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned();
|
||||||
|
|
||||||
res.fill_lower_triangle(Zero::zero(), 1);
|
res.fill_lower_triangle(Zero::zero(), 1);
|
||||||
|
@ -115,7 +115,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn p(&self) -> OMatrix<T, R, R> {
|
pub fn p(&self) -> OMatrix<T, R, R> {
|
||||||
let (dim, _) = self.lu.data.shape();
|
let (dim, _) = self.lu.shape_generic();
|
||||||
let mut id = Matrix::identity_generic(dim, dim);
|
let mut id = Matrix::identity_generic(dim, dim);
|
||||||
self.permute(&mut id);
|
self.permute(&mut id);
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ where
|
||||||
b: &Matrix<T, R2, C2, S2>,
|
b: &Matrix<T, R2, C2, S2>,
|
||||||
) -> Option<OMatrix<T, R2, C2>>
|
) -> Option<OMatrix<T, R2, C2>>
|
||||||
where
|
where
|
||||||
S2: Storage<T, R2, C2>,
|
S2: RawStorage<T, R2, C2>,
|
||||||
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
||||||
{
|
{
|
||||||
let mut res = b.clone_owned();
|
let mut res = b.clone_owned();
|
||||||
|
@ -209,7 +209,7 @@ where
|
||||||
b: &Matrix<T, R2, C2, S2>,
|
b: &Matrix<T, R2, C2, S2>,
|
||||||
) -> Option<OMatrix<T, R2, C2>>
|
) -> Option<OMatrix<T, R2, C2>>
|
||||||
where
|
where
|
||||||
S2: Storage<T, R2, C2>,
|
S2: RawStorage<T, R2, C2>,
|
||||||
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
||||||
{
|
{
|
||||||
let mut res = b.clone_owned();
|
let mut res = b.clone_owned();
|
||||||
|
@ -227,7 +227,7 @@ where
|
||||||
b: &Matrix<T, R2, C2, S2>,
|
b: &Matrix<T, R2, C2, S2>,
|
||||||
) -> Option<OMatrix<T, R2, C2>>
|
) -> Option<OMatrix<T, R2, C2>>
|
||||||
where
|
where
|
||||||
S2: Storage<T, R2, C2>,
|
S2: RawStorage<T, R2, C2>,
|
||||||
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
DefaultAllocator: Allocator<T, R2, C2> + Allocator<i32, R2>,
|
||||||
{
|
{
|
||||||
let mut res = b.clone_owned();
|
let mut res = b.clone_owned();
|
||||||
|
|
|
@ -7,7 +7,7 @@ use num_complex::Complex;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim, DimMin, DimMinimum};
|
use na::dimension::{Const, Dim, DimMin, DimMinimum};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -54,11 +54,12 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the QR decomposition of the matrix `m`.
|
/// Computes the QR decomposition of the matrix `m`.
|
||||||
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
|
|
||||||
let mut info = 0;
|
let mut info = 0;
|
||||||
let mut tau =
|
let mut tau = unsafe {
|
||||||
unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), U1).assume_init() };
|
Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init()
|
||||||
|
};
|
||||||
|
|
||||||
if nrows.value() == 0 || ncols.value() == 0 {
|
if nrows.value() == 0 || ncols.value() == 0 {
|
||||||
return Self { qr: m, tau };
|
return Self { qr: m, tau };
|
||||||
|
@ -93,7 +94,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
|
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +120,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
|
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
if min_nrows_ncols.value() == 0 {
|
if min_nrows_ncols.value() == 0 {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use simba::scalar::RealField;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim};
|
use na::dimension::{Const, Dim};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -71,7 +71,7 @@ where
|
||||||
"Unable to compute the eigenvalue decomposition of a non-square matrix."
|
"Unable to compute the eigenvalue decomposition of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let n = nrows.value();
|
let n = nrows.value();
|
||||||
|
|
||||||
let lda = n as i32;
|
let lda = n as i32;
|
||||||
|
@ -153,15 +153,15 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<Complex<T>, D>,
|
DefaultAllocator: Allocator<Complex<T>, D>,
|
||||||
{
|
{
|
||||||
let mut out =
|
let mut out = unsafe {
|
||||||
unsafe { OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>) };
|
OVector::new_uninitialized_generic(self.t.shape_generic().0, Const::<1>).assume_init()
|
||||||
|
};
|
||||||
|
|
||||||
for i in 0..out.len() {
|
for i in 0..out.len() {
|
||||||
out[i] = MaybeUninit::new(Complex::new(self.re[i], self.im[i]));
|
out[i] = Complex::new(self.re[i], self.im[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
out
|
||||||
unsafe { out.assume_init() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::cmp;
|
||||||
|
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim, DimMin, DimMinimum, U1};
|
use na::dimension::{Const, Dim, DimMin, DimMinimum, U1};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -89,7 +89,7 @@ macro_rules! svd_impl(
|
||||||
Allocator<$t, DimMinimum<R, C>> {
|
Allocator<$t, DimMinimum<R, C>> {
|
||||||
|
|
||||||
fn compute(mut m: OMatrix<$t, R, C>) -> Option<SVD<$t, R, C>> {
|
fn compute(mut m: OMatrix<$t, R, C>) -> Option<SVD<$t, R, C>> {
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
|
|
||||||
if nrows.value() == 0 || ncols.value() == 0 {
|
if nrows.value() == 0 || ncols.value() == 0 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -99,7 +99,6 @@ macro_rules! svd_impl(
|
||||||
|
|
||||||
let lda = nrows.value() as i32;
|
let lda = nrows.value() as i32;
|
||||||
|
|
||||||
// IMPORTANT TODO: this is still UB.
|
|
||||||
let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows).assume_init() };
|
let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows).assume_init() };
|
||||||
let mut s = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init() };
|
let mut s = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init() };
|
||||||
let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols).assume_init() };
|
let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols).assume_init() };
|
||||||
|
@ -152,8 +151,8 @@ macro_rules! svd_impl(
|
||||||
/// been manually changed by the user.
|
/// been manually changed by the user.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn recompose(self) -> OMatrix<$t, R, C> {
|
pub fn recompose(self) -> OMatrix<$t, R, C> {
|
||||||
let nrows = self.u.data.shape().0;
|
let nrows = self.u.shape_generic().0;
|
||||||
let ncols = self.vt.data.shape().1;
|
let ncols = self.vt.shape_generic().1;
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols);
|
let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols);
|
||||||
|
@ -178,8 +177,8 @@ macro_rules! svd_impl(
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
|
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
|
||||||
let nrows = self.u.data.shape().0;
|
let nrows = self.u.shape_generic().0;
|
||||||
let ncols = self.vt.data.shape().1;
|
let ncols = self.vt.shape_generic().1;
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows);
|
let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows);
|
||||||
|
@ -242,7 +241,7 @@ macro_rules! svd_complex_impl(
|
||||||
Allocator<Complex<$t>, R, R> +
|
Allocator<Complex<$t>, R, R> +
|
||||||
Allocator<Complex<$t>, C, C> +
|
Allocator<Complex<$t>, C, C> +
|
||||||
Allocator<$t, DimMinimum<R, C>> {
|
Allocator<$t, DimMinimum<R, C>> {
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
|
|
||||||
if nrows.value() == 0 || ncols.value() == 0 {
|
if nrows.value() == 0 || ncols.value() == 0 {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use simba::scalar::RealField;
|
||||||
use crate::ComplexHelper;
|
use crate::ComplexHelper;
|
||||||
use na::allocator::Allocator;
|
use na::allocator::Allocator;
|
||||||
use na::dimension::{Const, Dim};
|
use na::dimension::{Const, Dim};
|
||||||
use na::storage::Storage;
|
use na::storage::RawStorage;
|
||||||
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
|
||||||
|
|
||||||
use lapack;
|
use lapack;
|
||||||
|
@ -89,12 +89,11 @@ where
|
||||||
|
|
||||||
let jobz = if eigenvectors { b'V' } else { b'T' };
|
let jobz = if eigenvectors { b'V' } else { b'T' };
|
||||||
|
|
||||||
let nrows = m.data.shape().0;
|
let nrows = m.shape_generic().0;
|
||||||
let n = nrows.value();
|
let n = nrows.value();
|
||||||
|
|
||||||
let lda = n as i32;
|
let lda = n as i32;
|
||||||
|
|
||||||
// IMPORTANT TODO: this is still UB.
|
|
||||||
let mut values =
|
let mut values =
|
||||||
unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
|
||||||
let mut info = 0;
|
let mut info = 0;
|
||||||
|
|
|
@ -2,14 +2,16 @@ use crate::convert::serial::*;
|
||||||
use crate::coo::CooMatrix;
|
use crate::coo::CooMatrix;
|
||||||
use crate::csc::CscMatrix;
|
use crate::csc::CscMatrix;
|
||||||
use crate::csr::CsrMatrix;
|
use crate::csr::CsrMatrix;
|
||||||
use nalgebra::storage::Storage;
|
use nalgebra::storage::RawStorage;
|
||||||
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
|
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CooMatrix<T>
|
impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CooMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
S: Storage<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
convert_dense_coo(matrix)
|
convert_dense_coo(matrix)
|
||||||
|
@ -43,10 +45,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CsrMatrix<T>
|
impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CsrMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
S: Storage<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
convert_dense_csr(matrix)
|
convert_dense_csr(matrix)
|
||||||
|
@ -80,10 +84,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S> From<&'a Matrix<T, R, C, S>> for CscMatrix<T>
|
impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CscMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
S: Storage<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
convert_dense_csc(matrix)
|
convert_dense_csc(matrix)
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::ops::Add;
|
||||||
|
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
|
|
||||||
use nalgebra::storage::Storage;
|
use nalgebra::storage::RawStorage;
|
||||||
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
|
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
|
||||||
|
|
||||||
use crate::coo::CooMatrix;
|
use crate::coo::CooMatrix;
|
||||||
|
@ -16,10 +16,12 @@ use crate::csc::CscMatrix;
|
||||||
use crate::csr::CsrMatrix;
|
use crate::csr::CsrMatrix;
|
||||||
|
|
||||||
/// Converts a dense matrix to [`CooMatrix`].
|
/// Converts a dense matrix to [`CooMatrix`].
|
||||||
pub fn convert_dense_coo<T, R: Dim, C: Dim, S>(dense: &Matrix<T, R, C, S>) -> CooMatrix<T>
|
pub fn convert_dense_coo<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CooMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
S: Storage<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
|
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
|
||||||
|
|
||||||
|
@ -91,10 +93,10 @@ where
|
||||||
/// Converts a dense matrix to a [`CsrMatrix`].
|
/// Converts a dense matrix to a [`CsrMatrix`].
|
||||||
pub fn convert_dense_csr<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CsrMatrix<T>
|
pub fn convert_dense_csr<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CsrMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
S: Storage<T, R, C>,
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
let mut row_offsets = Vec::with_capacity(dense.nrows() + 1);
|
let mut row_offsets = Vec::with_capacity(dense.nrows() + 1);
|
||||||
let mut col_idx = Vec::new();
|
let mut col_idx = Vec::new();
|
||||||
|
@ -168,10 +170,10 @@ where
|
||||||
/// Converts a dense matrix to a [`CscMatrix`].
|
/// Converts a dense matrix to a [`CscMatrix`].
|
||||||
pub fn convert_dense_csc<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CscMatrix<T>
|
pub fn convert_dense_csc<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CscMatrix<T>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + PartialEq,
|
T: Scalar + Zero,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
S: Storage<T, R, C>,
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
let mut col_offsets = Vec::with_capacity(dense.ncols() + 1);
|
let mut col_offsets = Vec::with_capacity(dense.ncols() + 1);
|
||||||
let mut row_idx = Vec::new();
|
let mut row_idx = Vec::new();
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl<T: na::Scalar> CooMatrix<T> {
|
||||||
/// Panics if any part of the dense matrix is out of bounds of the sparse matrix
|
/// Panics if any part of the dense matrix is out of bounds of the sparse matrix
|
||||||
/// when inserted at `(r, c)`.
|
/// when inserted at `(r, c)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::Storage<T, R, C>>(
|
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::RawStorage<T, R, C>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
r: usize,
|
r: usize,
|
||||||
c: usize,
|
c: usize,
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::ops::serial::{
|
||||||
spmm_csc_prealloc, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc,
|
spmm_csc_prealloc, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc,
|
||||||
};
|
};
|
||||||
use crate::ops::Op;
|
use crate::ops::Op;
|
||||||
use nalgebra::allocator::{Allocator, InnerAllocator};
|
use nalgebra::allocator::Allocator;
|
||||||
use nalgebra::base::storage::Storage;
|
use nalgebra::base::storage::RawStorage;
|
||||||
use nalgebra::constraint::{DimEq, ShapeConstraint};
|
use nalgebra::constraint::{DimEq, ShapeConstraint};
|
||||||
use nalgebra::{
|
use nalgebra::{
|
||||||
ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix,
|
ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix,
|
||||||
|
@ -28,7 +28,7 @@ macro_rules! impl_bin_op {
|
||||||
// Note: The Neg bound is currently required because we delegate e.g.
|
// Note: The Neg bound is currently required because we delegate e.g.
|
||||||
// Sub to SpAdd with negative coefficients. This is not well-defined for
|
// Sub to SpAdd with negative coefficients. This is not well-defined for
|
||||||
// unsigned data types.
|
// unsigned data types.
|
||||||
$($scalar_type: $($bounds + )? Scalar + ClosedAdd + ClosedSub + ClosedMul + Zero + One + Neg<Output=T> + PartialEq)?
|
$($scalar_type: $($bounds + )? Scalar + ClosedAdd + ClosedSub + ClosedMul + Zero + One + Neg<Output=T>)?
|
||||||
{
|
{
|
||||||
type Output = $ret;
|
type Output = $ret;
|
||||||
fn $method(self, $b: $b_type) -> Self::Output {
|
fn $method(self, $b: $b_type) -> Self::Output {
|
||||||
|
@ -272,7 +272,7 @@ macro_rules! impl_spmm_cs_dense {
|
||||||
($matrix_type_name:ident, $spmm_fn:ident) => {
|
($matrix_type_name:ident, $spmm_fn:ident) => {
|
||||||
// Implement ref-ref
|
// Implement ref-ref
|
||||||
impl_spmm_cs_dense!(&'a $matrix_type_name<T>, &'a Matrix<T, R, C, S>, $spmm_fn, |lhs, rhs| {
|
impl_spmm_cs_dense!(&'a $matrix_type_name<T>, &'a Matrix<T, R, C, S>, $spmm_fn, |lhs, rhs| {
|
||||||
let (_, ncols) = rhs.data.shape();
|
let (_, ncols) = rhs.shape_generic();
|
||||||
let nrows = Dynamic::new(lhs.nrows());
|
let nrows = Dynamic::new(lhs.nrows());
|
||||||
let mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols);
|
let mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols);
|
||||||
$spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs));
|
$spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs));
|
||||||
|
@ -301,14 +301,14 @@ macro_rules! impl_spmm_cs_dense {
|
||||||
T: Scalar + ClosedMul + ClosedAdd + ClosedSub + ClosedDiv + Neg + Zero + One,
|
T: Scalar + ClosedMul + ClosedAdd + ClosedSub + ClosedDiv + Neg + Zero + One,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
S: Storage<T, R, C>,
|
S: RawStorage<T, R, C>,
|
||||||
DefaultAllocator: Allocator<T, Dynamic, C>,
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
// TODO: Is it possible to simplify these bounds?
|
// TODO: Is it possible to simplify these bounds?
|
||||||
ShapeConstraint:
|
ShapeConstraint:
|
||||||
// Bounds so that we can turn OMatrix<T, Dynamic, C> into a DMatrixSliceMut
|
// Bounds so that we can turn OMatrix<T, Dynamic, C> into a DMatrixSliceMut
|
||||||
DimEq<U1, <<DefaultAllocator as InnerAllocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::RStride>
|
DimEq<U1, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::RStride>
|
||||||
+ DimEq<C, Dynamic>
|
+ DimEq<C, Dynamic>
|
||||||
+ DimEq<Dynamic, <<DefaultAllocator as InnerAllocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::CStride>
|
+ DimEq<Dynamic, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::CStride>
|
||||||
// Bounds so that we can turn &Matrix<T, R, C, S> into a DMatrixSlice
|
// Bounds so that we can turn &Matrix<T, R, C, S> into a DMatrixSlice
|
||||||
+ DimEq<U1, S::RStride>
|
+ DimEq<U1, S::RStride>
|
||||||
+ DimEq<R, Dynamic>
|
+ DimEq<R, Dynamic>
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub fn spadd_cs_prealloc<T>(
|
||||||
a: Op<&CsMatrix<T>>,
|
a: Op<&CsMatrix<T>>,
|
||||||
) -> Result<(), OperationError>
|
) -> Result<(), OperationError>
|
||||||
where
|
where
|
||||||
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq,
|
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
|
||||||
{
|
{
|
||||||
match a {
|
match a {
|
||||||
Op::NoOp(a) => {
|
Op::NoOp(a) => {
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub fn spadd_csc_prealloc<T>(
|
||||||
a: Op<&CscMatrix<T>>,
|
a: Op<&CscMatrix<T>>,
|
||||||
) -> Result<(), OperationError>
|
) -> Result<(), OperationError>
|
||||||
where
|
where
|
||||||
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq,
|
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
|
||||||
{
|
{
|
||||||
assert_compatible_spadd_dims!(c, a);
|
assert_compatible_spadd_dims!(c, a);
|
||||||
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))
|
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub fn spadd_csr_prealloc<T>(
|
||||||
a: Op<&CsrMatrix<T>>,
|
a: Op<&CsrMatrix<T>>,
|
||||||
) -> Result<(), OperationError>
|
) -> Result<(), OperationError>
|
||||||
where
|
where
|
||||||
T: Scalar + ClosedAdd + ClosedMul + Zero + One + PartialEq,
|
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
|
||||||
{
|
{
|
||||||
assert_compatible_spadd_dims!(c, a);
|
assert_compatible_spadd_dims!(c, a);
|
||||||
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))
|
spadd_cs_prealloc(beta, &mut c.cs, alpha, a.map_same_op(|a| &a.cs))
|
||||||
|
|
|
@ -311,7 +311,7 @@ impl From<SparsityPatternFormatError> for SparseFormatError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SparsityPatternFormatError {
|
impl fmt::Display for SparsityPatternFormatError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
SparsityPatternFormatError::InvalidOffsetArrayLength => {
|
SparsityPatternFormatError::InvalidOffsetArrayLength => {
|
||||||
write!(f, "Length of offset array is not equal to (major_dim + 1).")
|
write!(f, "Length of offset array is not equal to (major_dim + 1).")
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use crate::base::dimension::Dynamic;
|
use crate::base::dimension::Dynamic;
|
||||||
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
|
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
|
||||||
|
use crate::base::storage::Owned;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use crate::base::vec_storage::VecStorage;
|
use crate::base::vec_storage::VecStorage;
|
||||||
use crate::base::{ArrayStorage, Const, Matrix, Owned, Unit};
|
use crate::base::{ArrayStorage, Const, Matrix, Unit};
|
||||||
|
use crate::storage::OwnedUninit;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
@ -18,13 +21,16 @@ use crate::base::{ArrayStorage, Const, Matrix, Owned, Unit};
|
||||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||||
pub type OMatrix<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
|
pub type OMatrix<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
|
||||||
|
|
||||||
|
/// An owned matrix with uninitialized data.
|
||||||
|
pub type UninitMatrix<T, R, C> = Matrix<MaybeUninit<T>, R, C, OwnedUninit<T, R, C>>;
|
||||||
|
|
||||||
/// An owned matrix column-major matrix with `R` rows and `C` columns.
|
/// An owned matrix column-major matrix with `R` rows and `C` columns.
|
||||||
///
|
///
|
||||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
note = "use SMatrix for a statically-sized matrix using integer dimensions, or OMatrix for an owned matrix using types as dimensions."
|
note = "use SMatrix for a statically-sized matrix using integer dimensions, or OMatrix for an owned matrix using types as dimensions."
|
||||||
)]
|
)]
|
||||||
pub type MatrixMN<T, R, C> = OMatrix<T, R, C>;
|
pub type MatrixMN<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
|
||||||
|
|
||||||
/// An owned matrix column-major matrix with `D` columns.
|
/// An owned matrix column-major matrix with `D` columns.
|
||||||
///
|
///
|
||||||
|
@ -277,6 +283,9 @@ pub type OVector<T, D> = Matrix<T, D, U1, Owned<T, D, U1>>;
|
||||||
/// A statically sized D-dimensional column vector.
|
/// A statically sized D-dimensional column vector.
|
||||||
pub type SVector<T, const D: usize> = Matrix<T, Const<D>, U1, ArrayStorage<T, D, 1>>; // Owned<T, Const<D>, U1>>;
|
pub type SVector<T, const D: usize> = Matrix<T, Const<D>, U1, ArrayStorage<T, D, 1>>; // Owned<T, Const<D>, U1>>;
|
||||||
|
|
||||||
|
/// An owned matrix with uninitialized data.
|
||||||
|
pub type UninitVector<T, D> = Matrix<MaybeUninit<T>, D, U1, OwnedUninit<T, D, U1>>;
|
||||||
|
|
||||||
/// An owned matrix column-major matrix with `R` rows and `C` columns.
|
/// An owned matrix column-major matrix with `R` rows and `C` columns.
|
||||||
///
|
///
|
||||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
//! Abstract definition of a matrix data storage allocator.
|
//! Abstract definition of a matrix data storage allocator.
|
||||||
|
|
||||||
use std::mem::{ManuallyDrop, MaybeUninit};
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::base::dimension::{Dim, U1};
|
use crate::base::dimension::{Dim, U1};
|
||||||
use crate::base::storage::ContiguousStorageMut;
|
use crate::base::{DefaultAllocator, Scalar};
|
||||||
use crate::base::DefaultAllocator;
|
use crate::storage::{IsContiguous, RawStorageMut};
|
||||||
|
use crate::StorageMut;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()`
|
/// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()`
|
||||||
/// elements of type `T`.
|
/// elements of type `T`.
|
||||||
|
@ -16,12 +19,23 @@ use crate::base::DefaultAllocator;
|
||||||
///
|
///
|
||||||
/// Every allocator must be both static and dynamic. Though not all implementations may share the
|
/// Every allocator must be both static and dynamic. Though not all implementations may share the
|
||||||
/// same `Buffer` type.
|
/// same `Buffer` type.
|
||||||
///
|
pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
|
||||||
/// If you also want to be able to create uninitizalized or manually dropped memory buffers, see
|
|
||||||
/// [`Allocator`].
|
|
||||||
pub trait InnerAllocator<T, R: Dim, C: Dim = U1>: 'static + Sized {
|
|
||||||
/// The type of buffer this allocator can instanciate.
|
/// The type of buffer this allocator can instanciate.
|
||||||
type Buffer: ContiguousStorageMut<T, R, C>;
|
type Buffer: StorageMut<T, R, C> + IsContiguous + Clone + Debug;
|
||||||
|
/// The type of buffer with uninitialized components this allocator can instanciate.
|
||||||
|
type BufferUninit: RawStorageMut<MaybeUninit<T>, R, C> + IsContiguous;
|
||||||
|
|
||||||
|
/// Allocates a buffer with the given number of rows and columns without initializing its content.
|
||||||
|
unsafe fn allocate_uninitialized(nrows: R, ncols: C) -> MaybeUninit<Self::Buffer>;
|
||||||
|
/// Allocates a buffer with the given number of rows and columns without initializing its content.
|
||||||
|
fn allocate_uninit(nrows: R, ncols: C) -> Self::BufferUninit;
|
||||||
|
|
||||||
|
/// Assumes a data buffer to be initialized.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The user must make sure that every single entry of the buffer has been initialized,
|
||||||
|
/// or Undefined Behavior will immediately occur.
|
||||||
|
unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer;
|
||||||
|
|
||||||
/// Allocates a buffer initialized with the content of the given iterator.
|
/// Allocates a buffer initialized with the content of the given iterator.
|
||||||
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
||||||
|
@ -31,45 +45,15 @@ pub trait InnerAllocator<T, R: Dim, C: Dim = U1>: 'static + Sized {
|
||||||
) -> Self::Buffer;
|
) -> Self::Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as the [`InnerAllocator`] trait, but also provides methods to build uninitialized buffers,
|
/// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` ×
|
||||||
/// or buffers whose entries must be manually dropped.
|
/// `CFrom`) elements to a smaller or larger size (`RTo`, `CTo`).
|
||||||
pub trait Allocator<T, R: Dim, C: Dim = U1>:
|
pub trait Reallocator<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
|
||||||
InnerAllocator<T, R, C>
|
|
||||||
+ InnerAllocator<MaybeUninit<T>, R, C>
|
|
||||||
+ InnerAllocator<ManuallyDrop<T>, R, C>
|
|
||||||
{
|
|
||||||
/// Allocates a buffer with the given number of rows and columns without initializing its content.
|
|
||||||
fn allocate_uninitialized(
|
|
||||||
nrows: R,
|
|
||||||
ncols: C,
|
|
||||||
) -> <Self as InnerAllocator<MaybeUninit<T>, R, C>>::Buffer;
|
|
||||||
|
|
||||||
/// Assumes a data buffer to be initialized. This operation should be near zero-cost.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
/// The user must make sure that every single entry of the buffer has been initialized,
|
|
||||||
/// or Undefined Behavior will immediately occur.
|
|
||||||
unsafe fn assume_init(
|
|
||||||
uninit: <Self as InnerAllocator<MaybeUninit<T>, R, C>>::Buffer,
|
|
||||||
) -> <Self as InnerAllocator<T, R, C>>::Buffer;
|
|
||||||
|
|
||||||
/// Specifies that a given buffer's entries should be manually dropped.
|
|
||||||
fn manually_drop(
|
|
||||||
buf: <Self as InnerAllocator<T, R, C>>::Buffer,
|
|
||||||
) -> <Self as InnerAllocator<ManuallyDrop<T>, R, C>>::Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A matrix reallocator. Changes the size of the memory buffer that initially contains (RFrom ×
|
|
||||||
/// CFrom) elements to a smaller or larger size (RTo, CTo).
|
|
||||||
pub trait Reallocator<T, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
|
|
||||||
Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo>
|
Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo>
|
||||||
{
|
{
|
||||||
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
|
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
|
||||||
/// `buf`. Data stored by `buf` are linearly copied to the output:
|
/// `buf`. Data stored by `buf` are linearly copied to the output:
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// **NO! THIS IS STILL UB!**
|
|
||||||
/// * The copy is performed as if both were just arrays (without a matrix structure).
|
/// * The copy is performed as if both were just arrays (without a matrix structure).
|
||||||
/// * If `buf` is larger than the output size, then extra elements of `buf` are truncated.
|
/// * If `buf` is larger than the output size, then extra elements of `buf` are truncated.
|
||||||
/// * If `buf` is smaller than the output size, then extra elements of the output are left
|
/// * If `buf` is smaller than the output size, then extra elements of the output are left
|
||||||
|
@ -77,8 +61,8 @@ pub trait Reallocator<T, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
nrows: RTo,
|
nrows: RTo,
|
||||||
ncols: CTo,
|
ncols: CTo,
|
||||||
buf: <Self as InnerAllocator<T, RFrom, CFrom>>::Buffer,
|
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
|
||||||
) -> <Self as InnerAllocator<T, RTo, CTo>>::Buffer;
|
) -> <Self as Allocator<T, RTo, CTo>>::Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of rows of the result of a componentwise operation on two matrices.
|
/// The number of rows of the result of a componentwise operation on two matrices.
|
||||||
|
@ -89,16 +73,23 @@ pub type SameShapeC<C1, C2> = <ShapeConstraint as SameNumberOfColumns<C1, C2>>::
|
||||||
|
|
||||||
// TODO: Bad name.
|
// TODO: Bad name.
|
||||||
/// Restricts the given number of rows and columns to be respectively the same.
|
/// Restricts the given number of rows and columns to be respectively the same.
|
||||||
pub trait SameShapeAllocator<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim>:
|
pub trait SameShapeAllocator<T, R1, C1, R2, C2>:
|
||||||
Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>
|
Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
C2: Dim,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: Dim, R2: Dim, C1: Dim, C2: Dim> SameShapeAllocator<T, R1, C1, R2, C2>
|
impl<T, R1, R2, C1, C2> SameShapeAllocator<T, R1, C1, R2, C2> for DefaultAllocator
|
||||||
for DefaultAllocator
|
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
C2: Dim,
|
||||||
DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
|
DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
{
|
{
|
||||||
|
@ -106,15 +97,19 @@ where
|
||||||
|
|
||||||
// XXX: Bad name.
|
// XXX: Bad name.
|
||||||
/// Restricts the given number of rows to be equal.
|
/// Restricts the given number of rows to be equal.
|
||||||
pub trait SameShapeVectorAllocator<T, R1: Dim, R2: Dim>:
|
pub trait SameShapeVectorAllocator<T, R1, R2>:
|
||||||
Allocator<T, R1> + Allocator<T, SameShapeR<R1, R2>> + SameShapeAllocator<T, R1, U1, R2, U1>
|
Allocator<T, R1> + Allocator<T, SameShapeR<R1, R2>> + SameShapeAllocator<T, R1, U1, R2, U1>
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
R2: Dim,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: Dim, R2: Dim> SameShapeVectorAllocator<T, R1, R2> for DefaultAllocator
|
impl<T, R1, R2> SameShapeVectorAllocator<T, R1, R2> for DefaultAllocator
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
R2: Dim,
|
||||||
DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>,
|
DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
|
||||||
// use std::hash::{Hash, Hasher};
|
// use std::hash::{Hash, Hasher};
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::io::{Result as IOResult, Write};
|
||||||
|
@ -13,28 +12,43 @@ use serde::ser::SerializeSeq;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use abomonation::Abomonation;
|
use abomonation::Abomonation;
|
||||||
|
|
||||||
use crate::allocator::InnerAllocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{Const, ToTypenum};
|
use crate::base::dimension::{Const, ToTypenum};
|
||||||
use crate::base::storage::{
|
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
|
||||||
ContiguousStorage, ContiguousStorageMut, ReshapableStorage, Storage, StorageMut,
|
use crate::base::Scalar;
|
||||||
};
|
use crate::Storage;
|
||||||
use crate::base::Owned;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Static Storage.
|
* Static RawStorage.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// A array-based statically sized matrix data storage.
|
/// A array-based statically sized matrix data storage.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]);
|
pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]);
|
||||||
|
|
||||||
|
impl<T, const R: usize, const C: usize> ArrayStorage<T, R, C> {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
// SAFETY: this is OK because ArrayStorage is contiguous.
|
||||||
|
unsafe { self.as_slice_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||||
|
// SAFETY: this is OK because ArrayStorage is contiguous.
|
||||||
|
unsafe { self.as_mut_slice_unchecked() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove this once the stdlib implements Default for arrays.
|
// TODO: remove this once the stdlib implements Default for arrays.
|
||||||
impl<T: Default, const R: usize, const C: usize> Default for ArrayStorage<T, R, C>
|
impl<T: Default, const R: usize, const C: usize> Default for ArrayStorage<T, R, C>
|
||||||
where
|
where
|
||||||
|
@ -53,10 +67,8 @@ impl<T: Debug, const R: usize, const C: usize> Debug for ArrayStorage<T, R, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>>
|
unsafe impl<T, const R: usize, const C: usize> RawStorage<T, Const<R>, Const<C>>
|
||||||
for ArrayStorage<T, R, C>
|
for ArrayStorage<T, R, C>
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
|
|
||||||
{
|
{
|
||||||
type RStride = Const<1>;
|
type RStride = Const<1>;
|
||||||
type CStride = Const<R>;
|
type CStride = Const<R>;
|
||||||
|
@ -81,38 +93,36 @@ where
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_owned(self) -> Owned<T, Const<R>, Const<C>>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>>,
|
|
||||||
{
|
|
||||||
Owned(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clone_owned(&self) -> Owned<T, Const<R>, Const<C>>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>>,
|
|
||||||
{
|
|
||||||
let it = self.as_slice().iter().cloned();
|
|
||||||
Owned(DefaultAllocator::allocate_from_iterator(
|
|
||||||
self.shape().0,
|
|
||||||
self.shape().1,
|
|
||||||
it,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
||||||
std::slice::from_raw_parts(self.ptr(), R * C)
|
std::slice::from_raw_parts(self.ptr(), R * C)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, const R: usize, const C: usize> StorageMut<T, Const<R>, Const<C>>
|
unsafe impl<T: Scalar, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>>
|
||||||
for ArrayStorage<T, R, C>
|
for ArrayStorage<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
|
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn into_owned(self) -> Owned<T, Const<R>, Const<C>>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, Const<R>, Const<C>>,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_owned(&self) -> Owned<T, Const<R>, Const<C>>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, Const<R>, Const<C>>,
|
||||||
|
{
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T, const R: usize, const C: usize> RawStorageMut<T, Const<R>, Const<C>>
|
||||||
|
for ArrayStorage<T, R, C>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ptr_mut(&mut self) -> *mut T {
|
fn ptr_mut(&mut self) -> *mut T {
|
||||||
|
@ -125,23 +135,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, const R: usize, const C: usize> ContiguousStorage<T, Const<R>, Const<C>>
|
unsafe impl<T, const R: usize, const C: usize> IsContiguous for ArrayStorage<T, R, C> {}
|
||||||
for ArrayStorage<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, const R: usize, const C: usize> ContiguousStorageMut<T, Const<R>, Const<C>>
|
|
||||||
for ArrayStorage<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Const<R>, Const<C>, Buffer = Self>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const R1: usize, const C1: usize, const R2: usize, const C2: usize>
|
impl<T, const R1: usize, const C1: usize, const R2: usize, const C2: usize>
|
||||||
ReshapableStorage<T, Const<R1>, Const<C1>, Const<R2>, Const<C2>> for ArrayStorage<T, R1, C1>
|
ReshapableStorage<T, Const<R1>, Const<C1>, Const<R2>, Const<C2>> for ArrayStorage<T, R1, C1>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
Const<R1>: ToTypenum,
|
Const<R1>: ToTypenum,
|
||||||
Const<C1>: ToTypenum,
|
Const<C1>: ToTypenum,
|
||||||
Const<R2>: ToTypenum,
|
Const<R2>: ToTypenum,
|
||||||
|
@ -159,8 +158,8 @@ where
|
||||||
|
|
||||||
fn reshape_generic(self, _: Const<R2>, _: Const<C2>) -> Self::Output {
|
fn reshape_generic(self, _: Const<R2>, _: Const<C2>) -> Self::Output {
|
||||||
unsafe {
|
unsafe {
|
||||||
let data: [[T; R2]; C2] = mem::transmute_copy(&self.0);
|
let data: [[T; R2]; C2] = std::mem::transmute_copy(&self.0);
|
||||||
mem::forget(self.0);
|
std::mem::forget(self.0);
|
||||||
ArrayStorage(data)
|
ArrayStorage(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +174,7 @@ where
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T, const R: usize, const C: usize> Serialize for ArrayStorage<T, R, C>
|
impl<T, const R: usize, const C: usize> Serialize for ArrayStorage<T, R, C>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Scalar + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -194,7 +193,7 @@ where
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T, const R: usize, const C: usize> Deserialize<'a> for ArrayStorage<T, R, C>
|
impl<'a, T, const R: usize, const C: usize> Deserialize<'a> for ArrayStorage<T, R, C>
|
||||||
where
|
where
|
||||||
T: Deserialize<'a>,
|
T: Scalar + Deserialize<'a>,
|
||||||
{
|
{
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -211,7 +210,10 @@ struct ArrayStorageVisitor<T, const R: usize, const C: usize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C> {
|
impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
{
|
||||||
/// Construct a new sequence visitor.
|
/// Construct a new sequence visitor.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ArrayStorageVisitor {
|
ArrayStorageVisitor {
|
||||||
|
@ -223,7 +225,7 @@ impl<T, const R: usize, const C: usize> ArrayStorageVisitor<T, R, C> {
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T, const R: usize, const C: usize> Visitor<'a> for ArrayStorageVisitor<T, R, C>
|
impl<'a, T, const R: usize, const C: usize> Visitor<'a> for ArrayStorageVisitor<T, R, C>
|
||||||
where
|
where
|
||||||
T: Deserialize<'a>,
|
T: Scalar + Deserialize<'a>,
|
||||||
{
|
{
|
||||||
type Value = ArrayStorage<T, R, C>;
|
type Value = ArrayStorage<T, R, C>;
|
||||||
|
|
||||||
|
@ -255,13 +257,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T: Copy + bytemuck::Zeroable, const R: usize, const C: usize> bytemuck::Zeroable
|
unsafe impl<T: Scalar + Copy + bytemuck::Zeroable, const R: usize, const C: usize>
|
||||||
for ArrayStorage<T, R, C>
|
bytemuck::Zeroable for ArrayStorage<T, R, C>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T: Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::Pod
|
unsafe impl<T: Scalar + Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::Pod
|
||||||
for ArrayStorage<T, R, C>
|
for ArrayStorage<T, R, C>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -269,7 +271,7 @@ unsafe impl<T: Copy + bytemuck::Pod, const R: usize, const C: usize> bytemuck::P
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T, const R: usize, const C: usize> Abomonation for ArrayStorage<T, R, C>
|
impl<T, const R: usize, const C: usize> Abomonation for ArrayStorage<T, R, C>
|
||||||
where
|
where
|
||||||
T: Abomonation,
|
T: Scalar + Abomonation,
|
||||||
{
|
{
|
||||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||||
for element in self.as_slice() {
|
for element in self.as_slice() {
|
||||||
|
|
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
|
use crate::{RawStorage, SimdComplexField};
|
||||||
//! standard and highly optimized set of basic vector and matrix operations.
|
|
||||||
//!
|
|
||||||
//! To avoid unsoundness due to mishandling of uninitialized data, we divide our
|
|
||||||
//! methods into two groups: those that take in a `&mut` to a matrix, and those
|
|
||||||
//! that return an owned matrix that would otherwise result from setting a
|
|
||||||
//! parameter to zero in the other methods.
|
|
||||||
|
|
||||||
use crate::{MatrixSliceMut, SimdComplexField, VectorSliceMut};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use matrixmultiply;
|
|
||||||
use num::{One, Zero};
|
use num::{One, Zero};
|
||||||
use simba::scalar::{ClosedAdd, ClosedMul};
|
use simba::scalar::{ClosedAdd, ClosedMul};
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::mem;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
|
use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit};
|
||||||
use crate::base::constraint::{
|
use crate::base::constraint::{
|
||||||
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
|
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -24,9 +12,10 @@ use crate::base::storage::{Storage, StorageMut};
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice,
|
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice,
|
||||||
};
|
};
|
||||||
|
use crate::core::uninit::Init;
|
||||||
|
|
||||||
/// # Dot/scalar product
|
/// # Dot/scalar product
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S>
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
||||||
{
|
{
|
||||||
|
@ -37,7 +26,7 @@ where
|
||||||
conjugate: impl Fn(T) -> T,
|
conjugate: impl Fn(T) -> T,
|
||||||
) -> T
|
) -> T
|
||||||
where
|
where
|
||||||
SB: Storage<T, R2, C2>,
|
SB: RawStorage<T, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
{
|
{
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -205,7 +194,7 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
||||||
where
|
where
|
||||||
SB: Storage<T, R2, C2>,
|
SB: RawStorage<T, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
{
|
{
|
||||||
self.dotx(rhs, |e| e)
|
self.dotx(rhs, |e| e)
|
||||||
|
@ -235,7 +224,7 @@ where
|
||||||
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
||||||
where
|
where
|
||||||
T: SimdComplexField,
|
T: SimdComplexField,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: RawStorage<T, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
{
|
{
|
||||||
self.dotx(rhs, T::simd_conjugate)
|
self.dotx(rhs, T::simd_conjugate)
|
||||||
|
@ -262,7 +251,7 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
|
||||||
where
|
where
|
||||||
SB: Storage<T, R2, C2>,
|
SB: RawStorage<T, R2, C2>,
|
||||||
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,
|
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
@ -293,10 +282,7 @@ where
|
||||||
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
||||||
S: StorageMut<T, D>,
|
S: StorageMut<T, D>,
|
||||||
{
|
{
|
||||||
/// Computes `self = a * x * c + b * self`, where `a`, `b`, `c` are scalars,
|
/// Computes `self = a * x * c + b * self`.
|
||||||
/// and `x` is a vector of the same size as `self`.
|
|
||||||
///
|
|
||||||
/// For commutative scalars, this is equivalent to an [`axpy`] call.
|
|
||||||
///
|
///
|
||||||
/// If `b` is zero, `self` is never read from.
|
/// If `b` is zero, `self` is never read from.
|
||||||
///
|
///
|
||||||
|
@ -316,34 +302,7 @@ where
|
||||||
SB: Storage<T, D2>,
|
SB: Storage<T, D2>,
|
||||||
ShapeConstraint: DimEq<D, D2>,
|
ShapeConstraint: DimEq<D, D2>,
|
||||||
{
|
{
|
||||||
assert_eq!(self.nrows(), x.nrows(), "Axcpy: mismatched vector shapes.");
|
unsafe { axcpy_uninit(Init, self, a, x, c, b) };
|
||||||
|
|
||||||
let rstride1 = self.strides().0;
|
|
||||||
let rstride2 = x.strides().0;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// SAFETY: the conversion to slices is OK because we access the
|
|
||||||
// elements taking the strides into account.
|
|
||||||
let y = self.data.as_mut_slice_unchecked();
|
|
||||||
let x = x.data.as_slice_unchecked();
|
|
||||||
|
|
||||||
if !b.is_zero() {
|
|
||||||
for i in 0..x.len() {
|
|
||||||
let y = y.get_unchecked_mut(i * rstride1);
|
|
||||||
*y = a.inlined_clone()
|
|
||||||
* x.get_unchecked(i * rstride2).inlined_clone()
|
|
||||||
* c.inlined_clone()
|
|
||||||
+ b.inlined_clone() * y.inlined_clone();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 0..x.len() {
|
|
||||||
let y = y.get_unchecked_mut(i * rstride1);
|
|
||||||
*y = a.inlined_clone()
|
|
||||||
* x.get_unchecked(i * rstride2).inlined_clone()
|
|
||||||
* c.inlined_clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self = a * x + b * self`.
|
/// Computes `self = a * x + b * self`.
|
||||||
|
@ -399,38 +358,8 @@ where
|
||||||
SC: Storage<T, D3>,
|
SC: Storage<T, D3>,
|
||||||
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
|
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
|
||||||
{
|
{
|
||||||
let dim1 = self.nrows();
|
// Safety: this is safe because we are passing Status == Init.
|
||||||
let (nrows2, ncols2) = a.shape();
|
unsafe { gemv_uninit(Init, self, alpha, a, x, beta) }
|
||||||
let dim3 = x.nrows();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
ncols2 == dim3 && dim1 == nrows2,
|
|
||||||
"Gemv: dimensions mismatch."
|
|
||||||
);
|
|
||||||
|
|
||||||
if ncols2 == 0 {
|
|
||||||
// NOTE: we can't just always multiply by beta
|
|
||||||
// because we documented the guaranty that `self` is
|
|
||||||
// never read if `beta` is zero.
|
|
||||||
if beta.is_zero() {
|
|
||||||
self.fill(T::zero());
|
|
||||||
} else {
|
|
||||||
*self *= beta;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: avoid bound checks.
|
|
||||||
let col2 = a.column(0);
|
|
||||||
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
|
|
||||||
self.axcpy(alpha.inlined_clone(), &col2, val, beta);
|
|
||||||
|
|
||||||
for j in 1..ncols2 {
|
|
||||||
let col2 = a.column(j);
|
|
||||||
let val = unsafe { x.vget_unchecked(j).inlined_clone() };
|
|
||||||
|
|
||||||
self.axcpy(alpha.inlined_clone(), &col2, val, T::one());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -490,25 +419,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
|
|
||||||
/// vector, and `alpha, beta` two scalars. DEPRECATED: use `sygemv` instead.
|
|
||||||
#[inline]
|
|
||||||
#[deprecated(note = "This is renamed `sygemv` to match the original BLAS terminology.")]
|
|
||||||
pub fn gemv_symm<D2: Dim, D3: Dim, SB, SC>(
|
|
||||||
&mut self,
|
|
||||||
alpha: T,
|
|
||||||
a: &SquareMatrix<T, D2, SB>,
|
|
||||||
x: &Vector<T, D3, SC>,
|
|
||||||
beta: T,
|
|
||||||
) where
|
|
||||||
T: One,
|
|
||||||
SB: Storage<T, D2, D2>,
|
|
||||||
SC: Storage<T, D3>,
|
|
||||||
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
|
|
||||||
{
|
|
||||||
self.sygemv(alpha, a, x, beta)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
|
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
|
||||||
/// vector, and `alpha, beta` two scalars.
|
/// vector, and `alpha, beta` two scalars.
|
||||||
///
|
///
|
||||||
|
@ -709,331 +619,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, D: Dim, S> Vector<MaybeUninit<T>, D, S>
|
|
||||||
where
|
|
||||||
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
|
||||||
S: StorageMut<MaybeUninit<T>, D>,
|
|
||||||
{
|
|
||||||
/// Computes `alpha * a * x`, where `a` is a matrix, `x` a vector, and
|
|
||||||
/// `alpha` is a scalar.
|
|
||||||
///
|
|
||||||
/// `self` must be completely uninitialized, or data leaks will occur. After
|
|
||||||
/// this method is called, all entries in `self` will be initialized.
|
|
||||||
#[inline]
|
|
||||||
pub fn axc<D2: Dim, S2>(
|
|
||||||
&mut self,
|
|
||||||
a: T,
|
|
||||||
x: &Vector<T, D2, S2>,
|
|
||||||
c: T,
|
|
||||||
) -> VectorSliceMut<T, D, S::RStride, S::CStride>
|
|
||||||
where
|
|
||||||
S2: Storage<T, D2>,
|
|
||||||
ShapeConstraint: DimEq<D, D2>,
|
|
||||||
{
|
|
||||||
let rstride1 = self.strides().0;
|
|
||||||
let rstride2 = x.strides().0;
|
|
||||||
|
|
||||||
// Safety: see each individual remark.
|
|
||||||
unsafe {
|
|
||||||
// We don't mind `x` and `y` not being contiguous, as we'll only
|
|
||||||
// access the elements we're allowed to. (TODO: double check this)
|
|
||||||
let y = self.data.as_mut_slice_unchecked();
|
|
||||||
let x = x.data.as_slice_unchecked();
|
|
||||||
|
|
||||||
// The indices are within range, and only access elements that belong
|
|
||||||
// to `x` and `y` themselves.
|
|
||||||
for i in 0..y.len() {
|
|
||||||
*y.get_unchecked_mut(i * rstride1) = MaybeUninit::new(
|
|
||||||
a.inlined_clone()
|
|
||||||
* x.get_unchecked(i * rstride2).inlined_clone()
|
|
||||||
* c.inlined_clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've initialized all elements.
|
|
||||||
self.assume_init_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes `alpha * a * x`, where `a` is a matrix, `x` a vector, and
|
|
||||||
/// `alpha` is a scalar.
|
|
||||||
///
|
|
||||||
/// `self` must be completely uninitialized, or data leaks will occur. After
|
|
||||||
/// the method is called, `self` will be completely initialized. We return
|
|
||||||
/// an initialized mutable vector slice to `self` for convenience.
|
|
||||||
#[inline]
|
|
||||||
pub fn gemv_z<R2: Dim, C2: Dim, D3: Dim, SB, SC>(
|
|
||||||
&mut self,
|
|
||||||
alpha: T,
|
|
||||||
a: &Matrix<T, R2, C2, SB>,
|
|
||||||
x: &Vector<T, D3, SC>,
|
|
||||||
) -> VectorSliceMut<T, D, S::RStride, S::CStride>
|
|
||||||
where
|
|
||||||
T: One,
|
|
||||||
SB: Storage<T, R2, C2>,
|
|
||||||
SC: Storage<T, D3>,
|
|
||||||
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
|
|
||||||
{
|
|
||||||
let dim1 = self.nrows();
|
|
||||||
let (nrows2, ncols2) = a.shape();
|
|
||||||
let dim3 = x.nrows();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
ncols2 == dim3 && dim1 == nrows2,
|
|
||||||
"Gemv: dimensions mismatch."
|
|
||||||
);
|
|
||||||
|
|
||||||
if ncols2 == 0 {
|
|
||||||
self.fill_fn(|| MaybeUninit::new(T::zero()));
|
|
||||||
|
|
||||||
// Safety: all entries have just been initialized.
|
|
||||||
unsafe {
|
|
||||||
return self.assume_init_mut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: avoid bound checks.
|
|
||||||
let col2 = a.column(0);
|
|
||||||
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
|
|
||||||
let mut init = self.axc(alpha.inlined_clone(), &col2, val);
|
|
||||||
|
|
||||||
// Safety: all indices are within range.
|
|
||||||
unsafe {
|
|
||||||
for j in 1..ncols2 {
|
|
||||||
let col2 = a.column(j);
|
|
||||||
let val = x.vget_unchecked(j).inlined_clone();
|
|
||||||
init.axcpy(alpha.inlined_clone(), &col2, val, T::one());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn xxgemv_z<D2: Dim, D3: Dim, SB, SC>(
|
|
||||||
&mut self,
|
|
||||||
alpha: T,
|
|
||||||
a: &SquareMatrix<T, D2, SB>,
|
|
||||||
x: &Vector<T, D3, SC>,
|
|
||||||
dot: impl Fn(
|
|
||||||
&DVectorSlice<T, SB::RStride, SB::CStride>,
|
|
||||||
&DVectorSlice<T, SC::RStride, SC::CStride>,
|
|
||||||
) -> T,
|
|
||||||
) where
|
|
||||||
T: One,
|
|
||||||
SB: Storage<T, D2, D2>,
|
|
||||||
SC: Storage<T, D3>,
|
|
||||||
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
|
|
||||||
{
|
|
||||||
let dim1 = self.nrows();
|
|
||||||
let dim2 = a.nrows();
|
|
||||||
let dim3 = x.nrows();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
a.is_square(),
|
|
||||||
"Symmetric cgemv: the input matrix must be square."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
dim2 == dim3 && dim1 == dim2,
|
|
||||||
"Symmetric cgemv: dimensions mismatch."
|
|
||||||
);
|
|
||||||
|
|
||||||
if dim2 == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: avoid bound checks.
|
|
||||||
let col2 = a.column(0);
|
|
||||||
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
|
|
||||||
let mut res = self.axc(alpha.inlined_clone(), &col2, val);
|
|
||||||
|
|
||||||
res[0] += alpha.inlined_clone() * dot(&a.slice_range(1.., 0), &x.rows_range(1..));
|
|
||||||
|
|
||||||
for j in 1..dim2 {
|
|
||||||
let col2 = a.column(j);
|
|
||||||
let dot = dot(&col2.rows_range(j..), &x.rows_range(j..));
|
|
||||||
|
|
||||||
let val;
|
|
||||||
unsafe {
|
|
||||||
val = x.vget_unchecked(j).inlined_clone();
|
|
||||||
*res.vget_unchecked_mut(j) += alpha.inlined_clone() * dot;
|
|
||||||
}
|
|
||||||
res.rows_range_mut(j + 1..).axpy(
|
|
||||||
alpha.inlined_clone() * val,
|
|
||||||
&col2.rows_range(j + 1..),
|
|
||||||
T::one(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes `self = alpha * a * x`, where `a` is an **hermitian** matrix, `x` a
|
|
||||||
/// vector, and `alpha, beta` two scalars.
|
|
||||||
pub fn hegemv_z<D2: Dim, D3: Dim, SB, SC>(
|
|
||||||
&mut self,
|
|
||||||
alpha: T,
|
|
||||||
a: &SquareMatrix<T, D2, SB>,
|
|
||||||
x: &Vector<T, D3, SC>,
|
|
||||||
) where
|
|
||||||
T: SimdComplexField,
|
|
||||||
SB: Storage<T, D2, D2>,
|
|
||||||
SC: Storage<T, D3>,
|
|
||||||
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
|
|
||||||
{
|
|
||||||
self.xxgemv_z(alpha, a, x, |a, b| a.dotc(b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R1: Dim, C1: Dim, S: StorageMut<MaybeUninit<T>, R1, C1>> Matrix<MaybeUninit<T>, R1, C1, S>
|
|
||||||
where
|
|
||||||
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
|
||||||
// DefaultAllocator: Allocator<T, R1, C1>,
|
|
||||||
{
|
|
||||||
/// Computes `alpha * a * b`, where `a` and `b` are matrices, and `alpha` is
|
|
||||||
/// a scalar.
|
|
||||||
///
|
|
||||||
/// # Examples:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[macro_use] extern crate approx;
|
|
||||||
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
|
|
||||||
/// let mut mat1 = Matrix2x4::identity();
|
|
||||||
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
|
|
||||||
/// 4.0, 5.0, 6.0);
|
|
||||||
/// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4,
|
|
||||||
/// 0.5, 0.6, 0.7, 0.8,
|
|
||||||
/// 0.9, 1.0, 1.1, 1.2);
|
|
||||||
/// let expected = mat2 * mat3 * 10.0 + mat1 * 5.0;
|
|
||||||
///
|
|
||||||
/// mat1.gemm(10.0, &mat2, &mat3, 5.0);
|
|
||||||
/// assert_relative_eq!(mat1, expected);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn gemm_z<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>(
|
|
||||||
&mut self,
|
|
||||||
alpha: T,
|
|
||||||
a: &Matrix<T, R2, C2, SB>,
|
|
||||||
b: &Matrix<T, R3, C3, SC>,
|
|
||||||
) -> MatrixSliceMut<T, R1, C1, S::RStride, S::CStride>
|
|
||||||
where
|
|
||||||
SB: Storage<T, R2, C2>,
|
|
||||||
SC: Storage<T, R3, C3>,
|
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>
|
|
||||||
+ SameNumberOfColumns<C1, C3>
|
|
||||||
+ AreMultipliable<R2, C2, R3, C3>,
|
|
||||||
{
|
|
||||||
let ncols1 = self.ncols();
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
{
|
|
||||||
// We assume large matrices will be Dynamic but small matrices static.
|
|
||||||
// We could use matrixmultiply for large statically-sized matrices but the performance
|
|
||||||
// threshold to activate it would be different from SMALL_DIM because our code optimizes
|
|
||||||
// better for statically-sized matrices.
|
|
||||||
if R1::is::<Dynamic>()
|
|
||||||
|| C1::is::<Dynamic>()
|
|
||||||
|| R2::is::<Dynamic>()
|
|
||||||
|| C2::is::<Dynamic>()
|
|
||||||
|| R3::is::<Dynamic>()
|
|
||||||
|| C3::is::<Dynamic>()
|
|
||||||
{
|
|
||||||
// matrixmultiply can be used only if the std feature is available.
|
|
||||||
let nrows1 = self.nrows();
|
|
||||||
let (nrows2, ncols2) = a.shape();
|
|
||||||
let (nrows3, ncols3) = b.shape();
|
|
||||||
|
|
||||||
// Threshold determined empirically.
|
|
||||||
const SMALL_DIM: usize = 5;
|
|
||||||
|
|
||||||
if nrows1 > SMALL_DIM
|
|
||||||
&& ncols1 > SMALL_DIM
|
|
||||||
&& nrows2 > SMALL_DIM
|
|
||||||
&& ncols2 > SMALL_DIM
|
|
||||||
{
|
|
||||||
assert_eq!(
|
|
||||||
ncols2, nrows3,
|
|
||||||
"gemm: dimensions mismatch for multiplication."
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
(nrows1, ncols1),
|
|
||||||
(nrows2, ncols3),
|
|
||||||
"gemm: dimensions mismatch for addition."
|
|
||||||
);
|
|
||||||
|
|
||||||
// NOTE: this case should never happen because we enter this
|
|
||||||
// codepath only when ncols2 > SMALL_DIM. Though we keep this
|
|
||||||
// here just in case if in the future we change the conditions to
|
|
||||||
// enter this codepath.
|
|
||||||
if ncols1 == 0 {
|
|
||||||
self.fill_fn(|| MaybeUninit::new(T::zero()));
|
|
||||||
|
|
||||||
// Safety: there's no (uninitialized) values.
|
|
||||||
return unsafe { self.assume_init_mut() };
|
|
||||||
}
|
|
||||||
|
|
||||||
let (rsa, csa) = a.strides();
|
|
||||||
let (rsb, csb) = b.strides();
|
|
||||||
let (rsc, csc) = self.strides();
|
|
||||||
|
|
||||||
if T::is::<f32>() {
|
|
||||||
unsafe {
|
|
||||||
matrixmultiply::sgemm(
|
|
||||||
nrows2,
|
|
||||||
ncols2,
|
|
||||||
ncols3,
|
|
||||||
mem::transmute_copy(&alpha),
|
|
||||||
a.data.ptr() as *const f32,
|
|
||||||
rsa as isize,
|
|
||||||
csa as isize,
|
|
||||||
b.data.ptr() as *const f32,
|
|
||||||
rsb as isize,
|
|
||||||
csb as isize,
|
|
||||||
0.0,
|
|
||||||
self.data.ptr_mut() as *mut f32,
|
|
||||||
rsc as isize,
|
|
||||||
csc as isize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if T::is::<f64>() {
|
|
||||||
unsafe {
|
|
||||||
matrixmultiply::dgemm(
|
|
||||||
nrows2,
|
|
||||||
ncols2,
|
|
||||||
ncols3,
|
|
||||||
mem::transmute_copy(&alpha),
|
|
||||||
a.data.ptr() as *const f64,
|
|
||||||
rsa as isize,
|
|
||||||
csa as isize,
|
|
||||||
b.data.ptr() as *const f64,
|
|
||||||
rsb as isize,
|
|
||||||
csb as isize,
|
|
||||||
0.0,
|
|
||||||
self.data.ptr_mut() as *mut f64,
|
|
||||||
rsc as isize,
|
|
||||||
csc as isize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
|
||||||
unsafe {
|
|
||||||
return self.assume_init_mut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for j1 in 0..ncols1 {
|
|
||||||
// TODO: avoid bound checks.
|
|
||||||
let _ = self
|
|
||||||
.column_mut(j1)
|
|
||||||
.gemv_z(alpha.inlined_clone(), a, &b.column(j1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
|
||||||
unsafe { self.assume_init_mut() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S>
|
impl<T, R1: Dim, C1: Dim, S: StorageMut<T, R1, C1>> Matrix<T, R1, C1, S>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + ClosedAdd + ClosedMul,
|
||||||
|
@ -1170,122 +755,9 @@ where
|
||||||
+ SameNumberOfColumns<C1, C3>
|
+ SameNumberOfColumns<C1, C3>
|
||||||
+ AreMultipliable<R2, C2, R3, C3>,
|
+ AreMultipliable<R2, C2, R3, C3>,
|
||||||
{
|
{
|
||||||
let ncols1 = self.ncols();
|
// SAFETY: this is valid because our matrices are initialized and
|
||||||
|
// we are using status = Init.
|
||||||
#[cfg(feature = "std")]
|
unsafe { gemm_uninit(Init, self, alpha, a, b, beta) }
|
||||||
{
|
|
||||||
// We assume large matrices will be Dynamic but small matrices static.
|
|
||||||
// We could use matrixmultiply for large statically-sized matrices but the performance
|
|
||||||
// threshold to activate it would be different from SMALL_DIM because our code optimizes
|
|
||||||
// better for statically-sized matrices.
|
|
||||||
if R1::is::<Dynamic>()
|
|
||||||
|| C1::is::<Dynamic>()
|
|
||||||
|| R2::is::<Dynamic>()
|
|
||||||
|| C2::is::<Dynamic>()
|
|
||||||
|| R3::is::<Dynamic>()
|
|
||||||
|| C3::is::<Dynamic>()
|
|
||||||
{
|
|
||||||
// matrixmultiply can be used only if the std feature is available.
|
|
||||||
let nrows1 = self.nrows();
|
|
||||||
let (nrows2, ncols2) = a.shape();
|
|
||||||
let (nrows3, ncols3) = b.shape();
|
|
||||||
|
|
||||||
// Threshold determined empirically.
|
|
||||||
const SMALL_DIM: usize = 5;
|
|
||||||
|
|
||||||
if nrows1 > SMALL_DIM
|
|
||||||
&& ncols1 > SMALL_DIM
|
|
||||||
&& nrows2 > SMALL_DIM
|
|
||||||
&& ncols2 > SMALL_DIM
|
|
||||||
{
|
|
||||||
assert_eq!(
|
|
||||||
ncols2, nrows3,
|
|
||||||
"gemm: dimensions mismatch for multiplication."
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
(nrows1, ncols1),
|
|
||||||
(nrows2, ncols3),
|
|
||||||
"gemm: dimensions mismatch for addition."
|
|
||||||
);
|
|
||||||
|
|
||||||
// NOTE: this case should never happen because we enter this
|
|
||||||
// codepath only when ncols2 > SMALL_DIM. Though we keep this
|
|
||||||
// here just in case if in the future we change the conditions to
|
|
||||||
// enter this codepath.
|
|
||||||
if ncols2 == 0 {
|
|
||||||
// NOTE: we can't just always multiply by beta
|
|
||||||
// because we documented the guaranty that `self` is
|
|
||||||
// never read if `beta` is zero.
|
|
||||||
if beta.is_zero() {
|
|
||||||
self.fill(T::zero());
|
|
||||||
} else {
|
|
||||||
*self *= beta;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if T::is::<f32>() {
|
|
||||||
let (rsa, csa) = a.strides();
|
|
||||||
let (rsb, csb) = b.strides();
|
|
||||||
let (rsc, csc) = self.strides();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
matrixmultiply::sgemm(
|
|
||||||
nrows2,
|
|
||||||
ncols2,
|
|
||||||
ncols3,
|
|
||||||
mem::transmute_copy(&alpha),
|
|
||||||
a.data.ptr() as *const f32,
|
|
||||||
rsa as isize,
|
|
||||||
csa as isize,
|
|
||||||
b.data.ptr() as *const f32,
|
|
||||||
rsb as isize,
|
|
||||||
csb as isize,
|
|
||||||
mem::transmute_copy(&beta),
|
|
||||||
self.data.ptr_mut() as *mut f32,
|
|
||||||
rsc as isize,
|
|
||||||
csc as isize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if T::is::<f64>() {
|
|
||||||
let (rsa, csa) = a.strides();
|
|
||||||
let (rsb, csb) = b.strides();
|
|
||||||
let (rsc, csc) = self.strides();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
matrixmultiply::dgemm(
|
|
||||||
nrows2,
|
|
||||||
ncols2,
|
|
||||||
ncols3,
|
|
||||||
mem::transmute_copy(&alpha),
|
|
||||||
a.data.ptr() as *const f64,
|
|
||||||
rsa as isize,
|
|
||||||
csa as isize,
|
|
||||||
b.data.ptr() as *const f64,
|
|
||||||
rsb as isize,
|
|
||||||
csb as isize,
|
|
||||||
mem::transmute_copy(&beta),
|
|
||||||
self.data.ptr_mut() as *mut f64,
|
|
||||||
rsc as isize,
|
|
||||||
csc as isize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for j1 in 0..ncols1 {
|
|
||||||
// TODO: avoid bound checks.
|
|
||||||
self.column_mut(j1).gemv(
|
|
||||||
alpha.inlined_clone(),
|
|
||||||
a,
|
|
||||||
&b.column(j1),
|
|
||||||
beta.inlined_clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices.
|
/// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices.
|
||||||
|
@ -1579,33 +1051,78 @@ where
|
||||||
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
|
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
|
||||||
/// 0.5, 0.6, 0.7,
|
/// 0.5, 0.6, 0.7,
|
||||||
/// 0.9, 1.0, 1.1]);
|
/// 0.9, 1.0, 1.1]);
|
||||||
///
|
/// // The random shows that values on the workspace do not
|
||||||
|
/// // matter as they will be overwritten.
|
||||||
|
/// let mut workspace = DVector::new_random(2);
|
||||||
/// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0;
|
/// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0;
|
||||||
///
|
///
|
||||||
|
/// mat.quadform_tr_with_workspace(&mut workspace, 10.0, &lhs, &mid, 5.0);
|
||||||
|
/// assert_relative_eq!(mat, expected);
|
||||||
|
pub fn quadform_tr_with_workspace<D2, S2, R3, C3, S3, D4, S4>(
|
||||||
|
&mut self,
|
||||||
|
work: &mut Vector<T, D2, S2>,
|
||||||
|
alpha: T,
|
||||||
|
lhs: &Matrix<T, R3, C3, S3>,
|
||||||
|
mid: &SquareMatrix<T, D4, S4>,
|
||||||
|
beta: T,
|
||||||
|
) where
|
||||||
|
D2: Dim,
|
||||||
|
R3: Dim,
|
||||||
|
C3: Dim,
|
||||||
|
D4: Dim,
|
||||||
|
S2: StorageMut<T, D2>,
|
||||||
|
S3: Storage<T, R3, C3>,
|
||||||
|
S4: Storage<T, D4, D4>,
|
||||||
|
ShapeConstraint: DimEq<D1, D2> + DimEq<D1, R3> + DimEq<D2, R3> + DimEq<C3, D4>,
|
||||||
|
{
|
||||||
|
work.gemv(T::one(), lhs, &mid.column(0), T::zero());
|
||||||
|
self.ger(alpha.inlined_clone(), work, &lhs.column(0), beta);
|
||||||
|
|
||||||
|
for j in 1..mid.ncols() {
|
||||||
|
work.gemv(T::one(), lhs, &mid.column(j), T::zero());
|
||||||
|
self.ger(alpha.inlined_clone(), work, &lhs.column(j), T::one());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`.
|
||||||
|
///
|
||||||
|
/// This allocates a workspace vector of dimension D1 for intermediate results.
|
||||||
|
/// If `D1` is a type-level integer, then the allocation is performed on the stack.
|
||||||
|
/// Use `.quadform_tr_with_workspace(...)` instead to avoid allocations.
|
||||||
|
///
|
||||||
|
/// # Examples:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
|
||||||
|
/// let mut mat = Matrix2::identity();
|
||||||
|
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
|
||||||
|
/// 4.0, 5.0, 6.0);
|
||||||
|
/// let mid = Matrix3::new(0.1, 0.2, 0.3,
|
||||||
|
/// 0.5, 0.6, 0.7,
|
||||||
|
/// 0.9, 1.0, 1.1);
|
||||||
|
/// let expected = lhs * mid * lhs.transpose() * 10.0 + mat * 5.0;
|
||||||
|
///
|
||||||
/// mat.quadform_tr(10.0, &lhs, &mid, 5.0);
|
/// mat.quadform_tr(10.0, &lhs, &mid, 5.0);
|
||||||
/// assert_relative_eq!(mat, expected);
|
/// assert_relative_eq!(mat, expected);
|
||||||
pub fn quadform_tr<R3: Dim, C3: Dim, S3, D4: Dim, S4>(
|
pub fn quadform_tr<R3, C3, S3, D4, S4>(
|
||||||
&mut self,
|
&mut self,
|
||||||
alpha: T,
|
alpha: T,
|
||||||
lhs: &Matrix<T, R3, C3, S3>,
|
lhs: &Matrix<T, R3, C3, S3>,
|
||||||
mid: &SquareMatrix<T, D4, S4>,
|
mid: &SquareMatrix<T, D4, S4>,
|
||||||
beta: T,
|
beta: T,
|
||||||
) where
|
) where
|
||||||
|
R3: Dim,
|
||||||
|
C3: Dim,
|
||||||
|
D4: Dim,
|
||||||
S3: Storage<T, R3, C3>,
|
S3: Storage<T, R3, C3>,
|
||||||
S4: Storage<T, D4, D4>,
|
S4: Storage<T, D4, D4>,
|
||||||
ShapeConstraint: DimEq<D1, R3> + DimEq<C3, D4>,
|
ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>,
|
||||||
DefaultAllocator: Allocator<T, R3>,
|
DefaultAllocator: Allocator<T, D1>,
|
||||||
{
|
{
|
||||||
let mut work =
|
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
|
||||||
Matrix::new_uninitialized_generic(R3::from_usize(self.shape().0), Const::<1>);
|
let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
|
||||||
let mut work = work.gemv_z(T::one(), lhs, &mid.column(0));
|
self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta)
|
||||||
|
|
||||||
self.ger(alpha.inlined_clone(), &work, &lhs.column(0), beta);
|
|
||||||
|
|
||||||
for j in 1..mid.ncols() {
|
|
||||||
work.gemv(T::one(), lhs, &mid.column(j), T::zero());
|
|
||||||
self.ger(alpha.inlined_clone(), &work, &lhs.column(j), T::one());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`.
|
/// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`.
|
||||||
|
@ -1626,34 +1143,79 @@ where
|
||||||
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
|
/// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3,
|
||||||
/// 0.5, 0.6, 0.7,
|
/// 0.5, 0.6, 0.7,
|
||||||
/// 0.9, 1.0, 1.1]);
|
/// 0.9, 1.0, 1.1]);
|
||||||
///
|
/// // The random shows that values on the workspace do not
|
||||||
|
/// // matter as they will be overwritten.
|
||||||
|
/// let mut workspace = DVector::new_random(3);
|
||||||
/// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0;
|
/// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0;
|
||||||
///
|
///
|
||||||
/// mat.quadform(10.0, &mid, &rhs, 5.0);
|
/// mat.quadform_with_workspace(&mut workspace, 10.0, &mid, &rhs, 5.0);
|
||||||
/// assert_relative_eq!(mat, expected);
|
/// assert_relative_eq!(mat, expected);
|
||||||
pub fn quadform<D3: Dim, S3, R4: Dim, C4: Dim, S4>(
|
pub fn quadform_with_workspace<D2, S2, D3, S3, R4, C4, S4>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
work: &mut Vector<T, D2, S2>,
|
||||||
alpha: T,
|
alpha: T,
|
||||||
mid: &SquareMatrix<T, D3, S3>,
|
mid: &SquareMatrix<T, D3, S3>,
|
||||||
rhs: &Matrix<T, R4, C4, S4>,
|
rhs: &Matrix<T, R4, C4, S4>,
|
||||||
beta: T,
|
beta: T,
|
||||||
) where
|
) where
|
||||||
|
D2: Dim,
|
||||||
|
D3: Dim,
|
||||||
|
R4: Dim,
|
||||||
|
C4: Dim,
|
||||||
|
S2: StorageMut<T, D2>,
|
||||||
S3: Storage<T, D3, D3>,
|
S3: Storage<T, D3, D3>,
|
||||||
S4: Storage<T, R4, C4>,
|
S4: Storage<T, R4, C4>,
|
||||||
ShapeConstraint: DimEq<D3, R4> + DimEq<R4, D3> + DimEq<D1, C4>,
|
ShapeConstraint:
|
||||||
DefaultAllocator: Allocator<T, D3>,
|
DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>,
|
||||||
{
|
{
|
||||||
// TODO: figure out why type inference isn't doing its job.
|
work.gemv(T::one(), mid, &rhs.column(0), T::zero());
|
||||||
let mut work = Matrix::new_uninitialized_generic(D3::from_usize(mid.shape().0), Const::<1>);
|
|
||||||
let mut work = work.gemv_z::<D3, _, _, _, _>(T::one(), mid, &rhs.column(0));
|
|
||||||
|
|
||||||
self.column_mut(0)
|
self.column_mut(0)
|
||||||
.gemv_tr(alpha.inlined_clone(), rhs, &work, beta.inlined_clone());
|
.gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
|
||||||
|
|
||||||
for j in 1..rhs.ncols() {
|
for j in 1..rhs.ncols() {
|
||||||
work.gemv::<D3, D3, R4, S3, _>(T::one(), mid, &rhs.column(j), T::zero());
|
work.gemv(T::one(), mid, &rhs.column(j), T::zero());
|
||||||
self.column_mut(j)
|
self.column_mut(j)
|
||||||
.gemv_tr(alpha.inlined_clone(), rhs, &work, beta.inlined_clone());
|
.gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`.
|
||||||
|
///
|
||||||
|
/// This allocates a workspace vector of dimension D2 for intermediate results.
|
||||||
|
/// If `D2` is a type-level integer, then the allocation is performed on the stack.
|
||||||
|
/// Use `.quadform_with_workspace(...)` instead to avoid allocations.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
|
||||||
|
/// let mut mat = Matrix2::identity();
|
||||||
|
/// let rhs = Matrix3x2::new(1.0, 2.0,
|
||||||
|
/// 3.0, 4.0,
|
||||||
|
/// 5.0, 6.0);
|
||||||
|
/// let mid = Matrix3::new(0.1, 0.2, 0.3,
|
||||||
|
/// 0.5, 0.6, 0.7,
|
||||||
|
/// 0.9, 1.0, 1.1);
|
||||||
|
/// let expected = rhs.transpose() * mid * rhs * 10.0 + mat * 5.0;
|
||||||
|
///
|
||||||
|
/// mat.quadform(10.0, &mid, &rhs, 5.0);
|
||||||
|
/// assert_relative_eq!(mat, expected);
|
||||||
|
pub fn quadform<D2, S2, R3, C3, S3>(
|
||||||
|
&mut self,
|
||||||
|
alpha: T,
|
||||||
|
mid: &SquareMatrix<T, D2, S2>,
|
||||||
|
rhs: &Matrix<T, R3, C3, S3>,
|
||||||
|
beta: T,
|
||||||
|
) where
|
||||||
|
D2: Dim,
|
||||||
|
R3: Dim,
|
||||||
|
C3: Dim,
|
||||||
|
S2: Storage<T, D2, D2>,
|
||||||
|
S3: Storage<T, R3, C3>,
|
||||||
|
ShapeConstraint: DimEq<D2, R3> + DimEq<D1, C3> + AreMultipliable<C3, R3, D2, U1>,
|
||||||
|
DefaultAllocator: Allocator<T, D2>,
|
||||||
|
{
|
||||||
|
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
|
||||||
|
let mut work = Vector::zeros_generic(mid.shape_generic().0, Const::<1>);
|
||||||
|
self.quadform_with_workspace(&mut work, alpha, mid, rhs, beta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -11,17 +13,49 @@ use rand::{
|
||||||
Rng,
|
Rng,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{iter, mem::MaybeUninit};
|
use std::iter;
|
||||||
use typenum::{self, Cmp, Greater};
|
use typenum::{self, Cmp, Greater};
|
||||||
|
|
||||||
use simba::scalar::{ClosedAdd, ClosedMul};
|
use simba::scalar::{ClosedAdd, ClosedMul};
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, InnerAllocator};
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{Dim, DimName, Dynamic, ToTypenum};
|
use crate::base::dimension::{Dim, DimName, Dynamic, ToTypenum};
|
||||||
use crate::base::storage::Storage;
|
use crate::base::storage::RawStorage;
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector,
|
ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector,
|
||||||
};
|
};
|
||||||
|
use crate::UninitMatrix;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
/// When "no_unsound_assume_init" is enabled, expands to `unimplemented!()` instead of `new_uninitialized_generic().assume_init()`.
|
||||||
|
/// Intended as a placeholder, each callsite should be refactored to use uninitialized memory soundly
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unimplemented_or_uninitialized_generic {
|
||||||
|
($nrows:expr, $ncols:expr) => {{
|
||||||
|
#[cfg(feature="no_unsound_assume_init")] {
|
||||||
|
// Some of the call sites need the number of rows and columns from this to infer a type, so
|
||||||
|
// uninitialized memory is used to infer the type, as `T: Zero` isn't available at all callsites.
|
||||||
|
// This may technically still be UB even though the assume_init is dead code, but all callsites should be fixed before #556 is closed.
|
||||||
|
let typeinference_helper = crate::base::Matrix::new_uninitialized_generic($nrows, $ncols);
|
||||||
|
unimplemented!();
|
||||||
|
typeinference_helper.assume_init()
|
||||||
|
}
|
||||||
|
#[cfg(not(feature="no_unsound_assume_init"))] { crate::base::Matrix::new_uninitialized_generic($nrows, $ncols).assume_init() }
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Scalar, R: Dim, C: Dim> UninitMatrix<T, R, C>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, R, C>,
|
||||||
|
{
|
||||||
|
pub fn uninit(nrows: R, ncols: C) -> Self {
|
||||||
|
// SAFETY: this is OK because the dimension automatically match the storage
|
||||||
|
// because we are building an owned storage.
|
||||||
|
unsafe {
|
||||||
|
Self::from_data_statically_unchecked(DefaultAllocator::allocate_uninit(nrows, ncols))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// # Generic constructors
|
/// # Generic constructors
|
||||||
/// This set of matrix and vector construction functions are all generic
|
/// This set of matrix and vector construction functions are all generic
|
||||||
|
@ -29,16 +63,23 @@ use crate::base::{
|
||||||
/// the dimension as inputs.
|
/// the dimension as inputs.
|
||||||
///
|
///
|
||||||
/// These functions should only be used when working on dimension-generic code.
|
/// These functions should only be used when working on dimension-generic code.
|
||||||
impl<T, R: Dim, C: Dim> OMatrix<T, R, C>
|
impl<T: Scalar, R: Dim, C: Dim> OMatrix<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C>,
|
DefaultAllocator: Allocator<T, R, C>,
|
||||||
{
|
{
|
||||||
|
/// Creates a new uninitialized matrix.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// If the matrix has a compile-time dimension, this panics
|
||||||
|
/// if `nrows != R::to_usize()` or `ncols != C::to_usize()`.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> MaybeUninit<Self> {
|
||||||
|
Self::from_uninitialized_data(DefaultAllocator::allocate_uninitialized(nrows, ncols))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a matrix with all its elements set to `elem`.
|
/// Creates a matrix with all its elements set to `elem`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self
|
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
let len = nrows.value() * ncols.value();
|
let len = nrows.value() * ncols.value();
|
||||||
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
|
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
|
||||||
}
|
}
|
||||||
|
@ -47,10 +88,7 @@ where
|
||||||
///
|
///
|
||||||
/// Same as `from_element_generic`.
|
/// Same as `from_element_generic`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self
|
pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
let len = nrows.value() * ncols.value();
|
let len = nrows.value() * ncols.value();
|
||||||
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
|
Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len))
|
||||||
}
|
}
|
||||||
|
@ -59,7 +97,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zeros_generic(nrows: R, ncols: C) -> Self
|
pub fn zeros_generic(nrows: R, ncols: C) -> Self
|
||||||
where
|
where
|
||||||
T: Zero + Clone,
|
T: Zero,
|
||||||
{
|
{
|
||||||
Self::from_element_generic(nrows, ncols, T::zero())
|
Self::from_element_generic(nrows, ncols, T::zero())
|
||||||
}
|
}
|
||||||
|
@ -79,37 +117,32 @@ where
|
||||||
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
|
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
|
||||||
/// row-by-row.
|
/// row-by-row.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self
|
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
assert!(
|
assert!(
|
||||||
slice.len() == nrows.value() * ncols.value(),
|
slice.len() == nrows.value() * ncols.value(),
|
||||||
"Matrix init. error: the slice did not contain the right number of elements."
|
"Matrix init. error: the slice did not contain the right number of elements."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut res = Self::new_uninitialized_generic(nrows, ncols);
|
let mut res = Matrix::uninit(nrows, ncols);
|
||||||
let mut iter = slice.iter();
|
let mut iter = slice.iter();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
for i in 0..nrows.value() {
|
for i in 0..nrows.value() {
|
||||||
for j in 0..ncols.value() {
|
for j in 0..ncols.value() {
|
||||||
unsafe {
|
*res.get_unchecked_mut((i, j)) =
|
||||||
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone());
|
MaybeUninit::new(iter.next().unwrap().inlined_clone())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
// SAFETY: the result has been fully initialized above.
|
||||||
unsafe { res.assume_init() }
|
res.assume_init()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a matrix with its elements filled with the components provided by a slice. The
|
/// Creates a matrix with its elements filled with the components provided by a slice. The
|
||||||
/// components must have the same layout as the matrix data storage (i.e. column-major).
|
/// components must have the same layout as the matrix data storage (i.e. column-major).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self
|
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
Self::from_iterator_generic(nrows, ncols, slice.iter().cloned())
|
Self::from_iterator_generic(nrows, ncols, slice.iter().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,18 +153,18 @@ where
|
||||||
where
|
where
|
||||||
F: FnMut(usize, usize) -> T,
|
F: FnMut(usize, usize) -> T,
|
||||||
{
|
{
|
||||||
let mut res = Self::new_uninitialized_generic(nrows, ncols);
|
let mut res = Matrix::uninit(nrows, ncols);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
for j in 0..ncols.value() {
|
for j in 0..ncols.value() {
|
||||||
for i in 0..nrows.value() {
|
for i in 0..nrows.value() {
|
||||||
unsafe {
|
|
||||||
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
|
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
// SAFETY: the result has been fully initialized above.
|
||||||
unsafe { res.assume_init() }
|
res.assume_init()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new identity matrix.
|
/// Creates a new identity matrix.
|
||||||
|
@ -141,7 +174,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn identity_generic(nrows: R, ncols: C) -> Self
|
pub fn identity_generic(nrows: R, ncols: C) -> Self
|
||||||
where
|
where
|
||||||
T: Zero + One + Scalar,
|
T: Zero + One,
|
||||||
{
|
{
|
||||||
Self::from_diagonal_element_generic(nrows, ncols, T::one())
|
Self::from_diagonal_element_generic(nrows, ncols, T::one())
|
||||||
}
|
}
|
||||||
|
@ -153,7 +186,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self
|
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self
|
||||||
where
|
where
|
||||||
T: Zero + One + Scalar,
|
T: Zero + One,
|
||||||
{
|
{
|
||||||
let mut res = Self::zeros_generic(nrows, ncols);
|
let mut res = Self::zeros_generic(nrows, ncols);
|
||||||
|
|
||||||
|
@ -171,7 +204,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self
|
pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self
|
||||||
where
|
where
|
||||||
T: Zero + Clone,
|
T: Zero,
|
||||||
{
|
{
|
||||||
let mut res = Self::zeros_generic(nrows, ncols);
|
let mut res = Self::zeros_generic(nrows, ncols);
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -180,7 +213,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() }
|
unsafe { *res.get_unchecked_mut((i, i)) = elt.inlined_clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
|
@ -205,8 +238,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
|
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
|
||||||
where
|
where
|
||||||
T: Clone,
|
SB: RawStorage<T, Const<1>, C>,
|
||||||
SB: Storage<T, Const<1>, C>,
|
|
||||||
{
|
{
|
||||||
assert!(!rows.is_empty(), "At least one row must be given.");
|
assert!(!rows.is_empty(), "At least one row must be given.");
|
||||||
let nrows = R::try_to_usize().unwrap_or_else(|| rows.len());
|
let nrows = R::try_to_usize().unwrap_or_else(|| rows.len());
|
||||||
|
@ -225,7 +257,7 @@ where
|
||||||
|
|
||||||
// TODO: optimize that.
|
// TODO: optimize that.
|
||||||
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
|
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
|
||||||
rows[i][(0, j)].clone()
|
rows[i][(0, j)].inlined_clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,8 +280,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
|
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
|
||||||
where
|
where
|
||||||
T: Clone,
|
SB: RawStorage<T, R>,
|
||||||
SB: Storage<T, R>,
|
|
||||||
{
|
{
|
||||||
assert!(!columns.is_empty(), "At least one column must be given.");
|
assert!(!columns.is_empty(), "At least one column must be given.");
|
||||||
let ncols = C::try_to_usize().unwrap_or_else(|| columns.len());
|
let ncols = C::try_to_usize().unwrap_or_else(|| columns.len());
|
||||||
|
@ -268,7 +299,7 @@ where
|
||||||
|
|
||||||
// TODO: optimize that.
|
// TODO: optimize that.
|
||||||
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
|
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
|
||||||
columns[j][i].clone()
|
columns[j][i].inlined_clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +352,7 @@ where
|
||||||
|
|
||||||
impl<T, D: Dim> OMatrix<T, D, D>
|
impl<T, D: Dim> OMatrix<T, D, D>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
|
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
|
||||||
|
@ -342,11 +374,11 @@ where
|
||||||
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0);
|
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_diagonal<SB: Storage<T, D>>(diag: &Vector<T, D, SB>) -> Self
|
pub fn from_diagonal<SB: RawStorage<T, D>>(diag: &Vector<T, D, SB>) -> Self
|
||||||
where
|
where
|
||||||
T: Zero + Scalar,
|
T: Zero,
|
||||||
{
|
{
|
||||||
let (dim, _) = diag.data.shape();
|
let (dim, _) = diag.shape_generic();
|
||||||
let mut res = Self::zeros_generic(dim, dim);
|
let mut res = Self::zeros_generic(dim, dim);
|
||||||
|
|
||||||
for i in 0..diag.len() {
|
for i in 0..diag.len() {
|
||||||
|
@ -366,6 +398,12 @@ where
|
||||||
*/
|
*/
|
||||||
macro_rules! impl_constructors(
|
macro_rules! impl_constructors(
|
||||||
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
||||||
|
/// Creates a new uninitialized matrix or vector.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn new_uninitialized($($args: usize),*) -> MaybeUninit<Self> {
|
||||||
|
Self::new_uninitialized_generic($($gargs),*)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a matrix or vector with all its elements set to `elem`.
|
/// Creates a matrix or vector with all its elements set to `elem`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -387,10 +425,7 @@ macro_rules! impl_constructors(
|
||||||
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
|
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_element($($args: usize,)* elem: T) -> Self
|
pub fn from_element($($args: usize,)* elem: T) -> Self {
|
||||||
where
|
|
||||||
T: Clone
|
|
||||||
{
|
|
||||||
Self::from_element_generic($($gargs, )* elem)
|
Self::from_element_generic($($gargs, )* elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,10 +452,7 @@ macro_rules! impl_constructors(
|
||||||
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
|
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn repeat($($args: usize,)* elem: T) -> Self
|
pub fn repeat($($args: usize,)* elem: T) -> Self {
|
||||||
where
|
|
||||||
T: Clone
|
|
||||||
{
|
|
||||||
Self::repeat_generic($($gargs, )* elem)
|
Self::repeat_generic($($gargs, )* elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,9 +478,7 @@ macro_rules! impl_constructors(
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zeros($($args: usize),*) -> Self
|
pub fn zeros($($args: usize),*) -> Self
|
||||||
where
|
where T: Zero {
|
||||||
T: Zero + Clone
|
|
||||||
{
|
|
||||||
Self::zeros_generic($($gargs),*)
|
Self::zeros_generic($($gargs),*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +534,8 @@ macro_rules! impl_constructors(
|
||||||
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_fn<F: FnMut(usize, usize) -> T>($($args: usize,)* f: F) -> Self {
|
pub fn from_fn<F>($($args: usize,)* f: F) -> Self
|
||||||
|
where F: FnMut(usize, usize) -> T {
|
||||||
Self::from_fn_generic($($gargs, )* f)
|
Self::from_fn_generic($($gargs, )* f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,9 +559,7 @@ macro_rules! impl_constructors(
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn identity($($args: usize,)*) -> Self
|
pub fn identity($($args: usize,)*) -> Self
|
||||||
where
|
where T: Zero + One {
|
||||||
T: Zero + One + Scalar
|
|
||||||
{
|
|
||||||
Self::identity_generic($($gargs),* )
|
Self::identity_generic($($gargs),* )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,9 +582,7 @@ macro_rules! impl_constructors(
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self
|
pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self
|
||||||
where
|
where T: Zero + One {
|
||||||
T: Zero + One + Scalar
|
|
||||||
{
|
|
||||||
Self::from_diagonal_element_generic($($gargs, )* elt)
|
Self::from_diagonal_element_generic($($gargs, )* elt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,9 +609,7 @@ macro_rules! impl_constructors(
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self
|
pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self
|
||||||
where
|
where T: Zero {
|
||||||
T: Zero + Scalar
|
|
||||||
{
|
|
||||||
Self::from_partial_diagonal_generic($($gargs, )* elts)
|
Self::from_partial_diagonal_generic($($gargs, )* elts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,16 +628,14 @@ macro_rules! impl_constructors(
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "rand")]
|
#[cfg(feature = "rand")]
|
||||||
pub fn new_random($($args: usize),*) -> Self
|
pub fn new_random($($args: usize),*) -> Self
|
||||||
where
|
where Standard: Distribution<T> {
|
||||||
Standard: Distribution<T>
|
|
||||||
{
|
|
||||||
Self::new_random_generic($($gargs),*)
|
Self::new_random_generic($($gargs),*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/// # Constructors of statically-sized vectors or statically-sized matrices
|
/// # Constructors of statically-sized vectors or statically-sized matrices
|
||||||
impl<T, R: DimName, C: DimName> OMatrix<T, R, C>
|
impl<T: Scalar, R: DimName, C: DimName> OMatrix<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C>,
|
DefaultAllocator: Allocator<T, R, C>,
|
||||||
{
|
{
|
||||||
|
@ -623,19 +646,8 @@ where
|
||||||
); // Arguments for non-generic constructors.
|
); // Arguments for non-generic constructors.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: DimName, C: DimName> OMatrix<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C>,
|
|
||||||
{
|
|
||||||
/// Creates a new uninitialized matrix or vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_uninitialized() -> OMatrix<MaybeUninit<T>, R, C> {
|
|
||||||
Self::new_uninitialized_generic(R::name(), C::name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Constructors of matrices with a dynamic number of columns
|
/// # Constructors of matrices with a dynamic number of columns
|
||||||
impl<T, R: DimName> OMatrix<T, R, Dynamic>
|
impl<T: Scalar, R: DimName> OMatrix<T, R, Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, Dynamic>,
|
DefaultAllocator: Allocator<T, R, Dynamic>,
|
||||||
{
|
{
|
||||||
|
@ -645,19 +657,8 @@ where
|
||||||
ncols);
|
ncols);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: DimName> OMatrix<T, R, Dynamic>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, Dynamic>,
|
|
||||||
{
|
|
||||||
/// Creates a new uninitialized matrix or vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_uninitialized(ncols: usize) -> OMatrix<MaybeUninit<T>, R, Dynamic> {
|
|
||||||
Self::new_uninitialized_generic(R::name(), Dynamic::new(ncols))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Constructors of dynamic vectors and matrices with a dynamic number of rows
|
/// # Constructors of dynamic vectors and matrices with a dynamic number of rows
|
||||||
impl<T, C: DimName> OMatrix<T, Dynamic, C>
|
impl<T: Scalar, C: DimName> OMatrix<T, Dynamic, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, Dynamic, C>,
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
{
|
{
|
||||||
|
@ -667,19 +668,8 @@ where
|
||||||
nrows);
|
nrows);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C: DimName> OMatrix<T, Dynamic, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, Dynamic, C>,
|
|
||||||
{
|
|
||||||
/// Creates a new uninitialized matrix or vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_uninitialized(nrows: usize) -> OMatrix<MaybeUninit<T>, Dynamic, C> {
|
|
||||||
Self::new_uninitialized_generic(Dynamic::new(nrows), C::name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Constructors of fully dynamic matrices
|
/// # Constructors of fully dynamic matrices
|
||||||
impl<T> OMatrix<T, Dynamic, Dynamic>
|
impl<T: Scalar> OMatrix<T, Dynamic, Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
|
DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
|
||||||
{
|
{
|
||||||
|
@ -689,20 +679,6 @@ where
|
||||||
nrows, ncols);
|
nrows, ncols);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OMatrix<T, Dynamic, Dynamic>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, Dynamic, Dynamic>,
|
|
||||||
{
|
|
||||||
/// Creates a new uninitialized matrix or vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_uninitialized(
|
|
||||||
nrows: usize,
|
|
||||||
ncols: usize,
|
|
||||||
) -> OMatrix<MaybeUninit<T>, Dynamic, Dynamic> {
|
|
||||||
Self::new_uninitialized_generic(Dynamic::new(nrows), Dynamic::new(ncols))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Constructors that don't necessarily require all dimensions
|
* Constructors that don't necessarily require all dimensions
|
||||||
|
@ -711,10 +687,8 @@ where
|
||||||
*/
|
*/
|
||||||
macro_rules! impl_constructors_from_data(
|
macro_rules! impl_constructors_from_data(
|
||||||
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
||||||
impl<T, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*>
|
impl<T: Scalar, $($DimIdent: $DimBound, )*> OMatrix<T $(, $Dims)*>
|
||||||
where
|
where DefaultAllocator: Allocator<T $(, $Dims)*> {
|
||||||
DefaultAllocator: Allocator<T $(, $Dims)*>
|
|
||||||
{
|
|
||||||
/// Creates a matrix with its elements filled with the components provided by a slice
|
/// Creates a matrix with its elements filled with the components provided by a slice
|
||||||
/// in row-major order.
|
/// in row-major order.
|
||||||
///
|
///
|
||||||
|
@ -741,10 +715,7 @@ macro_rules! impl_constructors_from_data(
|
||||||
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self
|
pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self {
|
||||||
where
|
|
||||||
T: Clone
|
|
||||||
{
|
|
||||||
Self::from_row_slice_generic($($gargs, )* $data)
|
Self::from_row_slice_generic($($gargs, )* $data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,10 +742,7 @@ macro_rules! impl_constructors_from_data(
|
||||||
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self
|
pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self {
|
||||||
where
|
|
||||||
T: Clone
|
|
||||||
{
|
|
||||||
Self::from_column_slice_generic($($gargs, )* $data)
|
Self::from_column_slice_generic($($gargs, )* $data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,7 +845,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rand-no-std")]
|
#[cfg(feature = "rand-no-std")]
|
||||||
impl<T, R: Dim, C: Dim> Distribution<OMatrix<T, R, C>> for Standard
|
impl<T: Scalar, R: Dim, C: Dim> Distribution<OMatrix<T, R, C>> for Standard
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C>,
|
DefaultAllocator: Allocator<T, R, C>,
|
||||||
Standard: Distribution<T>,
|
Standard: Distribution<T>,
|
||||||
|
@ -892,10 +860,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<T, R: Dim, C: Dim> Arbitrary for OMatrix<T, R, C>
|
impl<T, R, C> Arbitrary for OMatrix<T, R, C>
|
||||||
where
|
where
|
||||||
T: Arbitrary + Send,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
T: Scalar + Arbitrary + Send,
|
||||||
DefaultAllocator: Allocator<T, R, C>,
|
DefaultAllocator: Allocator<T, R, C>,
|
||||||
|
Owned<T, R, C>: Clone + Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use crate::base::dimension::{Const, Dim, DimName, Dynamic};
|
use crate::base::dimension::{Const, Dim, DimName, Dynamic};
|
||||||
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
|
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
|
||||||
use crate::base::{MatrixSlice, MatrixSliceMutMN};
|
use crate::base::{MatrixSlice, MatrixSliceMutMN, Scalar};
|
||||||
|
|
||||||
use num_rational::Ratio;
|
use num_rational::Ratio;
|
||||||
|
|
||||||
/// # Creating matrix slices from `&[T]`
|
/// # Creating matrix slices from `&[T]`
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSlice<'a, T, R, C, RStride, CStride> {
|
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
|
MatrixSlice<'a, T, R, C, RStride, CStride>
|
||||||
|
{
|
||||||
/// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
|
/// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -55,7 +57,7 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> MatrixSlice<'a, T, R, C,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
|
impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
|
||||||
/// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
|
/// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -85,7 +87,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
|
||||||
|
|
||||||
macro_rules! impl_constructors(
|
macro_rules! impl_constructors(
|
||||||
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
||||||
impl<'a, T, $($DimIdent: $DimBound),*> MatrixSlice<'a, T, $($Dims),*> {
|
impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSlice<'a, T, $($Dims),*> {
|
||||||
/// Creates a new matrix slice from the given data array.
|
/// Creates a new matrix slice from the given data array.
|
||||||
///
|
///
|
||||||
/// Panics if `data` does not contain enough elements.
|
/// Panics if `data` does not contain enough elements.
|
||||||
|
@ -101,7 +103,7 @@ macro_rules! impl_constructors(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> {
|
impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> {
|
||||||
/// Creates a new matrix slice with the specified strides from the given data array.
|
/// Creates a new matrix slice with the specified strides from the given data array.
|
||||||
///
|
///
|
||||||
/// Panics if `data` does not contain enough elements.
|
/// Panics if `data` does not contain enough elements.
|
||||||
|
@ -141,7 +143,7 @@ impl_constructors!(Dynamic, Dynamic;
|
||||||
nrows, ncols);
|
nrows, ncols);
|
||||||
|
|
||||||
/// # Creating mutable matrix slices from `&mut [T]`
|
/// # Creating mutable matrix slices from `&mut [T]`
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
MatrixSliceMutMN<'a, T, R, C, RStride, CStride>
|
MatrixSliceMutMN<'a, T, R, C, RStride, CStride>
|
||||||
{
|
{
|
||||||
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
|
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
|
||||||
|
@ -215,7 +217,7 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
|
impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
|
||||||
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
|
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -245,7 +247,7 @@ impl<'a, T, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
|
||||||
|
|
||||||
macro_rules! impl_constructors_mut(
|
macro_rules! impl_constructors_mut(
|
||||||
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
||||||
impl<'a, T, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> {
|
impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> {
|
||||||
/// Creates a new mutable matrix slice from the given data array.
|
/// Creates a new mutable matrix slice from the given data array.
|
||||||
///
|
///
|
||||||
/// Panics if `data` does not contain enough elements.
|
/// Panics if `data` does not contain enough elements.
|
||||||
|
@ -261,7 +263,7 @@ macro_rules! impl_constructors_mut(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> {
|
impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> {
|
||||||
/// Creates a new mutable matrix slice with the specified strides from the given data array.
|
/// Creates a new mutable matrix slice with the specified strides from the given data array.
|
||||||
///
|
///
|
||||||
/// Panics if `data` does not contain enough elements.
|
/// Panics if `data` does not contain enough elements.
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
|
||||||
use std::convert::{AsMut, AsRef, From, Into};
|
|
||||||
use std::mem::{self, ManuallyDrop, MaybeUninit};
|
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use simba::scalar::{SubsetOf, SupersetOf};
|
use simba::scalar::{SubsetOf, SupersetOf};
|
||||||
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
|
use std::convert::{AsMut, AsRef, From, Into};
|
||||||
|
|
||||||
use simba::simd::{PrimitiveSimdValue, SimdValue};
|
use simba::simd::{PrimitiveSimdValue, SimdValue};
|
||||||
|
|
||||||
|
@ -16,7 +14,7 @@ use crate::base::dimension::{
|
||||||
Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
|
Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
|
||||||
};
|
};
|
||||||
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
||||||
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
|
use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
|
ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
|
||||||
MatrixSliceMut, OMatrix, Scalar,
|
MatrixSliceMut, OMatrix, Scalar,
|
||||||
|
@ -26,12 +24,17 @@ use crate::base::{DVector, VecStorage};
|
||||||
use crate::base::{SliceStorage, SliceStorageMut};
|
use crate::base::{SliceStorage, SliceStorageMut};
|
||||||
use crate::constraint::DimEq;
|
use crate::constraint::DimEq;
|
||||||
use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector};
|
use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
// TODO: too bad this won't work for slice conversions.
|
// TODO: too bad this won't work for slice conversions.
|
||||||
impl<T1, T2, R1: Dim, C1: Dim, R2: Dim, C2: Dim> SubsetOf<OMatrix<T2, R2, C2>>
|
impl<T1, T2, R1, C1, R2, C2> SubsetOf<OMatrix<T2, R2, C2>> for OMatrix<T1, R1, C1>
|
||||||
for OMatrix<T1, R1, C1>
|
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
T1: Scalar,
|
||||||
|
T2: Scalar + SupersetOf<T1>,
|
||||||
DefaultAllocator:
|
DefaultAllocator:
|
||||||
Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>,
|
Allocator<T2, R2, C2> + Allocator<T1, R1, C1> + SameShapeAllocator<T1, R1, C1, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
|
@ -41,11 +44,11 @@ where
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
let nrows2 = R2::from_usize(nrows);
|
let nrows2 = R2::from_usize(nrows);
|
||||||
let ncols2 = C2::from_usize(ncols);
|
let ncols2 = C2::from_usize(ncols);
|
||||||
|
let mut res = Matrix::uninit(nrows2, ncols2);
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows2, ncols2);
|
|
||||||
|
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
|
// Safety: all indices are in range.
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked_mut((i, j)) =
|
*res.get_unchecked_mut((i, j)) =
|
||||||
MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
|
MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
|
||||||
|
@ -53,7 +56,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
// Safety: res is now fully initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,23 +70,25 @@ where
|
||||||
let (nrows2, ncols2) = m.shape();
|
let (nrows2, ncols2) = m.shape();
|
||||||
let nrows = R1::from_usize(nrows2);
|
let nrows = R1::from_usize(nrows2);
|
||||||
let ncols = C1::from_usize(ncols2);
|
let ncols = C1::from_usize(ncols2);
|
||||||
|
let mut res = Matrix::uninit(nrows, ncols);
|
||||||
|
|
||||||
let mut res = OMatrix::new_uninitialized_generic(nrows, ncols);
|
|
||||||
for i in 0..nrows2 {
|
for i in 0..nrows2 {
|
||||||
for j in 0..ncols2 {
|
for j in 0..ncols2 {
|
||||||
|
// Safety: all indices are in range.
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked_mut((i, j)) =
|
*res.get_unchecked_mut((i, j)) =
|
||||||
MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked());
|
MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all entries have been initialized.
|
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Matrix<T, R, C, S> {
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> IntoIterator
|
||||||
|
for &'a Matrix<T, R, C, S>
|
||||||
|
{
|
||||||
type Item = &'a T;
|
type Item = &'a T;
|
||||||
type IntoIter = MatrixIter<'a, T, R, C, S>;
|
type IntoIter = MatrixIter<'a, T, R, C, S>;
|
||||||
|
|
||||||
|
@ -93,7 +98,9 @@ impl<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Matrix<T,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IntoIterator for &'a mut Matrix<T, R, C, S> {
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IntoIterator
|
||||||
|
for &'a mut Matrix<T, R, C, S>
|
||||||
|
{
|
||||||
type Item = &'a mut T;
|
type Item = &'a mut T;
|
||||||
type IntoIter = MatrixIterMut<'a, T, R, C, S>;
|
type IntoIter = MatrixIterMut<'a, T, R, C, S>;
|
||||||
|
|
||||||
|
@ -103,35 +110,32 @@ impl<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IntoIterator for &'a mut Mat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<[T; D]> for SVector<T, D> {
|
impl<T: Scalar, const D: usize> From<[T; D]> for SVector<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [T; D]) -> Self {
|
fn from(arr: [T; D]) -> Self {
|
||||||
Self::from_data(ArrayStorage([arr; 1]))
|
unsafe { Self::from_data_statically_unchecked(ArrayStorage([arr; 1])) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<SVector<T, D>> for [T; D] {
|
impl<T: Scalar, const D: usize> From<SVector<T, D>> for [T; D] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(vec: SVector<T, D>) -> Self {
|
fn from(vec: SVector<T, D>) -> Self {
|
||||||
let data = ManuallyDrop::new(vec.data.0);
|
// TODO: unfortunately, we must clone because we can move out of an array.
|
||||||
// Safety: [[T; D]; 1] always has the same data layout as [T; D].
|
vec.data.0[0].clone()
|
||||||
let res = unsafe { (data.as_ptr() as *const [_; D]).read() };
|
|
||||||
mem::forget(data);
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, const D: usize> From<[T; D]> for RowSVector<T, D>
|
impl<T: Scalar, const D: usize> From<[T; D]> for RowSVector<T, D>
|
||||||
where
|
where
|
||||||
Const<D>: IsNotStaticOne,
|
Const<D>: IsNotStaticOne,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [T; D]) -> Self {
|
fn from(arr: [T; D]) -> Self {
|
||||||
SVector::<T, D>::from(arr).transpose_into()
|
SVector::<T, D>::from(arr).transpose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, const D: usize> From<RowSVector<T, D>> for [T; D]
|
impl<T: Scalar, const D: usize> From<RowSVector<T, D>> for [T; D]
|
||||||
where
|
where
|
||||||
Const<D>: IsNotStaticOne,
|
Const<D>: IsNotStaticOne,
|
||||||
{
|
{
|
||||||
|
@ -144,10 +148,11 @@ where
|
||||||
macro_rules! impl_from_into_asref_1D(
|
macro_rules! impl_from_into_asref_1D(
|
||||||
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
|
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
|
||||||
impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
|
impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
|
||||||
where
|
where T: Scalar,
|
||||||
S: ContiguousStorage<T, $NRows, $NCols> {
|
S: RawStorage<T, $NRows, $NCols> + IsContiguous {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &[T; $SZ] {
|
fn as_ref(&self) -> &[T; $SZ] {
|
||||||
|
// Safety: this is OK thanks to the IsContiguous trait.
|
||||||
unsafe {
|
unsafe {
|
||||||
&*(self.data.ptr() as *const [T; $SZ])
|
&*(self.data.ptr() as *const [T; $SZ])
|
||||||
}
|
}
|
||||||
|
@ -155,10 +160,11 @@ macro_rules! impl_from_into_asref_1D(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
|
impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
|
||||||
where
|
where T: Scalar,
|
||||||
S: ContiguousStorageMut<T, $NRows, $NCols> {
|
S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> &mut [T; $SZ] {
|
fn as_mut(&mut self) -> &mut [T; $SZ] {
|
||||||
|
// Safety: this is OK thanks to the IsContiguous trait.
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *(self.data.ptr_mut() as *mut [T; $SZ])
|
&mut *(self.data.ptr_mut() as *mut [T; $SZ])
|
||||||
}
|
}
|
||||||
|
@ -182,14 +188,14 @@ impl_from_into_asref_1D!(
|
||||||
(U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16;
|
(U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16;
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<T, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T, R, C> {
|
impl<T: Scalar, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T, R, C> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [[T; R]; C]) -> Self {
|
fn from(arr: [[T; R]; C]) -> Self {
|
||||||
Self::from_data(ArrayStorage(arr))
|
unsafe { Self::from_data_statically_unchecked(ArrayStorage(arr)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] {
|
impl<T: Scalar, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(vec: SMatrix<T, R, C>) -> Self {
|
fn from(vec: SMatrix<T, R, C>) -> Self {
|
||||||
vec.data.0
|
vec.data.0
|
||||||
|
@ -203,20 +209,22 @@ macro_rules! impl_from_into_asref_borrow_2D(
|
||||||
($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
|
($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
|
||||||
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
|
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
|
||||||
) => {
|
) => {
|
||||||
impl<T, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
|
impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
|
||||||
where S: ContiguousStorage<T, $NRows, $NCols> {
|
where S: RawStorage<T, $NRows, $NCols> + IsContiguous {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
|
fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
|
||||||
|
// Safety: OK thanks to the IsContiguous trait.
|
||||||
unsafe {
|
unsafe {
|
||||||
&*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
|
&*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
|
impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
|
||||||
where S: ContiguousStorageMut<T, $NRows, $NCols> {
|
where S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
|
fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
|
||||||
|
// Safety: OK thanks to the IsContiguous trait.
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
|
&mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
|
||||||
}
|
}
|
||||||
|
@ -244,9 +252,13 @@ impl_from_into_asref_borrow_2D!(
|
||||||
(U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6);
|
(U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6);
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
|
impl<'a, T, RStride, CStride, const R: usize, const C: usize>
|
||||||
From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>>
|
From<MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>>
|
||||||
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
|
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSlice<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
|
@ -254,9 +266,13 @@ impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
|
impl<'a, T, C, RStride, CStride> From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
|
||||||
From<MatrixSlice<'a, T, Dynamic, C, RStride, CStride>>
|
|
||||||
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
|
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
C: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
|
@ -264,18 +280,26 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim>
|
impl<'a, T, R, RStride, CStride> From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
|
||||||
From<MatrixSlice<'a, T, R, Dynamic, RStride, CStride>>
|
|
||||||
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
|
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R: DimName,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
|
impl<'a, T, RStride, CStride, const R: usize, const C: usize>
|
||||||
From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>>
|
From<MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>>
|
||||||
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
|
for Matrix<T, Const<R>, Const<C>, ArrayStorage<T, R, C>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSliceMut<'a, T, Const<R>, Const<C>, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
|
@ -283,9 +307,13 @@ impl<'a, T: Clone, RStride: Dim, CStride: Dim, const R: usize, const C: usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
|
impl<'a, T, C, RStride, CStride> From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
|
||||||
From<MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>>
|
|
||||||
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
|
for Matrix<T, Dynamic, C, VecStorage<T, Dynamic, C>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
C: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
|
@ -293,26 +321,37 @@ impl<'a, T: Clone, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, T: Clone, R: DimName, RStride: Dim, CStride: Dim>
|
impl<'a, T, R, RStride, CStride> From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
|
||||||
From<MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>>
|
|
||||||
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
|
for Matrix<T, R, Dynamic, VecStorage<T, R, Dynamic>>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R: DimName,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self {
|
fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self {
|
||||||
matrix_slice.into_owned()
|
matrix_slice.into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
|
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix<T, R, C, S>>
|
||||||
From<&'a Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
|
for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
|
||||||
where
|
where
|
||||||
S: Storage<T, R, C>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
RSlice: Dim,
|
||||||
|
CSlice: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
ShapeConstraint: DimEq<R, RSlice>
|
ShapeConstraint: DimEq<R, RSlice>
|
||||||
+ DimEq<C, CSlice>
|
+ DimEq<C, CSlice>
|
||||||
+ DimEq<RStride, S::RStride>
|
+ DimEq<RStride, S::RStride>
|
||||||
+ DimEq<CStride, S::CStride>,
|
+ DimEq<CStride, S::CStride>,
|
||||||
{
|
{
|
||||||
fn from(m: &'a Matrix<T, R, C, S>) -> Self {
|
fn from(m: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
let (row, col) = m.data.shape();
|
let (row, col) = m.shape_generic();
|
||||||
let row_slice = RSlice::from_usize(row.value());
|
let row_slice = RSlice::from_usize(row.value());
|
||||||
let col_slice = CSlice::from_usize(col.value());
|
let col_slice = CSlice::from_usize(col.value());
|
||||||
|
|
||||||
|
@ -327,23 +366,29 @@ where
|
||||||
(row_slice, col_slice),
|
(row_slice, col_slice),
|
||||||
(rstride_slice, cstride_slice),
|
(rstride_slice, cstride_slice),
|
||||||
);
|
);
|
||||||
|
Matrix::from_data_statically_unchecked(data)
|
||||||
Self::from_data(data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
|
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
|
||||||
From<&'a mut Matrix<T, R, C, S>> for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
|
for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride>
|
||||||
where
|
where
|
||||||
S: Storage<T, R, C>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
RSlice: Dim,
|
||||||
|
CSlice: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
ShapeConstraint: DimEq<R, RSlice>
|
ShapeConstraint: DimEq<R, RSlice>
|
||||||
+ DimEq<C, CSlice>
|
+ DimEq<C, CSlice>
|
||||||
+ DimEq<RStride, S::RStride>
|
+ DimEq<RStride, S::RStride>
|
||||||
+ DimEq<CStride, S::CStride>,
|
+ DimEq<CStride, S::CStride>,
|
||||||
{
|
{
|
||||||
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
|
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
|
||||||
let (row, col) = m.data.shape();
|
let (row, col) = m.shape_generic();
|
||||||
let row_slice = RSlice::from_usize(row.value());
|
let row_slice = RSlice::from_usize(row.value());
|
||||||
let col_slice = CSlice::from_usize(col.value());
|
let col_slice = CSlice::from_usize(col.value());
|
||||||
|
|
||||||
|
@ -358,23 +403,29 @@ where
|
||||||
(row_slice, col_slice),
|
(row_slice, col_slice),
|
||||||
(rstride_slice, cstride_slice),
|
(rstride_slice, cstride_slice),
|
||||||
);
|
);
|
||||||
|
Matrix::from_data_statically_unchecked(data)
|
||||||
Matrix::from_data(data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RSlice: Dim, CSlice: Dim, RStride: Dim, CStride: Dim, S>
|
impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix<T, R, C, S>>
|
||||||
From<&'a mut Matrix<T, R, C, S>> for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
|
for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride>
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
RSlice: Dim,
|
||||||
|
CSlice: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
|
S: RawStorageMut<T, R, C>,
|
||||||
ShapeConstraint: DimEq<R, RSlice>
|
ShapeConstraint: DimEq<R, RSlice>
|
||||||
+ DimEq<C, CSlice>
|
+ DimEq<C, CSlice>
|
||||||
+ DimEq<RStride, S::RStride>
|
+ DimEq<RStride, S::RStride>
|
||||||
+ DimEq<CStride, S::CStride>,
|
+ DimEq<CStride, S::CStride>,
|
||||||
{
|
{
|
||||||
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
|
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
|
||||||
let (row, col) = m.data.shape();
|
let (row, col) = m.shape_generic();
|
||||||
let row_slice = RSlice::from_usize(row.value());
|
let row_slice = RSlice::from_usize(row.value());
|
||||||
let col_slice = CSlice::from_usize(col.value());
|
let col_slice = CSlice::from_usize(col.value());
|
||||||
|
|
||||||
|
@ -389,22 +440,21 @@ where
|
||||||
(row_slice, col_slice),
|
(row_slice, col_slice),
|
||||||
(rstride_slice, cstride_slice),
|
(rstride_slice, cstride_slice),
|
||||||
);
|
);
|
||||||
|
Matrix::from_data_statically_unchecked(data)
|
||||||
Matrix::from_data(data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, T> From<Vec<T>> for DVector<T> {
|
impl<'a, T: Scalar> From<Vec<T>> for DVector<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(vec: Vec<T>) -> Self {
|
fn from(vec: Vec<T>) -> Self {
|
||||||
Self::from_vec(vec)
|
Self::from_vec(vec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> From<&'a Matrix<T, R, C, S>>
|
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage<T, R, C> + IsContiguous>
|
||||||
for &'a [T]
|
From<&'a Matrix<T, R, C, S>> for &'a [T]
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
|
@ -412,8 +462,8 @@ impl<'a, T, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> From<&'a Matrix<T, R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> From<&'a mut Matrix<T, R, C, S>>
|
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut<T, R, C> + IsContiguous>
|
||||||
for &'a mut [T]
|
From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self {
|
fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self {
|
||||||
|
@ -421,27 +471,27 @@ impl<'a, T, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> From<&'a mut Matri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> From<&'a [T]> for DVectorSlice<'a, T> {
|
impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(slice: &'a [T]) -> Self {
|
fn from(slice: &'a [T]) -> Self {
|
||||||
Self::from_slice(slice, slice.len())
|
Self::from_slice(slice, slice.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> From<DVectorSlice<'a, T>> for &'a [T] {
|
impl<'a, T: Scalar> From<DVectorSlice<'a, T>> for &'a [T] {
|
||||||
fn from(vec: DVectorSlice<'a, T>) -> &'a [T] {
|
fn from(vec: DVectorSlice<'a, T>) -> &'a [T] {
|
||||||
vec.data.into_slice()
|
vec.data.into_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
|
impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(slice: &'a mut [T]) -> Self {
|
fn from(slice: &'a mut [T]) -> Self {
|
||||||
Self::from_slice(slice, slice.len())
|
Self::from_slice(slice, slice.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> From<DVectorSliceMut<'a, T>> for &'a mut [T] {
|
impl<'a, T: Scalar> From<DVectorSliceMut<'a, T>> for &'a mut [T] {
|
||||||
fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] {
|
fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] {
|
||||||
vec.data.into_slice_mut()
|
vec.data.into_slice_mut()
|
||||||
}
|
}
|
||||||
|
@ -456,7 +506,7 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self {
|
fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self {
|
||||||
let (nrows, ncols) = arr[0].data.shape();
|
let (nrows, ncols) = arr[0].shape_generic();
|
||||||
|
|
||||||
Self::from_fn_generic(nrows, ncols, |i, j| {
|
Self::from_fn_generic(nrows, ncols, |i, j| {
|
||||||
[
|
[
|
||||||
|
@ -477,7 +527,7 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self {
|
fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self {
|
||||||
let (nrows, ncols) = arr[0].data.shape();
|
let (nrows, ncols) = arr[0].shape_generic();
|
||||||
|
|
||||||
Self::from_fn_generic(nrows, ncols, |i, j| {
|
Self::from_fn_generic(nrows, ncols, |i, j| {
|
||||||
[
|
[
|
||||||
|
@ -500,7 +550,7 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self {
|
fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self {
|
||||||
let (nrows, ncols) = arr[0].data.shape();
|
let (nrows, ncols) = arr[0].shape_generic();
|
||||||
|
|
||||||
Self::from_fn_generic(nrows, ncols, |i, j| {
|
Self::from_fn_generic(nrows, ncols, |i, j| {
|
||||||
[
|
[
|
||||||
|
@ -526,7 +576,7 @@ where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
{
|
{
|
||||||
fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self {
|
fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self {
|
||||||
let (nrows, ncols) = arr[0].data.shape();
|
let (nrows, ncols) = arr[0].shape_generic();
|
||||||
|
|
||||||
Self::from_fn_generic(nrows, ncols, |i, j| {
|
Self::from_fn_generic(nrows, ncols, |i, j| {
|
||||||
[
|
[
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
|
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
|
||||||
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut};
|
use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
|
||||||
use crate::base::Matrix;
|
use crate::base::{Matrix, Scalar};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
@ -23,7 +23,7 @@ macro_rules! coords_impl(
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
|
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
pub struct $T<T> {
|
pub struct $T<T: Scalar> {
|
||||||
$(pub $comps: T),*
|
$(pub $comps: T),*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,20 +31,22 @@ macro_rules! coords_impl(
|
||||||
|
|
||||||
macro_rules! deref_impl(
|
macro_rules! deref_impl(
|
||||||
($R: ty, $C: ty; $Target: ident) => {
|
($R: ty, $C: ty; $Target: ident) => {
|
||||||
impl<T, S> Deref for Matrix<T, $R, $C, S>
|
impl<T: Scalar, S> Deref for Matrix<T, $R, $C, S>
|
||||||
where S: ContiguousStorage<T, $R, $C> {
|
where S: RawStorage<T, $R, $C> + IsContiguous {
|
||||||
type Target = $Target<T>;
|
type Target = $Target<T>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
// Safety: this is OK because of the IsContiguous trait.
|
||||||
unsafe { &*(self.data.ptr() as *const Self::Target) }
|
unsafe { &*(self.data.ptr() as *const Self::Target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> DerefMut for Matrix<T, $R, $C, S>
|
impl<T: Scalar, S> DerefMut for Matrix<T, $R, $C, S>
|
||||||
where S: ContiguousStorageMut<T, $R, $C> {
|
where S: RawStorageMut<T, $R, $C> + IsContiguous {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
// Safety: this is OK because of the IsContiguous trait.
|
||||||
unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) }
|
unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,72 +4,50 @@
|
||||||
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
|
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::mem;
|
||||||
use std::mem::{self, ManuallyDrop, MaybeUninit};
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use super::Const;
|
||||||
|
use crate::base::allocator::{Allocator, Reallocator};
|
||||||
|
use crate::base::array_storage::ArrayStorage;
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use crate::base::dimension::Dynamic;
|
use crate::base::dimension::Dynamic;
|
||||||
|
|
||||||
use super::Const;
|
|
||||||
use crate::base::allocator::{Allocator, InnerAllocator, Reallocator};
|
|
||||||
use crate::base::array_storage::ArrayStorage;
|
|
||||||
use crate::base::dimension::{Dim, DimName};
|
use crate::base::dimension::{Dim, DimName};
|
||||||
use crate::base::storage::{
|
use crate::base::storage::{RawStorage, RawStorageMut};
|
||||||
ContiguousStorage, ContiguousStorageMut, InnerOwned, Storage, StorageMut,
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
};
|
|
||||||
use crate::base::vec_storage::VecStorage;
|
use crate::base::vec_storage::VecStorage;
|
||||||
use crate::U1;
|
use crate::base::Scalar;
|
||||||
|
use std::mem::{ManuallyDrop, MaybeUninit};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Allocator.
|
* Allocator.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// A helper struct that controls how the storage for a matrix should be allocated.
|
|
||||||
///
|
|
||||||
/// This struct is useless on its own. Instead, it's used in trait
|
|
||||||
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
|
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
|
||||||
/// matrices respectively.
|
/// matrices respectively.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct DefaultAllocator;
|
pub struct DefaultAllocator;
|
||||||
|
|
||||||
// Static - Static
|
// Static - Static
|
||||||
impl<T, const R: usize, const C: usize> InnerAllocator<T, Const<R>, Const<C>> for DefaultAllocator {
|
impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
|
||||||
|
for DefaultAllocator
|
||||||
|
{
|
||||||
type Buffer = ArrayStorage<T, R, C>;
|
type Buffer = ArrayStorage<T, R, C>;
|
||||||
|
type BufferUninit = ArrayStorage<MaybeUninit<T>, R, C>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
unsafe fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> MaybeUninit<Self::Buffer> {
|
||||||
nrows: Const<R>,
|
mem::MaybeUninit::<Self::Buffer>::uninit()
|
||||||
ncols: Const<C>,
|
|
||||||
iter: I,
|
|
||||||
) -> Self::Buffer {
|
|
||||||
let mut res = Self::allocate_uninitialized(nrows, ncols);
|
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
for (res, e) in res.as_mut_slice().iter_mut().zip(iter.into_iter()) {
|
|
||||||
*res = MaybeUninit::new(e);
|
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
|
||||||
count == nrows.value() * ncols.value(),
|
|
||||||
"Matrix init. from iterator: iterator not long enough."
|
|
||||||
);
|
|
||||||
|
|
||||||
// Safety: we have initialized all entries.
|
|
||||||
unsafe { <Self as Allocator<T, Const<R>, Const<C>>>::assume_init(res) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for DefaultAllocator {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> {
|
fn allocate_uninit(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> {
|
||||||
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
|
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
|
||||||
let array = unsafe { MaybeUninit::uninit().assume_init() };
|
let array: [[MaybeUninit<T>; R]; C] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
ArrayStorage(array)
|
ArrayStorage(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,41 +61,53 @@ impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for Def
|
||||||
ArrayStorage((&uninit as *const _ as *const [_; C]).read())
|
ArrayStorage((&uninit as *const _ as *const [_; C]).read())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies that a given buffer's entries should be manually dropped.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn manually_drop(buf: ArrayStorage<T, R, C>) -> ArrayStorage<ManuallyDrop<T>, R, C> {
|
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
||||||
// SAFETY:
|
nrows: Const<R>,
|
||||||
// * `ManuallyDrop<T>` and T are guaranteed to have the same layout
|
ncols: Const<C>,
|
||||||
// * `ManuallyDrop` does not drop, so there are no double-frees
|
iter: I,
|
||||||
// And thus the conversion is safe
|
) -> Self::Buffer {
|
||||||
unsafe { ArrayStorage((&ManuallyDrop::new(buf) as *const _ as *const [_; C]).read()) }
|
#[cfg(feature = "no_unsound_assume_init")]
|
||||||
|
let mut res: Self::Buffer = unimplemented!();
|
||||||
|
#[cfg(not(feature = "no_unsound_assume_init"))]
|
||||||
|
let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols).assume_init() };
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
// Safety: this is OK because the Buffer is known to be contiguous.
|
||||||
|
let res_slice = unsafe { res.as_mut_slice_unchecked() };
|
||||||
|
for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) {
|
||||||
|
*res = e;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
count == nrows.value() * ncols.value(),
|
||||||
|
"Matrix init. from iterator: iterator not long enough."
|
||||||
|
);
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic - Static
|
// Dynamic - Static
|
||||||
// Dynamic - Dynamic
|
// Dynamic - Dynamic
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, C: Dim> InnerAllocator<T, Dynamic, C> for DefaultAllocator {
|
impl<T: Scalar, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
|
||||||
type Buffer = VecStorage<T, Dynamic, C>;
|
type Buffer = VecStorage<T, Dynamic, C>;
|
||||||
|
type BufferUninit = VecStorage<MaybeUninit<T>, Dynamic, C>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> MaybeUninit<Self::Buffer> {
|
||||||
nrows: Dynamic,
|
let mut res = Vec::new();
|
||||||
ncols: C,
|
let length = nrows.value() * ncols.value();
|
||||||
iter: I,
|
res.reserve_exact(length);
|
||||||
) -> Self::Buffer {
|
res.set_len(length);
|
||||||
let it = iter.into_iter();
|
|
||||||
let res: Vec<T> = it.collect();
|
|
||||||
assert!(res.len() == nrows.value() * ncols.value(),
|
|
||||||
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
|
||||||
|
|
||||||
VecStorage::new(nrows, ncols, res)
|
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> VecStorage<MaybeUninit<T>, Dynamic, C> {
|
fn allocate_uninit(nrows: Dynamic, ncols: C) -> VecStorage<MaybeUninit<T>, Dynamic, C> {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let length = nrows.value() * ncols.value();
|
let length = nrows.value() * ncols.value();
|
||||||
data.reserve_exact(length);
|
data.reserve_exact(length);
|
||||||
|
@ -143,32 +133,10 @@ impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
|
||||||
VecStorage::new(nrows, ncols, new_data)
|
VecStorage::new(nrows, ncols, new_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn manually_drop(buf: VecStorage<T, Dynamic, C>) -> VecStorage<ManuallyDrop<T>, Dynamic, C> {
|
|
||||||
// Avoids a double-drop.
|
|
||||||
let (nrows, ncols) = buf.shape();
|
|
||||||
let vec: Vec<_> = buf.into();
|
|
||||||
let mut md = ManuallyDrop::new(vec);
|
|
||||||
|
|
||||||
// Safety:
|
|
||||||
// - ManuallyDrop<T> has the same alignment and layout as T.
|
|
||||||
// - The length and capacity come from a valid vector.
|
|
||||||
let new_data =
|
|
||||||
unsafe { Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()) };
|
|
||||||
|
|
||||||
VecStorage::new(nrows, ncols, new_data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static - Dynamic
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
impl<T, R: DimName> InnerAllocator<T, R, Dynamic> for DefaultAllocator {
|
|
||||||
type Buffer = VecStorage<T, R, Dynamic>;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
||||||
nrows: R,
|
nrows: Dynamic,
|
||||||
ncols: Dynamic,
|
ncols: C,
|
||||||
iter: I,
|
iter: I,
|
||||||
) -> Self::Buffer {
|
) -> Self::Buffer {
|
||||||
let it = iter.into_iter();
|
let it = iter.into_iter();
|
||||||
|
@ -180,9 +148,24 @@ impl<T, R: DimName> InnerAllocator<T, R, Dynamic> for DefaultAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
|
// Static - Dynamic
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<T: Scalar, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
|
||||||
|
type Buffer = VecStorage<T, R, Dynamic>;
|
||||||
|
type BufferUninit = VecStorage<MaybeUninit<T>, R, Dynamic>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> VecStorage<MaybeUninit<T>, R, Dynamic> {
|
unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> MaybeUninit<Self::Buffer> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let length = nrows.value() * ncols.value();
|
||||||
|
res.reserve_exact(length);
|
||||||
|
res.set_len(length);
|
||||||
|
|
||||||
|
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn allocate_uninit(nrows: R, ncols: Dynamic) -> VecStorage<MaybeUninit<T>, R, Dynamic> {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let length = nrows.value() * ncols.value();
|
let length = nrows.value() * ncols.value();
|
||||||
data.reserve_exact(length);
|
data.reserve_exact(length);
|
||||||
|
@ -209,253 +192,59 @@ impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn manually_drop(buf: VecStorage<T, R, Dynamic>) -> VecStorage<ManuallyDrop<T>, R, Dynamic> {
|
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
|
||||||
// Avoids a double-drop.
|
nrows: R,
|
||||||
let (nrows, ncols) = buf.shape();
|
ncols: Dynamic,
|
||||||
let vec: Vec<_> = buf.into();
|
iter: I,
|
||||||
let mut md = ManuallyDrop::new(vec);
|
) -> Self::Buffer {
|
||||||
|
let it = iter.into_iter();
|
||||||
|
let res: Vec<T> = it.collect();
|
||||||
|
assert!(res.len() == nrows.value() * ncols.value(),
|
||||||
|
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
||||||
|
|
||||||
// Safety:
|
VecStorage::new(nrows, ncols, res)
|
||||||
// - ManuallyDrop<T> has the same alignment and layout as T.
|
|
||||||
// - The length and capacity come from a valid vector.
|
|
||||||
let new_data =
|
|
||||||
unsafe { Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()) };
|
|
||||||
|
|
||||||
VecStorage::new(nrows, ncols, new_data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The owned storage type for a matrix.
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct Owned<T, R: Dim, C: Dim>(pub InnerOwned<T, R, C>)
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>;
|
|
||||||
|
|
||||||
impl<T: Copy, R: Dim, C: Dim> Copy for Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
InnerOwned<T, R, C>: Copy,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone, R: Dim, C: Dim> Clone for Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
if Self::is_array() {
|
|
||||||
// We first clone the data.
|
|
||||||
let slice = unsafe { self.as_slice_unchecked() };
|
|
||||||
let vec = ManuallyDrop::new(slice.to_owned());
|
|
||||||
|
|
||||||
// We then transmute it back into an array and then an Owned.
|
|
||||||
unsafe { mem::transmute_copy(&*vec.as_ptr()) }
|
|
||||||
} else {
|
|
||||||
// We first clone the data.
|
|
||||||
let clone = ManuallyDrop::new(self.as_vec_storage().clone());
|
|
||||||
|
|
||||||
// We then transmute it back into an Owned.
|
|
||||||
unsafe { mem::transmute_copy(&clone) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check that the auxiliary copies are elided.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, R: Dim, C: Dim> fmt::Debug for Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if Self::is_array() {
|
|
||||||
let slice = unsafe { self.as_slice_unchecked() };
|
|
||||||
slice.fmt(f)
|
|
||||||
} else {
|
|
||||||
self.as_vec_storage().fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const R: usize, const C: usize> Owned<T, Const<R>, Const<C>> {
|
|
||||||
fn new(array: [[T; R]; C]) -> Self {
|
|
||||||
Self(ArrayStorage(array))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim> Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
{
|
|
||||||
/// Returns whether `Self` stores an [`ArrayStorage`]. This is a zero-cost
|
|
||||||
/// operation.
|
|
||||||
const fn is_array() -> bool {
|
|
||||||
R::is_static() && C::is_static()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether `Self` stores a [`VecStorage`].
|
|
||||||
const fn is_vec() -> bool {
|
|
||||||
!Self::is_array()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the underlying [`VecStorage`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// This method will panic if `Self` does not contain a [`VecStorage`].
|
|
||||||
fn as_vec_storage(&self) -> &VecStorage<T, R, C> {
|
|
||||||
assert!(Self::is_vec());
|
|
||||||
|
|
||||||
// Safety: `self` is transparent and must contain a `VecStorage`.
|
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying [`VecStorage`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// This method will panic if `Self` does not contain a [`VecStorage`].
|
|
||||||
fn as_vec_storage_mut(&mut self) -> &mut VecStorage<T, R, C> {
|
|
||||||
assert!(Self::is_vec());
|
|
||||||
|
|
||||||
// Safety: `self` is transparent and must contain a `VecStorage`.
|
|
||||||
unsafe { &mut *(self as *mut _ as *mut _) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, R: Dim, C: Dim> Storage<T, R, C> for Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
{
|
|
||||||
type RStride = U1;
|
|
||||||
|
|
||||||
type CStride = R;
|
|
||||||
|
|
||||||
fn ptr(&self) -> *const T {
|
|
||||||
if Self::is_array() {
|
|
||||||
&self as *const _ as *const T
|
|
||||||
} else {
|
|
||||||
self.as_vec_storage().as_vec().as_ptr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shape(&self) -> (R, C) {
|
|
||||||
if Self::is_array() {
|
|
||||||
(R::default(), C::default())
|
|
||||||
} else {
|
|
||||||
let vec = self.as_vec_storage();
|
|
||||||
(vec.nrows, vec.ncols)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn strides(&self) -> (Self::RStride, Self::CStride) {
|
|
||||||
if Self::is_array() {
|
|
||||||
(U1::name(), R::default())
|
|
||||||
} else {
|
|
||||||
let vec = self.as_vec_storage();
|
|
||||||
(U1::name(), vec.nrows)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_contiguous(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
|
||||||
if Self::is_array() {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
self.ptr(),
|
|
||||||
R::try_to_usize().unwrap() * C::try_to_usize().unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self.as_vec_storage().as_vec().as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn into_owned(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn clone_owned(&self) -> Self
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, R: Dim, C: Dim> StorageMut<T, R, C> for Owned<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>,
|
|
||||||
{
|
|
||||||
fn ptr_mut(&mut self) -> *mut T {
|
|
||||||
if Self::is_array() {
|
|
||||||
&mut self as *mut _ as *mut T
|
|
||||||
} else {
|
|
||||||
self.as_vec_storage_mut().as_vec().as_ptr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
|
|
||||||
if Self::is_array() {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
self.ptr_mut(),
|
|
||||||
R::try_to_usize().unwrap() * C::try_to_usize().unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self.as_vec_storage_mut().as_vec_mut().as_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, R: Dim, C: Dim> ContiguousStorage<T, R, C> for Owned<T, R, C> where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, R: Dim, C: Dim> ContiguousStorageMut<T, R, C> for Owned<T, R, C> where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, C>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Reallocator.
|
* Reallocator.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// Anything -> Static × Static
|
// Anything -> Static × Static
|
||||||
impl<T, RFrom: Dim, CFrom: Dim, const RTO: usize, const CTO: usize>
|
impl<T: Scalar, RFrom, CFrom, const RTO: usize, const CTO: usize>
|
||||||
Reallocator<T, RFrom, CFrom, Const<RTO>, Const<CTO>> for DefaultAllocator
|
Reallocator<T, RFrom, CFrom, Const<RTO>, Const<CTO>> for DefaultAllocator
|
||||||
where
|
where
|
||||||
|
RFrom: Dim,
|
||||||
|
CFrom: Dim,
|
||||||
Self: Allocator<T, RFrom, CFrom>,
|
Self: Allocator<T, RFrom, CFrom>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: Const<RTO>,
|
rto: Const<RTO>,
|
||||||
cto: Const<CTO>,
|
cto: Const<CTO>,
|
||||||
buf: InnerOwned<T, RFrom, CFrom>,
|
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
|
||||||
) -> ArrayStorage<T, RTO, CTO> {
|
) -> ArrayStorage<T, RTO, CTO> {
|
||||||
|
#[cfg(feature = "no_unsound_assume_init")]
|
||||||
|
let mut res: ArrayStorage<T, RTO, CTO> = unimplemented!();
|
||||||
|
#[cfg(not(feature = "no_unsound_assume_init"))]
|
||||||
let mut res =
|
let mut res =
|
||||||
<Self as Allocator<_, Const<RTO>, Const<CTO>>>::allocate_uninitialized(rto, cto);
|
<Self as Allocator<T, Const<RTO>, Const<CTO>>>::allocate_uninitialized(rto, cto)
|
||||||
|
.assume_init();
|
||||||
|
|
||||||
let (rfrom, cfrom) = buf.shape();
|
let (rfrom, cfrom) = buf.shape();
|
||||||
|
|
||||||
let len_from = rfrom.value() * cfrom.value();
|
let len_from = rfrom.value() * cfrom.value();
|
||||||
let len_to = rto.value() * cto.value();
|
let len_to = rto.value() * cto.value();
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
|
||||||
buf.ptr(),
|
|
||||||
res.ptr_mut() as *mut T,
|
|
||||||
cmp::min(len_from, len_to),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Safety: TODO
|
res
|
||||||
<Self as Allocator<_, Const<RTO>, Const<CTO>>>::assume_init(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static × Static -> Dynamic × Any
|
// Static × Static -> Dynamic × Any
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, CTo, const RFROM: usize, const CFROM: usize>
|
impl<T: Scalar, CTo, const RFROM: usize, const CFROM: usize>
|
||||||
Reallocator<T, Const<RFROM>, Const<CFROM>, Dynamic, CTo> for DefaultAllocator
|
Reallocator<T, Const<RFROM>, Const<CFROM>, Dynamic, CTo> for DefaultAllocator
|
||||||
where
|
where
|
||||||
CTo: Dim,
|
CTo: Dim,
|
||||||
|
@ -466,25 +255,25 @@ where
|
||||||
cto: CTo,
|
cto: CTo,
|
||||||
buf: ArrayStorage<T, RFROM, CFROM>,
|
buf: ArrayStorage<T, RFROM, CFROM>,
|
||||||
) -> VecStorage<T, Dynamic, CTo> {
|
) -> VecStorage<T, Dynamic, CTo> {
|
||||||
let mut res = <Self as Allocator<T, Dynamic, CTo>>::allocate_uninitialized(rto, cto);
|
#[cfg(feature = "no_unsound_assume_init")]
|
||||||
|
let mut res: VecStorage<T, Dynamic, CTo> = unimplemented!();
|
||||||
|
#[cfg(not(feature = "no_unsound_assume_init"))]
|
||||||
|
let mut res =
|
||||||
|
<Self as Allocator<T, Dynamic, CTo>>::allocate_uninitialized(rto, cto).assume_init();
|
||||||
|
|
||||||
let (rfrom, cfrom) = buf.shape();
|
let (rfrom, cfrom) = buf.shape();
|
||||||
|
|
||||||
let len_from = rfrom.value() * cfrom.value();
|
let len_from = rfrom.value() * cfrom.value();
|
||||||
let len_to = rto.value() * cto.value();
|
let len_to = rto.value() * cto.value();
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
|
||||||
buf.ptr(),
|
|
||||||
res.ptr_mut() as *mut T,
|
|
||||||
cmp::min(len_from, len_to),
|
|
||||||
);
|
|
||||||
|
|
||||||
<Self as Allocator<T, Dynamic, CTo>>::assume_init(res)
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static × Static -> Static × Dynamic
|
// Static × Static -> Static × Dynamic
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, RTo, const RFROM: usize, const CFROM: usize>
|
impl<T: Scalar, RTo, const RFROM: usize, const CFROM: usize>
|
||||||
Reallocator<T, Const<RFROM>, Const<CFROM>, RTo, Dynamic> for DefaultAllocator
|
Reallocator<T, Const<RFROM>, Const<CFROM>, RTo, Dynamic> for DefaultAllocator
|
||||||
where
|
where
|
||||||
RTo: DimName,
|
RTo: DimName,
|
||||||
|
@ -495,25 +284,27 @@ where
|
||||||
cto: Dynamic,
|
cto: Dynamic,
|
||||||
buf: ArrayStorage<T, RFROM, CFROM>,
|
buf: ArrayStorage<T, RFROM, CFROM>,
|
||||||
) -> VecStorage<T, RTo, Dynamic> {
|
) -> VecStorage<T, RTo, Dynamic> {
|
||||||
let mut res = <Self as Allocator<T, RTo, Dynamic>>::allocate_uninitialized(rto, cto);
|
#[cfg(feature = "no_unsound_assume_init")]
|
||||||
|
let mut res: VecStorage<T, RTo, Dynamic> = unimplemented!();
|
||||||
|
#[cfg(not(feature = "no_unsound_assume_init"))]
|
||||||
|
let mut res =
|
||||||
|
<Self as Allocator<T, RTo, Dynamic>>::allocate_uninitialized(rto, cto).assume_init();
|
||||||
|
|
||||||
let (rfrom, cfrom) = buf.shape();
|
let (rfrom, cfrom) = buf.shape();
|
||||||
|
|
||||||
let len_from = rfrom.value() * cfrom.value();
|
let len_from = rfrom.value() * cfrom.value();
|
||||||
let len_to = rto.value() * cto.value();
|
let len_to = rto.value() * cto.value();
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
|
||||||
buf.ptr(),
|
|
||||||
res.ptr_mut() as *mut T,
|
|
||||||
cmp::min(len_from, len_to),
|
|
||||||
);
|
|
||||||
|
|
||||||
<Self as Allocator<T, RTo, Dynamic>>::assume_init(res)
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All conversion from a dynamic buffer to a dynamic buffer.
|
// All conversion from a dynamic buffer to a dynamic buffer.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo> for DefaultAllocator {
|
impl<T: Scalar, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo>
|
||||||
|
for DefaultAllocator
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: Dynamic,
|
rto: Dynamic,
|
||||||
|
@ -526,7 +317,7 @@ impl<T, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CTo> for D
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
|
impl<T: Scalar, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
|
||||||
for DefaultAllocator
|
for DefaultAllocator
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -541,7 +332,7 @@ impl<T, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dynamic>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
|
impl<T: Scalar, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
|
||||||
for DefaultAllocator
|
for DefaultAllocator
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -556,7 +347,7 @@ impl<T, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic, CTo>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dynamic, RTo, Dynamic>
|
impl<T: Scalar, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dynamic, RTo, Dynamic>
|
||||||
for DefaultAllocator
|
for DefaultAllocator
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
//! Traits and tags for identifying the dimension of all algebraic entities.
|
//! Traits and tags for identifying the dimension of all algebraic entities.
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::{Any, TypeId};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
use std::ops::{Add, Div, Mul, Sub};
|
||||||
|
@ -11,8 +11,8 @@ use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned}
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
/// Stores the dimension of dynamically-sized algebraic entities.
|
/// Dim of dynamically-sized algebraic entities.
|
||||||
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
pub struct Dynamic {
|
pub struct Dynamic {
|
||||||
value: usize,
|
value: usize,
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ impl IsNotStaticOne for Dynamic {}
|
||||||
|
|
||||||
/// Trait implemented by any type that can be used as a dimension. This includes type-level
|
/// Trait implemented by any type that can be used as a dimension. This includes type-level
|
||||||
/// integers and `Dynamic` (for dimensions not known at compile-time).
|
/// integers and `Dynamic` (for dimensions not known at compile-time).
|
||||||
pub trait Dim: 'static + Debug + Copy + Default + PartialEq + Send + Sync {
|
pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is<D: Dim>() -> bool {
|
fn is<D: Dim>() -> bool {
|
||||||
TypeId::of::<Self>() == TypeId::of::<D>()
|
TypeId::of::<Self>() == TypeId::of::<D>()
|
||||||
|
@ -65,16 +65,6 @@ pub trait Dim: 'static + Debug + Copy + Default + PartialEq + Send + Sync {
|
||||||
/// Dynamic`.
|
/// Dynamic`.
|
||||||
fn try_to_usize() -> Option<usize>;
|
fn try_to_usize() -> Option<usize>;
|
||||||
|
|
||||||
/// Returns whether `Self` has a known compile-time value.
|
|
||||||
fn is_static() -> bool {
|
|
||||||
Self::try_to_usize().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether `Self` does not have a known compile-time value.
|
|
||||||
fn is_dynamic() -> bool {
|
|
||||||
Self::try_to_usize().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the run-time value of `self`. For type-level integers, this is the same as
|
/// Gets the run-time value of `self`. For type-level integers, this is the same as
|
||||||
/// `Self::try_to_usize().unwrap()`.
|
/// `Self::try_to_usize().unwrap()`.
|
||||||
fn value(&self) -> usize;
|
fn value(&self) -> usize;
|
||||||
|
@ -206,10 +196,7 @@ dim_ops!(
|
||||||
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
|
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
|
||||||
);
|
);
|
||||||
|
|
||||||
/// A wrapper around const types, which provides the capability of performing
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
/// type-level arithmetic. This might get removed if const-generics become
|
|
||||||
/// more powerful in the future.
|
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Const<const R: usize>;
|
pub struct Const<const R: usize>;
|
||||||
|
|
||||||
/// Trait implemented exclusively by type-level integers.
|
/// Trait implemented exclusively by type-level integers.
|
||||||
|
|
|
@ -2,9 +2,6 @@ use num::{One, Zero};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use std::iter::ExactSizeIterator;
|
use std::iter::ExactSizeIterator;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
use std::mem;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, Reallocator};
|
use crate::base::allocator::{Allocator, Reallocator};
|
||||||
|
@ -12,8 +9,10 @@ use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, Shap
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use crate::base::dimension::Dynamic;
|
use crate::base::dimension::Dynamic;
|
||||||
use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
|
use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
|
||||||
use crate::base::storage::{ContiguousStorageMut, ReshapableStorage, Storage, StorageMut};
|
use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage};
|
||||||
use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
|
use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
|
||||||
|
use crate::Storage;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// # Rows and columns extraction
|
/// # Rows and columns extraction
|
||||||
impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
@ -50,11 +49,11 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = &'a usize>,
|
I: IntoIterator<Item = &'a usize>,
|
||||||
I::IntoIter: ExactSizeIterator + Clone,
|
I::IntoIter: ExactSizeIterator + Clone,
|
||||||
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
{
|
{
|
||||||
let irows = irows.into_iter();
|
let irows = irows.into_iter();
|
||||||
let ncols = self.data.shape().1;
|
let ncols = self.shape_generic().1;
|
||||||
let mut res =
|
let mut res = Matrix::uninit(Dynamic::new(irows.len()), ncols);
|
||||||
OMatrix::<T, Dynamic, C>::new_uninitialized_generic(Dynamic::new(irows.len()), ncols);
|
|
||||||
|
|
||||||
// First, check that all the indices from irows are valid.
|
// First, check that all the indices from irows are valid.
|
||||||
// This will allow us to use unchecked access in the inner loop.
|
// This will allow us to use unchecked access in the inner loop.
|
||||||
|
@ -68,13 +67,15 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
let src = self.column(j);
|
let src = self.column(j);
|
||||||
|
|
||||||
for (destination, source) in irows.clone().enumerate() {
|
for (destination, source) in irows.clone().enumerate() {
|
||||||
|
// Safety: all indices are in range.
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.vget_unchecked_mut(destination) =
|
*res.vget_unchecked_mut(destination) =
|
||||||
MaybeUninit::new(src.vget_unchecked(*source).clone());
|
MaybeUninit::new(src.vget_unchecked(*source).inlined_clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: res is now fully initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,32 +89,30 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Allocator<T, R, Dynamic>,
|
DefaultAllocator: Allocator<T, R, Dynamic>,
|
||||||
{
|
{
|
||||||
let icols = icols.into_iter();
|
let icols = icols.into_iter();
|
||||||
let nrows = self.data.shape().0;
|
let nrows = self.shape_generic().0;
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows, Dynamic::new(icols.len()));
|
let mut res = Matrix::uninit(nrows, Dynamic::new(icols.len()));
|
||||||
|
|
||||||
for (destination, source) in icols.enumerate() {
|
for (destination, source) in icols.enumerate() {
|
||||||
for (d, s) in res
|
// NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit.
|
||||||
.column_mut(destination)
|
res.column_mut(destination)
|
||||||
.iter_mut()
|
.zip_apply(&self.column(*source), |out, e| {
|
||||||
.zip(self.column(*source).iter())
|
*out = MaybeUninit::new(e.inlined_clone())
|
||||||
{
|
});
|
||||||
*d = MaybeUninit::new(s.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: res is now fully initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Set rows, columns, and diagonal
|
/// # Set rows, columns, and diagonal
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Fills the diagonal of this matrix with the content of the given vector.
|
/// Fills the diagonal of this matrix with the content of the given vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
|
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
|
||||||
where
|
where
|
||||||
T: Clone,
|
|
||||||
R: DimMin<C>,
|
R: DimMin<C>,
|
||||||
S2: Storage<T, R2>,
|
S2: RawStorage<T, R2>,
|
||||||
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
|
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
@ -121,7 +120,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
|
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
|
||||||
|
|
||||||
for i in 0..min_nrows_ncols {
|
for i in 0..min_nrows_ncols {
|
||||||
unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone() }
|
unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +143,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
|
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
|
||||||
where
|
where
|
||||||
T: Clone,
|
S2: RawStorage<T, U1, C2>,
|
||||||
S2: Storage<T, U1, C2>,
|
|
||||||
ShapeConstraint: SameNumberOfColumns<C, C2>,
|
ShapeConstraint: SameNumberOfColumns<C, C2>,
|
||||||
{
|
{
|
||||||
self.row_mut(i).copy_from(row);
|
self.row_mut(i).copy_from(row);
|
||||||
|
@ -155,8 +153,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
|
pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
|
||||||
where
|
where
|
||||||
T: Clone,
|
S2: RawStorage<T, R2, U1>,
|
||||||
S2: Storage<T, R2, U1>,
|
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2>,
|
ShapeConstraint: SameNumberOfRows<R, R2>,
|
||||||
{
|
{
|
||||||
self.column_mut(i).copy_from(column);
|
self.column_mut(i).copy_from(column);
|
||||||
|
@ -164,23 +161,23 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # In-place filling
|
/// # In-place filling
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
/// Sets all the elements of this matrix to the value returned by the closure.
|
||||||
|
#[inline]
|
||||||
|
pub fn fill_with(&mut self, val: impl Fn() -> T) {
|
||||||
|
for e in self.iter_mut() {
|
||||||
|
*e = val()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets all the elements of this matrix to `val`.
|
/// Sets all the elements of this matrix to `val`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill(&mut self, val: T)
|
pub fn fill(&mut self, val: T)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
for e in self.iter_mut() {
|
for e in self.iter_mut() {
|
||||||
*e = val.clone()
|
*e = val.inlined_clone()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets all the elements of this matrix to `f()`.
|
|
||||||
#[inline]
|
|
||||||
pub fn fill_fn<F: FnMut() -> T>(&mut self, mut f: F) {
|
|
||||||
for e in self.iter_mut() {
|
|
||||||
*e = f();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +185,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_with_identity(&mut self)
|
pub fn fill_with_identity(&mut self)
|
||||||
where
|
where
|
||||||
T: Zero + One + Scalar,
|
T: Scalar + Zero + One,
|
||||||
{
|
{
|
||||||
self.fill(T::zero());
|
self.fill(T::zero());
|
||||||
self.fill_diagonal(T::one());
|
self.fill_diagonal(T::one());
|
||||||
|
@ -198,13 +195,13 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_diagonal(&mut self, val: T)
|
pub fn fill_diagonal(&mut self, val: T)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
let n = cmp::min(nrows, ncols);
|
let n = cmp::min(nrows, ncols);
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
unsafe { *self.get_unchecked_mut((i, i)) = val.clone() }
|
unsafe { *self.get_unchecked_mut((i, i)) = val.inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,11 +209,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_row(&mut self, i: usize, val: T)
|
pub fn fill_row(&mut self, i: usize, val: T)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
assert!(i < self.nrows(), "Row index out of bounds.");
|
assert!(i < self.nrows(), "Row index out of bounds.");
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
|
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,11 +221,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_column(&mut self, j: usize, val: T)
|
pub fn fill_column(&mut self, j: usize, val: T)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
assert!(j < self.ncols(), "Row index out of bounds.");
|
assert!(j < self.ncols(), "Row index out of bounds.");
|
||||||
for i in 0..self.nrows() {
|
for i in 0..self.nrows() {
|
||||||
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
|
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,11 +239,11 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
|
pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
for i in (j + shift)..self.nrows() {
|
for i in (j + shift)..self.nrows() {
|
||||||
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
|
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,19 +258,19 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
|
pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
for j in shift..self.ncols() {
|
for j in shift..self.ncols() {
|
||||||
// TODO: is there a more efficient way to avoid the min ?
|
// TODO: is there a more efficient way to avoid the min ?
|
||||||
// (necessary for rectangular matrices)
|
// (necessary for rectangular matrices)
|
||||||
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
|
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
|
||||||
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
|
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
|
impl<T: Scalar, D: Dim, S: RawStorageMut<T, D, D>> Matrix<T, D, D, S> {
|
||||||
/// Copies the upper-triangle of this matrix to its lower-triangular part.
|
/// Copies the upper-triangle of this matrix to its lower-triangular part.
|
||||||
///
|
///
|
||||||
/// This makes the matrix symmetric. Panics if the matrix is not square.
|
/// This makes the matrix symmetric. Panics if the matrix is not square.
|
||||||
|
@ -284,7 +281,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
|
||||||
for j in 0..dim {
|
for j in 0..dim {
|
||||||
for i in j + 1..dim {
|
for i in j + 1..dim {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
|
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +296,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
|
||||||
for j in 1..self.ncols() {
|
for j in 1..self.ncols() {
|
||||||
for i in 0..j {
|
for i in 0..j {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
|
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +304,7 @@ impl<T: Clone, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # In-place swapping
|
/// # In-place swapping
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Swaps two rows in-place.
|
/// Swaps two rows in-place.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn swap_rows(&mut self, irow1: usize, irow2: usize) {
|
pub fn swap_rows(&mut self, irow1: usize, irow2: usize) {
|
||||||
|
@ -343,7 +340,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// # Rows and columns removal
|
/// # Rows and columns removal
|
||||||
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Column removal.
|
* Column removal.
|
||||||
|
@ -367,7 +364,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
|
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
|
||||||
{
|
{
|
||||||
let mut m = self.into_owned();
|
let mut m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let mut offset: usize = 0;
|
let mut offset: usize = 0;
|
||||||
let mut target: usize = 0;
|
let mut target: usize = 0;
|
||||||
while offset + target < ncols.value() {
|
while offset + target < ncols.value() {
|
||||||
|
@ -401,7 +398,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
|
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
|
||||||
{
|
{
|
||||||
let mut m = self.into_owned();
|
let mut m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let mut offset: usize = 0;
|
let mut offset: usize = 0;
|
||||||
let mut target: usize = 0;
|
let mut target: usize = 0;
|
||||||
while offset + target < nrows.value() * ncols.value() {
|
while offset + target < nrows.value() * ncols.value() {
|
||||||
|
@ -464,7 +461,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>,
|
DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>,
|
||||||
{
|
{
|
||||||
let mut m = self.into_owned();
|
let mut m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
assert!(
|
assert!(
|
||||||
i + nremove.value() <= ncols.value(),
|
i + nremove.value() <= ncols.value(),
|
||||||
"Column index out of range."
|
"Column index out of range."
|
||||||
|
@ -543,7 +540,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>,
|
DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>,
|
||||||
{
|
{
|
||||||
let mut m = self.into_owned();
|
let mut m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
assert!(
|
assert!(
|
||||||
i + nremove.value() <= nrows.value(),
|
i + nremove.value() <= nrows.value(),
|
||||||
"Row index out of range."
|
"Row index out of range."
|
||||||
|
@ -552,7 +549,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
if nremove.value() != 0 {
|
if nremove.value() != 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
compress_rows(
|
compress_rows(
|
||||||
&mut m.data.as_mut_slice(),
|
&mut m.as_mut_slice(),
|
||||||
nrows.value(),
|
nrows.value(),
|
||||||
ncols.value(),
|
ncols.value(),
|
||||||
i,
|
i,
|
||||||
|
@ -572,7 +569,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Rows and columns insertion
|
/// # Rows and columns insertion
|
||||||
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Columns insertion.
|
* Columns insertion.
|
||||||
|
@ -633,7 +630,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>,
|
DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>,
|
||||||
{
|
{
|
||||||
let m = self.into_owned();
|
let m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
||||||
nrows,
|
nrows,
|
||||||
ncols.add(ninsert),
|
ncols.add(ninsert),
|
||||||
|
@ -717,7 +714,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>,
|
DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>,
|
||||||
{
|
{
|
||||||
let m = self.into_owned();
|
let m = self.into_owned();
|
||||||
let (nrows, ncols) = m.data.shape();
|
let (nrows, ncols) = m.shape_generic();
|
||||||
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
||||||
nrows.add(ninsert),
|
nrows.add(ninsert),
|
||||||
ncols,
|
ncols,
|
||||||
|
@ -728,7 +725,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
if ninsert.value() != 0 {
|
if ninsert.value() != 0 {
|
||||||
extend_rows(
|
extend_rows(
|
||||||
&mut res.data.as_mut_slice(),
|
&mut res.as_mut_slice(),
|
||||||
nrows.value(),
|
nrows.value(),
|
||||||
ncols.value(),
|
ncols.value(),
|
||||||
i,
|
i,
|
||||||
|
@ -741,7 +738,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Resizing and reshaping
|
/// # Resizing and reshaping
|
||||||
impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns.
|
/// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns.
|
||||||
///
|
///
|
||||||
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
@ -763,7 +760,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
|
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
|
||||||
{
|
{
|
||||||
let ncols = self.data.shape().1;
|
let ncols = self.shape_generic().1;
|
||||||
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
|
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,7 +773,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
|
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
|
||||||
{
|
{
|
||||||
let nrows = self.data.shape().0;
|
let nrows = self.shape_generic().0;
|
||||||
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
|
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,10 +806,10 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
DefaultAllocator: Reallocator<T, R, C, R2, C2>,
|
DefaultAllocator: Reallocator<T, R, C, R2, C2>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
let mut data = self.data.into_owned();
|
let mut data = self.into_owned();
|
||||||
|
|
||||||
if new_nrows.value() == nrows {
|
if new_nrows.value() == nrows {
|
||||||
let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.0) };
|
let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.data) };
|
||||||
let mut res = Matrix::from_data(res);
|
let mut res = Matrix::from_data(res);
|
||||||
if new_ncols.value() > ncols {
|
if new_ncols.value() > ncols {
|
||||||
res.columns_range_mut(ncols..).fill(val);
|
res.columns_range_mut(ncols..).fill(val);
|
||||||
|
@ -832,14 +829,14 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
nrows - new_nrows.value(),
|
nrows - new_nrows.value(),
|
||||||
);
|
);
|
||||||
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
||||||
new_nrows, new_ncols, data.0,
|
new_nrows, new_ncols, data.data,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
|
||||||
new_nrows, new_ncols, data.0,
|
new_nrows, new_ncols, data.data,
|
||||||
));
|
));
|
||||||
extend_rows(
|
extend_rows(
|
||||||
&mut res.data.as_mut_slice(),
|
&mut res.as_mut_slice(),
|
||||||
nrows,
|
nrows,
|
||||||
new_ncols.value(),
|
new_ncols.value(),
|
||||||
nrows,
|
nrows,
|
||||||
|
@ -849,7 +846,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_ncols.value() > ncols {
|
if new_ncols.value() > ncols {
|
||||||
res.columns_range_mut(ncols..).fill(val.clone());
|
res.columns_range_mut(ncols..).fill(val.inlined_clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_nrows.value() > nrows {
|
if new_nrows.value() > nrows {
|
||||||
|
@ -931,7 +928,7 @@ impl<T: Clone, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
/// # In-place resizing
|
/// # In-place resizing
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T: Clone> OMatrix<T, Dynamic, Dynamic> {
|
impl<T: Scalar> OMatrix<T, Dynamic, Dynamic> {
|
||||||
/// Resizes this matrix in-place.
|
/// Resizes this matrix in-place.
|
||||||
///
|
///
|
||||||
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
@ -942,20 +939,13 @@ impl<T: Clone> OMatrix<T, Dynamic, Dynamic> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
|
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
|
||||||
{
|
{
|
||||||
// IMPORTANT TODO: this method is still UB, and we should decide how to
|
// TODO: avoid the clone.
|
||||||
// update the API to take it into account.
|
*self = self.clone().resize(new_nrows, new_ncols, val);
|
||||||
|
|
||||||
let placeholder = unsafe {
|
|
||||||
Matrix::new_uninitialized_generic(Dynamic::new(0), Dynamic::new(0)).assume_init()
|
|
||||||
};
|
|
||||||
let old = mem::replace(self, placeholder);
|
|
||||||
let new = old.resize(new_nrows, new_ncols, val);
|
|
||||||
let _ = mem::replace(self, new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T: Clone, C: Dim> OMatrix<T, Dynamic, C>
|
impl<T: Scalar, C: Dim> OMatrix<T, Dynamic, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, Dynamic, C>,
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
{
|
{
|
||||||
|
@ -970,16 +960,13 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
|
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
|
||||||
{
|
{
|
||||||
let placeholder =
|
// TODO: avoid the clone.
|
||||||
Matrix::from_fn_generic(Dynamic::new(0), self.data.shape().1, |_, _| val.clone());
|
*self = self.clone().resize_vertically(new_nrows, val);
|
||||||
let old = mem::replace(self, placeholder);
|
|
||||||
let new = old.resize_vertically(new_nrows, val);
|
|
||||||
let _ = mem::replace(self, new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T: Clone, R: Dim> OMatrix<T, R, Dynamic>
|
impl<T: Scalar, R: Dim> OMatrix<T, R, Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, Dynamic>,
|
DefaultAllocator: Allocator<T, R, Dynamic>,
|
||||||
{
|
{
|
||||||
|
@ -994,15 +981,18 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
|
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
|
||||||
{
|
{
|
||||||
let placeholder =
|
// TODO: avoid the clone.
|
||||||
Matrix::from_fn_generic(self.data.shape().0, Dynamic::new(0), |_, _| val.clone());
|
*self = self.clone().resize_horizontally(new_ncols, val);
|
||||||
let old = mem::replace(self, placeholder);
|
|
||||||
let new = old.resize_horizontally(new_ncols, val);
|
|
||||||
let _ = mem::replace(self, new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn compress_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, nremove: usize) {
|
unsafe fn compress_rows<T: Scalar>(
|
||||||
|
data: &mut [T],
|
||||||
|
nrows: usize,
|
||||||
|
ncols: usize,
|
||||||
|
i: usize,
|
||||||
|
nremove: usize,
|
||||||
|
) {
|
||||||
let new_nrows = nrows - nremove;
|
let new_nrows = nrows - nremove;
|
||||||
|
|
||||||
if new_nrows == 0 || ncols == 0 {
|
if new_nrows == 0 || ncols == 0 {
|
||||||
|
@ -1035,7 +1025,13 @@ unsafe fn compress_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize,
|
||||||
|
|
||||||
// Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index.
|
// Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index.
|
||||||
// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements.
|
// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements.
|
||||||
unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, ninsert: usize) {
|
unsafe fn extend_rows<T: Scalar>(
|
||||||
|
data: &mut [T],
|
||||||
|
nrows: usize,
|
||||||
|
ncols: usize,
|
||||||
|
i: usize,
|
||||||
|
ninsert: usize,
|
||||||
|
) {
|
||||||
let new_nrows = nrows + ninsert;
|
let new_nrows = nrows + ninsert;
|
||||||
|
|
||||||
if new_nrows == 0 || ncols == 0 {
|
if new_nrows == 0 || ncols == 0 {
|
||||||
|
@ -1065,7 +1061,12 @@ unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, n
|
||||||
/// Extend the number of columns of the `Matrix` with elements from
|
/// Extend the number of columns of the `Matrix` with elements from
|
||||||
/// a given iterator.
|
/// a given iterator.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, R: Dim, S: Extend<T>> Extend<T> for Matrix<T, R, Dynamic, S> {
|
impl<T, R, S> Extend<T> for Matrix<T, R, Dynamic, S>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
S: Extend<T>,
|
||||||
|
{
|
||||||
/// Extend the number of columns of the `Matrix` with elements
|
/// Extend the number of columns of the `Matrix` with elements
|
||||||
/// from the given iterator.
|
/// from the given iterator.
|
||||||
///
|
///
|
||||||
|
@ -1110,6 +1111,7 @@ impl<T, R: Dim, S: Extend<T>> Extend<T> for Matrix<T, R, Dynamic, S> {
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, S> Extend<T> for Matrix<T, Dynamic, U1, S>
|
impl<T, S> Extend<T> for Matrix<T, Dynamic, U1, S>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
S: Extend<T>,
|
S: Extend<T>,
|
||||||
{
|
{
|
||||||
/// Extend the number of rows of a `Vector` with elements
|
/// Extend the number of rows of a `Vector` with elements
|
||||||
|
@ -1128,10 +1130,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<T, R: Dim, S, RV: Dim, SV> Extend<Vector<T, RV, SV>> for Matrix<T, R, Dynamic, S>
|
impl<T, R, S, RV, SV> Extend<Vector<T, RV, SV>> for Matrix<T, R, Dynamic, S>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
S: Extend<Vector<T, RV, SV>>,
|
S: Extend<Vector<T, RV, SV>>,
|
||||||
SV: Storage<T, RV>,
|
RV: Dim,
|
||||||
|
SV: RawStorage<T, RV>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, RV>,
|
ShapeConstraint: SameNumberOfRows<R, RV>,
|
||||||
{
|
{
|
||||||
/// Extends the number of columns of a `Matrix` with `Vector`s
|
/// Extends the number of columns of a `Matrix` with `Vector`s
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Indexing
|
//! Indexing
|
||||||
|
|
||||||
use crate::base::storage::{Storage, StorageMut};
|
use crate::base::storage::{RawStorage, RawStorageMut};
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, U1,
|
Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
@ -310,7 +310,7 @@ fn dimrange_rangetoinclusive_usize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper trait used for indexing operations.
|
/// A helper trait used for indexing operations.
|
||||||
pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized {
|
pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>>: Sized {
|
||||||
/// The output type returned by methods.
|
/// The output type returned by methods.
|
||||||
type Output: 'a;
|
type Output: 'a;
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper trait used for indexing operations.
|
/// A helper trait used for indexing operations.
|
||||||
pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>>:
|
pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>>:
|
||||||
MatrixIndex<'a, T, R, C, S>
|
MatrixIndex<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
/// The output type returned by methods.
|
/// The output type returned by methods.
|
||||||
|
@ -476,7 +476,7 @@ pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>>:
|
||||||
/// 4, 7,
|
/// 4, 7,
|
||||||
/// 5, 8)));
|
/// 5, 8)));
|
||||||
/// ```
|
/// ```
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Produces a view of the data at the given index, or
|
/// Produces a view of the data at the given index, or
|
||||||
/// `None` if the index is out of bounds.
|
/// `None` if the index is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -494,7 +494,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
|
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
S: RawStorageMut<T, R, C>,
|
||||||
I: MatrixIndexMut<'a, T, R, C, S>,
|
I: MatrixIndexMut<'a, T, R, C, S>,
|
||||||
{
|
{
|
||||||
index.get_mut(self)
|
index.get_mut(self)
|
||||||
|
@ -516,7 +516,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
|
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
S: RawStorageMut<T, R, C>,
|
||||||
I: MatrixIndexMut<'a, T, R, C, S>,
|
I: MatrixIndexMut<'a, T, R, C, S>,
|
||||||
{
|
{
|
||||||
index.index_mut(self)
|
index.index_mut(self)
|
||||||
|
@ -539,7 +539,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
|
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
S: RawStorageMut<T, R, C>,
|
||||||
I: MatrixIndexMut<'a, T, R, C, S>,
|
I: MatrixIndexMut<'a, T, R, C, S>,
|
||||||
{
|
{
|
||||||
index.get_unchecked_mut(self)
|
index.get_unchecked_mut(self)
|
||||||
|
@ -548,9 +548,12 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
// EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS
|
// EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS
|
||||||
|
|
||||||
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndex<'a, T, R, C, S> for usize
|
impl<'a, T, R, C, S> MatrixIndex<'a, T, R, C, S> for usize
|
||||||
where
|
where
|
||||||
S: Storage<T, R, C>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
type Output = &'a T;
|
type Output = &'a T;
|
||||||
|
|
||||||
|
@ -567,9 +570,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndexMut<'a, T, R, C, S> for usize
|
impl<'a, T, R, C, S> MatrixIndexMut<'a, T, R, C, S> for usize
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorageMut<T, R, C>,
|
||||||
{
|
{
|
||||||
type OutputMut = &'a mut T;
|
type OutputMut = &'a mut T;
|
||||||
|
|
||||||
|
@ -577,7 +583,7 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
|
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
S: RawStorageMut<T, R, C>,
|
||||||
{
|
{
|
||||||
matrix.data.get_unchecked_linear_mut(self)
|
matrix.data.get_unchecked_linear_mut(self)
|
||||||
}
|
}
|
||||||
|
@ -585,9 +591,11 @@ where
|
||||||
|
|
||||||
// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES
|
// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES
|
||||||
|
|
||||||
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndex<'a, T, R, C, S> for (usize, usize)
|
impl<'a, T: 'a, R, C, S> MatrixIndex<'a, T, R, C, S> for (usize, usize)
|
||||||
where
|
where
|
||||||
S: Storage<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
type Output = &'a T;
|
type Output = &'a T;
|
||||||
|
|
||||||
|
@ -595,7 +603,7 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool {
|
fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool {
|
||||||
let (rows, cols) = self;
|
let (rows, cols) = self;
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
|
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,9 +615,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a, R: Dim, C: Dim, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize)
|
impl<'a, T: 'a, R, C, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize)
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: RawStorageMut<T, R, C>,
|
||||||
{
|
{
|
||||||
type OutputMut = &'a mut T;
|
type OutputMut = &'a mut T;
|
||||||
|
|
||||||
|
@ -617,7 +627,7 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
|
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
S: RawStorageMut<T, R, C>,
|
||||||
{
|
{
|
||||||
let (row, col) = self;
|
let (row, col) = self;
|
||||||
matrix.data.get_unchecked_mut(row, col)
|
matrix.data.get_unchecked_mut(row, col)
|
||||||
|
@ -643,10 +653,12 @@ macro_rules! impl_index_pair {
|
||||||
$(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*]
|
$(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*]
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
impl<'a, T: 'a, $R: Dim, $C: Dim, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*>
|
impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
|
||||||
MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx)
|
|
||||||
where
|
where
|
||||||
S: Storage<T, R, C>,
|
T: Scalar,
|
||||||
|
$R: Dim,
|
||||||
|
$C: Dim,
|
||||||
|
S: RawStorage<T, R, C>,
|
||||||
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
|
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
|
||||||
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
|
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
|
||||||
{
|
{
|
||||||
|
@ -656,7 +668,7 @@ macro_rules! impl_index_pair {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool {
|
fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool {
|
||||||
let (rows, cols) = self;
|
let (rows, cols) = self;
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
|
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,21 +678,23 @@ macro_rules! impl_index_pair {
|
||||||
use crate::base::SliceStorage;
|
use crate::base::SliceStorage;
|
||||||
|
|
||||||
let (rows, cols) = self;
|
let (rows, cols) = self;
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
|
|
||||||
let data =
|
let data =
|
||||||
SliceStorage::new_unchecked(&matrix.data,
|
SliceStorage::new_unchecked(&matrix.data,
|
||||||
(rows.lower(nrows), cols.lower(ncols)),
|
(rows.lower(nrows), cols.lower(ncols)),
|
||||||
(rows.length(nrows), cols.length(ncols)));
|
(rows.length(nrows), cols.length(ncols)));
|
||||||
|
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a, $R: Dim, $C: Dim, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*>
|
impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
|
||||||
MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx)
|
|
||||||
where
|
where
|
||||||
S: StorageMut<T, R, C>,
|
T: Scalar,
|
||||||
|
$R: Dim,
|
||||||
|
$C: Dim,
|
||||||
|
S: RawStorageMut<T, R, C>,
|
||||||
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
|
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
|
||||||
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
|
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
|
||||||
{
|
{
|
||||||
|
@ -692,14 +706,14 @@ macro_rules! impl_index_pair {
|
||||||
use crate::base::SliceStorageMut;
|
use crate::base::SliceStorageMut;
|
||||||
|
|
||||||
let (rows, cols) = self;
|
let (rows, cols) = self;
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
|
|
||||||
let data =
|
let data =
|
||||||
SliceStorageMut::new_unchecked(&mut matrix.data,
|
SliceStorageMut::new_unchecked(&mut matrix.data,
|
||||||
(rows.lower(nrows), cols.lower(ncols)),
|
(rows.lower(nrows), cols.lower(ncols)),
|
||||||
(rows.length(nrows), cols.length(ncols)));
|
(rows.length(nrows), cols.length(ncols)));
|
||||||
|
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,13 @@ use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use crate::base::dimension::{Dim, U1};
|
use crate::base::dimension::{Dim, U1};
|
||||||
use crate::base::storage::{Storage, StorageMut};
|
use crate::base::storage::{RawStorage, RawStorageMut};
|
||||||
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut};
|
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar};
|
||||||
|
|
||||||
macro_rules! iterator {
|
macro_rules! iterator {
|
||||||
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
|
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
|
||||||
/// An iterator through a dense matrix with arbitrary strides matrix.
|
/// An iterator through a dense matrix with arbitrary strides matrix.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
|
pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
|
||||||
ptr: $Ptr,
|
ptr: $Ptr,
|
||||||
inner_ptr: $Ptr,
|
inner_ptr: $Ptr,
|
||||||
|
@ -170,8 +171,8 @@ macro_rules! iterator {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator!(struct MatrixIter for Storage.ptr -> *const T, &'a T, &'a S);
|
iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S);
|
||||||
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
|
iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
@ -180,18 +181,18 @@ iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a
|
||||||
*/
|
*/
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// An iterator through the rows of a matrix.
|
/// An iterator through the rows of a matrix.
|
||||||
pub struct RowIter<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> {
|
pub struct RowIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
|
||||||
mat: &'a Matrix<T, R, C, S>,
|
mat: &'a Matrix<T, R, C, S>,
|
||||||
curr: usize,
|
curr: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> RowIter<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> RowIter<'a, T, R, C, S> {
|
||||||
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
|
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
RowIter { mat, curr: 0 }
|
RowIter { mat, curr: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> {
|
||||||
type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>;
|
type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -219,7 +220,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIter<'a, T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
|
||||||
for RowIter<'a, T, R, C, S>
|
for RowIter<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -229,13 +230,14 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator through the mutable rows of a matrix.
|
/// An iterator through the mutable rows of a matrix.
|
||||||
pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> {
|
#[derive(Debug)]
|
||||||
|
pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
|
||||||
mat: *mut Matrix<T, R, C, S>,
|
mat: *mut Matrix<T, R, C, S>,
|
||||||
curr: usize,
|
curr: usize,
|
||||||
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
|
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> {
|
||||||
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
|
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
|
||||||
RowIterMut {
|
RowIterMut {
|
||||||
mat,
|
mat,
|
||||||
|
@ -249,7 +251,9 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a, T, R, C,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator for RowIterMut<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
|
||||||
|
for RowIterMut<'a, T, R, C, S>
|
||||||
|
{
|
||||||
type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>;
|
type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -274,7 +278,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator for RowIterMut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
|
||||||
for RowIterMut<'a, T, R, C, S>
|
for RowIterMut<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -290,18 +294,18 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
|
||||||
*/
|
*/
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// An iterator through the columns of a matrix.
|
/// An iterator through the columns of a matrix.
|
||||||
pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: Storage<T, R, C>> {
|
pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
|
||||||
mat: &'a Matrix<T, R, C, S>,
|
mat: &'a Matrix<T, R, C, S>,
|
||||||
curr: usize,
|
curr: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ColumnIter<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ColumnIter<'a, T, R, C, S> {
|
||||||
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
|
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
|
||||||
ColumnIter { mat, curr: 0 }
|
ColumnIter { mat, curr: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for ColumnIter<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for ColumnIter<'a, T, R, C, S> {
|
||||||
type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>;
|
type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -329,7 +333,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for ColumnIter<'a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
|
||||||
for ColumnIter<'a, T, R, C, S>
|
for ColumnIter<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -339,13 +343,14 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator through the mutable columns of a matrix.
|
/// An iterator through the mutable columns of a matrix.
|
||||||
pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: StorageMut<T, R, C>> {
|
#[derive(Debug)]
|
||||||
|
pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
|
||||||
mat: *mut Matrix<T, R, C, S>,
|
mat: *mut Matrix<T, R, C, S>,
|
||||||
curr: usize,
|
curr: usize,
|
||||||
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
|
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> {
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> {
|
||||||
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
|
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
|
||||||
ColumnIterMut {
|
ColumnIterMut {
|
||||||
mat,
|
mat,
|
||||||
|
@ -359,7 +364,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'a, T, R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
|
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
|
||||||
for ColumnIterMut<'a, T, R, C, S>
|
for ColumnIterMut<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>;
|
type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>;
|
||||||
|
@ -386,7 +391,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
|
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
|
||||||
for ColumnIterMut<'a, T, R, C, S>
|
for ColumnIterMut<'a, T, R, C, S>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,9 +9,11 @@ use crate::base::{DefaultAllocator, OMatrix, Scalar};
|
||||||
* Simd structures.
|
* Simd structures.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
impl<T, R: Dim, C: Dim> SimdValue for OMatrix<T, R, C>
|
impl<T, R, C> SimdValue for OMatrix<T, R, C>
|
||||||
where
|
where
|
||||||
T: Scalar + SimdValue,
|
T: Scalar + SimdValue,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar,
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
{
|
{
|
||||||
|
@ -42,7 +44,6 @@ where
|
||||||
fn replace(&mut self, i: usize, val: Self::Element) {
|
fn replace(&mut self, i: usize, val: Self::Element) {
|
||||||
self.zip_apply(&val, |mut a, b| {
|
self.zip_apply(&val, |mut a, b| {
|
||||||
a.replace(i, b);
|
a.replace(i, b);
|
||||||
a
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +51,6 @@ where
|
||||||
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
|
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
|
||||||
self.zip_apply(&val, |mut a, b| {
|
self.zip_apply(&val, |mut a, b| {
|
||||||
a.replace_unchecked(i, b);
|
a.replace_unchecked(i, b);
|
||||||
a
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
|
use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, InnerAllocator};
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1};
|
use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1};
|
||||||
use crate::base::iter::MatrixIter;
|
use crate::base::iter::MatrixIter;
|
||||||
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
|
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage};
|
||||||
use crate::base::{Matrix, Owned};
|
use crate::base::{Matrix, Scalar};
|
||||||
|
|
||||||
macro_rules! slice_storage_impl(
|
macro_rules! slice_storage_impl(
|
||||||
($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => {
|
($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => {
|
||||||
|
@ -82,7 +81,7 @@ macro_rules! slice_storage_impl(
|
||||||
impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
$T<'a, T, R, C, RStride, CStride>
|
$T<'a, T, R, C, RStride, CStride>
|
||||||
where
|
where
|
||||||
Self: ContiguousStorage<T, R, C>
|
Self: RawStorage<T, R, C> + IsContiguous
|
||||||
{
|
{
|
||||||
/// Extracts the original slice from this storage
|
/// Extracts the original slice from this storage
|
||||||
pub fn into_slice(self) -> &'a [T] {
|
pub fn into_slice(self) -> &'a [T] {
|
||||||
|
@ -100,19 +99,19 @@ macro_rules! slice_storage_impl(
|
||||||
|
|
||||||
slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \
|
slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \
|
||||||
to another matrix data storage.";
|
to another matrix data storage.";
|
||||||
Storage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T));
|
RawStorage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T));
|
||||||
|
|
||||||
slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \
|
slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \
|
||||||
internal mutable reference to another matrix data storage.";
|
internal mutable reference to another matrix data storage.";
|
||||||
StorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T)
|
RawStorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T)
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
|
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
|
||||||
for SliceStorage<'a, T, R, C, RStride, CStride>
|
for SliceStorage<'a, T, R, C, RStride, CStride>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
|
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
|
||||||
for SliceStorage<'a, T, R, C, RStride, CStride>
|
for SliceStorage<'a, T, R, C, RStride, CStride>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -126,10 +125,10 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
SliceStorageMut<'a, T, R, C, RStride, CStride>
|
SliceStorageMut<'a, T, R, C, RStride, CStride>
|
||||||
where
|
where
|
||||||
Self: ContiguousStorageMut<T, R, C>,
|
Self: RawStorageMut<T, R, C> + IsContiguous,
|
||||||
{
|
{
|
||||||
/// Extracts the original slice from this storage
|
/// Extracts the original slice from this storage
|
||||||
pub fn into_slice_mut(self) -> &'a mut [T] {
|
pub fn into_slice_mut(self) -> &'a mut [T] {
|
||||||
|
@ -145,7 +144,7 @@ where
|
||||||
|
|
||||||
macro_rules! storage_impl(
|
macro_rules! storage_impl(
|
||||||
($($T: ident),* $(,)*) => {$(
|
($($T: ident),* $(,)*) => {$(
|
||||||
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
|
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage<T, R, C>
|
||||||
for $T<'a, T, R, C, RStride, CStride> {
|
for $T<'a, T, R, C, RStride, CStride> {
|
||||||
|
|
||||||
type RStride = RStride;
|
type RStride = RStride;
|
||||||
|
@ -182,26 +181,6 @@ macro_rules! storage_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_owned(self) -> Owned<T, R, C>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
|
||||||
{
|
|
||||||
self.clone_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clone_owned(&self) -> Owned<T, R, C>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
|
||||||
{
|
|
||||||
let (nrows, ncols) = self.shape();
|
|
||||||
let it = MatrixIter::new(self).cloned();
|
|
||||||
Owned( DefaultAllocator::allocate_from_iterator(nrows, ncols, it))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
@ -214,39 +193,29 @@ macro_rules! storage_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
|
||||||
|
for $T<'a, T, R, C, RStride, CStride> {
|
||||||
|
#[inline]
|
||||||
|
fn into_owned(self) -> Owned<T, R, C>
|
||||||
|
where DefaultAllocator: Allocator<T, R, C> {
|
||||||
|
self.clone_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_owned(&self) -> Owned<T, R, C>
|
||||||
|
where DefaultAllocator: Allocator<T, R, C> {
|
||||||
|
let (nrows, ncols) = self.shape();
|
||||||
|
let it = MatrixIter::new(self).cloned();
|
||||||
|
DefaultAllocator::allocate_from_iterator(nrows, ncols, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
)*}
|
)*}
|
||||||
);
|
);
|
||||||
|
|
||||||
storage_impl!(SliceStorage, SliceStorageMut);
|
storage_impl!(SliceStorage, SliceStorageMut);
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut<T, R, C>
|
||||||
SliceStorage<'a, MaybeUninit<T>, R, C, RStride, CStride>
|
|
||||||
{
|
|
||||||
/// Assumes a slice storage's entries to be initialized. This operation
|
|
||||||
/// should be near zero-cost.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
/// All of the slice storage's entries must be initialized, otherwise
|
|
||||||
/// Undefined Behavior will be triggered.
|
|
||||||
pub unsafe fn assume_init(self) -> SliceStorage<'a, T, R, C, RStride, CStride> {
|
|
||||||
SliceStorage::from_raw_parts(self.ptr as *const T, self.shape, self.strides)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
|
||||||
SliceStorageMut<'a, MaybeUninit<T>, R, C, RStride, CStride>
|
|
||||||
{
|
|
||||||
/// Assumes a slice storage's entries to be initialized. This operation should be near zero-cost.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
/// The user must make sure that every single entry of the buffer has been initialized,
|
|
||||||
/// or Undefined Behavior will immediately occur.
|
|
||||||
pub unsafe fn assume_init(self) -> SliceStorageMut<'a, T, R, C, RStride, CStride> {
|
|
||||||
SliceStorageMut::from_raw_parts(self.ptr as *mut T, self.shape, self.strides)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<T, R, C>
|
|
||||||
for SliceStorageMut<'a, T, R, C, RStride, CStride>
|
for SliceStorageMut<'a, T, R, C, RStride, CStride>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -266,37 +235,22 @@ unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<T, R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1>
|
unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for SliceStorage<'a, T, R, U1, U1, CStride> {}
|
||||||
for SliceStorage<'a, T, R, U1, U1, CStride>
|
unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1>
|
|
||||||
for SliceStorageMut<'a, T, R, U1, U1, CStride>
|
for SliceStorageMut<'a, T, R, U1, U1, CStride>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a, T, R: Dim, CStride: Dim> ContiguousStorageMut<T, R, U1>
|
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
|
||||||
for SliceStorageMut<'a, T, R, U1, U1, CStride>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
|
|
||||||
for SliceStorage<'a, T, R, C, U1, R>
|
for SliceStorage<'a, T, R, C, U1, R>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
|
||||||
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
|
|
||||||
for SliceStorageMut<'a, T, R, C, U1, R>
|
for SliceStorageMut<'a, T, R, C, U1, R>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<T, R, C>
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
for SliceStorageMut<'a, T, R, C, U1, R>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn assert_slice_index(
|
fn assert_slice_index(
|
||||||
&self,
|
&self,
|
||||||
|
@ -344,7 +298,6 @@ macro_rules! matrix_slice_impl(
|
||||||
$fixed_slice_with_steps: ident,
|
$fixed_slice_with_steps: ident,
|
||||||
$generic_slice: ident,
|
$generic_slice: ident,
|
||||||
$generic_slice_with_steps: ident,
|
$generic_slice_with_steps: ident,
|
||||||
$full_slice: ident,
|
|
||||||
$rows_range_pair: ident,
|
$rows_range_pair: ident,
|
||||||
$columns_range_pair: ident) => {
|
$columns_range_pair: ident) => {
|
||||||
/*
|
/*
|
||||||
|
@ -403,14 +356,14 @@ macro_rules! matrix_slice_impl(
|
||||||
pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice)
|
pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice)
|
||||||
-> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> {
|
-> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> {
|
||||||
|
|
||||||
let my_shape = $me.data.shape();
|
let my_shape = $me.shape_generic();
|
||||||
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0));
|
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0));
|
||||||
|
|
||||||
let shape = (nrows, my_shape.1);
|
let shape = (nrows, my_shape.1);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape);
|
let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +374,7 @@ macro_rules! matrix_slice_impl(
|
||||||
-> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
|
-> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
|
||||||
where RSlice: Dim {
|
where RSlice: Dim {
|
||||||
|
|
||||||
let my_shape = $me.data.shape();
|
let my_shape = $me.shape_generic();
|
||||||
let my_strides = $me.data.strides();
|
let my_strides = $me.data.strides();
|
||||||
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0));
|
$me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0));
|
||||||
|
|
||||||
|
@ -430,7 +383,7 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides);
|
let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,23 +444,24 @@ macro_rules! matrix_slice_impl(
|
||||||
pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
|
pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
|
||||||
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> {
|
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> {
|
||||||
|
|
||||||
let my_shape = $me.data.shape();
|
let my_shape = $me.shape_generic();
|
||||||
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0));
|
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0));
|
||||||
let shape = (my_shape.0, ncols);
|
let shape = (my_shape.0, ncols);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_unchecked($data, (0, first_col), shape);
|
let data = $SliceStorage::new_unchecked($data, (0, first_col), shape);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may
|
/// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may
|
||||||
/// or may not be values known at compile-time.
|
/// or may not be values known at compile-time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
|
pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
|
||||||
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> {
|
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> {
|
||||||
|
|
||||||
let my_shape = $me.data.shape();
|
let my_shape = $me.shape_generic();
|
||||||
let my_strides = $me.data.strides();
|
let my_strides = $me.data.strides();
|
||||||
|
|
||||||
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step));
|
$me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step));
|
||||||
|
@ -517,7 +471,7 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides);
|
let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,10 +491,11 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_unchecked($data, start, shape);
|
let data = $SliceStorage::new_unchecked($data, start, shape);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Slices this matrix starting at its component `(start.0, start.1)` and with
|
/// Slices this matrix starting at its component `(start.0, start.1)` and with
|
||||||
/// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is
|
/// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is
|
||||||
/// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the
|
/// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the
|
||||||
|
@ -564,7 +519,7 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_unchecked($data, (irow, icol), shape);
|
let data = $SliceStorage::new_unchecked($data, (irow, icol), shape);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,14 +536,16 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
/// Creates a slice that may or may not have a fixed size and stride.
|
/// Creates a slice that may or may not have a fixed size and stride.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $generic_slice<RSlice: Dim, CSlice: Dim>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
|
pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
|
||||||
-> $MatrixSlice<T, RSlice, CSlice, S::RStride, S::CStride>
|
-> $MatrixSlice<'_, T, RSlice, CSlice, S::RStride, S::CStride>
|
||||||
{
|
where RSlice: Dim,
|
||||||
|
CSlice: Dim {
|
||||||
|
|
||||||
$me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0));
|
$me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_unchecked($data, start, shape);
|
let data = $SliceStorage::new_unchecked($data, start, shape);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,16 +567,10 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides);
|
let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides);
|
||||||
Matrix::from_data(data)
|
Matrix::from_data_statically_unchecked(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a slice containing the entire matrix.
|
|
||||||
pub fn $full_slice($me: $Me) -> $MatrixSlice<T, R, C, S::RStride, S::CStride> {
|
|
||||||
let (nrows, ncols) = $me.shape();
|
|
||||||
$me.$generic_slice((0, 0), (R::from_usize(nrows), C::from_usize(ncols)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Splitting.
|
* Splitting.
|
||||||
|
@ -633,7 +584,7 @@ macro_rules! matrix_slice_impl(
|
||||||
-> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>,
|
-> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>,
|
||||||
$MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) {
|
$MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) {
|
||||||
|
|
||||||
let (nrows, ncols) = $me.data.shape();
|
let (nrows, ncols) = $me.shape_generic();
|
||||||
let strides = $me.data.strides();
|
let strides = $me.data.strides();
|
||||||
|
|
||||||
let start1 = r1.begin(nrows);
|
let start1 = r1.begin(nrows);
|
||||||
|
@ -654,8 +605,8 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides);
|
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides);
|
||||||
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides);
|
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides);
|
||||||
let slice1 = Matrix::from_data(data1);
|
let slice1 = Matrix::from_data_statically_unchecked(data1);
|
||||||
let slice2 = Matrix::from_data(data2);
|
let slice2 = Matrix::from_data_statically_unchecked(data2);
|
||||||
|
|
||||||
(slice1, slice2)
|
(slice1, slice2)
|
||||||
}
|
}
|
||||||
|
@ -669,7 +620,7 @@ macro_rules! matrix_slice_impl(
|
||||||
-> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>,
|
-> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>,
|
||||||
$MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) {
|
$MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) {
|
||||||
|
|
||||||
let (nrows, ncols) = $me.data.shape();
|
let (nrows, ncols) = $me.shape_generic();
|
||||||
let strides = $me.data.strides();
|
let strides = $me.data.strides();
|
||||||
|
|
||||||
let start1 = r1.begin(ncols);
|
let start1 = r1.begin(ncols);
|
||||||
|
@ -690,8 +641,8 @@ macro_rules! matrix_slice_impl(
|
||||||
|
|
||||||
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides);
|
let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides);
|
||||||
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides);
|
let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides);
|
||||||
let slice1 = Matrix::from_data(data1);
|
let slice1 = Matrix::from_data_statically_unchecked(data1);
|
||||||
let slice2 = Matrix::from_data(data2);
|
let slice2 = Matrix::from_data_statically_unchecked(data2);
|
||||||
|
|
||||||
(slice1, slice2)
|
(slice1, slice2)
|
||||||
}
|
}
|
||||||
|
@ -707,9 +658,9 @@ pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> =
|
||||||
Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>;
|
Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>;
|
||||||
|
|
||||||
/// # Slicing based on index and length
|
/// # Slicing based on index and length
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
matrix_slice_impl!(
|
matrix_slice_impl!(
|
||||||
self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data;
|
self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data;
|
||||||
row,
|
row,
|
||||||
row_part,
|
row_part,
|
||||||
rows,
|
rows,
|
||||||
|
@ -732,15 +683,14 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
fixed_slice_with_steps,
|
fixed_slice_with_steps,
|
||||||
generic_slice,
|
generic_slice,
|
||||||
generic_slice_with_steps,
|
generic_slice_with_steps,
|
||||||
full_slice,
|
|
||||||
rows_range_pair,
|
rows_range_pair,
|
||||||
columns_range_pair);
|
columns_range_pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Mutable slicing based on index and length
|
/// # Mutable slicing based on index and length
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
matrix_slice_impl!(
|
matrix_slice_impl!(
|
||||||
self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut.get_address_unchecked_mut(), &mut self.data;
|
self: &mut Self, MatrixSliceMut, SliceStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data;
|
||||||
row_mut,
|
row_mut,
|
||||||
row_part_mut,
|
row_part_mut,
|
||||||
rows_mut,
|
rows_mut,
|
||||||
|
@ -763,29 +713,10 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
fixed_slice_with_steps_mut,
|
fixed_slice_with_steps_mut,
|
||||||
generic_slice_mut,
|
generic_slice_mut,
|
||||||
generic_slice_with_steps_mut,
|
generic_slice_with_steps_mut,
|
||||||
full_slice_mut,
|
|
||||||
rows_range_pair_mut,
|
rows_range_pair_mut,
|
||||||
columns_range_pair_mut);
|
columns_range_pair_mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
|
||||||
MatrixSlice<'a, MaybeUninit<T>, R, C, RStride, CStride>
|
|
||||||
{
|
|
||||||
/// Assumes a matrix slices's entries to be initialized. This operation should be near zero-cost.
|
|
||||||
pub unsafe fn slice_assume_init(self) -> MatrixSlice<'a, T, R, C, RStride, CStride> {
|
|
||||||
Matrix::from_data(self.data.assume_init())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
|
||||||
MatrixSliceMut<'a, MaybeUninit<T>, R, C, RStride, CStride>
|
|
||||||
{
|
|
||||||
/// Assumes a matrix slices's entries to be initialized. This operation should be near zero-cost.
|
|
||||||
pub unsafe fn slice_assume_init(self) -> MatrixSliceMut<'a, T, R, C, RStride, CStride> {
|
|
||||||
Matrix::from_data(self.data.assume_init())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A range with a size that may be known at compile-time.
|
/// A range with a size that may be known at compile-time.
|
||||||
///
|
///
|
||||||
/// This may be:
|
/// This may be:
|
||||||
|
@ -922,7 +853,7 @@ impl<D: Dim> SliceRange<D> for RangeInclusive<usize> {
|
||||||
|
|
||||||
// TODO: see how much of this overlaps with the general indexing
|
// TODO: see how much of this overlaps with the general indexing
|
||||||
// methods from indexing.rs.
|
// methods from indexing.rs.
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
|
/// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
|
||||||
/// by the range `cols`.
|
/// by the range `cols`.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -936,7 +867,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
RowRange: SliceRange<R>,
|
RowRange: SliceRange<R>,
|
||||||
ColRange: SliceRange<C>,
|
ColRange: SliceRange<C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.data.shape();
|
let (nrows, ncols) = self.shape_generic();
|
||||||
self.generic_slice(
|
self.generic_slice(
|
||||||
(rows.begin(nrows), cols.begin(ncols)),
|
(rows.begin(nrows), cols.begin(ncols)),
|
||||||
(rows.size(nrows), cols.size(ncols)),
|
(rows.size(nrows), cols.size(ncols)),
|
||||||
|
@ -966,7 +897,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
// TODO: see how much of this overlaps with the general indexing
|
// TODO: see how much of this overlaps with the general indexing
|
||||||
// methods from indexing.rs.
|
// methods from indexing.rs.
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns
|
/// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns
|
||||||
/// indexed by the range `cols`.
|
/// indexed by the range `cols`.
|
||||||
pub fn slice_range_mut<RowRange, ColRange>(
|
pub fn slice_range_mut<RowRange, ColRange>(
|
||||||
|
@ -978,7 +909,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
RowRange: SliceRange<R>,
|
RowRange: SliceRange<R>,
|
||||||
ColRange: SliceRange<C>,
|
ColRange: SliceRange<C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.data.shape();
|
let (nrows, ncols) = self.shape_generic();
|
||||||
self.generic_slice_mut(
|
self.generic_slice_mut(
|
||||||
(rows.begin(nrows), cols.begin(ncols)),
|
(rows.begin(nrows), cols.begin(ncols)),
|
||||||
(rows.size(nrows), cols.size(ncols)),
|
(rows.size(nrows), cols.size(ncols)),
|
||||||
|
@ -1004,9 +935,13 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
impl<'a, T, R, C, RStride, CStride> From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
|
||||||
From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
|
|
||||||
for MatrixSlice<'a, T, R, C, RStride, CStride>
|
for MatrixSlice<'a, T, R, C, RStride, CStride>
|
||||||
|
where
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
{
|
{
|
||||||
fn from(slice_mut: MatrixSliceMut<'a, T, R, C, RStride, CStride>) -> Self {
|
fn from(slice_mut: MatrixSliceMut<'a, T, R, C, RStride, CStride>) -> Self {
|
||||||
let data = SliceStorage {
|
let data = SliceStorage {
|
||||||
|
@ -1016,6 +951,6 @@ impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
|
||||||
_phantoms: PhantomData,
|
_phantoms: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
Matrix::from_data(data)
|
unsafe { Matrix::from_data_statically_unchecked(data) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::storage::Storage;
|
use crate::storage::RawStorage;
|
||||||
use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector};
|
use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector};
|
||||||
use num::{Signed, Zero};
|
use num::{Signed, Zero};
|
||||||
use simba::simd::SimdSigned;
|
use simba::simd::SimdSigned;
|
||||||
|
|
||||||
/// # Find the min and max components
|
/// # Find the min and max components
|
||||||
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Returns the absolute value of the component with the largest absolute value.
|
/// Returns the absolute value of the component with the largest absolute value.
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -167,7 +167,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Computes the index of the matrix component with the largest absolute value.
|
/// Computes the index of the matrix component with the largest absolute value.
|
||||||
///
|
///
|
||||||
/// # Examples:
|
/// # Examples:
|
||||||
|
@ -203,7 +203,7 @@ impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matri
|
||||||
|
|
||||||
// TODO: find a way to avoid code duplication just for complex number support.
|
// TODO: find a way to avoid code duplication just for complex number support.
|
||||||
/// # Find the min and max components (vector-specific methods)
|
/// # Find the min and max components (vector-specific methods)
|
||||||
impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
|
impl<T: Scalar, D: Dim, S: RawStorage<T, D>> Vector<T, D, S> {
|
||||||
/// Computes the index of the vector component with the largest complex or real absolute value.
|
/// Computes the index of the vector component with the largest complex or real absolute value.
|
||||||
///
|
///
|
||||||
/// # Examples:
|
/// # Examples:
|
||||||
|
|
|
@ -33,10 +33,12 @@ mod unit;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
mod vec_storage;
|
mod vec_storage;
|
||||||
|
|
||||||
|
mod blas_uninit;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod helper;
|
pub mod helper;
|
||||||
mod interpolation;
|
mod interpolation;
|
||||||
mod min_max;
|
mod min_max;
|
||||||
|
pub mod uninit;
|
||||||
|
|
||||||
pub use self::matrix::*;
|
pub use self::matrix::*;
|
||||||
pub use self::norm::*;
|
pub use self::norm::*;
|
||||||
|
@ -50,5 +52,6 @@ pub use self::alias::*;
|
||||||
pub use self::alias_slice::*;
|
pub use self::alias_slice::*;
|
||||||
pub use self::array_storage::*;
|
pub use self::array_storage::*;
|
||||||
pub use self::matrix_slice::*;
|
pub use self::matrix_slice::*;
|
||||||
|
pub use self::storage::*;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub use self::vec_storage::*;
|
pub use self::vec_storage::*;
|
||||||
|
|
|
@ -434,7 +434,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
{
|
{
|
||||||
let n = self.norm();
|
let n = self.norm();
|
||||||
let le = n.simd_le(min_norm);
|
let le = n.simd_le(min_norm);
|
||||||
self.apply(|e| e.simd_unscale(n).select(le, e));
|
self.apply(|e| *e = e.simd_unscale(n).select(le, *e));
|
||||||
SimdOption::new(n, le)
|
SimdOption::new(n, le)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,13 +508,8 @@ where
|
||||||
/// The i-the canonical basis element.
|
/// The i-the canonical basis element.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn canonical_basis_element(i: usize) -> Self {
|
fn canonical_basis_element(i: usize) -> Self {
|
||||||
assert!(i < D::dim(), "Index out of bound.");
|
|
||||||
|
|
||||||
let mut res = Self::zero();
|
let mut res = Self::zero();
|
||||||
unsafe {
|
res[i] = T::one();
|
||||||
*res.data.get_unchecked_linear_mut(i) = T::one();
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
247
src/base/ops.rs
247
src/base/ops.rs
|
@ -1,29 +1,31 @@
|
||||||
use num::{One, Zero};
|
use num::{One, Zero};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::ops::{
|
use std::ops::{
|
||||||
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
|
||||||
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
|
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
|
||||||
|
|
||||||
use crate::base::allocator::{
|
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
||||||
Allocator, InnerAllocator, SameShapeAllocator, SameShapeC, SameShapeR,
|
use crate::base::blas_uninit::gemm_uninit;
|
||||||
};
|
|
||||||
use crate::base::constraint::{
|
use crate::base::constraint::{
|
||||||
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
|
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
|
||||||
};
|
};
|
||||||
use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
|
use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
|
||||||
use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut};
|
use crate::base::storage::{Storage, StorageMut};
|
||||||
|
use crate::base::uninit::Uninit;
|
||||||
use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice};
|
use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice};
|
||||||
use crate::{MatrixSliceMut, SimdComplexField};
|
use crate::storage::IsContiguous;
|
||||||
|
use crate::uninit::{Init, InitStatus};
|
||||||
|
use crate::{RawStorage, RawStorageMut, SimdComplexField};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Indexing.
|
* Indexing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -33,10 +35,7 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T, R, C, S>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim, S> Index<(usize, usize)> for Matrix<T, R, C, S>
|
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<(usize, usize)> for Matrix<T, R, C, S> {
|
||||||
where
|
|
||||||
S: Storage<T, R, C>,
|
|
||||||
{
|
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -52,7 +51,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutable versions.
|
// Mutable versions.
|
||||||
impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
|
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, i: usize) -> &mut T {
|
fn index_mut(&mut self, i: usize) -> &mut T {
|
||||||
let ij = self.vector_to_matrix_index(i);
|
let ij = self.vector_to_matrix_index(i);
|
||||||
|
@ -60,10 +59,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim, S> IndexMut<(usize, usize)> for Matrix<T, R, C, S>
|
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<(usize, usize)> for Matrix<T, R, C, S> {
|
||||||
where
|
|
||||||
S: StorageMut<T, R, C>,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
|
fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
|
||||||
let shape = self.shape();
|
let shape = self.shape();
|
||||||
|
@ -135,25 +131,27 @@ macro_rules! componentwise_binop_impl(
|
||||||
($Trait: ident, $method: ident, $bound: ident;
|
($Trait: ident, $method: ident, $bound: ident;
|
||||||
$TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident,
|
$TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident,
|
||||||
$method_assign_statically_unchecked_rhs: ident;
|
$method_assign_statically_unchecked_rhs: ident;
|
||||||
$method_to: ident, $method_to_statically_unchecked: ident) => {
|
$method_to: ident, $method_to_statically_unchecked_uninit: ident) => {
|
||||||
|
|
||||||
impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
|
impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
|
||||||
where
|
where T: Scalar + $bound {
|
||||||
T: Scalar + $bound
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Methods without dimension checking at compile-time.
|
* Methods without dimension checking at compile-time.
|
||||||
* This is useful for code reuse because the sum representative system does not play
|
* This is useful for code reuse because the sum representative system does not plays
|
||||||
* nicely with static checks.
|
* easily with static checks.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method_to_statically_unchecked<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
fn $method_to_statically_unchecked_uninit<Status, R2: Dim, C2: Dim, SB,
|
||||||
&self, rhs: &Matrix<T, R2, C2, SB>, out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>
|
R3: Dim, C3: Dim, SC>(&self,
|
||||||
) where
|
status: Status,
|
||||||
SB: Storage<T, R2, C2>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>
|
out: &mut Matrix<Status::Value, R3, C3, SC>)
|
||||||
{
|
where Status: InitStatus<T>,
|
||||||
|
SB: RawStorage<T, R2, C2>,
|
||||||
|
SC: RawStorageMut<Status::Value, R3, C3> {
|
||||||
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
||||||
assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
|
assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
|
||||||
|
|
||||||
|
@ -165,29 +163,26 @@ macro_rules! componentwise_binop_impl(
|
||||||
let arr2 = rhs.data.as_slice_unchecked();
|
let arr2 = rhs.data.as_slice_unchecked();
|
||||||
let out = out.data.as_mut_slice_unchecked();
|
let out = out.data.as_mut_slice_unchecked();
|
||||||
for i in 0 .. arr1.len() {
|
for i in 0 .. arr1.len() {
|
||||||
*out.get_unchecked_mut(i) = MaybeUninit::new(
|
Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()));
|
||||||
arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
*out.get_unchecked_mut((i, j)) = MaybeUninit::new(
|
let val = self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone());
|
||||||
self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone())
|
Status::init(out.get_unchecked_mut((i, j)), val);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method_assign_statically_unchecked<R2: Dim, C2: Dim, SB>(
|
fn $method_assign_statically_unchecked<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
|
||||||
&mut self, rhs: &Matrix<T, R2, C2, SB>
|
where R2: Dim,
|
||||||
) where
|
C2: Dim,
|
||||||
SA: StorageMut<T, R1, C1>,
|
SA: StorageMut<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>
|
SB: Storage<T, R2, C2> {
|
||||||
{
|
|
||||||
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
||||||
|
|
||||||
// This is the most common case and should be deduced at compile-time.
|
// This is the most common case and should be deduced at compile-time.
|
||||||
|
@ -210,12 +205,12 @@ macro_rules! componentwise_binop_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method_assign_statically_unchecked_rhs<R2: Dim, C2: Dim, SB>(
|
fn $method_assign_statically_unchecked_rhs<R2, C2, SB>(&self, rhs: &mut Matrix<T, R2, C2, SB>)
|
||||||
&self, rhs: &mut Matrix<T, R2, C2, SB>
|
where R2: Dim,
|
||||||
) where
|
C2: Dim,
|
||||||
SB: StorageMut<T, R2, C2>
|
SB: StorageMut<T, R2, C2> {
|
||||||
{
|
|
||||||
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
|
||||||
|
|
||||||
// This is the most common case and should be deduced at compile-time.
|
// This is the most common case and should be deduced at compile-time.
|
||||||
|
@ -250,20 +245,15 @@ macro_rules! componentwise_binop_impl(
|
||||||
*/
|
*/
|
||||||
/// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations.
|
/// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $method_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
pub fn $method_to<R2: Dim, C2: Dim, SB,
|
||||||
&self,
|
R3: Dim, C3: Dim, SC>(&self,
|
||||||
rhs: &Matrix<T, R2, C2, SB>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>
|
out: &mut Matrix<T, R3, C3, SC>)
|
||||||
) where
|
where SB: Storage<T, R2, C2>,
|
||||||
SB: Storage<T, R2, C2>,
|
SC: StorageMut<T, R3, C3>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
|
||||||
ShapeConstraint:
|
SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
|
||||||
SameNumberOfRows<R1, R2> +
|
self.$method_to_statically_unchecked_uninit(Init, rhs, out)
|
||||||
SameNumberOfColumns<C1, C2> +
|
|
||||||
SameNumberOfRows<R1, R3> +
|
|
||||||
SameNumberOfColumns<C1, C3>
|
|
||||||
{
|
|
||||||
self.$method_to_statically_unchecked(rhs, out)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,14 +275,13 @@ macro_rules! componentwise_binop_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
|
impl<'a, T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
|
||||||
where
|
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
|
||||||
T: Scalar + $bound,
|
T: Scalar + $bound,
|
||||||
SA: Storage<T, R1, C1>,
|
SA: Storage<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>,
|
DefaultAllocator: SameShapeAllocator<T, R2, C2, R1, C1>,
|
||||||
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1>
|
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> {
|
||||||
{
|
|
||||||
type Output = MatrixSum<T, R2, C2, R1, C1>;
|
type Output = MatrixSum<T, R2, C2, R1, C1>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -304,14 +293,13 @@ macro_rules! componentwise_binop_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
impl<T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
||||||
where
|
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
|
||||||
T: Scalar + $bound,
|
T: Scalar + $bound,
|
||||||
SA: Storage<T, R1, C1>,
|
SA: Storage<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
|
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
||||||
{
|
|
||||||
type Output = MatrixSum<T, R1, C1, R2, C2>;
|
type Output = MatrixSum<T, R1, C1, R2, C2>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -320,14 +308,13 @@ macro_rules! componentwise_binop_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
|
impl<'a, 'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
|
||||||
where
|
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
|
||||||
T: Scalar + $bound,
|
T: Scalar + $bound,
|
||||||
SA: Storage<T, R1, C1>,
|
SA: Storage<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
|
DefaultAllocator: SameShapeAllocator<T, R1, C1, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
||||||
{
|
|
||||||
type Output = MatrixSum<T, R1, C1, R2, C2>;
|
type Output = MatrixSum<T, R1, C1, R2, C2>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -335,33 +322,33 @@ macro_rules! componentwise_binop_impl(
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
|
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
|
||||||
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
|
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
let mut res = Matrix::uninit(nrows, ncols);
|
||||||
|
self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res);
|
||||||
self.$method_to_statically_unchecked(rhs, &mut res);
|
// SAFETY: the output has been initialized above.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
impl<'b, T, R1, C1, R2, C2, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
||||||
where
|
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
|
||||||
T: Scalar + $bound,
|
T: Scalar + $bound,
|
||||||
SA: StorageMut<T, R1, C1>,
|
SA: StorageMut<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) {
|
fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) {
|
||||||
self.$method_assign_statically_unchecked(rhs)
|
self.$method_assign_statically_unchecked(rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
impl<T, R1, C1, R2, C2, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
|
||||||
where
|
where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
|
||||||
T: Scalar + $bound,
|
T: Scalar + $bound,
|
||||||
SA: StorageMut<T, R1, C1>,
|
SA: StorageMut<T, R1, C1>,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) {
|
fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) {
|
||||||
self.$method_assign(&rhs)
|
self.$method_assign(&rhs)
|
||||||
|
@ -372,10 +359,10 @@ macro_rules! componentwise_binop_impl(
|
||||||
|
|
||||||
componentwise_binop_impl!(Add, add, ClosedAdd;
|
componentwise_binop_impl!(Add, add, ClosedAdd;
|
||||||
AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut;
|
AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut;
|
||||||
add_to, add_to_statically_unchecked);
|
add_to, add_to_statically_unchecked_uninit);
|
||||||
componentwise_binop_impl!(Sub, sub, ClosedSub;
|
componentwise_binop_impl!(Sub, sub, ClosedSub;
|
||||||
SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut;
|
SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut;
|
||||||
sub_to, sub_to_statically_unchecked);
|
sub_to, sub_to_statically_unchecked_uninit);
|
||||||
|
|
||||||
impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C>
|
impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C>
|
||||||
where
|
where
|
||||||
|
@ -574,9 +561,12 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
|
fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
|
||||||
let mut res = Matrix::new_uninitialized_generic(self.data.shape().0, rhs.data.shape().1);
|
let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1);
|
||||||
let _ = self.mul_to(rhs, &mut res);
|
unsafe {
|
||||||
unsafe { res.assume_init() }
|
// SAFETY: this is OK because status = Uninit && bevy == 0
|
||||||
|
gemm_uninit(Uninit, &mut res, T::one(), self, rhs, T::zero());
|
||||||
|
res.assume_init()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,14 +624,16 @@ where
|
||||||
// TODO: this is too restrictive:
|
// TODO: this is too restrictive:
|
||||||
// − we can't use `a *= b` when `a` is a mutable slice.
|
// − we can't use `a *= b` when `a` is a mutable slice.
|
||||||
// − we can't use `a *= b` when C2 is not equal to C1.
|
// − we can't use `a *= b` when C2 is not equal to C1.
|
||||||
impl<T, R1: Dim, C1: Dim, R2: Dim, SA, SB> MulAssign<Matrix<T, R2, C1, SB>>
|
impl<T, R1, C1, R2, SA, SB> MulAssign<Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
|
||||||
for Matrix<T, R1, C1, SA>
|
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
||||||
SB: Storage<T, R2, C1>,
|
SB: Storage<T, R2, C1>,
|
||||||
SA: ContiguousStorageMut<T, R1, C1>,
|
SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
|
||||||
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
|
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
|
||||||
DefaultAllocator: Allocator<T, R1, C1> + InnerAllocator<T, R1, C1, Buffer = SA>,
|
DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: Matrix<T, R2, C1, SB>) {
|
fn mul_assign(&mut self, rhs: Matrix<T, R2, C1, SB>) {
|
||||||
|
@ -649,15 +641,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, T, R1: Dim, C1: Dim, R2: Dim, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>>
|
impl<'b, T, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
|
||||||
for Matrix<T, R1, C1, SA>
|
|
||||||
where
|
where
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
||||||
SB: Storage<T, R2, C1>,
|
SB: Storage<T, R2, C1>,
|
||||||
SA: ContiguousStorageMut<T, R1, C1>,
|
SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
|
||||||
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
|
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
|
||||||
// TODO: this is too restrictive. See comments for the non-ref version.
|
// TODO: this is too restrictive. See comments for the non-ref version.
|
||||||
DefaultAllocator: Allocator<T, R1, C1> + InnerAllocator<T, R1, C1, Buffer = SA>,
|
DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) {
|
fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) {
|
||||||
|
@ -680,8 +674,9 @@ where
|
||||||
DefaultAllocator: Allocator<T, C1, C2>,
|
DefaultAllocator: Allocator<T, C1, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
||||||
{
|
{
|
||||||
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1);
|
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
|
||||||
self.tr_mul_to(rhs, &mut res);
|
self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dot(b));
|
||||||
|
// SAFETY: this is OK because the result is now initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,23 +690,26 @@ where
|
||||||
DefaultAllocator: Allocator<T, C1, C2>,
|
DefaultAllocator: Allocator<T, C1, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
||||||
{
|
{
|
||||||
let mut res = Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1);
|
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
|
||||||
self.ad_mul_to(rhs, &mut res);
|
self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dotc(b));
|
||||||
|
// SAFETY: this is OK because the result is now initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn xx_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
fn xx_mul_to_uninit<Status, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
||||||
&self,
|
&self,
|
||||||
|
status: Status,
|
||||||
rhs: &Matrix<T, R2, C2, SB>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>,
|
out: &mut Matrix<Status::Value, R3, C3, SC>,
|
||||||
dot: impl Fn(
|
dot: impl Fn(
|
||||||
&VectorSlice<'_, T, R1, SA::RStride, SA::CStride>,
|
&VectorSlice<'_, T, R1, SA::RStride, SA::CStride>,
|
||||||
&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>,
|
&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>,
|
||||||
) -> T,
|
) -> T,
|
||||||
) where
|
) where
|
||||||
SB: Storage<T, R2, C2>,
|
Status: InitStatus<T>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>,
|
SB: RawStorage<T, R2, C2>,
|
||||||
|
SC: RawStorageMut<Status::Value, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
||||||
{
|
{
|
||||||
let (nrows1, ncols1) = self.shape();
|
let (nrows1, ncols1) = self.shape();
|
||||||
|
@ -740,9 +738,8 @@ where
|
||||||
for i in 0..ncols1 {
|
for i in 0..ncols1 {
|
||||||
for j in 0..ncols2 {
|
for j in 0..ncols2 {
|
||||||
let dot = dot(&self.column(i), &rhs.column(j));
|
let dot = dot(&self.column(i), &rhs.column(j));
|
||||||
unsafe {
|
let elt = unsafe { out.get_unchecked_mut((i, j)) };
|
||||||
*out.get_unchecked_mut((i, j)) = MaybeUninit::new(dot);
|
Status::init(elt, dot);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -753,13 +750,13 @@ where
|
||||||
pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
||||||
&self,
|
&self,
|
||||||
rhs: &Matrix<T, R2, C2, SB>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>,
|
out: &mut Matrix<T, R3, C3, SC>,
|
||||||
) where
|
) where
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>,
|
SC: StorageMut<T, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
||||||
{
|
{
|
||||||
self.xx_mul_to(rhs, out, |a, b| a.dot(b))
|
self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dot(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid
|
/// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid
|
||||||
|
@ -768,31 +765,30 @@ where
|
||||||
pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
||||||
&self,
|
&self,
|
||||||
rhs: &Matrix<T, R2, C2, SB>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
out: &mut Matrix<MaybeUninit<T>, R3, C3, SC>,
|
out: &mut Matrix<T, R3, C3, SC>,
|
||||||
) where
|
) where
|
||||||
T: SimdComplexField,
|
T: SimdComplexField,
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>,
|
SC: StorageMut<T, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
||||||
{
|
{
|
||||||
self.xx_mul_to(rhs, out, |a, b| a.dotc(b))
|
self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dotc(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations.
|
/// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_to<'a, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
pub fn mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
|
||||||
&self,
|
&self,
|
||||||
rhs: &Matrix<T, R2, C2, SB>,
|
rhs: &Matrix<T, R2, C2, SB>,
|
||||||
out: &'a mut Matrix<MaybeUninit<T>, R3, C3, SC>,
|
out: &mut Matrix<T, R3, C3, SC>,
|
||||||
) -> MatrixSliceMut<'a, T, R3, C3, SC::RStride, SC::CStride>
|
) where
|
||||||
where
|
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
SC: StorageMut<MaybeUninit<T>, R3, C3>,
|
SC: StorageMut<T, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R3, R1>
|
ShapeConstraint: SameNumberOfRows<R3, R1>
|
||||||
+ SameNumberOfColumns<C3, C2>
|
+ SameNumberOfColumns<C3, C2>
|
||||||
+ AreMultipliable<R1, C1, R2, C2>,
|
+ AreMultipliable<R1, C1, R2, C2>,
|
||||||
{
|
{
|
||||||
out.gemm_z(T::one(), self, rhs)
|
out.gemm(T::one(), self, rhs, T::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kronecker product of two matrices (aka. tensor product of the corresponding linear
|
/// The kronecker product of two matrices (aka. tensor product of the corresponding linear
|
||||||
|
@ -809,34 +805,31 @@ where
|
||||||
SB: Storage<T, R2, C2>,
|
SB: Storage<T, R2, C2>,
|
||||||
DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>,
|
DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>,
|
||||||
{
|
{
|
||||||
let (nrows1, ncols1) = self.data.shape();
|
let (nrows1, ncols1) = self.shape_generic();
|
||||||
let (nrows2, ncols2) = rhs.data.shape();
|
let (nrows2, ncols2) = rhs.shape_generic();
|
||||||
|
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2));
|
let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2));
|
||||||
|
|
||||||
{
|
|
||||||
let mut data_res = res.data.ptr_mut();
|
let mut data_res = res.data.ptr_mut();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
for j1 in 0..ncols1.value() {
|
for j1 in 0..ncols1.value() {
|
||||||
for j2 in 0..ncols2.value() {
|
for j2 in 0..ncols2.value() {
|
||||||
for i1 in 0..nrows1.value() {
|
for i1 in 0..nrows1.value() {
|
||||||
unsafe {
|
|
||||||
let coeff = self.get_unchecked((i1, j1)).inlined_clone();
|
let coeff = self.get_unchecked((i1, j1)).inlined_clone();
|
||||||
|
|
||||||
for i2 in 0..nrows2.value() {
|
for i2 in 0..nrows2.value() {
|
||||||
*data_res = MaybeUninit::new(
|
*data_res = MaybeUninit::new(
|
||||||
coeff.inlined_clone()
|
coeff.inlined_clone() * rhs.get_unchecked((i2, j2)).inlined_clone(),
|
||||||
* rhs.get_unchecked((i2, j2)).inlined_clone(),
|
|
||||||
);
|
);
|
||||||
data_res = data_res.offset(1);
|
data_res = data_res.offset(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { res.assume_init() }
|
// SAFETY: the result matrix has been initialized by the loop above.
|
||||||
|
res.assume_init()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,10 @@ use simba::scalar::{ClosedAdd, ClosedMul, ComplexField, RealField};
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{Dim, DimMin};
|
use crate::base::dimension::{Dim, DimMin};
|
||||||
use crate::base::storage::Storage;
|
use crate::base::storage::Storage;
|
||||||
use crate::base::{DefaultAllocator, Matrix, SquareMatrix};
|
use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix};
|
||||||
|
use crate::RawStorage;
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// The total number of elements of this matrix.
|
/// The total number of elements of this matrix.
|
||||||
///
|
///
|
||||||
/// # Examples:
|
/// # Examples:
|
||||||
|
|
|
@ -1,38 +1,27 @@
|
||||||
|
use std::any::Any;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// The basic scalar trait for all structures of `nalgebra`.
|
/// The basic scalar type for all structures of `nalgebra`.
|
||||||
///
|
///
|
||||||
/// This is by design a very loose trait, and does not make any assumption on
|
/// This does not make any assumption on the algebraic properties of `Self`.
|
||||||
/// the algebraic properties of `Self`. It has various purposes and objectives:
|
pub trait Scalar: Clone + PartialEq + Debug + Any {
|
||||||
/// - Enforces simple and future-proof trait bounds.
|
|
||||||
/// - Enables important optimizations for floating point types via specialization.
|
|
||||||
/// - Makes debugging generic code possible in most circumstances.
|
|
||||||
pub trait Scalar: 'static + Clone + Debug {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Tests whether `Self` is the same as the type `T`.
|
/// Tests if `Self` the same as the type `T`
|
||||||
///
|
///
|
||||||
/// Typically used to test of `Self` is an `f32` or an `f64`, which is
|
/// Typically used to test of `Self` is a f32 or a f64 with `T::is::<f32>()`.
|
||||||
/// important as it allows for specialization and certain optimizations to
|
|
||||||
/// be made.
|
|
||||||
///
|
|
||||||
// If the need ever arose to get rid of the `'static` requirement, we could
|
|
||||||
// merely replace this method by two unsafe associated methods `is_f32` and
|
|
||||||
// `is_f64`.
|
|
||||||
fn is<T: Scalar>() -> bool {
|
fn is<T: Scalar>() -> bool {
|
||||||
TypeId::of::<Self>() == TypeId::of::<T>()
|
TypeId::of::<Self>() == TypeId::of::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performance hack: Clone doesn't get inlined for Copy types in debug
|
#[inline(always)]
|
||||||
/// mode, so make it inline anyway.
|
/// Performance hack: Clone doesn't get inlined for Copy types in debug mode, so make it inline anyway.
|
||||||
fn inlined_clone(&self) -> Self {
|
fn inlined_clone(&self) -> Self {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfortunately, this blanket impl leads to many misleading compiler messages
|
impl<T: Copy + PartialEq + Debug + Any> Scalar for T {
|
||||||
// telling you to implement Copy, even though Scalar is what's really needed.
|
|
||||||
impl<T: 'static + Copy + Debug> Scalar for T {
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn inlined_clone(&self) -> T {
|
fn inlined_clone(&self) -> T {
|
||||||
*self
|
*self
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::storage::Storage;
|
use crate::storage::RawStorage;
|
||||||
use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1};
|
use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1};
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use simba::scalar::{ClosedAdd, Field, SupersetOf};
|
use simba::scalar::{ClosedAdd, Field, SupersetOf};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// # Folding on columns and rows
|
/// # Folding on columns and rows
|
||||||
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Returns a row vector where each element is the result of the application of `f` on the
|
/// Returns a row vector where each element is the result of the application of `f` on the
|
||||||
/// corresponding column of the original matrix.
|
/// corresponding column of the original matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -19,16 +18,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, U1, C>,
|
DefaultAllocator: Allocator<T, U1, C>,
|
||||||
{
|
{
|
||||||
let ncols = self.data.shape().1;
|
let ncols = self.shape_generic().1;
|
||||||
let mut res = RowOVector::new_uninitialized_generic(Const::<1>, ncols);
|
let mut res = Matrix::uninit(Const::<1>, ncols);
|
||||||
|
|
||||||
for i in 0..ncols.value() {
|
for i in 0..ncols.value() {
|
||||||
// TODO: avoid bound checking of column.
|
// TODO: avoid bound checking of column.
|
||||||
|
// Safety: all indices are in range.
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i)));
|
*res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: res is now fully initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,16 +46,18 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, C>,
|
DefaultAllocator: Allocator<T, C>,
|
||||||
{
|
{
|
||||||
let ncols = self.data.shape().1;
|
let ncols = self.shape_generic().1;
|
||||||
let mut res = Matrix::new_uninitialized_generic(ncols, Const::<1>);
|
let mut res = Matrix::uninit(ncols, Const::<1>);
|
||||||
|
|
||||||
for i in 0..ncols.value() {
|
for i in 0..ncols.value() {
|
||||||
// TODO: avoid bound checking of column.
|
// TODO: avoid bound checking of column.
|
||||||
|
// Safety: all indices are in range.
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i)));
|
*res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: res is now fully initialized.
|
||||||
unsafe { res.assume_init() }
|
unsafe { res.assume_init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,22 +66,24 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn compress_columns(
|
pub fn compress_columns(
|
||||||
&self,
|
&self,
|
||||||
mut init: OVector<T, R>,
|
init: OVector<T, R>,
|
||||||
f: impl Fn(&mut OVector<T, R>, VectorSlice<T, R, S::RStride, S::CStride>),
|
f: impl Fn(&mut OVector<T, R>, VectorSlice<'_, T, R, S::RStride, S::CStride>),
|
||||||
) -> OVector<T, R>
|
) -> OVector<T, R>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R>,
|
DefaultAllocator: Allocator<T, R>,
|
||||||
{
|
{
|
||||||
|
let mut res = init;
|
||||||
|
|
||||||
for i in 0..self.ncols() {
|
for i in 0..self.ncols() {
|
||||||
f(&mut init, self.column(i))
|
f(&mut res, self.column(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
init
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Common statistics operations
|
/// # Common statistics operations
|
||||||
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Sum computation.
|
* Sum computation.
|
||||||
|
@ -178,7 +183,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
T: ClosedAdd + Zero,
|
T: ClosedAdd + Zero,
|
||||||
DefaultAllocator: Allocator<T, R>,
|
DefaultAllocator: Allocator<T, R>,
|
||||||
{
|
{
|
||||||
let nrows = self.data.shape().0;
|
let nrows = self.shape_generic().0;
|
||||||
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
|
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
|
||||||
*out += col;
|
*out += col;
|
||||||
})
|
})
|
||||||
|
@ -281,10 +286,10 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
T: Field + SupersetOf<f64>,
|
T: Field + SupersetOf<f64>,
|
||||||
DefaultAllocator: Allocator<T, R>,
|
DefaultAllocator: Allocator<T, R>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.data.shape();
|
let (nrows, ncols) = self.shape_generic();
|
||||||
|
|
||||||
let mut mean = self.column_mean();
|
let mut mean = self.column_mean();
|
||||||
mean.apply(|e| -(e.inlined_clone() * e));
|
mean.apply(|e| *e = -(e.inlined_clone() * e.inlined_clone()));
|
||||||
|
|
||||||
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
|
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
|
||||||
self.compress_columns(mean, |out, col| {
|
self.compress_columns(mean, |out, col| {
|
||||||
|
@ -389,7 +394,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
T: Field + SupersetOf<f64>,
|
T: Field + SupersetOf<f64>,
|
||||||
DefaultAllocator: Allocator<T, R>,
|
DefaultAllocator: Allocator<T, R>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.data.shape();
|
let (nrows, ncols) = self.shape_generic();
|
||||||
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
|
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
|
||||||
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
|
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
|
||||||
out.axpy(denom.inlined_clone(), &col, T::one())
|
out.axpy(denom.inlined_clone(), &col, T::one())
|
||||||
|
|
|
@ -2,27 +2,32 @@
|
||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, InnerAllocator, SameShapeC, SameShapeR};
|
use crate::base::allocator::{Allocator, SameShapeC, SameShapeR};
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{Dim, U1};
|
use crate::base::dimension::{Dim, U1};
|
||||||
use crate::base::Owned;
|
use crate::base::Scalar;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Aliases for allocation results.
|
* Aliases for allocation results.
|
||||||
*/
|
*/
|
||||||
|
/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`.
|
||||||
|
pub type SameShapeStorage<T, R1, C1, R2, C2> =
|
||||||
|
<DefaultAllocator as Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>>::Buffer;
|
||||||
|
|
||||||
// TODO: better name than Owned ?
|
// TODO: better name than Owned ?
|
||||||
/// The owned data storage that can be allocated from `S`.
|
/// The owned data storage that can be allocated from `S`.
|
||||||
pub type InnerOwned<T, R, C = U1> = <DefaultAllocator as InnerAllocator<T, R, C>>::Buffer;
|
pub type Owned<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::Buffer;
|
||||||
|
|
||||||
/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`.
|
/// The owned data storage that can be allocated from `S`.
|
||||||
pub type SameShapeStorage<T, R1, C1, R2, C2> = Owned<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>;
|
pub type OwnedUninit<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::BufferUninit;
|
||||||
|
|
||||||
/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
|
/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
|
||||||
pub type RStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::RStride;
|
pub type RStride<T, R, C = U1> =
|
||||||
|
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::RStride;
|
||||||
|
|
||||||
/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
|
/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
|
||||||
pub type CStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::CStride;
|
pub type CStride<T, R, C = U1> =
|
||||||
|
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::CStride;
|
||||||
|
|
||||||
/// The trait shared by all matrix data storage.
|
/// The trait shared by all matrix data storage.
|
||||||
///
|
///
|
||||||
|
@ -33,7 +38,7 @@ pub type CStride<T, R, C = U1> = <InnerOwned<T, R, C> as Storage<T, R, C>>::CStr
|
||||||
/// should **not** allow the user to modify the size of the underlying buffer with safe methods
|
/// should **not** allow the user to modify the size of the underlying buffer with safe methods
|
||||||
/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
|
/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
|
||||||
/// vector's size so that it no longer contains enough elements: this will lead to UB.
|
/// vector's size so that it no longer contains enough elements: this will lead to UB.
|
||||||
pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized {
|
pub unsafe trait RawStorage<T, R: Dim, C: Dim = U1>: Sized {
|
||||||
/// The static stride of this storage's rows.
|
/// The static stride of this storage's rows.
|
||||||
type RStride: Dim;
|
type RStride: Dim;
|
||||||
|
|
||||||
|
@ -118,17 +123,17 @@ pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized {
|
||||||
///
|
///
|
||||||
/// Call the safe alternative `matrix.as_slice()` instead.
|
/// Call the safe alternative `matrix.as_slice()` instead.
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T];
|
unsafe fn as_slice_unchecked(&self) -> &[T];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
|
||||||
/// Builds a matrix data storage that does not contain any reference.
|
/// Builds a matrix data storage that does not contain any reference.
|
||||||
fn into_owned(self) -> Owned<T, R, C>
|
fn into_owned(self) -> Owned<T, R, C>
|
||||||
where
|
where
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>;
|
DefaultAllocator: Allocator<T, R, C>;
|
||||||
|
|
||||||
/// Clones this data storage to one that does not contain any reference.
|
/// Clones this data storage to one that does not contain any reference.
|
||||||
fn clone_owned(&self) -> Owned<T, R, C>
|
fn clone_owned(&self) -> Owned<T, R, C>
|
||||||
where
|
where
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>;
|
DefaultAllocator: Allocator<T, R, C>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +142,7 @@ pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: Sized {
|
||||||
/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable
|
/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable
|
||||||
/// matrix slice can provide mutable access to its elements even if it does not own its data (it
|
/// matrix slice can provide mutable access to its elements even if it does not own its data (it
|
||||||
/// contains only an internal reference to them).
|
/// contains only an internal reference to them).
|
||||||
pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>: Storage<T, R, C> {
|
pub unsafe trait RawStorageMut<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
|
||||||
/// The matrix mutable data pointer.
|
/// The matrix mutable data pointer.
|
||||||
fn ptr_mut(&mut self) -> *mut T;
|
fn ptr_mut(&mut self) -> *mut T;
|
||||||
|
|
||||||
|
@ -212,40 +217,37 @@ pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>: Storage<T, R, C> {
|
||||||
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
|
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A matrix storage that is stored contiguously in memory.
|
pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>:
|
||||||
///
|
Storage<T, R, C> + RawStorageMut<T, R, C>
|
||||||
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
|
{
|
||||||
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
|
||||||
/// failing to comply to this may cause Undefined Behaviors.
|
|
||||||
pub unsafe trait ContiguousStorage<T, R: Dim, C: Dim = U1>: Storage<T, R, C> {
|
|
||||||
/// Converts this data storage to a contiguous slice.
|
|
||||||
fn as_slice(&self) -> &[T] {
|
|
||||||
// SAFETY: this is safe because this trait guarantees the fact
|
|
||||||
// that the data is stored contiguously.
|
|
||||||
unsafe { self.as_slice_unchecked() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable matrix storage that is stored contiguously in memory.
|
unsafe impl<S, T, R, C> StorageMut<T, R, C> for S
|
||||||
|
where
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<T, R, C> + RawStorageMut<T, R, C>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker trait indicating that a storage is stored contiguously in memory.
|
||||||
///
|
///
|
||||||
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
|
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
|
||||||
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
||||||
/// failing to comply to this may cause Undefined Behaviors.
|
/// failing to comply to this may cause Undefined Behaviors.
|
||||||
pub unsafe trait ContiguousStorageMut<T, R: Dim, C: Dim = U1>:
|
pub unsafe trait IsContiguous {}
|
||||||
ContiguousStorage<T, R, C> + StorageMut<T, R, C>
|
|
||||||
{
|
|
||||||
/// Converts this data storage to a contiguous mutable slice.
|
|
||||||
fn as_mut_slice(&mut self) -> &mut [T] {
|
|
||||||
// SAFETY: this is safe because this trait guarantees the fact
|
|
||||||
// that the data is stored contiguously.
|
|
||||||
unsafe { self.as_mut_slice_unchecked() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A matrix storage that can be reshaped in-place.
|
/// A matrix storage that can be reshaped in-place.
|
||||||
pub trait ReshapableStorage<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim>: Storage<T, R1, C1> {
|
pub trait ReshapableStorage<T, R1, C1, R2, C2>: RawStorage<T, R1, C1>
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
{
|
||||||
/// The reshaped storage type.
|
/// The reshaped storage type.
|
||||||
type Output: Storage<T, R2, C2>;
|
type Output: RawStorage<T, R2, C2>;
|
||||||
|
|
||||||
/// Reshapes the storage into the output storage type.
|
/// Reshapes the storage into the output storage type.
|
||||||
fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;
|
fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::base::{DimName, ToTypenum, Vector, Vector2, Vector3};
|
use crate::base::{DimName, Scalar, ToTypenum, Vector, Vector2, Vector3};
|
||||||
use crate::storage::Storage;
|
use crate::storage::RawStorage;
|
||||||
use typenum::{self, Cmp, Greater};
|
use typenum::{self, Cmp, Greater};
|
||||||
|
|
||||||
macro_rules! impl_swizzle {
|
macro_rules! impl_swizzle {
|
||||||
|
@ -11,7 +11,7 @@ macro_rules! impl_swizzle {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn $name(&self) -> $Result<T>
|
pub fn $name(&self) -> $Result<T>
|
||||||
where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
|
where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
|
||||||
$Result::new($(self[$i].clone()),*)
|
$Result::new($(self[$i].inlined_clone()),*)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
)*
|
)*
|
||||||
|
@ -19,7 +19,7 @@ macro_rules! impl_swizzle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Swizzling
|
/// # Swizzling
|
||||||
impl<T: Clone, D, S: Storage<T, D>> Vector<T, D, S>
|
impl<T: Scalar, D, S: RawStorage<T, D>> Vector<T, D, S>
|
||||||
where
|
where
|
||||||
D: DimName + ToTypenum,
|
D: DimName + ToTypenum,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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::allocator::Allocator;
|
||||||
use crate::base::DefaultAllocator;
|
use crate::base::DefaultAllocator;
|
||||||
use crate::storage::{InnerOwned, Storage};
|
use crate::storage::RawStorage;
|
||||||
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
|
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
|
||||||
|
|
||||||
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
||||||
|
@ -113,10 +113,10 @@ mod rkyv_impl {
|
||||||
|
|
||||||
impl<T, R, C, S> PartialEq for Unit<Matrix<T, R, C, S>>
|
impl<T, R, C, S> PartialEq for Unit<Matrix<T, R, C, S>>
|
||||||
where
|
where
|
||||||
T: PartialEq,
|
T: Scalar + PartialEq,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
S: Storage<T, R, C>,
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
@ -126,10 +126,10 @@ where
|
||||||
|
|
||||||
impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>>
|
impl<T, R, C, S> Eq for Unit<Matrix<T, R, C, S>>
|
||||||
where
|
where
|
||||||
T: Eq,
|
T: Scalar + Eq,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
S: Storage<T, R, C>,
|
S: RawStorage<T, R, C>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ impl<T> Unit<T> {
|
||||||
/// Wraps the given reference, assuming it is already normalized.
|
/// Wraps the given reference, assuming it is already normalized.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_ref_unchecked(value: &T) -> &Self {
|
pub fn from_ref_unchecked(value: &T) -> &Self {
|
||||||
unsafe { &*(value as *const _ as *const _) }
|
unsafe { &*(value as *const T as *const Self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the underlying value.
|
/// Retrieves the underlying value.
|
||||||
|
@ -331,7 +331,7 @@ impl<T> Deref for Unit<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
unsafe { &*(self as *const _ as *const T) }
|
unsafe { &*(self as *const Self as *const T) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +344,6 @@ where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar,
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
InnerOwned<T::Element, R, C>: Clone,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 2]) -> Self {
|
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 2]) -> Self {
|
||||||
|
@ -361,7 +360,6 @@ where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar,
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
InnerOwned<T::Element, R, C>: Clone,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 4]) -> Self {
|
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 4]) -> Self {
|
||||||
|
@ -380,7 +378,6 @@ where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar,
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
InnerOwned<T::Element, R, C>: Clone,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 8]) -> Self {
|
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 8]) -> Self {
|
||||||
|
@ -403,7 +400,6 @@ where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar,
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
|
||||||
InnerOwned<T::Element, R, C>: Clone,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 16]) -> Self {
|
fn from(arr: [Unit<OMatrix<T::Element, R, C>>; 16]) -> Self {
|
||||||
|
|
|
@ -4,14 +4,12 @@ use std::io::{Result as IOResult, Write};
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::allocator::InnerAllocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{Dim, DimName, Dynamic, U1};
|
use crate::base::dimension::{Dim, DimName, Dynamic, U1};
|
||||||
use crate::base::storage::{
|
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
|
||||||
ContiguousStorage, ContiguousStorageMut, ReshapableStorage, Storage, StorageMut,
|
use crate::base::{Scalar, Vector};
|
||||||
};
|
|
||||||
use crate::base::{Owned, Vector};
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{
|
use serde::{
|
||||||
|
@ -19,20 +17,22 @@ use serde::{
|
||||||
ser::{Serialize, Serializer},
|
ser::{Serialize, Serializer},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::Storage;
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use abomonation::Abomonation;
|
use abomonation::Abomonation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Storage.
|
* RawStorage.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// A Vec-based matrix data storage. It may be dynamically-sized.
|
/// A Vec-based matrix data storage. It may be dynamically-sized.
|
||||||
|
#[repr(C)]
|
||||||
#[derive(Eq, Debug, Clone, PartialEq)]
|
#[derive(Eq, Debug, Clone, PartialEq)]
|
||||||
pub struct VecStorage<T, R: Dim, C: Dim> {
|
pub struct VecStorage<T, R: Dim, C: Dim> {
|
||||||
data: Vec<T>,
|
data: Vec<T>,
|
||||||
pub(crate) nrows: R,
|
nrows: R,
|
||||||
pub(crate) ncols: C,
|
ncols: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
@ -142,6 +142,18 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A slice containing all the components stored in this storage in column-major order.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
&self.data[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A mutable slice containing all the components stored in this storage in column-major order.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||||
|
&mut self.data[..]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
|
impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
|
||||||
|
@ -156,10 +168,7 @@ impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
|
||||||
* Dynamic − Dynamic
|
* Dynamic − Dynamic
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
unsafe impl<T, C: Dim> Storage<T, Dynamic, C> for VecStorage<T, Dynamic, C>
|
unsafe impl<T, C: Dim> RawStorage<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
|
|
||||||
{
|
|
||||||
type RStride = U1;
|
type RStride = U1;
|
||||||
type CStride = Dynamic;
|
type CStride = Dynamic;
|
||||||
|
|
||||||
|
@ -183,29 +192,34 @@ where
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_owned(self) -> Owned<T, Dynamic, C> {
|
|
||||||
Owned(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clone_owned(&self) -> Owned<T, Dynamic, C>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
Owned(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, R: DimName> Storage<T, R, Dynamic> for VecStorage<T, R, Dynamic>
|
unsafe impl<T: Scalar, C: Dim> Storage<T, Dynamic, C> for VecStorage<T, Dynamic, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>,
|
DefaultAllocator: Allocator<T, Dynamic, C, Buffer = Self>,
|
||||||
{
|
{
|
||||||
|
#[inline]
|
||||||
|
fn into_owned(self) -> Owned<T, Dynamic, C>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_owned(&self) -> Owned<T, Dynamic, C>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, Dynamic, C>,
|
||||||
|
{
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T, R: DimName> RawStorage<T, R, Dynamic> for VecStorage<T, R, Dynamic> {
|
||||||
type RStride = U1;
|
type RStride = U1;
|
||||||
type CStride = R;
|
type CStride = R;
|
||||||
|
|
||||||
|
@ -229,34 +243,39 @@ where
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_owned(self) -> Owned<T, R, Dynamic> {
|
|
||||||
Owned(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clone_owned(&self) -> Owned<T, R, Dynamic>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
Owned(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
unsafe fn as_slice_unchecked(&self) -> &[T] {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Scalar, R: DimName> Storage<T, R, Dynamic> for VecStorage<T, R, Dynamic>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, R, Dynamic, Buffer = Self>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn into_owned(self) -> Owned<T, R, Dynamic>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, R, Dynamic>,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_owned(&self) -> Owned<T, R, Dynamic>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, R, Dynamic>,
|
||||||
|
{
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* StorageMut, ContiguousStorage.
|
* RawStorageMut, ContiguousStorage.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
unsafe impl<T, C: Dim> StorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C>
|
unsafe impl<T, C: Dim> RawStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> {
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ptr_mut(&mut self) -> *mut T {
|
fn ptr_mut(&mut self) -> *mut T {
|
||||||
self.data.as_mut_ptr()
|
self.data.as_mut_ptr()
|
||||||
|
@ -268,18 +287,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, C: Dim> ContiguousStorage<T, Dynamic, C> for VecStorage<T, Dynamic, C> where
|
unsafe impl<T, R: Dim, C: Dim> IsContiguous for VecStorage<T, R, C> {}
|
||||||
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, C: Dim> ContiguousStorageMut<T, Dynamic, C> for VecStorage<T, Dynamic, C> where
|
impl<T, C1, C2> ReshapableStorage<T, Dynamic, C1, Dynamic, C2> for VecStorage<T, Dynamic, C1>
|
||||||
DefaultAllocator: InnerAllocator<T, Dynamic, C, Buffer = Self>
|
where
|
||||||
{
|
T: Scalar,
|
||||||
}
|
C1: Dim,
|
||||||
|
C2: Dim,
|
||||||
impl<T, C1: Dim, C2: Dim> ReshapableStorage<T, Dynamic, C1, Dynamic, C2>
|
|
||||||
for VecStorage<T, Dynamic, C1>
|
|
||||||
{
|
{
|
||||||
type Output = VecStorage<T, Dynamic, C2>;
|
type Output = VecStorage<T, Dynamic, C2>;
|
||||||
|
|
||||||
|
@ -293,8 +307,11 @@ impl<T, C1: Dim, C2: Dim> ReshapableStorage<T, Dynamic, C1, Dynamic, C2>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C1: Dim, R2: DimName> ReshapableStorage<T, Dynamic, C1, R2, Dynamic>
|
impl<T, C1, R2> ReshapableStorage<T, Dynamic, C1, R2, Dynamic> for VecStorage<T, Dynamic, C1>
|
||||||
for VecStorage<T, Dynamic, C1>
|
where
|
||||||
|
T: Scalar,
|
||||||
|
C1: Dim,
|
||||||
|
R2: DimName,
|
||||||
{
|
{
|
||||||
type Output = VecStorage<T, R2, Dynamic>;
|
type Output = VecStorage<T, R2, Dynamic>;
|
||||||
|
|
||||||
|
@ -308,10 +325,7 @@ impl<T, C1: Dim, R2: DimName> ReshapableStorage<T, Dynamic, C1, R2, Dynamic>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, R: DimName> StorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic>
|
unsafe impl<T, R: DimName> RawStorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> {
|
||||||
where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ptr_mut(&mut self) -> *mut T {
|
fn ptr_mut(&mut self) -> *mut T {
|
||||||
self.data.as_mut_ptr()
|
self.data.as_mut_ptr()
|
||||||
|
@ -323,8 +337,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: DimName, C2: Dim> ReshapableStorage<T, R1, Dynamic, Dynamic, C2>
|
impl<T, R1, C2> ReshapableStorage<T, R1, Dynamic, Dynamic, C2> for VecStorage<T, R1, Dynamic>
|
||||||
for VecStorage<T, R1, Dynamic>
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R1: DimName,
|
||||||
|
C2: Dim,
|
||||||
{
|
{
|
||||||
type Output = VecStorage<T, Dynamic, C2>;
|
type Output = VecStorage<T, Dynamic, C2>;
|
||||||
|
|
||||||
|
@ -338,8 +355,11 @@ impl<T, R1: DimName, C2: Dim> ReshapableStorage<T, R1, Dynamic, Dynamic, C2>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R1: DimName, R2: DimName> ReshapableStorage<T, R1, Dynamic, R2, Dynamic>
|
impl<T, R1, R2> ReshapableStorage<T, R1, Dynamic, R2, Dynamic> for VecStorage<T, R1, Dynamic>
|
||||||
for VecStorage<T, R1, Dynamic>
|
where
|
||||||
|
T: Scalar,
|
||||||
|
R1: DimName,
|
||||||
|
R2: DimName,
|
||||||
{
|
{
|
||||||
type Output = VecStorage<T, R2, Dynamic>;
|
type Output = VecStorage<T, R2, Dynamic>;
|
||||||
|
|
||||||
|
@ -368,16 +388,6 @@ impl<T: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<T, R, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, R: DimName> ContiguousStorage<T, R, Dynamic> for VecStorage<T, R, Dynamic> where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T, R: DimName> ContiguousStorageMut<T, R, Dynamic> for VecStorage<T, R, Dynamic> where
|
|
||||||
DefaultAllocator: InnerAllocator<T, R, Dynamic, Buffer = Self>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R: Dim> Extend<T> for VecStorage<T, R, Dynamic> {
|
impl<T, R: Dim> Extend<T> for VecStorage<T, R, Dynamic> {
|
||||||
/// Extends the number of columns of the `VecStorage` with elements
|
/// Extends the number of columns of the `VecStorage` with elements
|
||||||
/// from the given iterator.
|
/// from the given iterator.
|
||||||
|
@ -407,9 +417,12 @@ impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage<T, R, Dynamic> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, R: Dim, RV: Dim, SV> Extend<Vector<T, RV, SV>> for VecStorage<T, R, Dynamic>
|
impl<T, R, RV, SV> Extend<Vector<T, RV, SV>> for VecStorage<T, R, Dynamic>
|
||||||
where
|
where
|
||||||
SV: Storage<T, RV>,
|
T: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
RV: Dim,
|
||||||
|
SV: RawStorage<T, RV>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, RV>,
|
ShapeConstraint: SameNumberOfRows<R, RV>,
|
||||||
{
|
{
|
||||||
/// Extends the number of columns of the `VecStorage` with vectors
|
/// Extends the number of columns of the `VecStorage` with vectors
|
||||||
|
|
|
@ -1,52 +1,24 @@
|
||||||
use std::fmt;
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{Dim, DimName, Dynamic};
|
use crate::base::dimension::{Dim, Dynamic};
|
||||||
|
use crate::base::Scalar;
|
||||||
use crate::base::{DefaultAllocator, OMatrix};
|
use crate::base::{DefaultAllocator, OMatrix};
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
use crate::storage::Owned;
|
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
/// A random orthogonal matrix.
|
/// A random orthogonal matrix.
|
||||||
pub struct RandomOrthogonal<T, D: Dim = Dynamic>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct RandomOrthogonal<T: Scalar, D: Dim = Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
m: OMatrix<T, D, D>,
|
m: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: DimName> Copy for RandomOrthogonal<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: Copy,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone, D: Dim> Clone for RandomOrthogonal<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self { m: self.m.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: Dim> fmt::Debug for RandomOrthogonal<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("RandomOrthogonal")
|
|
||||||
.field("m", &self.m)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> RandomOrthogonal<T, D>
|
impl<T: ComplexField, D: Dim> RandomOrthogonal<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
|
|
|
@ -1,50 +1,25 @@
|
||||||
use std::fmt;
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{Dim, Dynamic};
|
use crate::base::dimension::{Dim, Dynamic};
|
||||||
use crate::base::{DefaultAllocator, OMatrix, Owned};
|
use crate::base::Scalar;
|
||||||
|
use crate::base::{DefaultAllocator, OMatrix};
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::debug::RandomOrthogonal;
|
use crate::debug::RandomOrthogonal;
|
||||||
|
|
||||||
/// A random, well-conditioned, symmetric definite-positive matrix.
|
/// A random, well-conditioned, symmetric definite-positive matrix.
|
||||||
pub struct RandomSDP<T, D: Dim = Dynamic>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct RandomSDP<T: Scalar, D: Dim = Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
m: OMatrix<T, D, D>,
|
m: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: Dim> Copy for RandomSDP<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: Copy,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone, D: Dim> Clone for RandomSDP<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self { m: self.m.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: Dim> fmt::Debug for RandomSDP<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
Owned<T, D, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("RandomSDP").field("m", &self.m).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> RandomSDP<T, D>
|
impl<T: ComplexField, D: Dim> RandomSDP<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
#![allow(clippy::op_ref)]
|
#![allow(clippy::op_ref)]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, SimdRealField, Translation3, Unit,
|
Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3,
|
||||||
UnitQuaternion, Vector3, Zero, U8,
|
Unit, UnitQuaternion, Vector3, Zero, U8,
|
||||||
};
|
};
|
||||||
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::{ClosedNeg, RealField};
|
||||||
|
|
||||||
/// A dual quaternion.
|
/// A dual quaternion.
|
||||||
///
|
///
|
||||||
|
@ -46,16 +46,16 @@ pub struct DualQuaternion<T> {
|
||||||
pub dual: Quaternion<T>,
|
pub dual: Quaternion<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq> Eq for DualQuaternion<T> {}
|
impl<T: Scalar + Eq> Eq for DualQuaternion<T> {}
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for DualQuaternion<T> {
|
impl<T: Scalar> PartialEq for DualQuaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, right: &Self) -> bool {
|
fn eq(&self, right: &Self) -> bool {
|
||||||
self.real == right.real && self.dual == right.dual
|
self.real == right.real && self.dual == right.dual
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Zero + Clone> Default for DualQuaternion<T> {
|
impl<T: Scalar + Zero> Default for DualQuaternion<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
real: Quaternion::default(),
|
real: Quaternion::default(),
|
||||||
|
@ -267,7 +267,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T: Serialize> Serialize for DualQuaternion<T> {
|
impl<T: SimdRealField> Serialize for DualQuaternion<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
|
@ -277,7 +280,10 @@ impl<T: Serialize> Serialize for DualQuaternion<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T: Deserialize<'a>> Deserialize<'a> for DualQuaternion<T> {
|
impl<'a, T: SimdRealField> Deserialize<'a> for DualQuaternion<T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'a>,
|
||||||
|
{
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
Des: Deserializer<'a>,
|
Des: Deserializer<'a>,
|
||||||
|
@ -293,14 +299,9 @@ impl<'a, T: Deserialize<'a>> Deserialize<'a> for DualQuaternion<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DualQuaternion<T> {
|
impl<T: RealField> DualQuaternion<T> {
|
||||||
// TODO: Cloning shouldn't be necessary.
|
fn to_vector(self) -> OVector<T, U8> {
|
||||||
// TODO: rename into `into_vector` to appease clippy.
|
(*self.as_ref()).into()
|
||||||
fn to_vector(self) -> OVector<T, U8>
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
(self.as_ref().clone()).into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,14 +357,14 @@ impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for DualQuaternion<T> {
|
||||||
/// A unit quaternions. May be used to represent a rotation followed by a translation.
|
/// A unit quaternions. May be used to represent a rotation followed by a translation.
|
||||||
pub type UnitDualQuaternion<T> = Unit<DualQuaternion<T>>;
|
pub type UnitDualQuaternion<T> = Unit<DualQuaternion<T>>;
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for UnitDualQuaternion<T> {
|
impl<T: Scalar + ClosedNeg + PartialEq + SimdRealField> PartialEq for UnitDualQuaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
self.as_ref().eq(rhs.as_ref())
|
self.as_ref().eq(rhs.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq> Eq for UnitDualQuaternion<T> {}
|
impl<T: Scalar + ClosedNeg + Eq + SimdRealField> Eq for UnitDualQuaternion<T> {}
|
||||||
|
|
||||||
impl<T: SimdRealField> Normed for DualQuaternion<T> {
|
impl<T: SimdRealField> Normed for DualQuaternion<T> {
|
||||||
type Norm = T::SimdRealField;
|
type Norm = T::SimdRealField;
|
||||||
|
@ -391,7 +392,10 @@ impl<T: SimdRealField> Normed for DualQuaternion<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> UnitDualQuaternion<T> {
|
impl<T: SimdRealField> UnitDualQuaternion<T>
|
||||||
|
where
|
||||||
|
T::Element: SimdRealField,
|
||||||
|
{
|
||||||
/// The underlying dual quaternion.
|
/// The underlying dual quaternion.
|
||||||
///
|
///
|
||||||
/// Same as `self.as_ref()`.
|
/// Same as `self.as_ref()`.
|
||||||
|
@ -410,12 +414,7 @@ impl<T> UnitDualQuaternion<T> {
|
||||||
pub fn dual_quaternion(&self) -> &DualQuaternion<T> {
|
pub fn dual_quaternion(&self) -> &DualQuaternion<T> {
|
||||||
self.as_ref()
|
self.as_ref()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SimdRealField> UnitDualQuaternion<T>
|
|
||||||
where
|
|
||||||
T::Element: SimdRealField,
|
|
||||||
{
|
|
||||||
/// Compute the conjugate of this unit quaternion.
|
/// Compute the conjugate of this unit quaternion.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -617,7 +616,7 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sclerp(&self, other: &Self, t: T) -> Self
|
pub fn sclerp(&self, other: &Self, t: T) -> Self
|
||||||
where
|
where
|
||||||
T: RealField + RelativeEq<Epsilon = T>,
|
T: RealField,
|
||||||
{
|
{
|
||||||
self.try_sclerp(other, t, T::default_epsilon())
|
self.try_sclerp(other, t, T::default_epsilon())
|
||||||
.expect("DualQuaternion sclerp: ambiguous configuration.")
|
.expect("DualQuaternion sclerp: ambiguous configuration.")
|
||||||
|
@ -637,7 +636,7 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
|
pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
|
||||||
where
|
where
|
||||||
T: RealField + RelativeEq<Epsilon = T>,
|
T: RealField,
|
||||||
{
|
{
|
||||||
let two = T::one() + T::one();
|
let two = T::one() + T::one();
|
||||||
let half = T::one() / two;
|
let half = T::one() / two;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
DualQuaternion, Isometry3, Quaternion, SimdRealField, Translation3, UnitDualQuaternion,
|
DualQuaternion, Isometry3, Quaternion, Scalar, SimdRealField, Translation3, UnitDualQuaternion,
|
||||||
UnitQuaternion,
|
UnitQuaternion,
|
||||||
};
|
};
|
||||||
use num::{One, Zero};
|
use num::{One, Zero};
|
||||||
|
@ -7,7 +7,7 @@ use num::{One, Zero};
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
use simba::scalar::SupersetOf;
|
use simba::scalar::SupersetOf;
|
||||||
|
|
||||||
impl<T> DualQuaternion<T> {
|
impl<T: Scalar> DualQuaternion<T> {
|
||||||
/// Creates a dual quaternion from its rotation and translation components.
|
/// Creates a dual quaternion from its rotation and translation components.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -60,7 +60,7 @@ impl<T> DualQuaternion<T> {
|
||||||
/// let q2 = q.cast::<f32>();
|
/// let q2 = q.cast::<f32>();
|
||||||
/// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0)));
|
/// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0)));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cast<To>(self) -> DualQuaternion<To>
|
pub fn cast<To: Scalar>(self) -> DualQuaternion<To>
|
||||||
where
|
where
|
||||||
DualQuaternion<To>: SupersetOf<Self>,
|
DualQuaternion<To>: SupersetOf<Self>,
|
||||||
{
|
{
|
||||||
|
@ -156,7 +156,7 @@ impl<T: SimdRealField> UnitDualQuaternion<T> {
|
||||||
/// let q2 = q.cast::<f32>();
|
/// let q2 = q.cast::<f32>();
|
||||||
/// assert_eq!(q2, UnitDualQuaternion::<f32>::identity());
|
/// assert_eq!(q2, UnitDualQuaternion::<f32>::identity());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cast<To>(self) -> UnitDualQuaternion<To>
|
pub fn cast<To: Scalar>(self) -> UnitDualQuaternion<To>
|
||||||
where
|
where
|
||||||
UnitDualQuaternion<To>: SupersetOf<Self>,
|
UnitDualQuaternion<To>: SupersetOf<Self>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,8 @@ use crate::geometry::{
|
||||||
|
|
||||||
impl<T1, T2> SubsetOf<DualQuaternion<T2>> for DualQuaternion<T1>
|
impl<T1, T2> SubsetOf<DualQuaternion<T2>> for DualQuaternion<T1>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: SimdRealField,
|
||||||
|
T2: SimdRealField + SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> DualQuaternion<T2> {
|
fn to_superset(&self) -> DualQuaternion<T2> {
|
||||||
|
@ -48,7 +49,8 @@ where
|
||||||
|
|
||||||
impl<T1, T2> SubsetOf<UnitDualQuaternion<T2>> for UnitDualQuaternion<T1>
|
impl<T1, T2> SubsetOf<UnitDualQuaternion<T2>> for UnitDualQuaternion<T1>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: SimdRealField,
|
||||||
|
T2: SimdRealField + SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> UnitDualQuaternion<T2> {
|
fn to_superset(&self) -> UnitDualQuaternion<T2> {
|
||||||
|
|
|
@ -56,21 +56,21 @@ use std::ops::{
|
||||||
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<T> AsRef<[T; 8]> for DualQuaternion<T> {
|
impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &[T; 8] {
|
fn as_ref(&self) -> &[T; 8] {
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
unsafe { &*(self as *const Self as *const [T; 8]) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsMut<[T; 8]> for DualQuaternion<T> {
|
impl<T: SimdRealField> AsMut<[T; 8]> for DualQuaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> &mut [T; 8] {
|
fn as_mut(&mut self) -> &mut [T; 8] {
|
||||||
unsafe { &mut *(self as *mut _ as *mut _) }
|
unsafe { &mut *(self as *mut Self as *mut [T; 8]) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Index<usize> for DualQuaternion<T> {
|
impl<T: SimdRealField> Index<usize> for DualQuaternion<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -79,7 +79,7 @@ impl<T> Index<usize> for DualQuaternion<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<usize> for DualQuaternion<T> {
|
impl<T: SimdRealField> IndexMut<usize> for DualQuaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, i: usize) -> &mut T {
|
fn index_mut(&mut self, i: usize) -> &mut T {
|
||||||
&mut self.as_mut()[i]
|
&mut self.as_mut()[i]
|
||||||
|
|
|
@ -15,7 +15,7 @@ use simba::simd::SimdRealField;
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit};
|
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit};
|
||||||
use crate::geometry::{AbstractRotation, Point, Translation};
|
use crate::geometry::{AbstractRotation, Point, Translation};
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ use crate::geometry::{AbstractRotation, Point, Translation};
|
||||||
/// # Conversion to a matrix
|
/// # Conversion to a matrix
|
||||||
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
|
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
|
||||||
///
|
///
|
||||||
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
@ -79,6 +80,7 @@ pub struct Isometry<T, R, const D: usize> {
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T, R, const D: usize> Abomonation for Isometry<T, R, D>
|
impl<T, R, const D: usize> Abomonation for Isometry<T, R, D>
|
||||||
where
|
where
|
||||||
|
T: SimdRealField,
|
||||||
R: Abomonation,
|
R: Abomonation,
|
||||||
Translation<T, D>: Abomonation,
|
Translation<T, D>: Abomonation,
|
||||||
{
|
{
|
||||||
|
@ -104,7 +106,10 @@ mod rkyv_impl {
|
||||||
use crate::{base::Scalar, geometry::Translation};
|
use crate::{base::Scalar, geometry::Translation};
|
||||||
use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
|
use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
|
||||||
|
|
||||||
impl<T: Archive, R: Archive, const D: usize> Archive for Isometry<T, R, D> {
|
impl<T: Scalar + Archive, R: Archive, const D: usize> Archive for Isometry<T, R, D>
|
||||||
|
where
|
||||||
|
T::Archived: Scalar,
|
||||||
|
{
|
||||||
type Archived = Isometry<T::Archived, R::Archived, D>;
|
type Archived = Isometry<T::Archived, R::Archived, D>;
|
||||||
type Resolver = (R::Resolver, <Translation<T, D> as Archive>::Resolver);
|
type Resolver = (R::Resolver, <Translation<T, D> as Archive>::Resolver);
|
||||||
|
|
||||||
|
@ -127,8 +132,8 @@ mod rkyv_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize<S>, R: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S>
|
impl<T: Scalar + Serialize<S>, R: Serialize<S>, S: Fallible + ?Sized, const D: usize>
|
||||||
for Isometry<T, R, D>
|
Serialize<S> for Isometry<T, R, D>
|
||||||
where
|
where
|
||||||
T::Archived: Scalar,
|
T::Archived: Scalar,
|
||||||
{
|
{
|
||||||
|
@ -140,7 +145,7 @@ mod rkyv_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Archive, R: Archive, _D: Fallible + ?Sized, const D: usize>
|
impl<T: Scalar + Archive, R: Archive, _D: Fallible + ?Sized, const D: usize>
|
||||||
Deserialize<Isometry<T, R, D>, _D> for Isometry<T::Archived, R::Archived, D>
|
Deserialize<Isometry<T, R, D>, _D> for Isometry<T::Archived, R::Archived, D>
|
||||||
where
|
where
|
||||||
T::Archived: Scalar + Deserialize<T, _D>,
|
T::Archived: Scalar + Deserialize<T, _D>,
|
||||||
|
@ -155,9 +160,9 @@ mod rkyv_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Isometry<T, R, D>
|
impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Isometry<T, R, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: hash::Hash,
|
Owned<T, Const<D>>: hash::Hash,
|
||||||
{
|
{
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.translation.hash(state);
|
self.translation.hash(state);
|
||||||
|
@ -165,9 +170,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, R: Copy, const D: usize> Copy for Isometry<T, R, D> where InnerOwned<T, Const<D>>: Copy {}
|
impl<T: Scalar + Copy, R: Copy, const D: usize> Copy for Isometry<T, R, D> where
|
||||||
|
Owned<T, Const<D>>: Copy
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Clone, R: Clone, const D: usize> Clone for Isometry<T, R, D> {
|
impl<T: Scalar, R: Clone, const D: usize> Clone for Isometry<T, R, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -630,7 +638,7 @@ where
|
||||||
* Display
|
* Display
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
impl<T: Scalar + fmt::Display, R, const D: usize> fmt::Display for Isometry<T, R, D>
|
impl<T: RealField + fmt::Display, R, const D: usize> fmt::Display for Isometry<T, R, D>
|
||||||
where
|
where
|
||||||
R: fmt::Display,
|
R: fmt::Display,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ where
|
||||||
T: SimdRealField + Arbitrary + Send,
|
T: SimdRealField + Arbitrary + Send,
|
||||||
T::Element: SimdRealField,
|
T::Element: SimdRealField,
|
||||||
R: AbstractRotation<T, D> + Arbitrary + Send,
|
R: AbstractRotation<T, D> + Arbitrary + Send,
|
||||||
InnerOwned<T, crate::Const<D>>: Send,
|
Owned<T, crate::Const<D>>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(rng: &mut Gen) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
|
|
|
@ -18,29 +18,27 @@ use crate::base::{Matrix4, Vector, Vector3};
|
||||||
use crate::geometry::{Point3, Projective3};
|
use crate::geometry::{Point3, Projective3};
|
||||||
|
|
||||||
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
|
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
pub struct Orthographic3<T> {
|
pub struct Orthographic3<T> {
|
||||||
matrix: Matrix4<T>,
|
matrix: Matrix4<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy> Copy for Orthographic3<T> {}
|
impl<T: RealField> Copy for Orthographic3<T> {}
|
||||||
|
|
||||||
impl<T: Clone> Clone for Orthographic3<T> {
|
impl<T: RealField> Clone for Orthographic3<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self::from_matrix_unchecked(self.matrix)
|
||||||
matrix: self.matrix.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for Orthographic3<T> {
|
impl<T: RealField> fmt::Debug for Orthographic3<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
self.matrix.fmt(f)
|
self.matrix.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for Orthographic3<T> {
|
impl<T: RealField> PartialEq for Orthographic3<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, right: &Self) -> bool {
|
fn eq(&self, right: &Self) -> bool {
|
||||||
self.matrix == right.matrix
|
self.matrix == right.matrix
|
||||||
|
@ -64,7 +62,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T: Serialize> Serialize for Orthographic3<T> {
|
impl<T: RealField + Serialize> Serialize for Orthographic3<T> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
|
@ -74,7 +72,7 @@ impl<T: Serialize> Serialize for Orthographic3<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T: Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
|
impl<'a, T: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
Des: Deserializer<'a>,
|
Des: Deserializer<'a>,
|
||||||
|
@ -85,8 +83,31 @@ impl<'a, T: Deserialize<'a>> Deserialize<'a> for Orthographic3<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Basic methods and casts.
|
|
||||||
impl<T> Orthographic3<T> {
|
impl<T> Orthographic3<T> {
|
||||||
|
/// Wraps the given matrix to interpret it as a 3D orthographic matrix.
|
||||||
|
///
|
||||||
|
/// It is not checked whether or not the given matrix actually represents an orthographic
|
||||||
|
/// projection.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
|
||||||
|
/// let mat = Matrix4::new(
|
||||||
|
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
|
||||||
|
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
|
||||||
|
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
|
||||||
|
/// 0.0, 0.0, 0.0, 1.0
|
||||||
|
/// );
|
||||||
|
/// let proj = Orthographic3::from_matrix_unchecked(mat);
|
||||||
|
/// assert_eq!(proj, Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0));
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_matrix_unchecked(matrix: Matrix4<T>) -> Self {
|
||||||
|
Self { matrix }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RealField> Orthographic3<T> {
|
||||||
/// Creates a new orthographic projection matrix.
|
/// Creates a new orthographic projection matrix.
|
||||||
///
|
///
|
||||||
/// This follows the OpenGL convention, so this will flip the `z` axis.
|
/// This follows the OpenGL convention, so this will flip the `z` axis.
|
||||||
|
@ -130,11 +151,8 @@ impl<T> Orthographic3<T> {
|
||||||
/// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0));
|
/// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self
|
pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self {
|
||||||
where
|
let matrix = Matrix4::<T>::identity();
|
||||||
T: RealField,
|
|
||||||
{
|
|
||||||
let matrix = Matrix4::identity();
|
|
||||||
let mut res = Self::from_matrix_unchecked(matrix);
|
let mut res = Self::from_matrix_unchecked(matrix);
|
||||||
|
|
||||||
res.set_left_and_right(left, right);
|
res.set_left_and_right(left, right);
|
||||||
|
@ -146,10 +164,7 @@ impl<T> Orthographic3<T> {
|
||||||
|
|
||||||
/// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
|
/// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self
|
pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self {
|
||||||
where
|
|
||||||
T: RealField,
|
|
||||||
{
|
|
||||||
assert!(
|
assert!(
|
||||||
znear != zfar,
|
znear != zfar,
|
||||||
"The far plane must not be equal to the near plane."
|
"The far plane must not be equal to the near plane."
|
||||||
|
@ -192,10 +207,7 @@ impl<T> Orthographic3<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn inverse(&self) -> Matrix4<T>
|
pub fn inverse(&self) -> Matrix4<T> {
|
||||||
where
|
|
||||||
T: RealField,
|
|
||||||
{
|
|
||||||
let mut res = self.to_homogeneous();
|
let mut res = self.to_homogeneous();
|
||||||
|
|
||||||
let inv_m11 = T::one() / self.matrix[(0, 0)];
|
let inv_m11 = T::one() / self.matrix[(0, 0)];
|
||||||
|
@ -229,7 +241,6 @@ impl<T> Orthographic3<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
// TODO: rename into `into_homogeneous` to appease clippy.
|
|
||||||
pub fn to_homogeneous(self) -> Matrix4<T> {
|
pub fn to_homogeneous(self) -> Matrix4<T> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
@ -265,8 +276,7 @@ impl<T> Orthographic3<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_projective(&self) -> &Projective3<T> {
|
pub fn as_projective(&self) -> &Projective3<T> {
|
||||||
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix.
|
unsafe { &*(self as *const Orthographic3<T> as *const Projective3<T>) }
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This transformation seen as a `Projective3`.
|
/// This transformation seen as a `Projective3`.
|
||||||
|
@ -279,7 +289,6 @@ impl<T> Orthographic3<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
// TODO: rename into `into_projective` to appease clippy.
|
|
||||||
pub fn to_projective(self) -> Projective3<T> {
|
pub fn to_projective(self) -> Projective3<T> {
|
||||||
Projective3::from_matrix_unchecked(self.matrix)
|
Projective3::from_matrix_unchecked(self.matrix)
|
||||||
}
|
}
|
||||||
|
@ -311,10 +320,7 @@ impl<T> Orthographic3<T> {
|
||||||
pub fn unwrap(self) -> Matrix4<T> {
|
pub fn unwrap(self) -> Matrix4<T> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// # Mathematical methods.
|
|
||||||
impl<T: RealField> Orthographic3<T> {
|
|
||||||
/// The left offset of the view cuboid.
|
/// The left offset of the view cuboid.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl<T: RealField> Clone for Perspective3<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RealField> fmt::Debug for Perspective3<T> {
|
impl<T: RealField> fmt::Debug for Perspective3<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
self.matrix.fmt(f)
|
self.matrix.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,7 @@ impl<T: RealField> Perspective3<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_projective(&self) -> &Projective3<T> {
|
pub fn as_projective(&self) -> &Projective3<T> {
|
||||||
// Safety: Self and Projective3 are both #[repr(transparent)] of a matrix.
|
unsafe { &*(self as *const Perspective3<T> as *const Projective3<T>) }
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This transformation seen as a `Projective3`.
|
/// This transformation seen as a `Projective3`.
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::fmt;
|
||||||
use std::hash;
|
use std::hash;
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::io::{Result as IOResult, Write};
|
||||||
use std::mem::{ManuallyDrop, MaybeUninit};
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
@ -15,13 +14,11 @@ use abomonation::Abomonation;
|
||||||
|
|
||||||
use simba::simd::SimdPartialOrd;
|
use simba::simd::SimdPartialOrd;
|
||||||
|
|
||||||
use crate::allocator::InnerAllocator;
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
||||||
use crate::base::{Const, DefaultAllocator, OVector};
|
use crate::base::{Const, DefaultAllocator, OVector, Scalar};
|
||||||
use crate::storage::InnerOwned;
|
use std::mem::MaybeUninit;
|
||||||
use crate::Scalar;
|
|
||||||
|
|
||||||
/// A point in an euclidean space.
|
/// A point in an euclidean space.
|
||||||
///
|
///
|
||||||
|
@ -42,16 +39,17 @@ use crate::Scalar;
|
||||||
/// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation
|
/// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation
|
||||||
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
|
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
|
||||||
/// of said transformations for details.
|
/// of said transformations for details.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
pub struct OPoint<T, D: DimName>
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OPoint<T: Scalar, D: DimName>
|
||||||
where
|
where
|
||||||
DefaultAllocator: InnerAllocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
/// The coordinates of this point, i.e., the shift from the origin.
|
/// The coordinates of this point, i.e., the shift from the origin.
|
||||||
pub coords: OVector<T, D>,
|
pub coords: OVector<T, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: hash::Hash, D: DimName> hash::Hash for OPoint<T, D>
|
impl<T: Scalar + hash::Hash, D: DimName> hash::Hash for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -60,37 +58,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: DimName> Copy for OPoint<T, D>
|
impl<T: Scalar + Copy, D: DimName> Copy for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
OVector<T, D>: Copy,
|
OVector<T, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, D: DimName> Clone for OPoint<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D>,
|
|
||||||
OVector<T, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self::from(self.coords.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: DimName> fmt::Debug for OPoint<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D>,
|
|
||||||
OVector<T, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("OPoint")
|
|
||||||
.field("coords", &self.coords)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T, D: DimName> bytemuck::Zeroable for OPoint<T, D>
|
unsafe impl<T: Scalar, D: DimName> bytemuck::Zeroable for OPoint<T, D>
|
||||||
where
|
where
|
||||||
OVector<T, D>: bytemuck::Zeroable,
|
OVector<T, D>: bytemuck::Zeroable,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
|
@ -98,7 +74,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T, D: DimName> bytemuck::Pod for OPoint<T, D>
|
unsafe impl<T: Scalar, D: DimName> bytemuck::Pod for OPoint<T, D>
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
OVector<T, D>: bytemuck::Pod,
|
OVector<T, D>: bytemuck::Pod,
|
||||||
|
@ -107,10 +83,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T: Serialize, D: DimName> Serialize for OPoint<T, D>
|
impl<T: Scalar, D: DimName> Serialize for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
<DefaultAllocator as InnerAllocator<T, D>>::Buffer: Serialize,
|
<DefaultAllocator as Allocator<T, D>>::Buffer: Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -121,10 +97,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T: Deserialize<'a>, D: DimName> Deserialize<'a> for OPoint<T, D>
|
impl<'a, T: Scalar, D: DimName> Deserialize<'a> for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
<DefaultAllocator as InnerAllocator<T, D>>::Buffer: Deserialize<'a>,
|
<DefaultAllocator as Allocator<T, D>>::Buffer: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
|
@ -139,6 +115,7 @@ where
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T, D: DimName> Abomonation for OPoint<T, D>
|
impl<T, D: DimName> Abomonation for OPoint<T, D>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
OVector<T, D>: Abomonation,
|
OVector<T, D>: Abomonation,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -155,7 +132,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, D: DimName> OPoint<T, D>
|
impl<T: Scalar, D: DimName> OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -173,9 +150,8 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map<T2, F: FnMut(T) -> T2>(&self, f: F) -> OPoint<T2, D>
|
pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, f: F) -> OPoint<T2, D>
|
||||||
where
|
where
|
||||||
T: Clone,
|
|
||||||
DefaultAllocator: Allocator<T2, D>,
|
DefaultAllocator: Allocator<T2, D>,
|
||||||
{
|
{
|
||||||
self.coords.map(f).into()
|
self.coords.map(f).into()
|
||||||
|
@ -187,19 +163,16 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nalgebra::{Point2, Point3};
|
/// # use nalgebra::{Point2, Point3};
|
||||||
/// let mut p = Point2::new(1.0, 2.0);
|
/// let mut p = Point2::new(1.0, 2.0);
|
||||||
/// p.apply(|e| e * 10.0);
|
/// p.apply(|e| *e = *e * 10.0);
|
||||||
/// assert_eq!(p, Point2::new(10.0, 20.0));
|
/// assert_eq!(p, Point2::new(10.0, 20.0));
|
||||||
///
|
///
|
||||||
/// // This works in any dimension.
|
/// // This works in any dimension.
|
||||||
/// let mut p = Point3::new(1.0, 2.0, 3.0);
|
/// let mut p = Point3::new(1.0, 2.0, 3.0);
|
||||||
/// p.apply(|e| e * 10.0);
|
/// p.apply(|e| *e = *e * 10.0);
|
||||||
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
|
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply<F: FnMut(T) -> T>(&mut self, f: F)
|
pub fn apply<F: FnMut(&mut T)>(&mut self, f: F) {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
self.coords.apply(f)
|
self.coords.apply(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,45 +194,25 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<D, U1>>
|
pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<D, U1>>
|
||||||
where
|
|
||||||
T: One + Clone,
|
|
||||||
D: DimNameAdd<U1>,
|
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
|
|
||||||
{
|
|
||||||
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
|
|
||||||
for i in 0..D::dim() {
|
|
||||||
unsafe {
|
|
||||||
*res.get_unchecked_mut(i) = MaybeUninit::new(self.coords[i].clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res[(D::dim(), 0)] = MaybeUninit::new(T::one());
|
|
||||||
|
|
||||||
unsafe { res.assume_init() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the
|
|
||||||
/// end of it. Unlike [`to_homogeneous`], this method does not require `T: Clone`.
|
|
||||||
pub fn into_homogeneous(self) -> OVector<T, DimNameSum<D, U1>>
|
|
||||||
where
|
where
|
||||||
T: One,
|
T: One,
|
||||||
D: DimNameAdd<U1>,
|
D: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
|
||||||
{
|
{
|
||||||
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
|
// TODO: this is mostly a copy-past from Vector::push.
|
||||||
let mut md = self.manually_drop();
|
// But we 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() {
|
// Safety: res has been fully initialized.
|
||||||
unsafe {
|
unsafe { res.assume_init() }
|
||||||
*res.get_unchecked_mut(i) =
|
|
||||||
MaybeUninit::new(ManuallyDrop::take(md.coords.get_unchecked_mut(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*res.get_unchecked_mut(D::dim()) = MaybeUninit::new(T::one());
|
|
||||||
res.assume_init()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new point with the given coordinates.
|
/// Creates a new point with the given coordinates.
|
||||||
|
@ -322,7 +275,9 @@ where
|
||||||
/// assert_eq!(it.next(), Some(3.0));
|
/// assert_eq!(it.next(), Some(3.0));
|
||||||
/// assert_eq!(it.next(), None);
|
/// assert_eq!(it.next(), None);
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> MatrixIter<T, D, Const<1>, InnerOwned<T, D>> {
|
pub fn iter(
|
||||||
|
&self,
|
||||||
|
) -> MatrixIter<'_, T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
|
||||||
self.coords.iter()
|
self.coords.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +301,9 @@ where
|
||||||
///
|
///
|
||||||
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
|
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_mut(&mut self) -> MatrixIterMut<T, D, Const<1>, InnerOwned<T, D>> {
|
pub fn iter_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> MatrixIterMut<'_, T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
|
||||||
self.coords.iter_mut()
|
self.coords.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +321,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AbsDiffEq, D: DimName> AbsDiffEq for OPoint<T, D>
|
impl<T: Scalar + AbsDiffEq, D: DimName> AbsDiffEq for OPoint<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
|
@ -382,7 +339,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RelativeEq, D: DimName> RelativeEq for OPoint<T, D>
|
impl<T: Scalar + RelativeEq, D: DimName> RelativeEq for OPoint<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
|
@ -404,7 +361,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: UlpsEq, D: DimName> UlpsEq for OPoint<T, D>
|
impl<T: Scalar + UlpsEq, D: DimName> UlpsEq for OPoint<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
|
@ -420,9 +377,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq, D: DimName> Eq for OPoint<T, D> where DefaultAllocator: Allocator<T, D> {}
|
impl<T: Scalar + Eq, D: DimName> Eq for OPoint<T, D> where DefaultAllocator: Allocator<T, D> {}
|
||||||
|
|
||||||
impl<T: PartialEq, D: DimName> PartialEq for OPoint<T, D>
|
impl<T: Scalar, D: DimName> PartialEq for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -432,7 +389,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialOrd, D: DimName> PartialOrd for OPoint<T, D>
|
impl<T: Scalar + PartialOrd, D: DimName> PartialOrd for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -497,7 +454,7 @@ where
|
||||||
* Display
|
* Display
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
impl<T: fmt::Display, D: DimName> fmt::Display for OPoint<T, D>
|
impl<T: Scalar + fmt::Display, D: DimName> fmt::Display for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::mem::{ManuallyDrop, MaybeUninit};
|
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -22,23 +20,10 @@ use simba::scalar::{ClosedDiv, SupersetOf};
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
|
|
||||||
/// # Other construction methods
|
/// # Other construction methods
|
||||||
impl<T, D: DimName> OPoint<T, D>
|
impl<T: Scalar, D: DimName> OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
/// Creates a new point with uninitialized coordinates.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_uninitialized() -> OPoint<MaybeUninit<T>, D> {
|
|
||||||
OPoint::from(OVector::new_uninitialized_generic(D::name(), Const::<1>))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts `self` into a point whose coordinates must be manually dropped.
|
|
||||||
/// This should be zero-cost.
|
|
||||||
#[inline]
|
|
||||||
pub fn manually_drop(self) -> OPoint<ManuallyDrop<T>, D> {
|
|
||||||
OPoint::from(self.coords.manually_drop())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new point with all coordinates equal to zero.
|
/// Creates a new point with all coordinates equal to zero.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -57,9 +42,9 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn origin() -> Self
|
pub fn origin() -> Self
|
||||||
where
|
where
|
||||||
T: Zero + Clone,
|
T: Zero,
|
||||||
{
|
{
|
||||||
Self::from(OVector::<_, D>::zeros())
|
Self::from(OVector::from_element(T::zero()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new point from a slice.
|
/// Creates a new point from a slice.
|
||||||
|
@ -77,11 +62,8 @@ where
|
||||||
/// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0));
|
/// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_slice(components: &[T]) -> Self
|
pub fn from_slice(components: &[T]) -> Self {
|
||||||
where
|
Self::from(OVector::from_row_slice(components))
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
Self::from(OVector::<_, D>::from_row_slice(components))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new point from its homogeneous vector representation.
|
/// Creates a new point from its homogeneous vector representation.
|
||||||
|
@ -139,7 +121,7 @@ where
|
||||||
/// let pt2 = pt.cast::<f32>();
|
/// let pt2 = pt.cast::<f32>();
|
||||||
/// assert_eq!(pt2, Point2::new(1.0f32, 2.0));
|
/// assert_eq!(pt2, Point2::new(1.0f32, 2.0));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cast<To>(self) -> OPoint<To, D>
|
pub fn cast<To: Scalar>(self) -> OPoint<To, D>
|
||||||
where
|
where
|
||||||
OPoint<To, D>: SupersetOf<Self>,
|
OPoint<To, D>: SupersetOf<Self>,
|
||||||
DefaultAllocator: Allocator<To, D>,
|
DefaultAllocator: Allocator<To, D>,
|
||||||
|
@ -169,7 +151,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rand-no-std")]
|
#[cfg(feature = "rand-no-std")]
|
||||||
impl<T, D: DimName> Distribution<OPoint<T, D>> for Standard
|
impl<T: Scalar, D: DimName> Distribution<OPoint<T, D>> for Standard
|
||||||
where
|
where
|
||||||
Standard: Distribution<T>,
|
Standard: Distribution<T>,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
|
@ -182,10 +164,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<T: Arbitrary + Send, D: DimName> Arbitrary for OPoint<T, D>
|
impl<T: Scalar + Arbitrary + Send, D: DimName> Arbitrary for OPoint<T, D>
|
||||||
where
|
where
|
||||||
|
<DefaultAllocator as Allocator<T, D>>::Buffer: Send,
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
crate::base::storage::InnerOwned<T, D>: Clone + Send,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
@ -201,7 +183,7 @@ where
|
||||||
// NOTE: the impl for Point1 is not with the others so that we
|
// NOTE: the impl for Point1 is not with the others so that we
|
||||||
// can add a section with the impl block comment.
|
// can add a section with the impl block comment.
|
||||||
/// # Construction from individual components
|
/// # Construction from individual components
|
||||||
impl<T> Point1<T> {
|
impl<T: Scalar> Point1<T> {
|
||||||
/// Initializes this point from its components.
|
/// Initializes this point from its components.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -220,7 +202,7 @@ impl<T> Point1<T> {
|
||||||
}
|
}
|
||||||
macro_rules! componentwise_constructors_impl(
|
macro_rules! componentwise_constructors_impl(
|
||||||
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
|
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
|
||||||
impl<T> $Point<T> {
|
impl<T: Scalar> $Point<T> {
|
||||||
#[doc = "Initializes this point from its components."]
|
#[doc = "Initializes this point from its components."]
|
||||||
#[doc = "# Example\n```"]
|
#[doc = "# Example\n```"]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
|
|
|
@ -2,7 +2,7 @@ use num::{One, Zero};
|
||||||
use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf};
|
use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf};
|
||||||
use simba::simd::PrimitiveSimdValue;
|
use simba::simd::PrimitiveSimdValue;
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, InnerAllocator};
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar};
|
use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar};
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ use crate::{DimName, OPoint};
|
||||||
|
|
||||||
impl<T1, T2, D: DimName> SubsetOf<OPoint<T2, D>> for OPoint<T1, D>
|
impl<T1, T2, D: DimName> SubsetOf<OPoint<T2, D>> for OPoint<T1, D>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: Scalar,
|
||||||
|
T2: Scalar + SupersetOf<T1>,
|
||||||
DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>,
|
DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -43,6 +44,7 @@ where
|
||||||
impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D>
|
impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D>
|
||||||
where
|
where
|
||||||
D: DimNameAdd<U1>,
|
D: DimNameAdd<U1>,
|
||||||
|
T1: Scalar,
|
||||||
T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>,
|
T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>,
|
||||||
DefaultAllocator: Allocator<T1, D>
|
DefaultAllocator: Allocator<T1, D>
|
||||||
+ Allocator<T2, D>
|
+ Allocator<T2, D>
|
||||||
|
@ -54,7 +56,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> {
|
fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> {
|
||||||
let p: OPoint<T2, D> = self.to_superset();
|
let p: OPoint<T2, D> = self.to_superset();
|
||||||
p.into_homogeneous()
|
p.to_homogeneous()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -64,25 +66,25 @@ where
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_superset_unchecked(v: &OVector<T2, DimNameSum<D, U1>>) -> Self {
|
fn from_superset_unchecked(v: &OVector<T2, DimNameSum<D, U1>>) -> Self {
|
||||||
let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone();
|
let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone();
|
||||||
Self {
|
Self {
|
||||||
coords: crate::convert_unchecked(coords),
|
coords: crate::convert_unchecked(coords),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Zero + One, D: DimName> From<OPoint<T, D>> for OVector<T, DimNameSum<D, U1>>
|
impl<T: Scalar + Zero + One, D: DimName> From<OPoint<T, D>> for OVector<T, DimNameSum<D, U1>>
|
||||||
where
|
where
|
||||||
D: DimNameAdd<U1>,
|
D: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>,
|
DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(t: OPoint<T, D>) -> Self {
|
fn from(t: OPoint<T, D>) -> Self {
|
||||||
t.into_homogeneous()
|
t.to_homogeneous()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<[T; D]> for Point<T, D> {
|
impl<T: Scalar, const D: usize> From<[T; D]> for Point<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: [T; D]) -> Self {
|
fn from(coords: [T; D]) -> Self {
|
||||||
Point {
|
Point {
|
||||||
|
@ -91,19 +93,16 @@ impl<T, const D: usize> From<[T; D]> for Point<T, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<Point<T, D>> for [T; D]
|
impl<T: Scalar, const D: usize> From<Point<T, D>> for [T; D] {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(p: Point<T, D>) -> Self {
|
fn from(p: Point<T, D>) -> Self {
|
||||||
p.coords.into()
|
p.coords.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, D: DimName> From<OVector<T, D>> for OPoint<T, D>
|
impl<T: Scalar, D: DimName> From<OVector<T, D>> for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: InnerAllocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: OVector<T, D>) -> Self {
|
fn from(coords: OVector<T, D>) -> Self {
|
||||||
|
@ -111,81 +110,85 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 2]> for Point<T, D>
|
impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 2]>
|
||||||
|
for Point<T, D>
|
||||||
where
|
where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar + Copy,
|
||||||
|
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Point<T::Element, D>; 2]) -> Self {
|
fn from(arr: [Point<T::Element, D>; 2]) -> Self {
|
||||||
Self::from(OVector::from([
|
Self::from(OVector::from([arr[0].coords, arr[1].coords]))
|
||||||
arr[0].coords.clone(),
|
|
||||||
arr[1].coords.clone(),
|
|
||||||
]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 4]> for Point<T, D>
|
impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 4]>
|
||||||
|
for Point<T, D>
|
||||||
where
|
where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar + Copy,
|
||||||
|
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Point<T::Element, D>; 4]) -> Self {
|
fn from(arr: [Point<T::Element, D>; 4]) -> Self {
|
||||||
Self::from(OVector::from([
|
Self::from(OVector::from([
|
||||||
arr[0].coords.clone(),
|
arr[0].coords,
|
||||||
arr[1].coords.clone(),
|
arr[1].coords,
|
||||||
arr[2].coords.clone(),
|
arr[2].coords,
|
||||||
arr[3].coords.clone(),
|
arr[3].coords,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 8]> for Point<T, D>
|
impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 8]>
|
||||||
|
for Point<T, D>
|
||||||
where
|
where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar + Copy,
|
||||||
|
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Point<T::Element, D>; 8]) -> Self {
|
fn from(arr: [Point<T::Element, D>; 8]) -> Self {
|
||||||
Self::from(OVector::from([
|
Self::from(OVector::from([
|
||||||
arr[0].coords.clone(),
|
arr[0].coords,
|
||||||
arr[1].coords.clone(),
|
arr[1].coords,
|
||||||
arr[2].coords.clone(),
|
arr[2].coords,
|
||||||
arr[3].coords.clone(),
|
arr[3].coords,
|
||||||
arr[4].coords.clone(),
|
arr[4].coords,
|
||||||
arr[5].coords.clone(),
|
arr[5].coords,
|
||||||
arr[6].coords.clone(),
|
arr[6].coords,
|
||||||
arr[7].coords.clone(),
|
arr[7].coords,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 16]>
|
impl<T: Scalar + Copy + PrimitiveSimdValue, const D: usize> From<[Point<T::Element, D>; 16]>
|
||||||
for Point<T, D>
|
for Point<T, D>
|
||||||
where
|
where
|
||||||
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
|
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
|
||||||
T::Element: Scalar,
|
T::Element: Scalar + Copy,
|
||||||
|
<DefaultAllocator as Allocator<T::Element, Const<D>>>::Buffer: Copy,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arr: [Point<T::Element, D>; 16]) -> Self {
|
fn from(arr: [Point<T::Element, D>; 16]) -> Self {
|
||||||
Self::from(OVector::from([
|
Self::from(OVector::from([
|
||||||
arr[0].coords.clone(),
|
arr[0].coords,
|
||||||
arr[1].coords.clone(),
|
arr[1].coords,
|
||||||
arr[2].coords.clone(),
|
arr[2].coords,
|
||||||
arr[3].coords.clone(),
|
arr[3].coords,
|
||||||
arr[4].coords.clone(),
|
arr[4].coords,
|
||||||
arr[5].coords.clone(),
|
arr[5].coords,
|
||||||
arr[6].coords.clone(),
|
arr[6].coords,
|
||||||
arr[7].coords.clone(),
|
arr[7].coords,
|
||||||
arr[8].coords.clone(),
|
arr[8].coords,
|
||||||
arr[9].coords.clone(),
|
arr[9].coords,
|
||||||
arr[10].coords.clone(),
|
arr[10].coords,
|
||||||
arr[11].coords.clone(),
|
arr[11].coords,
|
||||||
arr[12].coords.clone(),
|
arr[12].coords,
|
||||||
arr[13].coords.clone(),
|
arr[13].coords,
|
||||||
arr[14].coords.clone(),
|
arr[14].coords,
|
||||||
arr[15].coords.clone(),
|
arr[15].coords,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
|
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
|
||||||
use crate::base::{U1, U2, U3, U4, U5, U6};
|
use crate::base::{Scalar, U1, U2, U3, U4, U5, U6};
|
||||||
|
|
||||||
use crate::geometry::OPoint;
|
use crate::geometry::OPoint;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use crate::geometry::OPoint;
|
||||||
|
|
||||||
macro_rules! deref_impl(
|
macro_rules! deref_impl(
|
||||||
($D: ty, $Target: ident $(, $comps: ident)*) => {
|
($D: ty, $Target: ident $(, $comps: ident)*) => {
|
||||||
impl<T> Deref for OPoint<T, $D>
|
impl<T: Scalar> Deref for OPoint<T, $D>
|
||||||
{
|
{
|
||||||
type Target = $Target<T>;
|
type Target = $Target<T>;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ macro_rules! deref_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for OPoint<T, $D>
|
impl<T: Scalar> DerefMut for OPoint<T, $D>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::DefaultAllocator;
|
||||||
* Indexing.
|
* Indexing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
impl<T, D: DimName> Index<usize> for OPoint<T, D>
|
impl<T: Scalar, D: DimName> Index<usize> for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, D: DimName> IndexMut<usize> for OPoint<T, D>
|
impl<T: Scalar, D: DimName> IndexMut<usize> for OPoint<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use simba::simd::SimdValue;
|
use simba::simd::SimdValue;
|
||||||
|
|
||||||
use crate::base::OVector;
|
use crate::base::{OVector, Scalar};
|
||||||
|
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::Scalar;
|
|
||||||
|
|
||||||
impl<T: Scalar + SimdValue, const D: usize> SimdValue for Point<T, D>
|
impl<T: Scalar + SimdValue, const D: usize> SimdValue for Point<T, D>
|
||||||
where
|
where
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::io::{Result as IOResult, Write};
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
@ -26,29 +26,29 @@ use crate::geometry::{Point3, Rotation};
|
||||||
|
|
||||||
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
|
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
|
||||||
/// that may be used as a rotation.
|
/// that may be used as a rotation.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Quaternion<T> {
|
pub struct Quaternion<T> {
|
||||||
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
|
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
|
||||||
pub coords: Vector4<T>,
|
pub coords: Vector4<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> Hash for Quaternion<T> {
|
impl<T: Scalar + Hash> Hash for Quaternion<T> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.coords.hash(state)
|
self.coords.hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq> Eq for Quaternion<T> {}
|
impl<T: Scalar + Eq> Eq for Quaternion<T> {}
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for Quaternion<T> {
|
impl<T: Scalar> PartialEq for Quaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, right: &Self) -> bool {
|
fn eq(&self, right: &Self) -> bool {
|
||||||
self.coords == right.coords
|
self.coords == right.coords
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Zero + Clone> Default for Quaternion<T> {
|
impl<T: Scalar + Zero> Default for Quaternion<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Quaternion {
|
Quaternion {
|
||||||
coords: Vector4::zeros(),
|
coords: Vector4::zeros(),
|
||||||
|
@ -57,10 +57,10 @@ impl<T: Zero + Clone> Default for Quaternion<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T> bytemuck::Zeroable for Quaternion<T> where Vector4<T>: bytemuck::Zeroable {}
|
unsafe impl<T: Scalar> bytemuck::Zeroable for Quaternion<T> where Vector4<T>: bytemuck::Zeroable {}
|
||||||
|
|
||||||
#[cfg(feature = "bytemuck")]
|
#[cfg(feature = "bytemuck")]
|
||||||
unsafe impl<T> bytemuck::Pod for Quaternion<T>
|
unsafe impl<T: Scalar> bytemuck::Pod for Quaternion<T>
|
||||||
where
|
where
|
||||||
Vector4<T>: bytemuck::Pod,
|
Vector4<T>: bytemuck::Pod,
|
||||||
T: Copy,
|
T: Copy,
|
||||||
|
@ -68,7 +68,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T> Abomonation for Quaternion<T>
|
impl<T: Scalar> Abomonation for Quaternion<T>
|
||||||
where
|
where
|
||||||
Vector4<T>: Abomonation,
|
Vector4<T>: Abomonation,
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T> Serialize for Quaternion<T>
|
impl<T: Scalar> Serialize for Quaternion<T>
|
||||||
where
|
where
|
||||||
Owned<T, U4>: Serialize,
|
Owned<T, U4>: Serialize,
|
||||||
{
|
{
|
||||||
|
@ -99,7 +99,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T> Deserialize<'a> for Quaternion<T>
|
impl<'a, T: Scalar> Deserialize<'a> for Quaternion<T>
|
||||||
where
|
where
|
||||||
Owned<T, U4>: Deserialize<'a>,
|
Owned<T, U4>: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
|
@ -1045,8 +1045,8 @@ impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for Quaternion<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Display> fmt::Display for Quaternion<T> {
|
impl<T: RealField + fmt::Display> fmt::Display for Quaternion<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Quaternion {} − ({}, {}, {})",
|
"Quaternion {} − ({}, {}, {})",
|
||||||
|
@ -1097,7 +1097,7 @@ impl<T: SimdRealField> UnitQuaternion<T>
|
||||||
where
|
where
|
||||||
T::Element: SimdRealField,
|
T::Element: SimdRealField,
|
||||||
{
|
{
|
||||||
/// The rotation angle in \[0; pi\] of this unit quaternion.
|
/// The rotation angle in [0; pi] of this unit quaternion.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::dimension::U4;
|
use crate::base::dimension::U4;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ where
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<T: SimdRealField + Arbitrary> Arbitrary for Quaternion<T>
|
impl<T: SimdRealField + Arbitrary> Arbitrary for Quaternion<T>
|
||||||
where
|
where
|
||||||
InnerOwned<T, U4>: Send,
|
Owned<T, U4>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
@ -881,8 +881,8 @@ where
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<T: RealField + Arbitrary> Arbitrary for UnitQuaternion<T>
|
impl<T: RealField + Arbitrary> Arbitrary for UnitQuaternion<T>
|
||||||
where
|
where
|
||||||
InnerOwned<T, U4>: Send,
|
Owned<T, U4>: Send,
|
||||||
InnerOwned<T, U3>: Send,
|
Owned<T, U3>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
|
|
@ -28,7 +28,8 @@ use crate::geometry::{
|
||||||
|
|
||||||
impl<T1, T2> SubsetOf<Quaternion<T2>> for Quaternion<T1>
|
impl<T1, T2> SubsetOf<Quaternion<T2>> for Quaternion<T1>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: Scalar,
|
||||||
|
T2: Scalar + SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> Quaternion<T2> {
|
fn to_superset(&self) -> Quaternion<T2> {
|
||||||
|
@ -50,7 +51,8 @@ where
|
||||||
|
|
||||||
impl<T1, T2> SubsetOf<UnitQuaternion<T2>> for UnitQuaternion<T1>
|
impl<T1, T2> SubsetOf<UnitQuaternion<T2>> for UnitQuaternion<T1>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: Scalar,
|
||||||
|
T2: Scalar + SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> UnitQuaternion<T2> {
|
fn to_superset(&self) -> UnitQuaternion<T2> {
|
||||||
|
@ -237,14 +239,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Vector4<T>> for Quaternion<T> {
|
impl<T: Scalar> From<Vector4<T>> for Quaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: Vector4<T>) -> Self {
|
fn from(coords: Vector4<T>) -> Self {
|
||||||
Self { coords }
|
Self { coords }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<[T; 4]> for Quaternion<T> {
|
impl<T: Scalar> From<[T; 4]> for Quaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: [T; 4]) -> Self {
|
fn from(coords: [T; 4]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -12,14 +12,13 @@ impl<T: Scalar + SimdValue> Deref for Quaternion<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
// Safety: Self and IJKW are both stored as contiguous coordinates.
|
unsafe { &*(self as *const Self as *const Self::Target) }
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> {
|
impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
unsafe { &mut *(self as *mut _ as *mut _) }
|
unsafe { &mut *(self as *mut Self as *mut Self::Target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,12 +59,12 @@ use std::ops::{
|
||||||
|
|
||||||
use crate::base::dimension::U3;
|
use crate::base::dimension::U3;
|
||||||
use crate::base::storage::Storage;
|
use crate::base::storage::Storage;
|
||||||
use crate::base::{Const, Unit, Vector, Vector3};
|
use crate::base::{Const, Scalar, Unit, Vector, Vector3};
|
||||||
use crate::SimdRealField;
|
use crate::SimdRealField;
|
||||||
|
|
||||||
use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
|
use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
|
||||||
|
|
||||||
impl<T> Index<usize> for Quaternion<T> {
|
impl<T: Scalar> Index<usize> for Quaternion<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -73,7 +73,7 @@ impl<T> Index<usize> for Quaternion<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<usize> for Quaternion<T> {
|
impl<T: Scalar> IndexMut<usize> for Quaternion<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, i: usize) -> &mut T {
|
fn index_mut(&mut self, i: usize) -> &mut T {
|
||||||
&mut self.coords[i]
|
&mut self.coords[i]
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
|
use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::base::{Const, Matrix, Unit, Vector};
|
use crate::base::{Const, Matrix, Unit, Vector};
|
||||||
use crate::dimension::{Dim, U1};
|
use crate::dimension::{Dim, U1};
|
||||||
|
@ -9,7 +7,7 @@ use simba::scalar::ComplexField;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
|
|
||||||
/// A reflection wrt. a plane.
|
/// A reflection wrt. a plane.
|
||||||
pub struct Reflection<T, D: Dim, S> {
|
pub struct Reflection<T, D, S> {
|
||||||
axis: Vector<T, D, S>,
|
axis: Vector<T, D, S>,
|
||||||
bias: T,
|
bias: T,
|
||||||
}
|
}
|
||||||
|
@ -88,40 +86,40 @@ impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
|
||||||
pub fn reflect_rows<R2: Dim, C2: Dim, S2, S3>(
|
pub fn reflect_rows<R2: Dim, C2: Dim, S2, S3>(
|
||||||
&self,
|
&self,
|
||||||
lhs: &mut Matrix<T, R2, C2, S2>,
|
lhs: &mut Matrix<T, R2, C2, S2>,
|
||||||
work: &mut Vector<MaybeUninit<T>, R2, S3>,
|
work: &mut Vector<T, R2, S3>,
|
||||||
) where
|
) where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
S3: StorageMut<MaybeUninit<T>, R2>,
|
S3: StorageMut<T, R2>,
|
||||||
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
|
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
|
||||||
{
|
{
|
||||||
let mut work = lhs.mul_to(&self.axis, work);
|
lhs.mul_to(&self.axis, work);
|
||||||
|
|
||||||
if !self.bias.is_zero() {
|
if !self.bias.is_zero() {
|
||||||
work.add_scalar_mut(-self.bias);
|
work.add_scalar_mut(-self.bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
let m_two: T = crate::convert(-2.0f64);
|
let m_two: T = crate::convert(-2.0f64);
|
||||||
lhs.gerc(m_two, &work, &self.axis, T::one());
|
lhs.gerc(m_two, work, &self.axis, T::one());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the reflection to the rows of `lhs`.
|
/// Applies the reflection to the rows of `lhs`.
|
||||||
pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>(
|
pub fn reflect_rows_with_sign<R2: Dim, C2: Dim, S2, S3>(
|
||||||
&self,
|
&self,
|
||||||
lhs: &mut Matrix<T, R2, C2, S2>,
|
lhs: &mut Matrix<T, R2, C2, S2>,
|
||||||
work: &mut Vector<MaybeUninit<T>, R2, S3>,
|
work: &mut Vector<T, R2, S3>,
|
||||||
sign: T,
|
sign: T,
|
||||||
) where
|
) where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
S3: StorageMut<MaybeUninit<T>, R2>,
|
S3: StorageMut<T, R2>,
|
||||||
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
|
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
|
||||||
{
|
{
|
||||||
let mut work = lhs.mul_to(&self.axis, work);
|
lhs.mul_to(&self.axis, work);
|
||||||
|
|
||||||
if !self.bias.is_zero() {
|
if !self.bias.is_zero() {
|
||||||
work.add_scalar_mut(-self.bias);
|
work.add_scalar_mut(-self.bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
let m_two = sign.scale(crate::convert(-2.0f64));
|
let m_two = sign.scale(crate::convert(-2.0f64));
|
||||||
lhs.gerc(m_two, &work, &self.axis, sign);
|
lhs.gerc(m_two, work, &self.axis, sign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@ use std::io::{Result as IOResult, Write};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
use crate::storage::InnerOwned;
|
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use abomonation::Abomonation;
|
use abomonation::Abomonation;
|
||||||
|
@ -54,26 +53,29 @@ use crate::geometry::Point;
|
||||||
/// # Conversion
|
/// # Conversion
|
||||||
/// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
|
/// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
|
||||||
///
|
///
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rotation<T, const D: usize> {
|
pub struct Rotation<T, const D: usize> {
|
||||||
matrix: SMatrix<T, D, D>,
|
matrix: SMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: hash::Hash, const D: usize> hash::Hash for Rotation<T, D>
|
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Rotation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>, Const<D>>: hash::Hash,
|
<DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: hash::Hash,
|
||||||
{
|
{
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.matrix.hash(state)
|
self.matrix.hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, const D: usize> Copy for Rotation<T, D> where InnerOwned<T, Const<D>, Const<D>>: Copy {}
|
impl<T: Scalar + Copy, const D: usize> Copy for Rotation<T, D> where
|
||||||
|
<DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: Copy
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Clone, const D: usize> Clone for Rotation<T, D>
|
impl<T: Scalar, const D: usize> Clone for Rotation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>, Const<D>>: Clone,
|
<DefaultAllocator as Allocator<T, Const<D>, Const<D>>>::Buffer: Clone,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -100,6 +102,7 @@ where
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T, const D: usize> Abomonation for Rotation<T, D>
|
impl<T, const D: usize> Abomonation for Rotation<T, D>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
SMatrix<T, D, D>: Abomonation,
|
SMatrix<T, D, D>: Abomonation,
|
||||||
{
|
{
|
||||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||||
|
@ -118,7 +121,7 @@ where
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T: Scalar, const D: usize> Serialize for Rotation<T, D>
|
impl<T: Scalar, const D: usize> Serialize for Rotation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>, Const<D>>: Serialize,
|
Owned<T, Const<D>, Const<D>>: Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -129,9 +132,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T, const D: usize> Deserialize<'a> for Rotation<T, D>
|
impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Rotation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>, Const<D>>: Deserialize<'a>,
|
Owned<T, Const<D>, Const<D>>: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
|
@ -173,7 +176,7 @@ impl<T, const D: usize> Rotation<T, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Conversion to a matrix
|
/// # Conversion to a matrix
|
||||||
impl<T, const D: usize> Rotation<T, D> {
|
impl<T: Scalar, const D: usize> Rotation<T, D> {
|
||||||
/// A reference to the underlying matrix representation of this rotation.
|
/// A reference to the underlying matrix representation of this rotation.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -201,7 +204,7 @@ impl<T, const D: usize> Rotation<T, D> {
|
||||||
/// A mutable reference to the underlying matrix representation of this rotation.
|
/// A mutable reference to the underlying matrix representation of this rotation.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
|
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
|
||||||
pub fn matrix_mut(&mut self) -> &mut SMatrix<T, D, D> {
|
pub unsafe fn matrix_mut(&mut self) -> &mut SMatrix<T, D, D> {
|
||||||
&mut self.matrix
|
&mut self.matrix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +277,7 @@ impl<T, const D: usize> Rotation<T, D> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||||
where
|
where
|
||||||
T: Zero + One + Scalar,
|
T: Zero + One,
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ where
|
||||||
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation2<T>
|
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation2<T>
|
||||||
where
|
where
|
||||||
T::Element: SimdRealField,
|
T::Element: SimdRealField,
|
||||||
InnerOwned<T, U2, U2>: Send,
|
Owned<T, U2, U2>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
@ -976,8 +976,8 @@ where
|
||||||
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation3<T>
|
impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation3<T>
|
||||||
where
|
where
|
||||||
T::Element: SimdRealField,
|
T::Element: SimdRealField,
|
||||||
InnerOwned<T, U3, U3>: Send,
|
Owned<T, U3, U3>: Send,
|
||||||
InnerOwned<T, U3>: Send,
|
Owned<T, U3>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(g: &mut Gen) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
|
|
|
@ -17,11 +17,12 @@ use simba::simd::SimdRealField;
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
||||||
use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
|
use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
|
||||||
|
|
||||||
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
|
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
|
||||||
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
@ -64,7 +65,7 @@ where
|
||||||
|
|
||||||
impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Similarity<T, R, D>
|
impl<T: Scalar + hash::Hash, R: hash::Hash, const D: usize> hash::Hash for Similarity<T, R, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: hash::Hash,
|
Owned<T, Const<D>>: hash::Hash,
|
||||||
{
|
{
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.isometry.hash(state);
|
self.isometry.hash(state);
|
||||||
|
@ -75,7 +76,7 @@ where
|
||||||
impl<T: Scalar + Copy + Zero, R: AbstractRotation<T, D> + Copy, const D: usize> Copy
|
impl<T: Scalar + Copy + Zero, R: AbstractRotation<T, D> + Copy, const D: usize> Copy
|
||||||
for Similarity<T, R, D>
|
for Similarity<T, R, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: Copy,
|
Owned<T, Const<D>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ where
|
||||||
T: crate::RealField + Arbitrary + Send,
|
T: crate::RealField + Arbitrary + Send,
|
||||||
T::Element: crate::RealField,
|
T::Element: crate::RealField,
|
||||||
R: AbstractRotation<T, D> + Arbitrary + Send,
|
R: AbstractRotation<T, D> + Arbitrary + Send,
|
||||||
InnerOwned<T, crate::Const<D>>: Send,
|
Owned<T, crate::Const<D>>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(rng: &mut Gen) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash;
|
use std::hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -8,11 +7,11 @@ use std::marker::PhantomData;
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use simba::scalar::{ComplexField, RealField};
|
use simba::scalar::RealField;
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector};
|
use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector};
|
||||||
|
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
|
@ -120,7 +119,7 @@ macro_rules! category_mul_impl(
|
||||||
)*}
|
)*}
|
||||||
);
|
);
|
||||||
|
|
||||||
// We require stability upon multiplication.
|
// We require stability uppon multiplication.
|
||||||
impl<T: TCategory> TCategoryMul<T> for T {
|
impl<T: TCategory> TCategoryMul<T> for T {
|
||||||
type Representative = T;
|
type Representative = T;
|
||||||
}
|
}
|
||||||
|
@ -157,8 +156,9 @@ super_tcategory_impl!(
|
||||||
///
|
///
|
||||||
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
|
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
|
||||||
/// 3D transformation.
|
/// 3D transformation.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
pub struct Transform<T, C: TCategory, const D: usize>
|
#[derive(Debug)]
|
||||||
|
pub struct Transform<T: RealField, C: TCategory, const D: usize>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
|
@ -167,32 +167,29 @@ where
|
||||||
_phantom: PhantomData<C>,
|
_phantom: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D>
|
impl<T: RealField + hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash,
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash,
|
||||||
{
|
{
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.matrix.hash(state);
|
self.matrix.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D>
|
||||||
impl<T: Copy, C: TCategory, const D: usize> Copy for Transform<T, C, D>
|
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: Clone, C: TCategory, const D: usize> Clone for Transform<T, C, D>
|
impl<T: RealField, C: TCategory, const D: usize> Clone for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -200,25 +197,33 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug, C: TCategory, const D: usize> Debug for Transform<T, C, D>
|
#[cfg(feature = "bytemuck")]
|
||||||
|
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Zeroable for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
|
T: RealField + bytemuck::Zeroable,
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Debug,
|
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Zeroable,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Transform")
|
|
||||||
.field("matrix", &self.matrix)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bytemuck")]
|
||||||
|
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Pod for Transform<T, C, D>
|
||||||
|
where
|
||||||
|
T: RealField + bytemuck::Pod,
|
||||||
|
Const<D>: DimNameAdd<U1>,
|
||||||
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
|
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Pod,
|
||||||
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T, C: TCategory, const D: usize> Serialize for Transform<T, C, D>
|
impl<T: RealField, C: TCategory, const D: usize> Serialize for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Serialize,
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -229,11 +234,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T, C: TCategory, const D: usize> Deserialize<'a> for Transform<T, C, D>
|
impl<'a, T: RealField, C: TCategory, const D: usize> Deserialize<'a> for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Deserialize<'a>,
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
|
@ -247,14 +252,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq, C: TCategory, const D: usize> Eq for Transform<T, C, D>
|
impl<T: RealField + Eq, C: TCategory, const D: usize> Eq for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialEq, C: TCategory, const D: usize> PartialEq for Transform<T, C, D>
|
impl<T: RealField, C: TCategory, const D: usize> PartialEq for Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
|
@ -265,7 +270,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, C: TCategory, const D: usize> Transform<T, C, D>
|
impl<T: RealField, C: TCategory, const D: usize> Transform<T, C, D>
|
||||||
where
|
where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
|
@ -370,10 +375,7 @@ where
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release."
|
note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release."
|
||||||
)]
|
)]
|
||||||
pub fn clone_owned(&self) -> Transform<T, C, D>
|
pub fn clone_owned(&self) -> Transform<T, C, D> {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
Transform::from_matrix_unchecked(self.matrix.clone_owned())
|
Transform::from_matrix_unchecked(self.matrix.clone_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,10 +393,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
self.matrix().clone_owned()
|
self.matrix().clone_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,10 +422,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "Did you mean to use try_inverse_mut()?"]
|
#[must_use = "Did you mean to use try_inverse_mut()?"]
|
||||||
pub fn try_inverse(self) -> Option<Transform<T, C, D>>
|
pub fn try_inverse(self) -> Option<Transform<T, C, D>> {
|
||||||
where
|
|
||||||
T: ComplexField,
|
|
||||||
{
|
|
||||||
self.matrix
|
self.matrix
|
||||||
.try_inverse()
|
.try_inverse()
|
||||||
.map(Transform::from_matrix_unchecked)
|
.map(Transform::from_matrix_unchecked)
|
||||||
|
@ -452,7 +448,6 @@ where
|
||||||
#[must_use = "Did you mean to use inverse_mut()?"]
|
#[must_use = "Did you mean to use inverse_mut()?"]
|
||||||
pub fn inverse(self) -> Transform<T, C, D>
|
pub fn inverse(self) -> Transform<T, C, D>
|
||||||
where
|
where
|
||||||
T: ComplexField,
|
|
||||||
C: SubTCategoryOf<TProjective>,
|
C: SubTCategoryOf<TProjective>,
|
||||||
{
|
{
|
||||||
// TODO: specialize for TAffine?
|
// TODO: specialize for TAffine?
|
||||||
|
@ -484,10 +479,7 @@ where
|
||||||
/// assert!(!t.try_inverse_mut());
|
/// assert!(!t.try_inverse_mut());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_inverse_mut(&mut self) -> bool
|
pub fn try_inverse_mut(&mut self) -> bool {
|
||||||
where
|
|
||||||
T: ComplexField,
|
|
||||||
{
|
|
||||||
self.matrix.try_inverse_mut()
|
self.matrix.try_inverse_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +503,6 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inverse_mut(&mut self)
|
pub fn inverse_mut(&mut self)
|
||||||
where
|
where
|
||||||
T: ComplexField,
|
|
||||||
C: SubTCategoryOf<TProjective>,
|
C: SubTCategoryOf<TProjective>,
|
||||||
{
|
{
|
||||||
let _ = self.matrix.try_inverse_mut();
|
let _ = self.matrix.try_inverse_mut();
|
||||||
|
@ -552,8 +543,8 @@ where
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
C: SubTCategoryOf<TProjective>,
|
C: SubTCategoryOf<TProjective>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||||
+ Allocator<T, DimNameSum<Const<D>, U1>>,
|
+ Allocator<T, DimNameSum<Const<D>, U1>>, // + Allocator<T, D, D>
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
|
// + Allocator<T, D>
|
||||||
{
|
{
|
||||||
/// Transform the given point by the inverse of this transformation.
|
/// Transform the given point by the inverse of this transformation.
|
||||||
/// This may be cheaper than inverting the transformation and transforming
|
/// This may be cheaper than inverting the transformation and transforming
|
||||||
|
|
|
@ -9,7 +9,6 @@ use simba::scalar::{ClosedAdd, ClosedMul, RealField, SubsetOf};
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
||||||
use crate::storage::InnerOwned;
|
|
||||||
|
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
|
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
|
||||||
|
@ -373,8 +372,7 @@ md_impl_all!(
|
||||||
const D;
|
const D;
|
||||||
for CA, CB;
|
for CA, CB;
|
||||||
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
|
where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
|
||||||
Transform<T, CB, D>: Clone; // There's probably a better bound here.
|
|
||||||
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
|
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
|
||||||
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
|
[val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
|
||||||
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
|
[ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
|
||||||
|
@ -628,8 +626,7 @@ md_assign_impl_all!(
|
||||||
const D;
|
const D;
|
||||||
for CA, CB;
|
for CA, CB;
|
||||||
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
|
where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
|
||||||
InnerOwned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone;
|
|
||||||
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
|
self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
|
||||||
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
|
[val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
|
||||||
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() };
|
[ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() };
|
||||||
|
|
|
@ -15,13 +15,13 @@ use simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub};
|
||||||
|
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
||||||
|
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
|
|
||||||
/// A translation.
|
/// A translation.
|
||||||
#[repr(transparent)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Translation<T, const D: usize> {
|
pub struct Translation<T, const D: usize> {
|
||||||
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is
|
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is
|
||||||
|
@ -29,20 +29,20 @@ pub struct Translation<T, const D: usize> {
|
||||||
pub vector: SVector<T, D>,
|
pub vector: SVector<T, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: hash::Hash, const D: usize> hash::Hash for Translation<T, D>
|
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: hash::Hash,
|
Owned<T, Const<D>>: hash::Hash,
|
||||||
{
|
{
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.vector.hash(state)
|
self.vector.hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, const D: usize> Copy for Translation<T, D> {}
|
impl<T: Scalar + Copy, const D: usize> Copy for Translation<T, D> {}
|
||||||
|
|
||||||
impl<T: Clone, const D: usize> Clone for Translation<T, D>
|
impl<T: Scalar, const D: usize> Clone for Translation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: Clone,
|
Owned<T, Const<D>>: Clone,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -69,6 +69,7 @@ where
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<T, const D: usize> Abomonation for Translation<T, D>
|
impl<T, const D: usize> Abomonation for Translation<T, D>
|
||||||
where
|
where
|
||||||
|
T: Scalar,
|
||||||
SVector<T, D>: Abomonation,
|
SVector<T, D>: Abomonation,
|
||||||
{
|
{
|
||||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||||
|
@ -85,9 +86,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<T, const D: usize> Serialize for Translation<T, D>
|
impl<T: Scalar, const D: usize> Serialize for Translation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: Serialize,
|
Owned<T, Const<D>>: Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -98,9 +99,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
impl<'a, T, const D: usize> Deserialize<'a> for Translation<T, D>
|
impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, Const<D>>: Deserialize<'a>,
|
Owned<T, Const<D>>: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
where
|
where
|
||||||
|
@ -155,7 +156,7 @@ mod rkyv_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> Translation<T, D> {
|
impl<T: Scalar, const D: usize> Translation<T, D> {
|
||||||
/// Creates a new translation from the given vector.
|
/// Creates a new translation from the given vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated(note = "Use `::from` instead.")]
|
#[deprecated(note = "Use `::from` instead.")]
|
||||||
|
@ -181,7 +182,7 @@ impl<T, const D: usize> Translation<T, D> {
|
||||||
#[must_use = "Did you mean to use inverse_mut()?"]
|
#[must_use = "Did you mean to use inverse_mut()?"]
|
||||||
pub fn inverse(&self) -> Translation<T, D>
|
pub fn inverse(&self) -> Translation<T, D>
|
||||||
where
|
where
|
||||||
T: ClosedNeg + Scalar,
|
T: ClosedNeg,
|
||||||
{
|
{
|
||||||
Translation::from(-&self.vector)
|
Translation::from(-&self.vector)
|
||||||
}
|
}
|
||||||
|
@ -208,7 +209,7 @@ impl<T, const D: usize> Translation<T, D> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||||
where
|
where
|
||||||
T: Zero + One + Scalar,
|
T: Zero + One,
|
||||||
Const<D>: DimNameAdd<U1>,
|
Const<D>: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||||
{
|
{
|
||||||
|
@ -239,7 +240,7 @@ impl<T, const D: usize> Translation<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inverse_mut(&mut self)
|
pub fn inverse_mut(&mut self)
|
||||||
where
|
where
|
||||||
T: ClosedNeg + Scalar,
|
T: ClosedNeg,
|
||||||
{
|
{
|
||||||
self.vector.neg_mut()
|
self.vector.neg_mut()
|
||||||
}
|
}
|
||||||
|
@ -279,16 +280,16 @@ impl<T: Scalar + ClosedSub, const D: usize> Translation<T, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq, const D: usize> Eq for Translation<T, D> {}
|
impl<T: Scalar + Eq, const D: usize> Eq for Translation<T, D> {}
|
||||||
|
|
||||||
impl<T: PartialEq, const D: usize> PartialEq for Translation<T, D> {
|
impl<T: Scalar + PartialEq, const D: usize> PartialEq for Translation<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, right: &Translation<T, D>) -> bool {
|
fn eq(&self, right: &Translation<T, D>) -> bool {
|
||||||
self.vector == right.vector
|
self.vector == right.vector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D>
|
impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
{
|
{
|
||||||
|
@ -305,7 +306,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RelativeEq, const D: usize> RelativeEq for Translation<T, D>
|
impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Translation<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
{
|
{
|
||||||
|
@ -326,7 +327,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: UlpsEq, const D: usize> UlpsEq for Translation<T, D>
|
impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Translation<T, D>
|
||||||
where
|
where
|
||||||
T::Epsilon: Copy,
|
T::Epsilon: Copy,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use crate::base::storage::InnerOwned;
|
use crate::base::storage::Owned;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ where
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Translation<T, D>
|
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Translation<T, D>
|
||||||
where
|
where
|
||||||
InnerOwned<T, crate::Const<D>>: Send,
|
Owned<T, crate::Const<D>>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary(rng: &mut Gen) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
|
|
|
@ -27,7 +27,8 @@ use crate::Point;
|
||||||
|
|
||||||
impl<T1, T2, const D: usize> SubsetOf<Translation<T2, D>> for Translation<T1, D>
|
impl<T1, T2, const D: usize> SubsetOf<Translation<T2, D>> for Translation<T1, D>
|
||||||
where
|
where
|
||||||
T2: SupersetOf<T1>,
|
T1: Scalar,
|
||||||
|
T2: Scalar + SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> Translation<T2, D> {
|
fn to_superset(&self) -> Translation<T2, D> {
|
||||||
|
@ -192,14 +193,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<OVector<T, Const<D>>> for Translation<T, D> {
|
impl<T: Scalar, const D: usize> From<OVector<T, Const<D>>> for Translation<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(vector: OVector<T, Const<D>>) -> Self {
|
fn from(vector: OVector<T, Const<D>>) -> Self {
|
||||||
Translation { vector }
|
Translation { vector }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<[T; D]> for Translation<T, D> {
|
impl<T: Scalar, const D: usize> From<[T; D]> for Translation<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: [T; D]) -> Self {
|
fn from(coords: [T; D]) -> Self {
|
||||||
Translation {
|
Translation {
|
||||||
|
@ -208,17 +209,14 @@ impl<T, const D: usize> From<[T; D]> for Translation<T, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<Point<T, D>> for Translation<T, D> {
|
impl<T: Scalar, const D: usize> From<Point<T, D>> for Translation<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(pt: Point<T, D>) -> Self {
|
fn from(pt: Point<T, D>) -> Self {
|
||||||
Translation { vector: pt.coords }
|
Translation { vector: pt.coords }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<Translation<T, D>> for [T; D]
|
impl<T: Scalar, const D: usize> From<Translation<T, D>> for [T; D] {
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(t: Translation<T, D>) -> Self {
|
fn from(t: Translation<T, D>) -> Self {
|
||||||
t.vector.into()
|
t.vector.into()
|
||||||
|
|
|
@ -18,14 +18,14 @@ macro_rules! deref_impl(
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
unsafe { &*(self as *const _ as *const _) }
|
unsafe { &*(self as *const Translation<T, $D> as *const Self::Target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar> DerefMut for Translation<T, $D> {
|
impl<T: Scalar> DerefMut for Translation<T, $D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
unsafe { &mut *(self as *mut _ as *mut _) }
|
unsafe { &mut *(self as *mut Translation<T, $D> as *mut Self::Target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,12 +77,12 @@ an optimized set of tools for computer graphics and physics. Those features incl
|
||||||
unused_parens,
|
unused_parens,
|
||||||
unused_qualifications,
|
unused_qualifications,
|
||||||
unused_results,
|
unused_results,
|
||||||
missing_docs,
|
|
||||||
rust_2018_idioms,
|
rust_2018_idioms,
|
||||||
rust_2018_compatibility,
|
rust_2018_compatibility,
|
||||||
future_incompatible,
|
future_incompatible,
|
||||||
missing_copy_implementations
|
missing_copy_implementations
|
||||||
)]
|
)]
|
||||||
|
// #![deny(missing_docs)] // XXX: deny that
|
||||||
#![doc(
|
#![doc(
|
||||||
html_favicon_url = "https://nalgebra.org/img/favicon.ico",
|
html_favicon_url = "https://nalgebra.org/img/favicon.ico",
|
||||||
html_root_url = "https://docs.rs/nalgebra/0.25.0"
|
html_root_url = "https://docs.rs/nalgebra/0.25.0"
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::ops::{DivAssign, MulAssign};
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::dimension::Dim;
|
use crate::base::dimension::Dim;
|
||||||
use crate::base::storage::Storage;
|
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
|
use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
|
||||||
|
|
||||||
/// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns
|
/// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns
|
||||||
|
@ -18,7 +17,7 @@ where
|
||||||
{
|
{
|
||||||
assert!(matrix.is_square(), "Unable to balance a non-square matrix.");
|
assert!(matrix.is_square(), "Unable to balance a non-square matrix.");
|
||||||
|
|
||||||
let dim = matrix.data.shape().0;
|
let dim = matrix.shape_generic().0;
|
||||||
let radix: T = crate::convert(2.0f64);
|
let radix: T = crate::convert(2.0f64);
|
||||||
let mut d = OVector::from_element_generic(dim, Const::<1>, T::one());
|
let mut d = OVector::from_element_generic(dim, Const::<1>, T::one());
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
||||||
use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
|
use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
|
||||||
use crate::storage::{InnerOwned, Storage};
|
|
||||||
use crate::Dynamic;
|
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// The bidiagonalization of a general matrix.
|
/// The bidiagonalization of a general matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -35,6 +32,7 @@ use crate::linalg::householder;
|
||||||
OVector<T, DimMinimum<R, C>>: Deserialize<'de>,
|
OVector<T, DimMinimum<R, C>>: Deserialize<'de>,
|
||||||
OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Deserialize<'de>"))
|
OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Bidiagonal<T: ComplexField, R: DimMin<C>, C: Dim>
|
pub struct Bidiagonal<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DimMinimum<R, C>: DimSub<U1>,
|
DimMinimum<R, C>: DimSub<U1>,
|
||||||
|
@ -52,59 +50,17 @@ where
|
||||||
upper_diagonal: bool,
|
upper_diagonal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for Bidiagonal<T, R, C>
|
|
||||||
where
|
|
||||||
DimMinimum<R, C>: DimSub<U1>,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
|
||||||
+ Allocator<T, DimMinimum<R, C>>
|
|
||||||
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
|
|
||||||
InnerOwned<T, R, C>: Clone,
|
|
||||||
InnerOwned<T, DimMinimum<R, C>>: Clone,
|
|
||||||
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
uv: self.uv.clone(),
|
|
||||||
diagonal: self.diagonal.clone(),
|
|
||||||
off_diagonal: self.off_diagonal.clone(),
|
|
||||||
upper_diagonal: self.upper_diagonal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for Bidiagonal<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for Bidiagonal<T, R, C>
|
||||||
where
|
where
|
||||||
DimMinimum<R, C>: DimSub<U1>,
|
DimMinimum<R, C>: DimSub<U1>,
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
DefaultAllocator: Allocator<T, R, C>
|
||||||
+ Allocator<T, DimMinimum<R, C>>
|
+ Allocator<T, DimMinimum<R, C>>
|
||||||
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
|
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
|
||||||
InnerOwned<T, R, C>: Copy,
|
OMatrix<T, R, C>: Copy,
|
||||||
InnerOwned<T, DimMinimum<R, C>>: Copy,
|
OVector<T, DimMinimum<R, C>>: Copy,
|
||||||
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: Copy,
|
OVector<T, DimDiff<DimMinimum<R, C>, U1>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for Bidiagonal<T, R, C>
|
|
||||||
where
|
|
||||||
DimMinimum<R, C>: DimSub<U1>,
|
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
|
||||||
+ Allocator<T, DimMinimum<R, C>>
|
|
||||||
+ Allocator<T, DimDiff<DimMinimum<R, C>, U1>>,
|
|
||||||
InnerOwned<T, R, C>: fmt::Debug,
|
|
||||||
InnerOwned<T, DimMinimum<R, C>>: fmt::Debug,
|
|
||||||
InnerOwned<T, DimDiff<DimMinimum<R, C>, U1>>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Bidiagonal")
|
|
||||||
.field("uv", &self.uv)
|
|
||||||
.field("diagonal", &self.diagonal)
|
|
||||||
.field("off_diagonal", &self.off_diagonal)
|
|
||||||
.field("upper_diagonal", &self.upper_diagonal)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Bidiagonal<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Bidiagonal<T, R, C>
|
||||||
where
|
where
|
||||||
|
@ -117,7 +73,7 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the Bidiagonal decomposition using householder reflections.
|
/// Computes the Bidiagonal decomposition using householder reflections.
|
||||||
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
let dim = min_nrows_ncols.value();
|
let dim = min_nrows_ncols.value();
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -125,82 +81,72 @@ where
|
||||||
"Cannot compute the bidiagonalization of an empty matrix."
|
"Cannot compute the bidiagonalization of an empty matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut diagonal = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
|
let mut diagonal = Matrix::uninit(min_nrows_ncols, Const::<1>);
|
||||||
let mut off_diagonal =
|
let mut off_diagonal = Matrix::uninit(min_nrows_ncols.sub(Const::<1>), Const::<1>);
|
||||||
Matrix::new_uninitialized_generic(min_nrows_ncols.sub(Const::<1>), Const::<1>);
|
let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
|
||||||
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>);
|
let mut work = Matrix::zeros_generic(nrows, Const::<1>);
|
||||||
let mut work = Matrix::new_uninitialized_generic(nrows, Const::<1>);
|
|
||||||
|
|
||||||
let upper_diagonal = nrows.value() >= ncols.value();
|
let upper_diagonal = nrows.value() >= ncols.value();
|
||||||
|
|
||||||
// Safety: all pointers involved are valid for writes, aligned, and uninitialized.
|
|
||||||
unsafe {
|
|
||||||
if upper_diagonal {
|
if upper_diagonal {
|
||||||
for ite in 0..dim - 1 {
|
for ite in 0..dim - 1 {
|
||||||
householder::clear_column_unchecked(
|
diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
diagonal[ite].as_mut_ptr(),
|
|
||||||
ite,
|
ite,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
);
|
));
|
||||||
householder::clear_row_unchecked(
|
off_diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
off_diagonal[ite].as_mut_ptr(),
|
|
||||||
&mut axis_packed,
|
&mut axis_packed,
|
||||||
&mut work,
|
&mut work,
|
||||||
ite,
|
ite,
|
||||||
1,
|
1,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
householder::clear_column_unchecked(
|
diagonal[dim - 1] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
diagonal[dim - 1].as_mut_ptr(),
|
|
||||||
dim - 1,
|
dim - 1,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
);
|
));
|
||||||
} else {
|
} else {
|
||||||
for ite in 0..dim - 1 {
|
for ite in 0..dim - 1 {
|
||||||
householder::clear_row_unchecked(
|
diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
diagonal[ite].as_mut_ptr(),
|
|
||||||
&mut axis_packed,
|
&mut axis_packed,
|
||||||
&mut work,
|
&mut work,
|
||||||
ite,
|
ite,
|
||||||
0,
|
0,
|
||||||
);
|
));
|
||||||
householder::clear_column_unchecked(
|
off_diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
off_diagonal[ite].as_mut_ptr(),
|
|
||||||
ite,
|
ite,
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
householder::clear_row_unchecked(
|
diagonal[dim - 1] = MaybeUninit::new(householder::clear_row_unchecked(
|
||||||
&mut matrix,
|
&mut matrix,
|
||||||
diagonal[dim - 1].as_mut_ptr(),
|
|
||||||
&mut axis_packed,
|
&mut axis_packed,
|
||||||
&mut work,
|
&mut work,
|
||||||
dim - 1,
|
dim - 1,
|
||||||
0,
|
0,
|
||||||
);
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all values have been initialized.
|
// Safety: diagonal and off_diagonal have been fully initialized.
|
||||||
unsafe {
|
let (diagonal, off_diagonal) =
|
||||||
|
unsafe { (diagonal.assume_init(), off_diagonal.assume_init()) };
|
||||||
|
|
||||||
Bidiagonal {
|
Bidiagonal {
|
||||||
uv: matrix,
|
uv: matrix,
|
||||||
diagonal: diagonal.assume_init(),
|
diagonal,
|
||||||
off_diagonal: off_diagonal.assume_init(),
|
off_diagonal,
|
||||||
upper_diagonal,
|
upper_diagonal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether this decomposition contains an upper-diagonal matrix.
|
/// Indicates whether this decomposition contains an upper-diagonal matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -245,7 +191,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.uv.data.shape();
|
let (nrows, ncols) = self.uv.shape_generic();
|
||||||
|
|
||||||
let d = nrows.min(ncols);
|
let d = nrows.min(ncols);
|
||||||
let mut res = OMatrix::identity_generic(d, d);
|
let mut res = OMatrix::identity_generic(d, d);
|
||||||
|
@ -265,7 +211,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.uv.data.shape();
|
let (nrows, ncols) = self.uv.shape_generic();
|
||||||
|
|
||||||
let mut res = Matrix::identity_generic(nrows, nrows.min(ncols));
|
let mut res = Matrix::identity_generic(nrows, nrows.min(ncols));
|
||||||
let dim = self.diagonal.len();
|
let dim = self.diagonal.len();
|
||||||
|
@ -294,23 +240,21 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C>
|
pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C> + Allocator<T, Dynamic, U1>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.uv.data.shape();
|
let (nrows, ncols) = self.uv.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut res = Matrix::identity_generic(min_nrows_ncols, ncols);
|
let mut res = Matrix::identity_generic(min_nrows_ncols, ncols);
|
||||||
let mut work = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
|
let mut work = Matrix::zeros_generic(min_nrows_ncols, Const::<1>);
|
||||||
let mut axis_packed = Matrix::new_uninitialized_generic(ncols, Const::<1>);
|
let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>);
|
||||||
|
|
||||||
let shift = self.axis_shift().1;
|
let shift = self.axis_shift().1;
|
||||||
|
|
||||||
for i in (0..min_nrows_ncols.value() - shift).rev() {
|
for i in (0..min_nrows_ncols.value() - shift).rev() {
|
||||||
let axis = self.uv.slice_range(i, i + shift..);
|
let axis = self.uv.slice_range(i, i + shift..);
|
||||||
let mut axis_packed = axis_packed.rows_range_mut(i + shift..);
|
let mut axis_packed = axis_packed.rows_range_mut(i + shift..);
|
||||||
axis_packed.tr_copy_init_from(&axis);
|
axis_packed.tr_copy_from(&axis);
|
||||||
let axis_packed = unsafe { axis_packed.slice_assume_init() };
|
|
||||||
|
|
||||||
// TODO: sometimes, the axis might have a zero magnitude.
|
// TODO: sometimes, the axis might have a zero magnitude.
|
||||||
let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero());
|
let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero());
|
||||||
|
|
||||||
|
@ -404,7 +348,7 @@ where
|
||||||
// assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix.");
|
// assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix.");
|
||||||
//
|
//
|
||||||
// // TODO: is there a less naive method ?
|
// // TODO: is there a less naive method ?
|
||||||
// let (nrows, ncols) = self.uv.data.shape();
|
// let (nrows, ncols) = self.uv.shape_generic();
|
||||||
// let mut res = OMatrix::identity_generic(nrows, ncols);
|
// let mut res = OMatrix::identity_generic(nrows, ncols);
|
||||||
// self.solve_mut(&mut res);
|
// self.solve_mut(&mut res);
|
||||||
// res
|
// res
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -12,7 +9,7 @@ use crate::allocator::Allocator;
|
||||||
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector};
|
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector};
|
||||||
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1};
|
use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1};
|
||||||
use crate::storage::{InnerOwned, Storage, StorageMut};
|
use crate::storage::{Storage, StorageMut};
|
||||||
|
|
||||||
/// The Cholesky decomposition of a symmetric-definite-positive matrix.
|
/// The Cholesky decomposition of a symmetric-definite-positive matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -26,6 +23,7 @@ use crate::storage::{InnerOwned, Storage, StorageMut};
|
||||||
serde(bound(deserialize = "DefaultAllocator: Allocator<T, D>,
|
serde(bound(deserialize = "DefaultAllocator: Allocator<T, D>,
|
||||||
OMatrix<T, D, D>: Deserialize<'de>"))
|
OMatrix<T, D, D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cholesky<T: SimdComplexField, D: Dim>
|
pub struct Cholesky<T: SimdComplexField, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
|
@ -33,38 +31,12 @@ where
|
||||||
chol: OMatrix<T, D, D>,
|
chol: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl<T: SimdComplexField, D: Dim> Copy for Cholesky<T, D>
|
impl<T: SimdComplexField, D: Dim> Copy for Cholesky<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: SimdComplexField, D: Dim> Clone for Cholesky<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
chol: self.chol.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SimdComplexField, D: Dim> fmt::Debug for Cholesky<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
|
||||||
InnerOwned<T, D, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Cholesky")
|
|
||||||
.field("chol", &self.chol)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SimdComplexField, D: Dim> Cholesky<T, D>
|
impl<T: SimdComplexField, D: Dim> Cholesky<T, D>
|
||||||
where
|
where
|
||||||
|
@ -164,7 +136,7 @@ where
|
||||||
/// Computes the inverse of the decomposed matrix.
|
/// Computes the inverse of the decomposed matrix.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn inverse(&self) -> OMatrix<T, D, D> {
|
pub fn inverse(&self) -> OMatrix<T, D, D> {
|
||||||
let shape = self.chol.data.shape();
|
let shape = self.chol.shape_generic();
|
||||||
let mut res = OMatrix::identity_generic(shape.0, shape.1);
|
let mut res = OMatrix::identity_generic(shape.0, shape.1);
|
||||||
|
|
||||||
self.solve_mut(&mut res);
|
self.solve_mut(&mut res);
|
||||||
|
@ -254,8 +226,6 @@ where
|
||||||
DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>> + Allocator<T, R2>,
|
DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>> + Allocator<T, R2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
|
ShapeConstraint: SameNumberOfRows<R2, DimSum<D, U1>>,
|
||||||
{
|
{
|
||||||
// TODO: check that MaybeUninit manipulations are sound!
|
|
||||||
|
|
||||||
let mut col = col.into_owned();
|
let mut col = col.into_owned();
|
||||||
// for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
|
// for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition
|
||||||
let n = col.nrows();
|
let n = col.nrows();
|
||||||
|
@ -267,20 +237,19 @@ where
|
||||||
assert!(j < n, "j needs to be within the bound of the new matrix.");
|
assert!(j < n, "j needs to be within the bound of the new matrix.");
|
||||||
|
|
||||||
// loads the data into a new matrix with an additional jth row/column
|
// loads the data into a new matrix with an additional jth row/column
|
||||||
let mut chol = Matrix::new_uninitialized_generic(
|
// TODO: would it be worth it to avoid the zero-initialization?
|
||||||
self.chol.data.shape().0.add(Const::<1>),
|
let mut chol = Matrix::zeros_generic(
|
||||||
self.chol.data.shape().1.add(Const::<1>),
|
self.chol.shape_generic().0.add(Const::<1>),
|
||||||
|
self.chol.shape_generic().1.add(Const::<1>),
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: checked that every entry is initialized EXACTLY once.
|
|
||||||
chol.slice_range_mut(..j, ..j)
|
chol.slice_range_mut(..j, ..j)
|
||||||
.copy_init_from(&self.chol.slice_range(..j, ..j));
|
.copy_from(&self.chol.slice_range(..j, ..j));
|
||||||
chol.slice_range_mut(..j, j + 1..)
|
chol.slice_range_mut(..j, j + 1..)
|
||||||
.copy_init_from(&self.chol.slice_range(..j, j..));
|
.copy_from(&self.chol.slice_range(..j, j..));
|
||||||
chol.slice_range_mut(j + 1.., ..j)
|
chol.slice_range_mut(j + 1.., ..j)
|
||||||
.copy_init_from(&self.chol.slice_range(j.., ..j));
|
.copy_from(&self.chol.slice_range(j.., ..j));
|
||||||
chol.slice_range_mut(j + 1.., j + 1..)
|
chol.slice_range_mut(j + 1.., j + 1..)
|
||||||
.copy_init_from(&self.chol.slice_range(j.., j..));
|
.copy_from(&self.chol.slice_range(j.., j..));
|
||||||
|
|
||||||
// update the jth row
|
// update the jth row
|
||||||
let top_left_corner = self.chol.slice_range(..j, ..j);
|
let top_left_corner = self.chol.slice_range(..j, ..j);
|
||||||
|
@ -296,7 +265,7 @@ where
|
||||||
|
|
||||||
// update the center element
|
// update the center element
|
||||||
let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared()));
|
let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared()));
|
||||||
chol[(j, j)] = MaybeUninit::new(center_element);
|
chol[(j, j)] = center_element;
|
||||||
|
|
||||||
// update the jth column
|
// update the jth column
|
||||||
let bottom_left_corner = self.chol.slice_range(j.., ..j);
|
let bottom_left_corner = self.chol.slice_range(j.., ..j);
|
||||||
|
@ -307,9 +276,7 @@ where
|
||||||
&new_rowj_adjoint,
|
&new_rowj_adjoint,
|
||||||
T::one() / center_element,
|
T::one() / center_element,
|
||||||
);
|
);
|
||||||
chol.slice_range_mut(j + 1.., j).copy_init_from(&new_colj);
|
chol.slice_range_mut(j + 1.., j).copy_from(&new_colj);
|
||||||
|
|
||||||
let mut chol = unsafe { chol.assume_init() };
|
|
||||||
|
|
||||||
// update the bottom right corner
|
// update the bottom right corner
|
||||||
let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..);
|
let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..);
|
||||||
|
@ -330,27 +297,24 @@ where
|
||||||
D: DimSub<U1>,
|
D: DimSub<U1>,
|
||||||
DefaultAllocator: Allocator<T, DimDiff<D, U1>, DimDiff<D, U1>> + Allocator<T, D>,
|
DefaultAllocator: Allocator<T, DimDiff<D, U1>, DimDiff<D, U1>> + Allocator<T, D>,
|
||||||
{
|
{
|
||||||
// TODO: check that MaybeUninit manipulations are sound!
|
|
||||||
|
|
||||||
let n = self.chol.nrows();
|
let n = self.chol.nrows();
|
||||||
assert!(n > 0, "The matrix needs at least one column.");
|
assert!(n > 0, "The matrix needs at least one column.");
|
||||||
assert!(j < n, "j needs to be within the bound of the matrix.");
|
assert!(j < n, "j needs to be within the bound of the matrix.");
|
||||||
|
|
||||||
// loads the data into a new matrix except for the jth row/column
|
// loads the data into a new matrix except for the jth row/column
|
||||||
let mut chol = Matrix::new_uninitialized_generic(
|
// TODO: would it be worth it to avoid this zero initialization?
|
||||||
self.chol.data.shape().0.sub(Const::<1>),
|
let mut chol = Matrix::zeros_generic(
|
||||||
self.chol.data.shape().1.sub(Const::<1>),
|
self.chol.shape_generic().0.sub(Const::<1>),
|
||||||
|
self.chol.shape_generic().1.sub(Const::<1>),
|
||||||
);
|
);
|
||||||
|
|
||||||
chol.slice_range_mut(..j, ..j)
|
chol.slice_range_mut(..j, ..j)
|
||||||
.copy_init_from(&self.chol.slice_range(..j, ..j));
|
.copy_from(&self.chol.slice_range(..j, ..j));
|
||||||
chol.slice_range_mut(..j, j..)
|
chol.slice_range_mut(..j, j..)
|
||||||
.copy_init_from(&self.chol.slice_range(..j, j + 1..));
|
.copy_from(&self.chol.slice_range(..j, j + 1..));
|
||||||
chol.slice_range_mut(j.., ..j)
|
chol.slice_range_mut(j.., ..j)
|
||||||
.copy_init_from(&self.chol.slice_range(j + 1.., ..j));
|
.copy_from(&self.chol.slice_range(j + 1.., ..j));
|
||||||
chol.slice_range_mut(j.., j..)
|
chol.slice_range_mut(j.., j..)
|
||||||
.copy_init_from(&self.chol.slice_range(j + 1.., j + 1..));
|
.copy_from(&self.chol.slice_range(j + 1.., j + 1..));
|
||||||
let mut chol = unsafe { chol.assume_init() };
|
|
||||||
|
|
||||||
// updates the bottom right corner
|
// updates the bottom right corner
|
||||||
let mut bottom_right_corner = chol.slice_range_mut(j.., j..);
|
let mut bottom_right_corner = chol.slice_range_mut(j.., j..);
|
||||||
|
@ -366,12 +330,14 @@ where
|
||||||
///
|
///
|
||||||
/// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column`
|
/// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column`
|
||||||
/// where it is used on a square slice of the decomposition
|
/// where it is used on a square slice of the decomposition
|
||||||
fn xx_rank_one_update<Dm: Dim, Sm, Rx: Dim, Sx>(
|
fn xx_rank_one_update<Dm, Sm, Rx, Sx>(
|
||||||
chol: &mut Matrix<T, Dm, Dm, Sm>,
|
chol: &mut Matrix<T, Dm, Dm, Sm>,
|
||||||
x: &mut Vector<T, Rx, Sx>,
|
x: &mut Vector<T, Rx, Sx>,
|
||||||
sigma: T::RealField,
|
sigma: T::RealField,
|
||||||
) where
|
) where
|
||||||
//T: ComplexField,
|
//T: ComplexField,
|
||||||
|
Dm: Dim,
|
||||||
|
Rx: Dim,
|
||||||
Sm: StorageMut<T, Dm, Dm>,
|
Sm: StorageMut<T, Dm, Dm>,
|
||||||
Sx: StorageMut<T, Rx, U1>,
|
Sx: StorageMut<T, Rx, U1>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,11 +6,12 @@ use crate::allocator::{Allocator, Reallocator};
|
||||||
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
||||||
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::dimension::{Dim, DimMin, DimMinimum};
|
use crate::dimension::{Dim, DimMin, DimMinimum};
|
||||||
use crate::storage::{Storage, StorageMut};
|
use crate::storage::StorageMut;
|
||||||
use crate::ComplexField;
|
use crate::ComplexField;
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
use crate::linalg::{householder, PermutationSequence};
|
use crate::linalg::{householder, PermutationSequence};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// The QR decomposition (with column pivoting) of a general matrix.
|
/// The QR decomposition (with column pivoting) of a general matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -30,6 +31,7 @@ use crate::linalg::{householder, PermutationSequence};
|
||||||
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>,
|
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>,
|
||||||
OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
|
OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct ColPivQR<T: ComplexField, R: DimMin<C>, C: Dim>
|
pub struct ColPivQR<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
DefaultAllocator: Allocator<T, R, C>
|
||||||
|
@ -52,24 +54,6 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for ColPivQR<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
|
||||||
+ Allocator<T, DimMinimum<R, C>>
|
|
||||||
+ Allocator<(usize, usize), DimMinimum<R, C>>,
|
|
||||||
OMatrix<T, R, C>: Clone,
|
|
||||||
PermutationSequence<DimMinimum<R, C>>: Clone,
|
|
||||||
OVector<T, DimMinimum<R, C>>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
col_piv_qr: self.col_piv_qr.clone(),
|
|
||||||
p: self.p.clone(),
|
|
||||||
diag: self.diag.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> ColPivQR<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> ColPivQR<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C>
|
DefaultAllocator: Allocator<T, R, C>
|
||||||
|
@ -79,42 +63,37 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the `ColPivQR` decomposition using householder reflections.
|
/// Computes the `ColPivQR` decomposition using householder reflections.
|
||||||
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
||||||
|
|
||||||
let mut diag = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
|
|
||||||
|
|
||||||
if min_nrows_ncols.value() == 0 {
|
if min_nrows_ncols.value() == 0 {
|
||||||
// Safety: there's no (uninitialized) values.
|
|
||||||
unsafe {
|
|
||||||
return ColPivQR {
|
return ColPivQR {
|
||||||
col_piv_qr: matrix,
|
col_piv_qr: matrix,
|
||||||
p,
|
p,
|
||||||
diag: diag.assume_init(),
|
diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>),
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>);
|
||||||
|
|
||||||
for i in 0..min_nrows_ncols.value() {
|
for i in 0..min_nrows_ncols.value() {
|
||||||
let piv = matrix.slice_range(i.., i..).icamax_full();
|
let piv = matrix.slice_range(i.., i..).icamax_full();
|
||||||
let col_piv = piv.1 + i;
|
let col_piv = piv.1 + i;
|
||||||
matrix.swap_columns(i, col_piv);
|
matrix.swap_columns(i, col_piv);
|
||||||
p.append_permutation(i, col_piv);
|
p.append_permutation(i, col_piv);
|
||||||
|
|
||||||
// Safety: the pointer is valid for writes, aligned, and uninitialized.
|
diag[i] =
|
||||||
unsafe {
|
MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None));
|
||||||
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all values have been initialized.
|
// Safety: diag is now fully initialized.
|
||||||
unsafe {
|
let diag = unsafe { diag.assume_init() };
|
||||||
|
|
||||||
ColPivQR {
|
ColPivQR {
|
||||||
col_piv_qr: matrix,
|
col_piv_qr: matrix,
|
||||||
p,
|
p,
|
||||||
diag: diag.assume_init(),
|
diag,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +104,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.col_piv_qr.data.shape();
|
let (nrows, ncols) = self.col_piv_qr.shape_generic();
|
||||||
let mut res = self
|
let mut res = self
|
||||||
.col_piv_qr
|
.col_piv_qr
|
||||||
.rows_generic(0, nrows.min(ncols))
|
.rows_generic(0, nrows.min(ncols))
|
||||||
|
@ -142,7 +121,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
|
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.col_piv_qr.data.shape();
|
let (nrows, ncols) = self.col_piv_qr.shape_generic();
|
||||||
let mut res = self
|
let mut res = self
|
||||||
.col_piv_qr
|
.col_piv_qr
|
||||||
.resize_generic(nrows.min(ncols), ncols, T::zero());
|
.resize_generic(nrows.min(ncols), ncols, T::zero());
|
||||||
|
@ -157,7 +136,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.col_piv_qr.data.shape();
|
let (nrows, ncols) = self.col_piv_qr.shape_generic();
|
||||||
|
|
||||||
// NOTE: we could build the identity matrix and call q_mul on it.
|
// NOTE: we could build the identity matrix and call q_mul on it.
|
||||||
// Instead we don't so that we take in account the matrix sparseness.
|
// Instead we don't so that we take in account the matrix sparseness.
|
||||||
|
@ -320,7 +299,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: is there a less naive method ?
|
// TODO: is there a less naive method ?
|
||||||
let (nrows, ncols) = self.col_piv_qr.data.shape();
|
let (nrows, ncols) = self.col_piv_qr.shape_generic();
|
||||||
let mut res = OMatrix::identity_generic(nrows, ncols);
|
let mut res = OMatrix::identity_generic(nrows, ncols);
|
||||||
|
|
||||||
if self.solve_mut(&mut res) {
|
if self.solve_mut(&mut res) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
|
||||||
.data
|
.data
|
||||||
.shape()
|
.shape()
|
||||||
.0
|
.0
|
||||||
.add(kernel.data.shape().0)
|
.add(kernel.shape_generic().0)
|
||||||
.sub(Const::<1>);
|
.sub(Const::<1>);
|
||||||
let mut conv = OVector::zeros_generic(result_len, Const::<1>);
|
let mut conv = OVector::zeros_generic(result_len, Const::<1>);
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
|
||||||
.shape()
|
.shape()
|
||||||
.0
|
.0
|
||||||
.add(Const::<1>)
|
.add(Const::<1>)
|
||||||
.sub(kernel.data.shape().0);
|
.sub(kernel.shape_generic().0);
|
||||||
let mut conv = OVector::zeros_generic(result_len, Const::<1>);
|
let mut conv = OVector::zeros_generic(result_len, Const::<1>);
|
||||||
|
|
||||||
for i in 0..(vec - ker + 1) {
|
for i in 0..(vec - ker + 1) {
|
||||||
|
@ -126,7 +126,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
|
||||||
panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
|
panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut conv = OVector::zeros_generic(self.data.shape().0, Const::<1>);
|
let mut conv = OVector::zeros_generic(self.shape_generic().0, Const::<1>);
|
||||||
|
|
||||||
for i in 0..vec {
|
for i in 0..vec {
|
||||||
for j in 0..ker {
|
for j in 0..ker {
|
||||||
|
|
|
@ -4,12 +4,9 @@ use crate::{
|
||||||
base::{
|
base::{
|
||||||
allocator::Allocator,
|
allocator::Allocator,
|
||||||
dimension::{Const, Dim, DimMin, DimMinimum},
|
dimension::{Const, Dim, DimMin, DimMinimum},
|
||||||
storage::Storage,
|
|
||||||
DefaultAllocator,
|
DefaultAllocator,
|
||||||
},
|
},
|
||||||
convert,
|
convert, try_convert, ComplexField, OMatrix, RealField,
|
||||||
storage::InnerOwned,
|
|
||||||
try_convert, ComplexField, OMatrix, RealField,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::num::Zero;
|
use crate::num::Zero;
|
||||||
|
@ -49,7 +46,7 @@ where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), DimMinimum<D, D>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), DimMinimum<D, D>>,
|
||||||
{
|
{
|
||||||
fn new(a: OMatrix<T, D, D>, use_exact_norm: bool) -> Self {
|
fn new(a: OMatrix<T, D, D>, use_exact_norm: bool) -> Self {
|
||||||
let (nrows, ncols) = a.data.shape();
|
let (nrows, ncols) = a.shape_generic();
|
||||||
ExpmPadeHelper {
|
ExpmPadeHelper {
|
||||||
use_exact_norm,
|
use_exact_norm,
|
||||||
ident: OMatrix::<T, D, D>::identity_generic(nrows, ncols),
|
ident: OMatrix::<T, D, D>::identity_generic(nrows, ncols),
|
||||||
|
@ -350,7 +347,7 @@ where
|
||||||
D: Dim,
|
D: Dim,
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
|
||||||
{
|
{
|
||||||
let nrows = a.data.shape().0;
|
let nrows = a.shape_generic().0;
|
||||||
let mut v = crate::OVector::<T, D>::repeat_generic(nrows, Const::<1>, convert(1.0));
|
let mut v = crate::OVector::<T, D>::repeat_generic(nrows, Const::<1>, convert(1.0));
|
||||||
let m = a.transpose();
|
let m = a.transpose();
|
||||||
|
|
||||||
|
@ -435,7 +432,6 @@ where
|
||||||
+ Allocator<T, D>
|
+ Allocator<T, D>
|
||||||
+ Allocator<T::RealField, D>
|
+ Allocator<T::RealField, D>
|
||||||
+ Allocator<T::RealField, D, D>,
|
+ Allocator<T::RealField, D, D>,
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
{
|
{
|
||||||
/// Computes exponential of this matrix
|
/// Computes exponential of this matrix
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
|
||||||
OMatrix<T, R, C>: Deserialize<'de>,
|
OMatrix<T, R, C>: Deserialize<'de>,
|
||||||
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
|
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
pub struct FullPivLU<T, R: DimMin<C>, C: Dim>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct FullPivLU<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
|
@ -41,41 +40,11 @@ where
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for FullPivLU<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
||||||
PermutationSequence<DimMinimum<R, C>>: Copy,
|
|
||||||
OMatrix<T, R, C>: Copy,
|
OMatrix<T, R, C>: Copy,
|
||||||
|
PermutationSequence<DimMinimum<R, C>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for FullPivLU<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
|
||||||
PermutationSequence<DimMinimum<R, C>>: Clone,
|
|
||||||
OMatrix<T, R, C>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
lu: self.lu.clone(),
|
|
||||||
p: self.p.clone(),
|
|
||||||
q: self.q.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for FullPivLU<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
|
||||||
PermutationSequence<DimMinimum<R, C>>: fmt::Debug,
|
|
||||||
OMatrix<T, R, C>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("FullPivLU")
|
|
||||||
.field("lu", &self.lu)
|
|
||||||
.field("p", &self.p)
|
|
||||||
.field("q", &self.q)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> FullPivLU<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
||||||
|
@ -84,7 +53,7 @@ where
|
||||||
///
|
///
|
||||||
/// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
|
/// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`.
|
||||||
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
||||||
|
@ -132,7 +101,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
||||||
m.fill_upper_triangle(T::zero(), 1);
|
m.fill_upper_triangle(T::zero(), 1);
|
||||||
m.fill_diagonal(T::one());
|
m.fill_diagonal(T::one());
|
||||||
|
@ -146,7 +115,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +222,7 @@ where
|
||||||
"FullPivLU inverse: unable to compute the inverse of a non-square matrix."
|
"FullPivLU inverse: unable to compute the inverse of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
|
|
||||||
let mut res = OMatrix::identity_generic(nrows, ncols);
|
let mut res = OMatrix::identity_generic(nrows, ncols);
|
||||||
if self.solve_mut(&mut res) {
|
if self.solve_mut(&mut res) {
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
use std::fmt;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, OMatrix, OVector};
|
use crate::base::{DefaultAllocator, OMatrix, OVector};
|
||||||
use crate::dimension::{Const, DimDiff, DimSub, U1};
|
use crate::dimension::{Const, DimDiff, DimSub, U1};
|
||||||
use crate::storage::{InnerOwned, Storage};
|
|
||||||
use crate::Matrix;
|
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
|
use crate::Matrix;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// Hessenberg decomposition of a general matrix.
|
/// Hessenberg decomposition of a general matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -29,6 +26,7 @@ use crate::linalg::householder;
|
||||||
OMatrix<T, D, D>: Deserialize<'de>,
|
OMatrix<T, D, D>: Deserialize<'de>,
|
||||||
OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
|
OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Hessenberg<T: ComplexField, D: DimSub<U1>>
|
pub struct Hessenberg<T: ComplexField, D: DimSub<U1>>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
||||||
|
@ -37,43 +35,13 @@ where
|
||||||
subdiag: OVector<T, DimDiff<D, U1>>,
|
subdiag: OVector<T, DimDiff<D, U1>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> Copy for Hessenberg<T, D>
|
impl<T: ComplexField, D: DimSub<U1>> Copy for Hessenberg<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
InnerOwned<T, DimDiff<D, U1>>: Copy,
|
OVector<T, DimDiff<D, U1>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> Clone for Hessenberg<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
InnerOwned<T, DimDiff<D, U1>>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
hess: self.hess.clone(),
|
|
||||||
subdiag: self.subdiag.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> fmt::Debug for Hessenberg<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
|
||||||
InnerOwned<T, D, D>: fmt::Debug,
|
|
||||||
InnerOwned<T, DimDiff<D, U1>>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Hessenberg")
|
|
||||||
.field("hess", &self.hess)
|
|
||||||
.field("subdiag", &self.subdiag)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> Hessenberg<T, D>
|
impl<T: ComplexField, D: DimSub<U1>> Hessenberg<T, D>
|
||||||
where
|
where
|
||||||
|
@ -81,7 +49,7 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the Hessenberg decomposition using householder reflections.
|
/// Computes the Hessenberg decomposition using householder reflections.
|
||||||
pub fn new(hess: OMatrix<T, D, D>) -> Self {
|
pub fn new(hess: OMatrix<T, D, D>) -> Self {
|
||||||
let mut work = OVector::new_uninitialized_generic(hess.data.shape().0, Const::<1>);
|
let mut work = Matrix::zeros_generic(hess.shape_generic().0, Const::<1>);
|
||||||
Self::new_with_workspace(hess, &mut work)
|
Self::new_with_workspace(hess, &mut work)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,16 +57,13 @@ where
|
||||||
///
|
///
|
||||||
/// The workspace containing `D` elements must be provided but its content does not have to be
|
/// The workspace containing `D` elements must be provided but its content does not have to be
|
||||||
/// initialized.
|
/// initialized.
|
||||||
pub fn new_with_workspace(
|
pub fn new_with_workspace(mut hess: OMatrix<T, D, D>, work: &mut OVector<T, D>) -> Self {
|
||||||
mut hess: OMatrix<T, D, D>,
|
|
||||||
work: &mut OVector<MaybeUninit<T>, D>,
|
|
||||||
) -> Self {
|
|
||||||
assert!(
|
assert!(
|
||||||
hess.is_square(),
|
hess.is_square(),
|
||||||
"Cannot compute the hessenberg decomposition of a non-square matrix."
|
"Cannot compute the hessenberg decomposition of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let dim = hess.data.shape().0;
|
let dim = hess.shape_generic().0;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
dim.value() != 0,
|
dim.value() != 0,
|
||||||
|
@ -110,38 +75,27 @@ where
|
||||||
"Hessenberg: invalid workspace size."
|
"Hessenberg: invalid workspace size."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut subdiag = Matrix::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
|
|
||||||
|
|
||||||
if dim.value() == 0 {
|
if dim.value() == 0 {
|
||||||
// Safety: there's no (uninitialized) values.
|
return Hessenberg {
|
||||||
unsafe {
|
|
||||||
return Self {
|
|
||||||
hess,
|
hess,
|
||||||
subdiag: subdiag.assume_init(),
|
subdiag: Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let mut subdiag = Matrix::uninit(dim.sub(Const::<1>), Const::<1>);
|
||||||
|
|
||||||
for ite in 0..dim.value() - 1 {
|
for ite in 0..dim.value() - 1 {
|
||||||
// Safety: the pointer is valid for writes, aligned, and uninitialized.
|
subdiag[ite] = MaybeUninit::new(householder::clear_column_unchecked(
|
||||||
unsafe {
|
|
||||||
householder::clear_column_unchecked(
|
|
||||||
&mut hess,
|
&mut hess,
|
||||||
subdiag[ite].as_mut_ptr(),
|
|
||||||
ite,
|
ite,
|
||||||
1,
|
1,
|
||||||
Some(work),
|
Some(work),
|
||||||
);
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all values have been initialized.
|
// Safety: subdiag is now fully initialized.
|
||||||
unsafe {
|
let subdiag = unsafe { subdiag.assume_init() };
|
||||||
Self {
|
Hessenberg { hess, subdiag }
|
||||||
hess,
|
|
||||||
subdiag: subdiag.assume_init(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves `(q, h)` with `q` the orthogonal matrix of this decomposition and `h` the
|
/// Retrieves `(q, h)` with `q` the orthogonal matrix of this decomposition and `h` the
|
||||||
|
@ -170,10 +124,7 @@ where
|
||||||
/// This is less efficient than `.unpack_h()` as it allocates a new matrix.
|
/// This is less efficient than `.unpack_h()` as it allocates a new matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn h(&self) -> OMatrix<T, D, D>
|
pub fn h(&self) -> OMatrix<T, D, D> {
|
||||||
where
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
let dim = self.hess.nrows();
|
let dim = self.hess.nrows();
|
||||||
let mut res = self.hess.clone();
|
let mut res = self.hess.clone();
|
||||||
res.fill_lower_triangle(T::zero(), 2);
|
res.fill_lower_triangle(T::zero(), 2);
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
//! Construction of householder elementary reflections.
|
//! Construction of householder elementary reflections.
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector};
|
use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector};
|
||||||
use crate::dimension::Dim;
|
use crate::dimension::Dim;
|
||||||
use crate::storage::{Storage, StorageMut};
|
use crate::storage::StorageMut;
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
|
@ -46,29 +44,22 @@ pub fn reflection_axis_mut<T: ComplexField, D: Dim, S: StorageMut<T, D>>(
|
||||||
/// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th
|
/// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th
|
||||||
/// subdiagonal element.
|
/// subdiagonal element.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// Returns the signed norm of the column.
|
||||||
/// Behavior is undefined if any of the following conditions are violated:
|
|
||||||
///
|
|
||||||
/// - `diag_elt` must be valid for writes.
|
|
||||||
/// - `diag_elt` must be properly aligned.
|
|
||||||
///
|
|
||||||
/// Furthermore, if `diag_elt` was previously initialized, this method will leak
|
|
||||||
/// its data.
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
#[must_use]
|
||||||
|
pub fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
||||||
matrix: &mut OMatrix<T, R, C>,
|
matrix: &mut OMatrix<T, R, C>,
|
||||||
diag_elt: *mut T,
|
|
||||||
icol: usize,
|
icol: usize,
|
||||||
shift: usize,
|
shift: usize,
|
||||||
bilateral: Option<&mut OVector<MaybeUninit<T>, R>>,
|
bilateral: Option<&mut OVector<T, R>>,
|
||||||
) where
|
) -> T
|
||||||
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R>,
|
||||||
{
|
{
|
||||||
let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..);
|
let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..);
|
||||||
let mut axis = left.rows_range_mut(icol + shift..);
|
let mut axis = left.rows_range_mut(icol + shift..);
|
||||||
|
|
||||||
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
|
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
|
||||||
diag_elt.write(reflection_norm);
|
|
||||||
|
|
||||||
if not_zero {
|
if not_zero {
|
||||||
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
|
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
|
||||||
|
@ -78,38 +69,32 @@ pub unsafe fn clear_column_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
||||||
}
|
}
|
||||||
refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate());
|
refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reflection_norm
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th
|
/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th
|
||||||
/// superdiagonal element.
|
/// superdiagonal element.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// Returns the signed norm of the column.
|
||||||
/// Behavior is undefined if any of the following conditions are violated:
|
|
||||||
///
|
|
||||||
/// - `diag_elt` must be valid for writes.
|
|
||||||
/// - `diag_elt` must be properly aligned.
|
|
||||||
///
|
|
||||||
/// Furthermore, if `diag_elt` was previously initialized, this method will leak
|
|
||||||
/// its data.
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
#[must_use]
|
||||||
|
pub fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
||||||
matrix: &mut OMatrix<T, R, C>,
|
matrix: &mut OMatrix<T, R, C>,
|
||||||
diag_elt: *mut T,
|
axis_packed: &mut OVector<T, C>,
|
||||||
axis_packed: &mut OVector<MaybeUninit<T>, C>,
|
work: &mut OVector<T, R>,
|
||||||
work: &mut OVector<MaybeUninit<T>, R>,
|
|
||||||
irow: usize,
|
irow: usize,
|
||||||
shift: usize,
|
shift: usize,
|
||||||
) where
|
) -> T
|
||||||
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, C>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, C>,
|
||||||
{
|
{
|
||||||
let (mut top, mut bottom) = matrix.rows_range_pair_mut(irow, irow + 1..);
|
let (mut top, mut bottom) = matrix.rows_range_pair_mut(irow, irow + 1..);
|
||||||
let mut axis = axis_packed.rows_range_mut(irow + shift..);
|
let mut axis = axis_packed.rows_range_mut(irow + shift..);
|
||||||
axis.tr_copy_init_from(&top.columns_range(irow + shift..));
|
axis.tr_copy_from(&top.columns_range(irow + shift..));
|
||||||
let mut axis = axis.assume_init_mut();
|
|
||||||
|
|
||||||
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
|
let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis);
|
||||||
axis.conjugate_mut(); // So that reflect_rows actually cancels the first row.
|
axis.conjugate_mut(); // So that reflect_rows actually cancels the first row.
|
||||||
diag_elt.write(reflection_norm);
|
|
||||||
|
|
||||||
if not_zero {
|
if not_zero {
|
||||||
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
|
let refl = Reflection::new(Unit::new_unchecked(axis), T::zero());
|
||||||
|
@ -123,6 +108,8 @@ pub unsafe fn clear_row_unchecked<T: ComplexField, R: Dim, C: Dim>(
|
||||||
} else {
|
} else {
|
||||||
top.columns_range_mut(irow + shift..).tr_copy_from(&axis);
|
top.columns_range_mut(irow + shift..).tr_copy_from(&axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reflection_norm
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the orthogonal transformation described by the elementary reflector axii stored on
|
/// Computes the orthogonal transformation described by the elementary reflector axii stored on
|
||||||
|
@ -134,7 +121,7 @@ where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
assert!(m.is_square());
|
assert!(m.is_square());
|
||||||
let dim = m.data.shape().0;
|
let dim = m.shape_generic().0;
|
||||||
|
|
||||||
// NOTE: we could build the identity matrix and call p_mult on it.
|
// NOTE: we could build the identity matrix and call p_mult on it.
|
||||||
// Instead we don't so that we take in account the matrix sparseness.
|
// Instead we don't so that we take in account the matrix sparseness.
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -8,8 +5,9 @@ use crate::allocator::{Allocator, Reallocator};
|
||||||
use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar};
|
use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar};
|
||||||
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::dimension::{Dim, DimMin, DimMinimum};
|
use crate::dimension::{Dim, DimMin, DimMinimum};
|
||||||
use crate::storage::{InnerOwned, Storage, StorageMut};
|
use crate::storage::{Storage, StorageMut};
|
||||||
use simba::scalar::{ComplexField, Field};
|
use simba::scalar::{ComplexField, Field};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use crate::linalg::PermutationSequence;
|
use crate::linalg::PermutationSequence;
|
||||||
|
|
||||||
|
@ -29,7 +27,8 @@ use crate::linalg::PermutationSequence;
|
||||||
OMatrix<T, R, C>: Deserialize<'de>,
|
OMatrix<T, R, C>: Deserialize<'de>,
|
||||||
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
|
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
pub struct LU<T, R: DimMin<C>, C: Dim>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct LU<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
|
@ -37,43 +36,13 @@ where
|
||||||
p: PermutationSequence<DimMinimum<R, C>>,
|
p: PermutationSequence<DimMinimum<R, C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
|
||||||
impl<T: Copy, R: DimMin<C>, C: Dim> Copy for LU<T, R, C>
|
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
||||||
|
OMatrix<T, R, C>: Copy,
|
||||||
PermutationSequence<DimMinimum<R, C>>: Copy,
|
PermutationSequence<DimMinimum<R, C>>: Copy,
|
||||||
InnerOwned<T, R, C>: Copy,
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: Clone, R: DimMin<C>, C: Dim> Clone for LU<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
|
||||||
PermutationSequence<DimMinimum<R, C>>: Clone,
|
|
||||||
InnerOwned<T, R, C>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
lu: self.lu.clone(),
|
|
||||||
p: self.p.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for LU<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<(usize, usize), DimMinimum<R, C>>,
|
|
||||||
PermutationSequence<DimMinimum<R, C>>: fmt::Debug,
|
|
||||||
InnerOwned<T, R, C>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("LU")
|
|
||||||
.field("lu", &self.lu)
|
|
||||||
.field("p", &self.p)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`.
|
/// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`.
|
||||||
///
|
///
|
||||||
|
@ -121,7 +90,7 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
|
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
|
||||||
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
let mut p = PermutationSequence::identity_generic(min_nrows_ncols);
|
||||||
|
@ -163,7 +132,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
|
||||||
m.fill_upper_triangle(T::zero(), 1);
|
m.fill_upper_triangle(T::zero(), 1);
|
||||||
m.fill_diagonal(T::one());
|
m.fill_diagonal(T::one());
|
||||||
|
@ -180,7 +149,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
|
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
|
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
|
||||||
m.fill_upper_triangle(T::zero(), 1);
|
m.fill_upper_triangle(T::zero(), 1);
|
||||||
m.fill_diagonal(T::one());
|
m.fill_diagonal(T::one());
|
||||||
|
@ -193,7 +162,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
|
DefaultAllocator: Reallocator<T, R, C, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
|
let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero());
|
||||||
m.fill_upper_triangle(T::zero(), 1);
|
m.fill_upper_triangle(T::zero(), 1);
|
||||||
m.fill_diagonal(T::one());
|
m.fill_diagonal(T::one());
|
||||||
|
@ -207,7 +176,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +268,7 @@ where
|
||||||
"LU inverse: unable to compute the inverse of a non-square matrix."
|
"LU inverse: unable to compute the inverse of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let (nrows, ncols) = self.lu.data.shape();
|
let (nrows, ncols) = self.lu.shape_generic();
|
||||||
let mut res = OMatrix::identity_generic(nrows, ncols);
|
let mut res = OMatrix::identity_generic(nrows, ncols);
|
||||||
if self.try_inverse_to(&mut res) {
|
if self.try_inverse_to(&mut res) {
|
||||||
Some(res)
|
Some(res)
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -11,10 +8,8 @@ use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, Matrix, OVector, Scalar};
|
use crate::base::{DefaultAllocator, Matrix, OVector, Scalar};
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use crate::dimension::Dynamic;
|
use crate::dimension::Dynamic;
|
||||||
use crate::dimension::{Dim, DimName};
|
use crate::dimension::{Const, Dim, DimName};
|
||||||
use crate::iter::MatrixIter;
|
use crate::storage::StorageMut;
|
||||||
use crate::storage::{InnerOwned, StorageMut};
|
|
||||||
use crate::{Const, U1};
|
|
||||||
|
|
||||||
/// A sequence of row or column permutations.
|
/// A sequence of row or column permutations.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -28,47 +23,22 @@ use crate::{Const, U1};
|
||||||
serde(bound(deserialize = "DefaultAllocator: Allocator<(usize, usize), D>,
|
serde(bound(deserialize = "DefaultAllocator: Allocator<(usize, usize), D>,
|
||||||
OVector<(usize, usize), D>: Deserialize<'de>"))
|
OVector<(usize, usize), D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct PermutationSequence<D: Dim>
|
pub struct PermutationSequence<D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<(usize, usize), D>,
|
DefaultAllocator: Allocator<(usize, usize), D>,
|
||||||
{
|
{
|
||||||
len: usize,
|
len: usize,
|
||||||
ipiv: OVector<MaybeUninit<(usize, usize)>, D>,
|
ipiv: OVector<(usize, usize), D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Dim> Copy for PermutationSequence<D>
|
impl<D: Dim> Copy for PermutationSequence<D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<(usize, usize), D>,
|
DefaultAllocator: Allocator<(usize, usize), D>,
|
||||||
OVector<MaybeUninit<(usize, usize)>, D>: Copy,
|
OVector<(usize, usize), D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Dim> Clone for PermutationSequence<D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<(usize, usize), D>,
|
|
||||||
OVector<MaybeUninit<(usize, usize)>, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
len: self.len,
|
|
||||||
ipiv: self.ipiv.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: Dim> fmt::Debug for PermutationSequence<D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<(usize, usize), D>,
|
|
||||||
OVector<MaybeUninit<(usize, usize)>, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("PermutationSequence")
|
|
||||||
.field("len", &self.len)
|
|
||||||
.field("ipiv", &self.ipiv)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: DimName> PermutationSequence<D>
|
impl<D: DimName> PermutationSequence<D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<(usize, usize), D>,
|
DefaultAllocator: Allocator<(usize, usize), D>,
|
||||||
|
@ -101,7 +71,9 @@ where
|
||||||
pub fn identity_generic(dim: D) -> Self {
|
pub fn identity_generic(dim: D) -> Self {
|
||||||
Self {
|
Self {
|
||||||
len: 0,
|
len: 0,
|
||||||
ipiv: OVector::new_uninitialized_generic(dim, Const::<1>),
|
// TODO: using a uninitialized matrix would save some computation, but
|
||||||
|
// that loos difficult to setup with MaybeUninit.
|
||||||
|
ipiv: Matrix::repeat_generic(dim, Const::<1>, (0, 0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +86,7 @@ where
|
||||||
self.len < self.ipiv.len(),
|
self.len < self.ipiv.len(),
|
||||||
"Maximum number of permutations exceeded."
|
"Maximum number of permutations exceeded."
|
||||||
);
|
);
|
||||||
self.ipiv[self.len] = MaybeUninit::new((i, i2));
|
self.ipiv[self.len] = (i, i2);
|
||||||
self.len += 1;
|
self.len += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,8 +97,8 @@ where
|
||||||
where
|
where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
{
|
{
|
||||||
for perm in self.iter() {
|
for i in self.ipiv.rows_range(..self.len).iter() {
|
||||||
rhs.swap_rows(perm.0, perm.1)
|
rhs.swap_rows(i.0, i.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +108,8 @@ where
|
||||||
where
|
where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
{
|
{
|
||||||
for perm in self.iter().rev() {
|
for i in 0..self.len {
|
||||||
let (i1, i2) = perm;
|
let (i1, i2) = self.ipiv[self.len - i - 1];
|
||||||
rhs.swap_rows(i1, i2)
|
rhs.swap_rows(i1, i2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,8 +120,8 @@ where
|
||||||
where
|
where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
{
|
{
|
||||||
for perm in self.iter() {
|
for i in self.ipiv.rows_range(..self.len).iter() {
|
||||||
rhs.swap_columns(perm.0, perm.1)
|
rhs.swap_columns(i.0, i.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +133,8 @@ where
|
||||||
) where
|
) where
|
||||||
S2: StorageMut<T, R2, C2>,
|
S2: StorageMut<T, R2, C2>,
|
||||||
{
|
{
|
||||||
for perm in self.iter().rev() {
|
for i in 0..self.len {
|
||||||
let (i1, i2) = perm;
|
let (i1, i2) = self.ipiv[self.len - i - 1];
|
||||||
rhs.swap_columns(i1, i2)
|
rhs.swap_columns(i1, i2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,27 +161,4 @@ where
|
||||||
-T::one()
|
-T::one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the permutations that have been initialized.
|
|
||||||
pub fn iter(
|
|
||||||
&self,
|
|
||||||
) -> std::iter::Map<
|
|
||||||
std::iter::Copied<
|
|
||||||
std::iter::Take<
|
|
||||||
MatrixIter<
|
|
||||||
MaybeUninit<(usize, usize)>,
|
|
||||||
D,
|
|
||||||
U1,
|
|
||||||
InnerOwned<MaybeUninit<(usize, usize)>, D, U1>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
impl FnMut(MaybeUninit<(usize, usize)>) -> (usize, usize),
|
|
||||||
> {
|
|
||||||
self.ipiv
|
|
||||||
.iter()
|
|
||||||
.take(self.len)
|
|
||||||
.copied()
|
|
||||||
.map(|e| unsafe { e.assume_init() })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,31 +40,19 @@ where
|
||||||
|
|
||||||
// We use the buffer to hold the result of multiplier ^ 2, thus avoiding
|
// We use the buffer to hold the result of multiplier ^ 2, thus avoiding
|
||||||
// extra allocations.
|
// extra allocations.
|
||||||
let (nrows, ncols) = self.data.shape();
|
|
||||||
let mut multiplier = self.clone_owned();
|
let mut multiplier = self.clone_owned();
|
||||||
let mut buf = Matrix::new_uninitialized_generic(nrows, ncols);
|
let mut buf = self.clone_owned();
|
||||||
|
|
||||||
// Exponentiation by squares.
|
// Exponentiation by squares.
|
||||||
loop {
|
loop {
|
||||||
if e % two == one {
|
if e % two == one {
|
||||||
let init_buf = self.mul_to(&multiplier, &mut buf);
|
self.mul_to(&multiplier, &mut buf);
|
||||||
self.copy_from(&init_buf);
|
self.copy_from(&buf);
|
||||||
|
|
||||||
// Safety: `mul_to` leaves `buf` completely initialized.
|
|
||||||
unsafe {
|
|
||||||
buf.reinitialize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e /= two;
|
e /= two;
|
||||||
|
multiplier.mul_to(&multiplier, &mut buf);
|
||||||
let init_buf = multiplier.mul_to(&multiplier, &mut buf);
|
multiplier.copy_from(&buf);
|
||||||
multiplier.copy_from(&init_buf);
|
|
||||||
|
|
||||||
// Safety: `mul_to` leaves `buf` completely initialized.
|
|
||||||
unsafe {
|
|
||||||
buf.reinitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
if e == zero {
|
if e == zero {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -8,11 +6,12 @@ use crate::allocator::{Allocator, Reallocator};
|
||||||
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit};
|
||||||
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::dimension::{Const, Dim, DimMin, DimMinimum};
|
use crate::dimension::{Const, Dim, DimMin, DimMinimum};
|
||||||
use crate::storage::{InnerOwned, Storage, StorageMut};
|
use crate::storage::{Storage, StorageMut};
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// The QR decomposition of a general matrix.
|
/// The QR decomposition of a general matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -30,8 +29,8 @@ use crate::linalg::householder;
|
||||||
OMatrix<T, R, C>: Deserialize<'de>,
|
OMatrix<T, R, C>: Deserialize<'de>,
|
||||||
OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
|
OVector<T, DimMinimum<R, C>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct QR<T, R: DimMin<C>, C: Dim>
|
pub struct QR<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
|
@ -39,43 +38,13 @@ where
|
||||||
diag: OVector<T, DimMinimum<R, C>>,
|
diag: OVector<T, DimMinimum<R, C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for QR<T, R, C>
|
||||||
impl<T: Copy, R: DimMin<C>, C: Dim> Copy for QR<T, R, C>
|
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
||||||
InnerOwned<T, R, C>: Copy,
|
OMatrix<T, R, C>: Copy,
|
||||||
InnerOwned<T, DimMinimum<R, C>>: Copy,
|
OVector<T, DimMinimum<R, C>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<T: Clone, R: DimMin<C>, C: Dim> Clone for QR<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
|
||||||
InnerOwned<T, R, C>: Clone,
|
|
||||||
InnerOwned<T, DimMinimum<R, C>>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
qr: self.qr.clone(),
|
|
||||||
diag: self.diag.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, R: DimMin<C>, C: Dim> fmt::Debug for QR<T, R, C>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>>,
|
|
||||||
InnerOwned<T, R, C>: fmt::Debug,
|
|
||||||
InnerOwned<T, DimMinimum<R, C>>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("QR")
|
|
||||||
.field("qr", &self.qr)
|
|
||||||
.field("diag", &self.diag)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> QR<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> QR<T, R, C>
|
||||||
where
|
where
|
||||||
|
@ -83,32 +52,26 @@ where
|
||||||
{
|
{
|
||||||
/// Computes the QR decomposition using householder reflections.
|
/// Computes the QR decomposition using householder reflections.
|
||||||
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
pub fn new(mut matrix: OMatrix<T, R, C>) -> Self {
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut diag = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
|
|
||||||
|
|
||||||
if min_nrows_ncols.value() == 0 {
|
if min_nrows_ncols.value() == 0 {
|
||||||
return Self {
|
return QR {
|
||||||
qr: matrix,
|
qr: matrix,
|
||||||
diag: unsafe { diag.assume_init() },
|
diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>);
|
||||||
|
|
||||||
for i in 0..min_nrows_ncols.value() {
|
for i in 0..min_nrows_ncols.value() {
|
||||||
// Safety: the pointer is valid for writes, aligned, and uninitialized.
|
diag[i] =
|
||||||
unsafe {
|
MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None));
|
||||||
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: all values have been initialized.
|
// Safety: diag is now fully initialized.
|
||||||
unsafe {
|
let diag = unsafe { diag.assume_init() };
|
||||||
Self {
|
QR { qr: matrix, diag }
|
||||||
qr: matrix,
|
|
||||||
diag: diag.assume_init(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
|
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
|
||||||
|
@ -118,7 +81,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle();
|
let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle();
|
||||||
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
|
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
|
||||||
res
|
res
|
||||||
|
@ -132,7 +95,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
|
DefaultAllocator: Reallocator<T, R, C, DimMinimum<R, C>, C>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, T::zero());
|
let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, T::zero());
|
||||||
res.fill_lower_triangle(T::zero(), 1);
|
res.fill_lower_triangle(T::zero(), 1);
|
||||||
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
|
res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.modulus())));
|
||||||
|
@ -145,7 +108,7 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
|
|
||||||
// NOTE: we could build the identity matrix and call q_mul on it.
|
// NOTE: we could build the identity matrix and call q_mul on it.
|
||||||
// Instead we don't so that we take in account the matrix sparseness.
|
// Instead we don't so that we take in account the matrix sparseness.
|
||||||
|
@ -297,7 +260,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: is there a less naive method ?
|
// TODO: is there a less naive method ?
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.shape_generic();
|
||||||
let mut res = OMatrix::identity_generic(nrows, ncols);
|
let mut res = OMatrix::identity_generic(nrows, ncols);
|
||||||
|
|
||||||
if self.solve_mut(&mut res) {
|
if self.solve_mut(&mut res) {
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
#![allow(clippy::suspicious_operation_groupings)]
|
#![allow(clippy::suspicious_operation_groupings)]
|
||||||
use std::cmp;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use approx::AbsDiffEq;
|
use approx::AbsDiffEq;
|
||||||
use num_complex::Complex as NumComplex;
|
use num_complex::Complex as NumComplex;
|
||||||
use simba::scalar::{ComplexField, RealField};
|
use simba::scalar::{ComplexField, RealField};
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dynamic, U1, U2};
|
use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dynamic, U1, U2};
|
||||||
use crate::base::storage::{InnerOwned, Storage};
|
use crate::base::storage::Storage;
|
||||||
use crate::base::{
|
use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3};
|
||||||
DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
use crate::linalg::Hessenberg;
|
use crate::linalg::Hessenberg;
|
||||||
|
use crate::{Matrix, UninitVector};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// Schur decomposition of a square matrix.
|
/// Schur decomposition of a square matrix.
|
||||||
///
|
///
|
||||||
|
@ -36,7 +34,7 @@ use crate::linalg::Hessenberg;
|
||||||
OMatrix<T, D, D>: Deserialize<'de>"))
|
OMatrix<T, D, D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Schur<T, D: Dim>
|
pub struct Schur<T: ComplexField, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
|
@ -44,10 +42,10 @@ where
|
||||||
t: OMatrix<T, D, D>,
|
t: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: Dim> Copy for Schur<T, D>
|
impl<T: ComplexField, D: Dim> Copy for Schur<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +74,7 @@ where
|
||||||
/// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm
|
/// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm
|
||||||
/// continues indefinitely until convergence.
|
/// continues indefinitely until convergence.
|
||||||
pub fn try_new(m: OMatrix<T, D, D>, eps: T::RealField, max_niter: usize) -> Option<Self> {
|
pub fn try_new(m: OMatrix<T, D, D>, eps: T::RealField, max_niter: usize) -> Option<Self> {
|
||||||
let mut work = OVector::new_uninitialized_generic(m.data.shape().0, Const::<1>);
|
let mut work = Matrix::zeros_generic(m.shape_generic().0, Const::<1>);
|
||||||
|
|
||||||
Self::do_decompose(m, &mut work, eps, max_niter, true)
|
Self::do_decompose(m, &mut work, eps, max_niter, true)
|
||||||
.map(|(q, t)| Schur { q: q.unwrap(), t })
|
.map(|(q, t)| Schur { q: q.unwrap(), t })
|
||||||
|
@ -84,7 +82,7 @@ where
|
||||||
|
|
||||||
fn do_decompose(
|
fn do_decompose(
|
||||||
mut m: OMatrix<T, D, D>,
|
mut m: OMatrix<T, D, D>,
|
||||||
work: &mut OVector<MaybeUninit<T>, D>,
|
work: &mut OVector<T, D>,
|
||||||
eps: T::RealField,
|
eps: T::RealField,
|
||||||
max_niter: usize,
|
max_niter: usize,
|
||||||
compute_q: bool,
|
compute_q: bool,
|
||||||
|
@ -94,7 +92,7 @@ where
|
||||||
"Unable to compute the eigenvectors and eigenvalues of a non-square matrix."
|
"Unable to compute the eigenvectors and eigenvalues of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let dim = m.data.shape().0;
|
let dim = m.shape_generic().0;
|
||||||
|
|
||||||
// Specialization would make this easier.
|
// Specialization would make this easier.
|
||||||
if dim.value() == 0 {
|
if dim.value() == 0 {
|
||||||
|
@ -273,9 +271,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the eigenvalues of the decomposed matrix.
|
/// Computes the eigenvalues of the decomposed matrix.
|
||||||
fn do_eigenvalues(t: &OMatrix<T, D, D>, out: &mut OVector<MaybeUninit<T>, D>) -> bool {
|
fn do_eigenvalues(t: &OMatrix<T, D, D>, out: &mut OVector<T, D>) -> bool {
|
||||||
// TODO: check dropping stuff.
|
|
||||||
|
|
||||||
let dim = t.nrows();
|
let dim = t.nrows();
|
||||||
let mut m = 0;
|
let mut m = 0;
|
||||||
|
|
||||||
|
@ -283,7 +279,7 @@ where
|
||||||
let n = m + 1;
|
let n = m + 1;
|
||||||
|
|
||||||
if t[(n, m)].is_zero() {
|
if t[(n, m)].is_zero() {
|
||||||
out[m] = MaybeUninit::new(t[(m, m)]);
|
out[m] = t[(m, m)];
|
||||||
m += 1;
|
m += 1;
|
||||||
} else {
|
} else {
|
||||||
// Complex eigenvalue.
|
// Complex eigenvalue.
|
||||||
|
@ -292,22 +288,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if m == dim - 1 {
|
if m == dim - 1 {
|
||||||
out[m] = MaybeUninit::new(t[(m, m)]);
|
out[m] = t[(m, m)];
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the complex eigenvalues of the decomposed matrix.
|
/// Computes the complex eigenvalues of the decomposed matrix.
|
||||||
fn do_complex_eigenvalues(
|
fn do_complex_eigenvalues(t: &OMatrix<T, D, D>, out: &mut UninitVector<NumComplex<T>, D>)
|
||||||
t: &OMatrix<T, D, D>,
|
where
|
||||||
out: &mut OVector<MaybeUninit<NumComplex<T>>, D>,
|
|
||||||
) where
|
|
||||||
T: RealField,
|
T: RealField,
|
||||||
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
||||||
{
|
{
|
||||||
// TODO: check for dropping behavior.
|
|
||||||
|
|
||||||
let dim = t.nrows();
|
let dim = t.nrows();
|
||||||
let mut m = 0;
|
let mut m = 0;
|
||||||
|
|
||||||
|
@ -397,9 +389,9 @@ where
|
||||||
/// Return `None` if some eigenvalues are complex.
|
/// Return `None` if some eigenvalues are complex.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
|
pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
|
||||||
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>);
|
let mut out = Matrix::zeros_generic(self.t.shape_generic().0, Const::<1>);
|
||||||
if Self::do_eigenvalues(&self.t, &mut out) {
|
if Self::do_eigenvalues(&self.t, &mut out) {
|
||||||
Some(unsafe { out.assume_init() })
|
Some(out)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -412,8 +404,9 @@ where
|
||||||
T: RealField,
|
T: RealField,
|
||||||
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
||||||
{
|
{
|
||||||
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>);
|
let mut out = Matrix::uninit(self.t.shape_generic().0, Const::<1>);
|
||||||
Self::do_complex_eigenvalues(&self.t, &mut out);
|
Self::do_complex_eigenvalues(&self.t, &mut out);
|
||||||
|
// Safety: out has been fully initialized by do_complex_eigenvalues.
|
||||||
unsafe { out.assume_init() }
|
unsafe { out.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,7 +418,7 @@ fn decompose_2x2<T: ComplexField, D: Dim>(
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
let dim = m.data.shape().0;
|
let dim = m.shape_generic().0;
|
||||||
let mut q = None;
|
let mut q = None;
|
||||||
match compute_2x2_basis(&m.fixed_slice::<2, 2>(0, 0)) {
|
match compute_2x2_basis(&m.fixed_slice::<2, 2>(0, 0)) {
|
||||||
Some(rot) => {
|
Some(rot) => {
|
||||||
|
@ -519,14 +512,12 @@ where
|
||||||
/// Computes the eigenvalues of this matrix.
|
/// Computes the eigenvalues of this matrix.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
|
pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
|
||||||
// TODO: check drop stuff.
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
self.is_square(),
|
self.is_square(),
|
||||||
"Unable to compute eigenvalues of a non-square matrix."
|
"Unable to compute eigenvalues of a non-square matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut work = OVector::new_uninitialized_generic(self.data.shape().0, Const::<1>);
|
let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
|
||||||
|
|
||||||
// Special case for 2x2 matrices.
|
// Special case for 2x2 matrices.
|
||||||
if self.nrows() == 2 {
|
if self.nrows() == 2 {
|
||||||
|
@ -535,9 +526,9 @@ where
|
||||||
let me = self.fixed_slice::<2, 2>(0, 0);
|
let me = self.fixed_slice::<2, 2>(0, 0);
|
||||||
return match compute_2x2_eigvals(&me) {
|
return match compute_2x2_eigvals(&me) {
|
||||||
Some((a, b)) => {
|
Some((a, b)) => {
|
||||||
work[0] = MaybeUninit::new(a);
|
work[0] = a;
|
||||||
work[1] = MaybeUninit::new(b);
|
work[1] = b;
|
||||||
Some(unsafe { work.assume_init() })
|
Some(work)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
@ -552,8 +543,9 @@ where
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if Schur::do_eigenvalues(&schur.1, &mut work) {
|
if Schur::do_eigenvalues(&schur.1, &mut work) {
|
||||||
Some(unsafe { work.assume_init() })
|
Some(work)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -567,8 +559,8 @@ where
|
||||||
T: RealField,
|
T: RealField,
|
||||||
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
||||||
{
|
{
|
||||||
let dim = self.data.shape().0;
|
let dim = self.shape_generic().0;
|
||||||
let mut work = OVector::new_uninitialized_generic(dim, Const::<1>);
|
let mut work = Matrix::zeros_generic(dim, Const::<1>);
|
||||||
|
|
||||||
let schur = Schur::do_decompose(
|
let schur = Schur::do_decompose(
|
||||||
self.clone_owned(),
|
self.clone_owned(),
|
||||||
|
@ -578,8 +570,9 @@ where
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut eig = OVector::new_uninitialized_generic(dim, Const::<1>);
|
let mut eig = Matrix::uninit(dim, Const::<1>);
|
||||||
Schur::do_complex_eigenvalues(&schur.1, &mut eig);
|
Schur::do_complex_eigenvalues(&schur.1, &mut eig);
|
||||||
|
// Safety: eig has been fully initialized by do_complex_eigenvalues.
|
||||||
unsafe { eig.assume_init() }
|
unsafe { eig.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ use num::{One, Zero};
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2};
|
use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2};
|
||||||
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimName, DimSub, U1};
|
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
|
||||||
use crate::storage::{InnerOwned, Storage};
|
use crate::storage::Storage;
|
||||||
use simba::scalar::{ComplexField, RealField};
|
use simba::scalar::{ComplexField, RealField};
|
||||||
|
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
|
@ -54,14 +54,14 @@ where
|
||||||
pub singular_values: OVector<T::RealField, DimMinimum<R, C>>,
|
pub singular_values: OVector<T::RealField, DimMinimum<R, C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField + Copy, R: DimName + DimMin<C>, C: DimName> Copy for SVD<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for SVD<T, R, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
||||||
+ Allocator<T, R, DimMinimum<R, C>>
|
+ Allocator<T, R, DimMinimum<R, C>>
|
||||||
+ Allocator<T::RealField, DimMinimum<R, C>>,
|
+ Allocator<T::RealField, DimMinimum<R, C>>,
|
||||||
InnerOwned<T, R, DimMinimum<R, C>>: Copy,
|
OMatrix<T, R, DimMinimum<R, C>>: Copy,
|
||||||
InnerOwned<T, DimMinimum<R, C>, C>: Copy,
|
OMatrix<T, DimMinimum<R, C>, C>: Copy,
|
||||||
InnerOwned<T::RealField, DimMinimum<R, C>>: Copy,
|
OVector<T::RealField, DimMinimum<R, C>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ where
|
||||||
!matrix.is_empty(),
|
!matrix.is_empty(),
|
||||||
"Cannot compute the SVD of an empty matrix."
|
"Cannot compute the SVD of an empty matrix."
|
||||||
);
|
);
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.shape_generic();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
let dim = min_nrows_ncols.value();
|
let dim = min_nrows_ncols.value();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -8,8 +6,8 @@ use num::Zero;
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2};
|
use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2};
|
||||||
use crate::dimension::{Dim, DimDiff, DimName, DimSub, U1};
|
use crate::dimension::{Dim, DimDiff, DimSub, U1};
|
||||||
use crate::storage::{InnerOwned, Storage};
|
use crate::storage::Storage;
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
|
@ -31,6 +29,7 @@ use crate::linalg::SymmetricTridiagonal;
|
||||||
OVector<T::RealField, D>: Deserialize<'de>,
|
OVector<T::RealField, D>: Deserialize<'de>,
|
||||||
OMatrix<T, D, D>: Deserialize<'de>"))
|
OMatrix<T, D, D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct SymmetricEigen<T: ComplexField, D: Dim>
|
pub struct SymmetricEigen<T: ComplexField, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
||||||
|
@ -42,42 +41,14 @@ where
|
||||||
pub eigenvalues: OVector<T::RealField, D>,
|
pub eigenvalues: OVector<T::RealField, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimName> Copy for SymmetricEigen<T, D>
|
impl<T: ComplexField, D: Dim> Copy for SymmetricEigen<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
InnerOwned<T::RealField, D>: Copy,
|
OVector<T::RealField, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> Clone for SymmetricEigen<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
InnerOwned<T::RealField, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
eigenvectors: self.eigenvectors.clone(),
|
|
||||||
eigenvalues: self.eigenvalues.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> fmt::Debug for SymmetricEigen<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
|
||||||
InnerOwned<T, D, D>: fmt::Debug,
|
|
||||||
InnerOwned<T::RealField, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("SymmetricEigen")
|
|
||||||
.field("eigenvectors", &self.eigenvectors)
|
|
||||||
.field("eigenvalues", &self.eigenvalues)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> SymmetricEigen<T, D>
|
impl<T: ComplexField, D: Dim> SymmetricEigen<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
||||||
|
@ -299,10 +270,7 @@ where
|
||||||
///
|
///
|
||||||
/// This is useful if some of the eigenvalues have been manually modified.
|
/// This is useful if some of the eigenvalues have been manually modified.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn recompose(&self) -> OMatrix<T, D, D>
|
pub fn recompose(&self) -> OMatrix<T, D, D> {
|
||||||
where
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
let mut u_t = self.eigenvectors.clone();
|
let mut u_t = self.eigenvectors.clone();
|
||||||
for i in 0..self.eigenvalues.len() {
|
for i in 0..self.eigenvalues.len() {
|
||||||
let val = self.eigenvalues[i];
|
let val = self.eigenvalues[i];
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
use std::fmt;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{DefaultAllocator, OMatrix, OVector};
|
use crate::base::{DefaultAllocator, OMatrix, OVector};
|
||||||
use crate::dimension::{Const, DimDiff, DimName, DimSub, U1};
|
use crate::dimension::{Const, DimDiff, DimSub, U1};
|
||||||
use crate::storage::{InnerOwned, Storage};
|
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
|
use crate::Matrix;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
/// Tridiagonalization of a symmetric matrix.
|
/// Tridiagonalization of a symmetric matrix.
|
||||||
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
|
||||||
|
@ -28,7 +26,8 @@ use crate::linalg::householder;
|
||||||
OMatrix<T, D, D>: Deserialize<'de>,
|
OMatrix<T, D, D>: Deserialize<'de>,
|
||||||
OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
|
OVector<T, DimDiff<D, U1>>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
pub struct SymmetricTridiagonal<T, D: DimSub<U1>>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SymmetricTridiagonal<T: ComplexField, D: DimSub<U1>>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
||||||
{
|
{
|
||||||
|
@ -36,42 +35,14 @@ where
|
||||||
off_diagonal: OVector<T, DimDiff<D, U1>>,
|
off_diagonal: OVector<T, DimDiff<D, U1>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: DimSub<U1> + DimName> Copy for SymmetricTridiagonal<T, D>
|
impl<T: ComplexField, D: DimSub<U1>> Copy for SymmetricTridiagonal<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
InnerOwned<T, DimDiff<D, U1>>: Copy,
|
OVector<T, DimDiff<D, U1>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, D: DimSub<U1>> Clone for SymmetricTridiagonal<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
InnerOwned<T, DimDiff<D, U1>>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
tri: self.tri.clone(),
|
|
||||||
off_diagonal: self.off_diagonal.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: DimSub<U1>> fmt::Debug for SymmetricTridiagonal<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
|
||||||
InnerOwned<T, D, D>: fmt::Debug,
|
|
||||||
InnerOwned<T, DimDiff<D, U1>>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("SymmetricTridiagonal")
|
|
||||||
.field("tri", &self.tri)
|
|
||||||
.field("off_diagonal", &self.off_diagonal)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> SymmetricTridiagonal<T, D>
|
impl<T: ComplexField, D: DimSub<U1>> SymmetricTridiagonal<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T, DimDiff<D, U1>>,
|
||||||
|
@ -80,7 +51,7 @@ where
|
||||||
///
|
///
|
||||||
/// Only the lower-triangular part (including the diagonal) of `m` is read.
|
/// Only the lower-triangular part (including the diagonal) of `m` is read.
|
||||||
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
|
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
|
||||||
let dim = m.data.shape().0;
|
let dim = m.shape_generic().0;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
m.is_square(),
|
m.is_square(),
|
||||||
|
@ -91,8 +62,8 @@ where
|
||||||
"Unable to compute the symmetric tridiagonal decomposition of an empty matrix."
|
"Unable to compute the symmetric tridiagonal decomposition of an empty matrix."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut off_diagonal = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
|
let mut off_diagonal = Matrix::uninit(dim.sub(Const::<1>), Const::<1>);
|
||||||
let mut p = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
|
let mut p = Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>);
|
||||||
|
|
||||||
for i in 0..dim.value() - 1 {
|
for i in 0..dim.value() - 1 {
|
||||||
let mut m = m.rows_range_mut(i + 1..);
|
let mut m = m.rows_range_mut(i + 1..);
|
||||||
|
@ -104,8 +75,7 @@ where
|
||||||
if not_zero {
|
if not_zero {
|
||||||
let mut p = p.rows_range_mut(i..);
|
let mut p = p.rows_range_mut(i..);
|
||||||
|
|
||||||
p.hegemv_z(crate::convert(2.0), &m, &axis);
|
p.hegemv(crate::convert(2.0), &m, &axis, T::zero());
|
||||||
let p = unsafe { p.slice_assume_init() };
|
|
||||||
|
|
||||||
let dot = axis.dotc(&p);
|
let dot = axis.dotc(&p);
|
||||||
m.hegerc(-T::one(), &p, &axis, T::one());
|
m.hegerc(-T::one(), &p, &axis, T::one());
|
||||||
|
@ -114,9 +84,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: off_diagonal has been fully initialized.
|
||||||
|
let off_diagonal = unsafe { off_diagonal.assume_init() };
|
||||||
Self {
|
Self {
|
||||||
tri: m,
|
tri: m,
|
||||||
off_diagonal: unsafe { off_diagonal.assume_init() },
|
off_diagonal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
|
use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
|
||||||
use crate::dimension::{Dim, DimName};
|
use crate::dimension::Dim;
|
||||||
use crate::storage::{InnerOwned, Storage};
|
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::RealField;
|
||||||
|
|
||||||
/// UDU factorization.
|
/// UDU factorization.
|
||||||
|
@ -21,7 +18,8 @@ use simba::scalar::RealField;
|
||||||
deserialize = "OVector<T, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>"
|
deserialize = "OVector<T, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
pub struct UDU<T, D: Dim>
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UDU<T: RealField, D: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
{
|
{
|
||||||
|
@ -31,42 +29,14 @@ where
|
||||||
pub d: OVector<T, D>,
|
pub d: OVector<T, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, D: DimName> Copy for UDU<T, D>
|
impl<T: RealField, D: Dim> Copy for UDU<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
InnerOwned<T, D>: Copy,
|
OVector<T, D>: Copy,
|
||||||
InnerOwned<T, D, D>: Copy,
|
OMatrix<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone, D: Dim> Clone for UDU<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
|
||||||
InnerOwned<T, D>: Clone,
|
|
||||||
InnerOwned<T, D, D>: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
u: self.u.clone(),
|
|
||||||
d: self.d.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug, D: Dim> fmt::Debug for UDU<T, D>
|
|
||||||
where
|
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
|
||||||
InnerOwned<T, D>: fmt::Debug,
|
|
||||||
InnerOwned<T, D, D>: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("UDU")
|
|
||||||
.field("u", &self.u)
|
|
||||||
.field("d", &self.d)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: RealField, D: Dim> UDU<T, D>
|
impl<T: RealField, D: Dim> UDU<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
|
@ -79,7 +49,7 @@ where
|
||||||
/// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360
|
/// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360
|
||||||
pub fn new(p: OMatrix<T, D, D>) -> Option<Self> {
|
pub fn new(p: OMatrix<T, D, D>) -> Option<Self> {
|
||||||
let n = p.ncols();
|
let n = p.ncols();
|
||||||
let n_dim = p.data.shape().1;
|
let n_dim = p.shape_generic().1;
|
||||||
|
|
||||||
let mut d = OVector::zeros_generic(n_dim, Const::<1>);
|
let mut d = OVector::zeros_generic(n_dim, Const::<1>);
|
||||||
let mut u = OMatrix::zeros_generic(n_dim, n_dim);
|
let mut u = OMatrix::zeros_generic(n_dim, n_dim);
|
||||||
|
|
|
@ -263,7 +263,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `matrix`, but without the additional anonymous generic types
|
/// Same as `matrix`, but without the additional anonymous generic types
|
||||||
fn matrix_<R: Dim, C: Dim, ScalarStrategy>(
|
fn matrix_<R, C, ScalarStrategy>(
|
||||||
value_strategy: ScalarStrategy,
|
value_strategy: ScalarStrategy,
|
||||||
rows: DimRange<R>,
|
rows: DimRange<R>,
|
||||||
cols: DimRange<C>,
|
cols: DimRange<C>,
|
||||||
|
@ -271,6 +271,8 @@ fn matrix_<R: Dim, C: Dim, ScalarStrategy>(
|
||||||
where
|
where
|
||||||
ScalarStrategy: Strategy + Clone + 'static,
|
ScalarStrategy: Strategy + Clone + 'static,
|
||||||
ScalarStrategy::Value: Scalar,
|
ScalarStrategy::Value: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
DefaultAllocator: Allocator<ScalarStrategy::Value, R, C>,
|
DefaultAllocator: Allocator<ScalarStrategy::Value, R, C>,
|
||||||
{
|
{
|
||||||
let nrows = rows.lower_bound().value()..=rows.upper_bound().value();
|
let nrows = rows.lower_bound().value()..=rows.upper_bound().value();
|
||||||
|
@ -330,7 +332,12 @@ where
|
||||||
matrix_(value_strategy, length.into(), Const::<1>.into())
|
matrix_(value_strategy, length.into(), Const::<1>.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NParameters: Default, R: DimName, C: DimName> Default for MatrixParameters<NParameters, R, C> {
|
impl<NParameters, R, C> Default for MatrixParameters<NParameters, R, C>
|
||||||
|
where
|
||||||
|
NParameters: Default,
|
||||||
|
R: DimName,
|
||||||
|
C: DimName,
|
||||||
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rows: DimRange::from(R::name()),
|
rows: DimRange::from(R::name()),
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue