Almost!
This commit is contained in:
parent
a6b8dd6d78
commit
9a528e23b9
|
@ -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: Scalar, D: Dim>
|
pub struct Cholesky<T, 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: Scalar + Copy, D: Dim> Copy for Cholesky<T, D>
|
impl<T: Copy, D: Dim> Copy for Cholesky<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
OMatrix<T, D, D>: Copy,
|
Owned<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,22 +329,22 @@ where
|
||||||
|
|
||||||
if !b.is_zero() {
|
if !b.is_zero() {
|
||||||
for i in 0..x.len() {
|
for i in 0..x.len() {
|
||||||
unsafe {
|
|
||||||
let y = y.get_unchecked_mut(i * rstride1);
|
let y = y.get_unchecked_mut(i * rstride1);
|
||||||
*y = a.inlined_clone()
|
*y = a.inlined_clone()
|
||||||
* x.get_unchecked(i * rstride2).inlined_clone()
|
* x.get_unchecked(i * rstride2).inlined_clone()
|
||||||
* c.inlined_clone()
|
* c.inlined_clone()
|
||||||
+ b.inlined_clone() * y.inlined_clone();
|
+ b.inlined_clone() * y.inlined_clone();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i in 0..x.len() {
|
for i in 0..x.len() {
|
||||||
unsafe {
|
|
||||||
let y = y.get_unchecked_mut(i * rstride1);
|
let y = y.get_unchecked_mut(i * rstride1);
|
||||||
*y = a.inlined_clone()
|
*y = a.inlined_clone()
|
||||||
* x.get_unchecked(i * rstride2).inlined_clone()
|
* x.get_unchecked(i * rstride2).inlined_clone()
|
||||||
* c.inlined_clone();
|
* c.inlined_clone();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -788,17 +788,89 @@ where
|
||||||
|
|
||||||
for j in 1..ncols2 {
|
for j in 1..ncols2 {
|
||||||
let col2 = a.column(j);
|
let col2 = a.column(j);
|
||||||
let val = unsafe { x.vget_unchecked(j).inlined_clone() };
|
let val = x.vget_unchecked(j).inlined_clone() ;
|
||||||
init.axcpy(alpha.inlined_clone(), &col2, val, T::one());
|
init.axcpy(alpha.inlined_clone(), &col2, val, T::one());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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() };
|
||||||
|
self.axc(alpha.inlined_clone(), &col2, val);
|
||||||
|
|
||||||
|
let mut res = unsafe { self.assume_init_mut() };
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
impl<T, R1: Dim, C1: Dim, S: StorageMut<MaybeUninit<T>, R1, C1>> Matrix<MaybeUninit<T>, R1, C1, S>
|
||||||
where
|
where
|
||||||
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
|
||||||
// DefaultAllocator: Allocator<T, R1, C1>,
|
// DefaultAllocator: Allocator<T, R1, C1>,
|
||||||
{
|
{
|
||||||
/// Computes `alpha * a * b`, where `a` and `b` are matrices, and `alpha` is
|
/// Computes `alpha * a * b`, where `a` and `b` are matrices, and `alpha` is
|
||||||
/// a scalar.
|
/// a scalar.
|
||||||
|
@ -850,7 +922,7 @@ where
|
||||||
// matrixmultiply can be used only if the std feature is available.
|
// matrixmultiply can be used only if the std feature is available.
|
||||||
let nrows1 = self.nrows();
|
let nrows1 = self.nrows();
|
||||||
let (nrows2, ncols2) = a.shape();
|
let (nrows2, ncols2) = a.shape();
|
||||||
let (nrows3, ncols3) = b.shape();
|
let (_, ncols3) = b.shape();
|
||||||
|
|
||||||
// Threshold determined empirically.
|
// Threshold determined empirically.
|
||||||
const SMALL_DIM: usize = 5;
|
const SMALL_DIM: usize = 5;
|
||||||
|
@ -1502,9 +1574,9 @@ where
|
||||||
ShapeConstraint: DimEq<D1, R3> + DimEq<C3, D4>,
|
ShapeConstraint: DimEq<D1, R3> + DimEq<C3, D4>,
|
||||||
DefaultAllocator: Allocator<T, R3>,
|
DefaultAllocator: Allocator<T, R3>,
|
||||||
{
|
{
|
||||||
let work = Matrix::new_uninitialized_generic(R3::from_usize(self.shape().0), Const::<1>);
|
let mut work = Matrix::new_uninitialized_generic(R3::from_usize(self.shape().0), Const::<1>);
|
||||||
work.gemv_z(T::one(), lhs, &mid.column(0));
|
work.gemv_z(T::one(), lhs, &mid.column(0));
|
||||||
let work = unsafe { work.assume_init() };
|
let mut work = unsafe { work.assume_init() };
|
||||||
|
|
||||||
self.ger(alpha.inlined_clone(), &work, &lhs.column(0), beta);
|
self.ger(alpha.inlined_clone(), &work, &lhs.column(0), beta);
|
||||||
|
|
||||||
|
@ -1552,9 +1624,9 @@ where
|
||||||
DefaultAllocator: Allocator<T, D3>,
|
DefaultAllocator: Allocator<T, D3>,
|
||||||
{
|
{
|
||||||
// TODO: figure out why type inference wasn't doing its job.
|
// TODO: figure out why type inference wasn't doing its job.
|
||||||
let work = Matrix::new_uninitialized_generic(D3::from_usize(self.shape().0), Const::<1>);
|
let mut work = Matrix::new_uninitialized_generic(D3::from_usize(self.shape().0), Const::<1>);
|
||||||
work.gemv_z::<D3, D3, R4, S3, _>(T::one(), mid, &rhs.column(0));
|
work.gemv_z::<D3, D3, R4, S3, _>(T::one(), mid, &rhs.column(0));
|
||||||
let work = unsafe { work.assume_init() };
|
let mut work = unsafe { work.assume_init() };
|
||||||
|
|
||||||
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());
|
||||||
|
|
|
@ -109,13 +109,14 @@ impl<T, const D: usize> From<[T; D]> for SVector<T, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<SVector<T, D>> for [T; D] {
|
impl<T, const D: usize> From<SVector<T, D>> for [T; D]
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(vec: SVector<T, D>) -> Self {
|
fn from(vec: SVector<T, D>) -> Self {
|
||||||
// TODO: unfortunately, we must clone because we can move out of an array.
|
// TODO: unfortunately, we must clone because we can move out of an array.
|
||||||
|
vec.data.0[0].clone()
|
||||||
// Counterpoint: this seems to work?
|
|
||||||
vec.data.0[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,9 @@ type DefaultUninitBuffer<T, R, C> =
|
||||||
* Allocator.
|
* Allocator.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// A helper struct that controls how the storage for a matrix should be allocated.
|
/// 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
|
/// 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.
|
||||||
pub struct DefaultAllocator;
|
pub struct DefaultAllocator;
|
||||||
|
@ -72,7 +72,9 @@ impl<T, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>> for Def
|
||||||
_: Const<R>,
|
_: Const<R>,
|
||||||
_: Const<C>,
|
_: Const<C>,
|
||||||
) -> Owned<MaybeUninit<T>, Const<R>, Const<C>> {
|
) -> Owned<MaybeUninit<T>, Const<R>, Const<C>> {
|
||||||
ArrayStorage([[MaybeUninit::uninit(); R]; C])
|
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
|
||||||
|
let array = unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
|
ArrayStorage(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -126,9 +128,8 @@ impl<T, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
|
||||||
let mut data = ManuallyDrop::new(uninit.data);
|
let mut data = ManuallyDrop::new(uninit.data);
|
||||||
|
|
||||||
// Safety: MaybeUninit<T> has the same alignment and layout as T.
|
// Safety: MaybeUninit<T> has the same alignment and layout as T.
|
||||||
let new_data = unsafe {
|
let new_data =
|
||||||
Vec::from_raw_parts(data.as_mut_ptr() as *mut T, data.len(), data.capacity())
|
Vec::from_raw_parts(data.as_mut_ptr() as *mut T, data.len(), data.capacity());
|
||||||
};
|
|
||||||
|
|
||||||
VecStorage::new(uninit.nrows, uninit.ncols, new_data)
|
VecStorage::new(uninit.nrows, uninit.ncols, new_data)
|
||||||
}
|
}
|
||||||
|
@ -170,9 +171,8 @@ impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
|
||||||
let mut data = ManuallyDrop::new(uninit.data);
|
let mut data = ManuallyDrop::new(uninit.data);
|
||||||
|
|
||||||
// Safety: MaybeUninit<T> has the same alignment and layout as T.
|
// Safety: MaybeUninit<T> has the same alignment and layout as T.
|
||||||
let new_data = unsafe {
|
let new_data =
|
||||||
Vec::from_raw_parts(data.as_mut_ptr() as *mut T, data.len(), data.capacity())
|
Vec::from_raw_parts(data.as_mut_ptr() as *mut T, data.len(), data.capacity());
|
||||||
};
|
|
||||||
|
|
||||||
VecStorage::new(uninit.nrows, uninit.ncols, new_data)
|
VecStorage::new(uninit.nrows, uninit.ncols, new_data)
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ impl<T, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// Anything -> Static × Static
|
// Anything -> Static × Static
|
||||||
impl<T, RFrom:Dim, CFrom:Dim, const RTO: usize, const CTO: usize>
|
impl<T, RFrom: Dim, CFrom: Dim, 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
|
||||||
Self: Allocator<T, RFrom, CFrom>,
|
Self: Allocator<T, RFrom, CFrom>,
|
||||||
|
|
|
@ -178,7 +178,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
/// Sets all the elements of this matrix to `f()`.
|
/// Sets all the elements of this matrix to `f()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fill_fn<F: FnMut() -> T>(&mut self, f: F) {
|
pub fn fill_fn<F: FnMut() -> T>(&mut self, mut f: F) {
|
||||||
for e in self.iter_mut() {
|
for e in self.iter_mut() {
|
||||||
*e = f();
|
*e = f();
|
||||||
}
|
}
|
||||||
|
@ -942,8 +942,11 @@ impl<T: Clone> OMatrix<T, Dynamic, Dynamic> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
|
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
|
||||||
{
|
{
|
||||||
let placeholder =
|
// BEEEP!!!! BEEEEEEEP!!!
|
||||||
Matrix::new_uninitialized_generic(Dynamic::new(0), Dynamic::new(0)).assume_init();
|
|
||||||
|
let placeholder = unsafe {
|
||||||
|
Matrix::new_uninitialized_generic(Dynamic::new(0), Dynamic::new(0)).assume_init()
|
||||||
|
};
|
||||||
let old = mem::replace(self, placeholder);
|
let old = mem::replace(self, placeholder);
|
||||||
let new = old.resize(new_nrows, new_ncols, val);
|
let new = old.resize(new_nrows, new_ncols, val);
|
||||||
let _ = mem::replace(self, new);
|
let _ = mem::replace(self, new);
|
||||||
|
@ -966,7 +969,8 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
|
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
|
||||||
{
|
{
|
||||||
let placeholder = Matrix::from_fn_generic(Dynamic::new(0), self.data.shape().1, |_, _| val);
|
let placeholder =
|
||||||
|
Matrix::from_fn_generic(Dynamic::new(0), self.data.shape().1, |_, _| val.clone());
|
||||||
let old = mem::replace(self, placeholder);
|
let old = mem::replace(self, placeholder);
|
||||||
let new = old.resize_vertically(new_nrows, val);
|
let new = old.resize_vertically(new_nrows, val);
|
||||||
let _ = mem::replace(self, new);
|
let _ = mem::replace(self, new);
|
||||||
|
@ -989,7 +993,8 @@ where
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
|
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
|
||||||
{
|
{
|
||||||
let placeholder = Matrix::from_fn_generic(self.data.shape().0, Dynamic::new(0), |_, _| val);
|
let placeholder =
|
||||||
|
Matrix::from_fn_generic(self.data.shape().0, Dynamic::new(0), |_, _| val.clone());
|
||||||
let old = mem::replace(self, placeholder);
|
let old = mem::replace(self, placeholder);
|
||||||
let new = old.resize_horizontally(new_ncols, val);
|
let new = old.resize_horizontally(new_ncols, val);
|
||||||
let _ = mem::replace(self, new);
|
let _ = mem::replace(self, new);
|
||||||
|
@ -1059,11 +1064,7 @@ 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, S> Extend<T> for Matrix<T, R, Dynamic, S>
|
impl<T, R: Dim, S: Extend<T>> Extend<T> for Matrix<T, R, Dynamic, S> {
|
||||||
where
|
|
||||||
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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1249,7 +1249,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
/// Fills this matrix with the content of another one, after applying a function to
|
/// Fills this matrix with the content of another one, after applying a function to
|
||||||
/// the references of the entries of the other matrix. Both must have the same shape.
|
/// the references of the entries of the other matrix. Both must have the same shape.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn copy_from_fn<U, R2: Dim, C2: Dim, SB, F>(&mut self, other: &Matrix<U, R2, C2, SB>, f: F)
|
pub fn copy_from_fn<U, R2: Dim, C2: Dim, SB, F>(&mut self, other: &Matrix<U, R2, C2, SB>,mut f: F)
|
||||||
where
|
where
|
||||||
SB: Storage<U, R2, C2>,
|
SB: Storage<U, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
@ -1282,7 +1282,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
|
|
||||||
/// Fills this matrix with the content of another one via moves. Both must have the same shape.
|
/// Fills this matrix with the content of another one via moves. Both must have the same shape.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn move_from_fn<U, R2: Dim, C2: Dim, SB, F>(&mut self, other: Matrix<U, R2, C2, SB>, f: F)
|
pub fn move_from_fn<U, R2: Dim, C2: Dim, SB, F>(&mut self, other: Matrix<U, R2, C2, SB>, mut f: F)
|
||||||
where
|
where
|
||||||
SB: Storage<U, R2, C2>,
|
SB: Storage<U, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
@ -1322,7 +1322,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
pub fn tr_copy_from_fn<U, R2: Dim, C2: Dim, SB, F>(
|
pub fn tr_copy_from_fn<U, R2: Dim, C2: Dim, SB, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
other: &Matrix<U, R2, C2, SB>,
|
other: &Matrix<U, R2, C2, SB>,
|
||||||
f: F,
|
mut f: F,
|
||||||
) where
|
) where
|
||||||
SB: Storage<U, R2, C2>,
|
SB: Storage<U, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, C2> + SameNumberOfColumns<C, R2>,
|
ShapeConstraint: DimEq<R, C2> + SameNumberOfColumns<C, R2>,
|
||||||
|
@ -1359,7 +1359,7 @@ impl<T, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
|
||||||
pub fn tr_move_from_fn<U, R2: Dim, C2: Dim, SB, F>(
|
pub fn tr_move_from_fn<U, R2: Dim, C2: Dim, SB, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
other: Matrix<U, R2, C2, SB>,
|
other: Matrix<U, R2, C2, SB>,
|
||||||
f: F,
|
mut f: F,
|
||||||
) where
|
) where
|
||||||
SB: Storage<U, R2, C2>,
|
SB: Storage<U, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, C2> + SameNumberOfColumns<C, R2>,
|
ShapeConstraint: DimEq<R, C2> + SameNumberOfColumns<C, R2>,
|
||||||
|
|
|
@ -59,11 +59,12 @@ impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a column vector resulting from the folding of `f` on each column of this matrix.
|
/// Returns a column vector resulting from the folding of `f` on each column of this matrix.
|
||||||
|
// BEEEEP!!!! Pretty sure there's something fishy here.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn compress_columns(
|
pub fn compress_columns(
|
||||||
&self,
|
&self,
|
||||||
init: OVector<T, R>,
|
mut 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
|
||||||
|
|
|
@ -278,7 +278,8 @@ impl<'a, T: Deserialize<'a>> Deserialize<'a> for DualQuaternion<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DualQuaternion<T> {
|
impl<T> DualQuaternion<T> {
|
||||||
fn to_vector(self) -> OVector<T, U8> {
|
// TODO: Cloning shouldn't be necessary.
|
||||||
|
fn to_vector(self) -> OVector<T, U8>where T:Clone {
|
||||||
(*self.as_ref()).into()
|
(*self.as_ref()).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,9 @@ impl<T: Copy> Copy for Orthographic3<T> {}
|
||||||
impl<T: Clone> Clone for Orthographic3<T> {
|
impl<T: Clone> Clone for Orthographic3<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self::from_matrix_unchecked(self.matrix)
|
Self {
|
||||||
|
matrix: self.matrix.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ where
|
||||||
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
|
let mut res = OVector::<_, DimNameSum<D, U1>>::new_uninitialized();
|
||||||
for i in 0..D::dim() {
|
for i in 0..D::dim() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked(i) = MaybeUninit::new(self.coords[i].clone());
|
*res.get_unchecked_mut(i) = MaybeUninit::new(self.coords[i].clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,15 +236,16 @@ where
|
||||||
// to avoid double-dropping.
|
// to avoid double-dropping.
|
||||||
for i in 0..D::dim() {
|
for i in 0..D::dim() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked(i) = MaybeUninit::new(self.coords[i]);
|
*res.get_unchecked_mut(i) = MaybeUninit::new(*self.coords.get_unchecked(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix double drop
|
// Fix double drop
|
||||||
|
|
||||||
res[(D::dim(), 0)] = MaybeUninit::new(T::one());
|
unsafe {
|
||||||
|
*res.get_unchecked_mut(D::dim()) = MaybeUninit::new(T::one());
|
||||||
unsafe { res.assume_init() }
|
res.assume_init()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new point with the given coordinates.
|
/// Creates a new point with the given coordinates.
|
||||||
|
|
|
@ -91,7 +91,8 @@ 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, 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()
|
||||||
|
|
|
@ -550,8 +550,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, D, D>
|
+ Allocator<T, DimNameSum<Const<D>, U1>>,
|
||||||
// + Allocator<T, D>
|
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Clone,
|
||||||
{
|
{
|
||||||
/// 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
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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::Owned;
|
||||||
|
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
|
Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
|
||||||
|
@ -586,7 +586,8 @@ 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>>,
|
||||||
|
Owned<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() };
|
||||||
|
|
|
@ -26,8 +26,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>,
|
T2: SupersetOf<T1>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> Translation<T2, D> {
|
fn to_superset(&self) -> Translation<T2, D> {
|
||||||
|
@ -215,7 +215,10 @@ impl<T, const D: usize> From<Point<T, D>> for Translation<T, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const D: usize> From<Translation<T, D>> for [T; D] {
|
impl<T, 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()
|
||||||
|
|
|
@ -185,11 +185,13 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bidiagonal {
|
unsafe {
|
||||||
uv: matrix,
|
Bidiagonal {
|
||||||
diagonal: diagonal.assume_init(),
|
uv: matrix,
|
||||||
off_diagonal: off_diagonal.assume_init(),
|
diagonal: diagonal.assume_init(),
|
||||||
upper_diagonal,
|
off_diagonal: off_diagonal.assume_init(),
|
||||||
|
upper_diagonal,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +302,7 @@ where
|
||||||
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_init_from(&axis);
|
||||||
let mut axis_packed = unsafe { axis_packed.slice_assume_init() };
|
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());
|
||||||
|
|
|
@ -307,7 +307,7 @@ where
|
||||||
);
|
);
|
||||||
chol.slice_range_mut(j + 1.., j).copy_init_from(&new_colj);
|
chol.slice_range_mut(j + 1.., j).copy_init_from(&new_colj);
|
||||||
|
|
||||||
let chol = unsafe { chol.assume_init() };
|
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..);
|
||||||
|
@ -348,7 +348,7 @@ where
|
||||||
.copy_init_from(&self.chol.slice_range(j + 1.., ..j));
|
.copy_init_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_init_from(&self.chol.slice_range(j + 1.., j + 1..));
|
||||||
let chol = unsafe { chol.assume_init() };
|
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..);
|
||||||
|
|
|
@ -99,11 +99,11 @@ where
|
||||||
/// Creates a new sequence of D identity permutations.
|
/// Creates a new sequence of D identity permutations.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn identity_generic(dim: D) -> Self {
|
pub fn identity_generic(dim: D) -> Self {
|
||||||
unsafe {
|
|
||||||
Self {
|
Self {
|
||||||
len: 0,
|
len: 0,
|
||||||
ipiv: OVector::new_uninitialized_generic(dim, Const::<1>),
|
ipiv: OVector::new_uninitialized_generic(dim, Const::<1>),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,18 +40,24 @@ 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 = self.clone_owned();
|
|
||||||
|
// TODO: ACTUALLY MAKE BUF USEFUL! BEEEEEEEEP!!
|
||||||
|
|
||||||
// Exponentiation by squares.
|
// Exponentiation by squares.
|
||||||
loop {
|
loop {
|
||||||
if e % two == one {
|
if e % two == one {
|
||||||
|
let mut buf = Matrix::new_uninitialized_generic(nrows, ncols);
|
||||||
self.mul_to(&multiplier, &mut buf);
|
self.mul_to(&multiplier, &mut buf);
|
||||||
|
let buf = unsafe { buf.assume_init() };
|
||||||
self.copy_from(&buf);
|
self.copy_from(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
e /= two;
|
e /= two;
|
||||||
|
let mut buf = Matrix::new_uninitialized_generic(nrows, ncols);
|
||||||
multiplier.mul_to(&multiplier, &mut buf);
|
multiplier.mul_to(&multiplier, &mut buf);
|
||||||
|
let buf = unsafe { buf.assume_init() };
|
||||||
multiplier.copy_from(&buf);
|
multiplier.copy_from(&buf);
|
||||||
|
|
||||||
if e == zero {
|
if e == zero {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
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};
|
||||||
|
@ -6,7 +8,7 @@ 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::{Storage, StorageMut};
|
use crate::storage::{Owned, Storage, StorageMut};
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
|
@ -28,8 +30,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: ComplexField, R: DimMin<C>, C: Dim>
|
pub struct QR<T, 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>>,
|
||||||
{
|
{
|
||||||
|
@ -37,14 +39,42 @@ 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>>,
|
||||||
OMatrix<T, R, C>: Copy,
|
Owned<T, R, C>: Copy,
|
||||||
OVector<T, DimMinimum<R, C>>: Copy,
|
Owned<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>>,
|
||||||
|
Owned<T, R, C>: Clone,
|
||||||
|
Owned<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>>,
|
||||||
|
Owned<T, R, C>: fmt::Debug,
|
||||||
|
Owned<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
|
||||||
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<T, R, C> + Allocator<T, R> + Allocator<T, DimMinimum<R, C>>,
|
||||||
|
@ -54,18 +84,23 @@ where
|
||||||
let (nrows, ncols) = matrix.data.shape();
|
let (nrows, ncols) = matrix.data.shape();
|
||||||
let min_nrows_ncols = nrows.min(ncols);
|
let min_nrows_ncols = nrows.min(ncols);
|
||||||
|
|
||||||
let mut diag =
|
let mut diag = Matrix::new_uninitialized_generic(min_nrows_ncols, Const::<1>);
|
||||||
unsafe { crate::unimplemented_or_uninitialized_generic!(min_nrows_ncols, Const::<1>) };
|
|
||||||
|
|
||||||
if min_nrows_ncols.value() == 0 {
|
if min_nrows_ncols.value() == 0 {
|
||||||
return QR { qr: matrix, diag };
|
return Self {
|
||||||
|
qr: matrix,
|
||||||
|
diag: unsafe { diag.assume_init() },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..min_nrows_ncols.value() {
|
for i in 0..min_nrows_ncols.value() {
|
||||||
householder::clear_column_unchecked(&mut matrix, &mut diag[i], i, 0, None);
|
householder::clear_column_unchecked(&mut matrix, diag[i].as_mut_ptr(), i, 0, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
QR { qr: matrix, diag }
|
Self {
|
||||||
|
qr: matrix,
|
||||||
|
diag: unsafe { diag.assume_init() },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
|
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
#![allow(clippy::suspicious_operation_groupings)]
|
#![allow(clippy::suspicious_operation_groupings)]
|
||||||
|
use std::cmp;
|
||||||
|
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 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 std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
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::Storage;
|
use crate::base::storage::{Owned, Storage};
|
||||||
use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3};
|
use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3};
|
||||||
|
|
||||||
use crate::geometry::Reflection;
|
use crate::geometry::Reflection;
|
||||||
|
@ -32,8 +34,7 @@ use crate::linalg::Hessenberg;
|
||||||
serde(bound(deserialize = "DefaultAllocator: Allocator<T, D, D>,
|
serde(bound(deserialize = "DefaultAllocator: Allocator<T, D, D>,
|
||||||
OMatrix<T, D, D>: Deserialize<'de>"))
|
OMatrix<T, D, D>: Deserialize<'de>"))
|
||||||
)]
|
)]
|
||||||
#[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>,
|
||||||
{
|
{
|
||||||
|
@ -41,13 +42,39 @@ where
|
||||||
t: OMatrix<T, D, D>,
|
t: OMatrix<T, D, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> Copy for Schur<T, D>
|
impl<T: Copy, D: Dim> Copy for Schur<T, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, D, D>,
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
OMatrix<T, D, D>: Copy,
|
Owned<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone, D: Dim> Clone for Schur<T, D>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, D, D>,
|
||||||
|
Owned<T, D, D>: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
q: self.q.clone(),
|
||||||
|
t: self.t.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug, D: Dim> fmt::Debug for Schur<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("Schur")
|
||||||
|
.field("q", &self.q)
|
||||||
|
.field("t", &self.t)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, D: Dim> Schur<T, D>
|
impl<T: ComplexField, D: Dim> Schur<T, D>
|
||||||
where
|
where
|
||||||
D: DimSub<U1>, // For Hessenberg.
|
D: DimSub<U1>, // For Hessenberg.
|
||||||
|
@ -73,8 +100,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 =
|
let mut work = OVector::new_uninitialized_generic(m.data.shape().0, Const::<1>);
|
||||||
unsafe { crate::unimplemented_or_uninitialized_generic!(m.data.shape().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 })
|
||||||
|
@ -82,7 +108,7 @@ where
|
||||||
|
|
||||||
fn do_decompose(
|
fn do_decompose(
|
||||||
mut m: OMatrix<T, D, D>,
|
mut m: OMatrix<T, D, D>,
|
||||||
work: &mut OVector<T, D>,
|
work: &mut OVector<MaybeUninit<T>, D>,
|
||||||
eps: T::RealField,
|
eps: T::RealField,
|
||||||
max_niter: usize,
|
max_niter: usize,
|
||||||
compute_q: bool,
|
compute_q: bool,
|
||||||
|
@ -271,7 +297,9 @@ 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<T, D>) -> bool {
|
fn do_eigenvalues(t: &OMatrix<T, D, D>, out: &mut OVector<MaybeUninit<T>, D>) -> bool {
|
||||||
|
// TODO: check dropping stuff.
|
||||||
|
|
||||||
let dim = t.nrows();
|
let dim = t.nrows();
|
||||||
let mut m = 0;
|
let mut m = 0;
|
||||||
|
|
||||||
|
@ -279,7 +307,7 @@ where
|
||||||
let n = m + 1;
|
let n = m + 1;
|
||||||
|
|
||||||
if t[(n, m)].is_zero() {
|
if t[(n, m)].is_zero() {
|
||||||
out[m] = t[(m, m)];
|
out[m] = MaybeUninit::new(t[(m, m)]);
|
||||||
m += 1;
|
m += 1;
|
||||||
} else {
|
} else {
|
||||||
// Complex eigenvalue.
|
// Complex eigenvalue.
|
||||||
|
@ -288,7 +316,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if m == dim - 1 {
|
if m == dim - 1 {
|
||||||
out[m] = t[(m, m)];
|
out[m] = MaybeUninit::new(t[(m, m)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -297,11 +325,13 @@ where
|
||||||
/// 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>,
|
t: &OMatrix<T, D, D>,
|
||||||
out: &mut OVector<NumComplex<T>, D>,
|
out: &mut OVector<MaybeUninit<NumComplex<T>>, D>,
|
||||||
) where
|
) 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;
|
||||||
|
|
||||||
|
@ -309,7 +339,7 @@ where
|
||||||
let n = m + 1;
|
let n = m + 1;
|
||||||
|
|
||||||
if t[(n, m)].is_zero() {
|
if t[(n, m)].is_zero() {
|
||||||
out[m] = NumComplex::new(t[(m, m)], T::zero());
|
out[m] = MaybeUninit::new(NumComplex::new(t[(m, m)], T::zero()));
|
||||||
m += 1;
|
m += 1;
|
||||||
} else {
|
} else {
|
||||||
// Solve the 2x2 eigenvalue subproblem.
|
// Solve the 2x2 eigenvalue subproblem.
|
||||||
|
@ -391,11 +421,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 = unsafe {
|
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>);
|
||||||
crate::unimplemented_or_uninitialized_generic!(self.t.data.shape().0, Const::<1>)
|
|
||||||
};
|
|
||||||
if Self::do_eigenvalues(&self.t, &mut out) {
|
if Self::do_eigenvalues(&self.t, &mut out) {
|
||||||
Some(out)
|
Some(unsafe { out.assume_init() })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -408,11 +436,9 @@ where
|
||||||
T: RealField,
|
T: RealField,
|
||||||
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
||||||
{
|
{
|
||||||
let mut out = unsafe {
|
let mut out = OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>);
|
||||||
crate::unimplemented_or_uninitialized_generic!(self.t.data.shape().0, Const::<1>)
|
|
||||||
};
|
|
||||||
Self::do_complex_eigenvalues(&self.t, &mut out);
|
Self::do_complex_eigenvalues(&self.t, &mut out);
|
||||||
out
|
unsafe { out.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,14 +543,14 @@ 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 = unsafe {
|
let mut work = OVector::new_uninitialized_generic(self.data.shape().0, Const::<1>);
|
||||||
crate::unimplemented_or_uninitialized_generic!(self.data.shape().0, Const::<1>)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Special case for 2x2 matrices.
|
// Special case for 2x2 matrices.
|
||||||
if self.nrows() == 2 {
|
if self.nrows() == 2 {
|
||||||
|
@ -533,9 +559,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] = a;
|
work[0] = MaybeUninit::new(a);
|
||||||
work[1] = b;
|
work[1] = MaybeUninit::new(b);
|
||||||
Some(work)
|
Some(unsafe { work.assume_init() })
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
@ -551,7 +577,7 @@ where
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if Schur::do_eigenvalues(&schur.1, &mut work) {
|
if Schur::do_eigenvalues(&schur.1, &mut work) {
|
||||||
Some(work)
|
Some(unsafe { work.assume_init() })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -566,7 +592,7 @@ where
|
||||||
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
DefaultAllocator: Allocator<NumComplex<T>, D>,
|
||||||
{
|
{
|
||||||
let dim = self.data.shape().0;
|
let dim = self.data.shape().0;
|
||||||
let mut work = unsafe { crate::unimplemented_or_uninitialized_generic!(dim, Const::<1>) };
|
let mut work = OVector::new_uninitialized_generic(dim, Const::<1>);
|
||||||
|
|
||||||
let schur = Schur::do_decompose(
|
let schur = Schur::do_decompose(
|
||||||
self.clone_owned(),
|
self.clone_owned(),
|
||||||
|
@ -576,8 +602,8 @@ where
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut eig = unsafe { crate::unimplemented_or_uninitialized_generic!(dim, Const::<1>) };
|
let mut eig = OVector::new_uninitialized_generic(dim, Const::<1>);
|
||||||
Schur::do_complex_eigenvalues(&schur.1, &mut eig);
|
Schur::do_complex_eigenvalues(&schur.1, &mut eig);
|
||||||
eig
|
unsafe { eig.assume_init() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -8,7 +10,7 @@ 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, DimSub, U1};
|
use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
|
||||||
use crate::storage::Storage;
|
use crate::storage::{Owned, Storage};
|
||||||
use simba::scalar::{ComplexField, RealField};
|
use simba::scalar::{ComplexField, RealField};
|
||||||
|
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
|
@ -39,7 +41,6 @@ use crate::linalg::Bidiagonal;
|
||||||
OVector<T::RealField, DimMinimum<R, C>>: Deserialize<'de>"
|
OVector<T::RealField, DimMinimum<R, C>>: Deserialize<'de>"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct SVD<T: ComplexField, R: DimMin<C>, C: Dim>
|
pub struct SVD<T: ComplexField, R: DimMin<C>, C: Dim>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
||||||
|
@ -59,12 +60,48 @@ 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>>,
|
||||||
OMatrix<T, R, DimMinimum<R, C>>: Copy,
|
Owned<T, R, DimMinimum<R, C>>: Copy,
|
||||||
OMatrix<T, DimMinimum<R, C>, C>: Copy,
|
Owned<T, DimMinimum<R, C>, C>: Copy,
|
||||||
OVector<T::RealField, DimMinimum<R, C>>: Copy,
|
Owned<T::RealField, DimMinimum<R, C>>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> Clone for SVD<T, R, C>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
||||||
|
+ Allocator<T, R, DimMinimum<R, C>>
|
||||||
|
+ Allocator<T::RealField, DimMinimum<R, C>>,
|
||||||
|
Owned<T, R, DimMinimum<R, C>>: Clone,
|
||||||
|
Owned<T, DimMinimum<R, C>, C>: Clone,
|
||||||
|
Owned<T::RealField, DimMinimum<R, C>>: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
u: self.u.clone(),
|
||||||
|
v_t: self.v_t.clone(),
|
||||||
|
singular_values: self.singular_values.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> fmt::Debug for SVD<T, R, C>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
|
||||||
|
+ Allocator<T, R, DimMinimum<R, C>>
|
||||||
|
+ Allocator<T::RealField, DimMinimum<R, C>>,
|
||||||
|
Owned<T, R, DimMinimum<R, C>>: fmt::Debug,
|
||||||
|
Owned<T, DimMinimum<R, C>, C>: fmt::Debug,
|
||||||
|
Owned<T::RealField, DimMinimum<R, C>>: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SVD")
|
||||||
|
.field("u", &self.u)
|
||||||
|
.field("v_t", &self.v_t)
|
||||||
|
.field("singular_values", &self.singular_values)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, R: DimMin<C>, C: Dim> SVD<T, R, C>
|
impl<T: ComplexField, R: DimMin<C>, C: Dim> SVD<T, R, C>
|
||||||
where
|
where
|
||||||
DimMinimum<R, C>: DimSub<U1>, // for Bidiagonal.
|
DimMinimum<R, C>: DimSub<U1>, // for Bidiagonal.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize-no-std")]
|
#[cfg(feature = "serde-serialize-no-std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -7,7 +9,7 @@ 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, DimSub, U1};
|
use crate::dimension::{Dim, DimDiff, DimSub, U1};
|
||||||
use crate::storage::Storage;
|
use crate::storage::{Owned, Storage};
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::linalg::givens::GivensRotation;
|
use crate::linalg::givens::GivensRotation;
|
||||||
|
@ -29,7 +31,6 @@ 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>,
|
||||||
|
@ -44,11 +45,39 @@ where
|
||||||
impl<T: ComplexField, D: Dim> 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>,
|
||||||
OMatrix<T, D, D>: Copy,
|
Owned<T, D, D>: Copy,
|
||||||
OVector<T::RealField, D>: Copy,
|
Owned<T::RealField, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ComplexField, D: Dim> Clone for SymmetricEigen<T, D>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, D, D> + Allocator<T::RealField, D>,
|
||||||
|
Owned<T, D, D>: Clone,
|
||||||
|
Owned<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>,
|
||||||
|
Owned<T, D, D>: fmt::Debug,
|
||||||
|
Owned<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>,
|
||||||
|
@ -270,7 +299,10 @@ 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
|
||||||
|
Owned<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,10 +1,13 @@
|
||||||
|
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::Storage;
|
use crate::storage::{Owned, Storage};
|
||||||
use simba::scalar::ComplexField;
|
use simba::scalar::ComplexField;
|
||||||
|
|
||||||
use crate::linalg::householder;
|
use crate::linalg::householder;
|
||||||
|
@ -25,8 +28,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 SymmetricTridiagonal<T, D: DimSub<U1>>
|
||||||
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>>,
|
||||||
{
|
{
|
||||||
|
@ -34,14 +36,42 @@ where
|
||||||
off_diagonal: OVector<T, DimDiff<D, U1>>,
|
off_diagonal: OVector<T, DimDiff<D, U1>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ComplexField, D: DimSub<U1>> Copy for SymmetricTridiagonal<T, D>
|
impl<T: Copy, 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>>,
|
||||||
OMatrix<T, D, D>: Copy,
|
Owned<T, D, D>: Copy,
|
||||||
OVector<T, DimDiff<D, U1>>: Copy,
|
Owned<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>>,
|
||||||
|
Owned<T, D, D>: Clone,
|
||||||
|
Owned<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>>,
|
||||||
|
Owned<T, D, D>: fmt::Debug,
|
||||||
|
Owned<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>>,
|
||||||
|
@ -61,24 +91,21 @@ 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 = unsafe {
|
let mut off_diagonal = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
|
||||||
crate::unimplemented_or_uninitialized_generic!(dim.sub(Const::<1>), Const::<1>)
|
let mut p = OVector::new_uninitialized_generic(dim.sub(Const::<1>), Const::<1>);
|
||||||
};
|
|
||||||
let mut p = unsafe {
|
|
||||||
crate::unimplemented_or_uninitialized_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..);
|
||||||
let (mut axis, mut m) = m.columns_range_pair_mut(i, i + 1..);
|
let (mut axis, mut m) = m.columns_range_pair_mut(i, i + 1..);
|
||||||
|
|
||||||
let (norm, not_zero) = householder::reflection_axis_mut(&mut axis);
|
let (norm, not_zero) = householder::reflection_axis_mut(&mut axis);
|
||||||
off_diagonal[i] = norm;
|
off_diagonal[i] = MaybeUninit::new(norm);
|
||||||
|
|
||||||
if not_zero {
|
if not_zero {
|
||||||
let mut p = p.rows_range_mut(i..);
|
let mut p = p.rows_range_mut(i..);
|
||||||
|
|
||||||
p.hegemv(crate::convert(2.0), &m, &axis, T::zero());
|
p.hegemv_z(crate::convert(2.0), &m, &axis);
|
||||||
|
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());
|
||||||
|
@ -89,7 +116,7 @@ where
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tri: m,
|
tri: m,
|
||||||
off_diagonal,
|
off_diagonal: unsafe { off_diagonal.assume_init() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
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;
|
use crate::dimension::Dim;
|
||||||
use crate::storage::Storage;
|
use crate::storage::{Owned, Storage};
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::RealField;
|
||||||
|
|
||||||
/// UDU factorization.
|
/// UDU factorization.
|
||||||
|
@ -19,8 +21,7 @@ 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>"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug)]
|
pub struct UDU<T, D: Dim>
|
||||||
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>,
|
||||||
{
|
{
|
||||||
|
@ -30,14 +31,42 @@ where
|
||||||
pub d: OVector<T, D>,
|
pub d: OVector<T, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RealField, D: Dim> Copy for UDU<T, D>
|
impl<T: Copy, 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>,
|
||||||
OVector<T, D>: Copy,
|
Owned<T, D>: Copy,
|
||||||
OMatrix<T, D, D>: Copy,
|
Owned<T, D, D>: Copy,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone, D: Dim> Clone for UDU<T, D>
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<T, D> + Allocator<T, D, D>,
|
||||||
|
Owned<T, D>: Clone,
|
||||||
|
Owned<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>,
|
||||||
|
Owned<T, D>: fmt::Debug,
|
||||||
|
Owned<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>,
|
||||||
|
|
Loading…
Reference in New Issue