Remove all spurious allocation introduced by complex number support on decompositions.
This commit is contained in:
parent
921a05d523
commit
ce24ea972e
|
@ -253,7 +253,7 @@ where
|
||||||
/// be determined.
|
/// be determined.
|
||||||
///
|
///
|
||||||
/// Returns `false` if no solution was found (the decomposed matrix is singular).
|
/// Returns `false` if no solution was found (the decomposed matrix is singular).
|
||||||
pub fn solve_conjugate_transpose_mut<R2: Dim, C2: Dim>(
|
pub fn solve_adjoint_mut<R2: Dim, C2: Dim>(
|
||||||
&self,
|
&self,
|
||||||
b: &mut MatrixMN<N, R2, C2>,
|
b: &mut MatrixMN<N, R2, C2>,
|
||||||
) -> bool
|
) -> bool
|
||||||
|
|
|
@ -585,7 +585,7 @@ where
|
||||||
a: &SquareMatrix<N, D2, SB>,
|
a: &SquareMatrix<N, D2, SB>,
|
||||||
x: &Vector<N, D3, SC>,
|
x: &Vector<N, D3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
dotc: impl Fn(&DVectorSlice<N, SB::RStride, SB::CStride>, &DVectorSlice<N, SC::RStride, SC::CStride>) -> N,
|
dot: impl Fn(&DVectorSlice<N, SB::RStride, SB::CStride>, &DVectorSlice<N, SC::RStride, SC::CStride>) -> N,
|
||||||
) where
|
) where
|
||||||
N: One,
|
N: One,
|
||||||
SB: Storage<N, D2, D2>,
|
SB: Storage<N, D2, D2>,
|
||||||
|
@ -613,11 +613,11 @@ where
|
||||||
let col2 = a.column(0);
|
let col2 = a.column(0);
|
||||||
let val = unsafe { *x.vget_unchecked(0) };
|
let val = unsafe { *x.vget_unchecked(0) };
|
||||||
self.axpy(alpha * val, &col2, beta);
|
self.axpy(alpha * val, &col2, beta);
|
||||||
self[0] += alpha * dotc(&a.slice_range(1.., 0), &x.rows_range(1..));
|
self[0] += alpha * dot(&a.slice_range(1.., 0), &x.rows_range(1..));
|
||||||
|
|
||||||
for j in 1..dim2 {
|
for j in 1..dim2 {
|
||||||
let col2 = a.column(j);
|
let col2 = a.column(j);
|
||||||
let dot = dotc(&col2.rows_range(j..), &x.rows_range(j..));
|
let dot = dot(&col2.rows_range(j..), &x.rows_range(j..));
|
||||||
|
|
||||||
let val;
|
let val;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -1083,7 +1083,7 @@ impl<N, R1: Dim, C1: Dim, S: StorageMut<N, R1, C1>> Matrix<N, R1, C1, S>
|
||||||
where N: Scalar + Zero + ClosedAdd + ClosedMul
|
where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sygerx<D2: Dim, D3: Dim, SB, SC>(
|
fn xxgerx<D2: Dim, D3: Dim, SB, SC>(
|
||||||
&mut self,
|
&mut self,
|
||||||
alpha: N,
|
alpha: N,
|
||||||
x: &Vector<N, D2, SB>,
|
x: &Vector<N, D2, SB>,
|
||||||
|
@ -1186,7 +1186,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
||||||
{
|
{
|
||||||
self.sygerx(alpha, x, y, beta, |e| e)
|
self.xxgerx(alpha, x, y, beta, |e| e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric**
|
/// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric**
|
||||||
|
@ -1221,7 +1221,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
||||||
{
|
{
|
||||||
self.sygerx(alpha, x, y, beta, Complex::conjugate)
|
self.xxgerx(alpha, x, y, beta, Complex::conjugate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,10 +137,10 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, 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<N, R2, S2>)
|
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<N, R2, S2>)
|
||||||
where
|
where
|
||||||
R: DimMin<C>,
|
R: DimMin<C>,
|
||||||
S2: Storage<N, R2>,
|
S2: Storage<N, R2>,
|
||||||
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
|
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
let min_nrows_ncols = cmp::min(nrows, ncols);
|
let min_nrows_ncols = cmp::min(nrows, ncols);
|
||||||
|
@ -151,6 +151,21 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fills the diagonal of this matrix with the content of the given iterator.
|
||||||
|
///
|
||||||
|
/// This will fill as many diagonal elements as the iterator yields, up to the
|
||||||
|
/// minimum of the number of rows and columns of `self`, and starting with the
|
||||||
|
/// diagonal element at index (0, 0).
|
||||||
|
#[inline]
|
||||||
|
pub fn set_partial_diagonal(&mut self, diag: impl Iterator<Item = N>) {
|
||||||
|
let (nrows, ncols) = self.shape();
|
||||||
|
let min_nrows_ncols = cmp::min(nrows, ncols);
|
||||||
|
|
||||||
|
for (i, val) in diag.enumerate().take(min_nrows_ncols) {
|
||||||
|
unsafe { *self.get_unchecked_mut((i, i)) = val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Fills the selected row of this matrix with the content of the given vector.
|
/// Fills the selected row of this matrix with the content of the given vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<N, C2, S2>)
|
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<N, C2, S2>)
|
||||||
|
|
|
@ -981,14 +981,14 @@ impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
self.map(|e| e.conjugate())
|
self.map(|e| e.conjugate())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides each component of `self` by the given real.
|
/// Divides each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unscale(&self, real: N::Real) -> MatrixMN<N, R, C>
|
pub fn unscale(&self, real: N::Real) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
self.map(|e| e.unscale(real))
|
self.map(|e| e.unscale(real))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiplies each component of `self` by the given real.
|
/// Multiplies each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&self, real: N::Real) -> MatrixMN<N, R, C>
|
pub fn scale(&self, real: N::Real) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
|
@ -997,19 +997,19 @@ impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// The conjugate of `self` computed in-place.
|
/// The conjugate of the complex matrix `self` computed in-place.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn conjugate_mut(&mut self) {
|
pub fn conjugate_mut(&mut self) {
|
||||||
self.apply(|e| e.conjugate())
|
self.apply(|e| e.conjugate())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides each component of `self` by the given real.
|
/// Divides each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unscale_mut(&mut self, real: N::Real) {
|
pub fn unscale_mut(&mut self, real: N::Real) {
|
||||||
self.apply(|e| e.unscale(real))
|
self.apply(|e| e.unscale(real))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiplies each component of `self` by the given real.
|
/// Multiplies each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_mut(&mut self, real: N::Real) {
|
pub fn scale_mut(&mut self, real: N::Real) {
|
||||||
self.apply(|e| e.scale(real))
|
self.apply(|e| e.scale(real))
|
||||||
|
@ -1017,8 +1017,14 @@ impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Complex, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
impl<N: Complex, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
/// Sets `self` to its conjugate transpose.
|
/// Sets `self` to its adjoint.
|
||||||
pub fn conjugate_transpose_mut(&mut self) {
|
#[deprecated(note = "Renamed to `self.adjoint_mut()`.")]
|
||||||
|
pub fn conjugate_transform_mut(&mut self) {
|
||||||
|
self.adjoint_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets `self` to its adjoint (aka. conjugate-transpose).
|
||||||
|
pub fn adjoint_mut(&mut self) {
|
||||||
assert!(
|
assert!(
|
||||||
self.is_square(),
|
self.is_square(),
|
||||||
"Unable to transpose a non-square matrix in-place."
|
"Unable to transpose a non-square matrix in-place."
|
||||||
|
@ -1027,11 +1033,6 @@ impl<N: Complex, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
let dim = self.shape().0;
|
let dim = self.shape().0;
|
||||||
|
|
||||||
for i in 0..dim {
|
for i in 0..dim {
|
||||||
{
|
|
||||||
let diag = unsafe { self.get_unchecked_mut((i, i)) };
|
|
||||||
*diag = diag.conjugate();
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in 0..i {
|
for j in 0..i {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ref_ij = self.get_unchecked_mut((i, j)) as *mut N;
|
let ref_ij = self.get_unchecked_mut((i, j)) as *mut N;
|
||||||
|
@ -1042,6 +1043,11 @@ impl<N: Complex, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
*ref_ji = conj_ij;
|
*ref_ji = conj_ij;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let diag = unsafe { self.get_unchecked_mut((i, i)) };
|
||||||
|
*diag = diag.conjugate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1614,10 +1620,10 @@ impl<N: Complex, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, D>,
|
DefaultAllocator: Allocator<N, D>,
|
||||||
{
|
{
|
||||||
let c_hang = self.dotc(rhs).real();
|
let (c_hang, c_hang_sign) = self.dotc(rhs).to_exp();
|
||||||
|
|
||||||
// self == other
|
// self == other
|
||||||
if c_hang.abs() >= N::Real::one() {
|
if c_hang >= N::Real::one() {
|
||||||
return Some(Unit::new_unchecked(self.clone_owned()));
|
return Some(Unit::new_unchecked(self.clone_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1630,7 +1636,8 @@ impl<N: Complex, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
|
||||||
} else {
|
} else {
|
||||||
let ta = ((N::Real::one() - t) * hang).sin() / s_hang;
|
let ta = ((N::Real::one() - t) * hang).sin() / s_hang;
|
||||||
let tb = (t * hang).sin() / s_hang;
|
let tb = (t * hang).sin() / s_hang;
|
||||||
let res = &**self * N::from_real(ta) + &**rhs * N::from_real(tb);
|
let mut res = self.scale(ta);
|
||||||
|
res.axpy(c_hang_sign.scale(tb), &**rhs, N::one());
|
||||||
|
|
||||||
Some(Unit::new_unchecked(res))
|
Some(Unit::new_unchecked(res))
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
let v = &vs[0];
|
let v = &vs[0];
|
||||||
let mut a;
|
let mut a;
|
||||||
|
|
||||||
if v[0].modulus() > v[1].modulus() {
|
if v[0].norm1() > v[1].norm1() {
|
||||||
a = Self::from_column_slice(&[v[2], N::zero(), -v[0]]);
|
a = Self::from_column_slice(&[v[2], N::zero(), -v[0]]);
|
||||||
} else {
|
} else {
|
||||||
a = Self::from_column_slice(&[N::zero(), -v[2], v[1]]);
|
a = Self::from_column_slice(&[N::zero(), -v[2], v[1]]);
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl<N: Complex> Norm<N> for EuclideanNorm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::Real
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::Real
|
||||||
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
||||||
m.dotc(m).real().sqrt()
|
m.norm_squared().sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -43,7 +43,7 @@ impl<N: Complex> Norm<N> for EuclideanNorm {
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
||||||
m1.zip_fold(m2, N::Real::zero(), |acc, a, b| {
|
m1.zip_fold(m2, N::Real::zero(), |acc, a, b| {
|
||||||
let diff = a - b;
|
let diff = a - b;
|
||||||
acc + (diff.conjugate() * diff).real()
|
acc + diff.modulus_squared()
|
||||||
}).sqrt()
|
}).sqrt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,8 @@ impl<N: Complex> Norm<N> for UniformNorm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::Real
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::Real
|
||||||
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
||||||
|
// NOTE: we don't use `m.amax()` here because for the complex
|
||||||
|
// numbers this will return the max norm1 instead of the modulus.
|
||||||
m.fold(N::Real::zero(), |acc, a| acc.max(a.modulus()))
|
m.fold(N::Real::zero(), |acc, a| acc.max(a.modulus()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize(&self) -> MatrixMN<N, R, C>
|
pub fn normalize(&self) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
self.map(|e| e.unscale(self.norm()))
|
self.unscale(self.norm())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
|
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
|
||||||
|
@ -199,7 +201,7 @@ impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
if n <= min_norm {
|
if n <= min_norm {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.map(|e| e.unscale(n)))
|
Some(self.unscale(n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +218,7 @@ impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize_mut(&mut self) -> N::Real {
|
pub fn normalize_mut(&mut self) -> N::Real {
|
||||||
let n = self.norm();
|
let n = self.norm();
|
||||||
self.apply(|e| e.unscale(n));
|
self.unscale_mut(n);
|
||||||
|
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
@ -231,7 +233,7 @@ impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
if n <= min_norm {
|
if n <= min_norm {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.apply(|e| e.unscale(n));
|
self.unscale_mut(n);
|
||||||
Some(n)
|
Some(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl<N: Complex, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let m_two: N = ::convert(-2.0f64);
|
let m_two: N = ::convert(-2.0f64);
|
||||||
lhs.ger(m_two, &work, &self.axis.conjugate(), N::one());
|
lhs.gerc(m_two, &work, &self.axis, N::one());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the reflection to the rows of `lhs`.
|
/// Applies the reflection to the rows of `lhs`.
|
||||||
|
@ -118,6 +118,6 @@ impl<N: Complex, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let m_two = sign.scale(::convert(-2.0f64));
|
let m_two = sign.scale(::convert(-2.0f64));
|
||||||
lhs.ger(m_two, &work, &self.axis.conjugate(), sign);
|
lhs.gerc(m_two, &work, &self.axis, sign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,9 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
|
||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
use base::allocator::Allocator;
|
use base::allocator::Allocator;
|
||||||
use base::constraint::{DimEq, ShapeConstraint};
|
use base::dimension::{U1, U2};
|
||||||
use base::dimension::{Dim, U1, U2};
|
use base::storage::Storage;
|
||||||
use base::storage::{Storage, StorageMut};
|
use base::{DefaultAllocator, Unit, Vector, Vector2};
|
||||||
use base::{DefaultAllocator, Matrix, Unit, Vector, Vector2};
|
|
||||||
use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex};
|
use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -405,59 +404,3 @@ where DefaultAllocator: Allocator<N, U2, U2>
|
||||||
self.div_assign(rhs.to_rotation_matrix())
|
self.div_assign(rhs.to_rotation_matrix())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix = UnitComplex * Matrix
|
|
||||||
impl<N: Real> UnitComplex<N> {
|
|
||||||
/// Performs the multiplication `rhs = self * rhs` in-place.
|
|
||||||
pub fn rotate<R2: Dim, C2: Dim, S2: StorageMut<N, R2, C2>>(
|
|
||||||
&self,
|
|
||||||
rhs: &mut Matrix<N, R2, C2, S2>,
|
|
||||||
) where
|
|
||||||
ShapeConstraint: DimEq<R2, U2>,
|
|
||||||
{
|
|
||||||
assert_eq!(
|
|
||||||
rhs.nrows(),
|
|
||||||
2,
|
|
||||||
"Unit complex rotation: the input matrix must have exactly two rows."
|
|
||||||
);
|
|
||||||
let i = self.as_ref().im;
|
|
||||||
let r = self.as_ref().re;
|
|
||||||
|
|
||||||
for j in 0..rhs.ncols() {
|
|
||||||
unsafe {
|
|
||||||
let a = *rhs.get_unchecked((0, j));
|
|
||||||
let b = *rhs.get_unchecked((1, j));
|
|
||||||
|
|
||||||
*rhs.get_unchecked_mut((0, j)) = r * a - i * b;
|
|
||||||
*rhs.get_unchecked_mut((1, j)) = i * a + r * b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs the multiplication `lhs = lhs * self` in-place.
|
|
||||||
pub fn rotate_rows<R2: Dim, C2: Dim, S2: StorageMut<N, R2, C2>>(
|
|
||||||
&self,
|
|
||||||
lhs: &mut Matrix<N, R2, C2, S2>,
|
|
||||||
) where
|
|
||||||
ShapeConstraint: DimEq<C2, U2>,
|
|
||||||
{
|
|
||||||
assert_eq!(
|
|
||||||
lhs.ncols(),
|
|
||||||
2,
|
|
||||||
"Unit complex rotation: the input matrix must have exactly two columns."
|
|
||||||
);
|
|
||||||
let i = self.as_ref().im;
|
|
||||||
let r = self.as_ref().re;
|
|
||||||
|
|
||||||
// FIXME: can we optimize that to iterate on one column at a time ?
|
|
||||||
for j in 0..lhs.nrows() {
|
|
||||||
unsafe {
|
|
||||||
let a = *lhs.get_unchecked((j, 0));
|
|
||||||
let b = *lhs.get_unchecked((j, 1));
|
|
||||||
|
|
||||||
*lhs.get_unchecked_mut((j, 0)) = r * a + i * b;
|
|
||||||
*lhs.get_unchecked_mut((j, 1)) = -i * a + r * b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -179,9 +179,6 @@ where
|
||||||
DefaultAllocator: Allocator<N, DimMinimum<R, C>, DimMinimum<R, C>>
|
DefaultAllocator: Allocator<N, DimMinimum<R, C>, DimMinimum<R, C>>
|
||||||
+ Allocator<N, R, DimMinimum<R, C>>
|
+ Allocator<N, R, DimMinimum<R, C>>
|
||||||
+ Allocator<N, DimMinimum<R, C>, C>,
|
+ Allocator<N, DimMinimum<R, C>, C>,
|
||||||
// FIXME: the following bounds are ugly.
|
|
||||||
DimMinimum<R, C>: DimMin<DimMinimum<R, C>, Output = DimMinimum<R, C>>,
|
|
||||||
ShapeConstraint: DimEq<Dynamic, DimDiff<DimMinimum<R, C>, U1>>,
|
|
||||||
{
|
{
|
||||||
// FIXME: optimize by calling a reallocator.
|
// FIXME: optimize by calling a reallocator.
|
||||||
(self.u(), self.d(), self.v_t())
|
(self.u(), self.d(), self.v_t())
|
||||||
|
@ -192,19 +189,16 @@ where
|
||||||
pub fn d(&self) -> MatrixN<N, DimMinimum<R, C>>
|
pub fn d(&self) -> MatrixN<N, DimMinimum<R, C>>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, DimMinimum<R, C>, DimMinimum<R, C>>,
|
DefaultAllocator: Allocator<N, DimMinimum<R, C>, DimMinimum<R, C>>,
|
||||||
// FIXME: the following bounds are ugly.
|
|
||||||
DimMinimum<R, C>: DimMin<DimMinimum<R, C>, Output = DimMinimum<R, C>>,
|
|
||||||
ShapeConstraint: DimEq<Dynamic, DimDiff<DimMinimum<R, C>, U1>>,
|
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.uv.data.shape();
|
let (nrows, ncols) = self.uv.data.shape();
|
||||||
|
|
||||||
let d = nrows.min(ncols);
|
let d = nrows.min(ncols);
|
||||||
let mut res = MatrixN::identity_generic(d, d);
|
let mut res = MatrixN::identity_generic(d, d);
|
||||||
res.set_diagonal(&self.diagonal.map(|e| N::from_real(e.modulus())));
|
res.set_partial_diagonal(self.diagonal.iter().map(|e| N::from_real(e.modulus())));
|
||||||
|
|
||||||
let start = self.axis_shift();
|
let start = self.axis_shift();
|
||||||
res.slice_mut(start, (d.value() - 1, d.value() - 1))
|
res.slice_mut(start, (d.value() - 1, d.value() - 1))
|
||||||
.set_diagonal(&self.off_diagonal.map(|e| N::from_real(e.modulus())));
|
.set_partial_diagonal(self.off_diagonal.iter().map(|e| N::from_real(e.modulus())));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,11 +70,12 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
|
|
||||||
let mut col = matrix.slice_range_mut(j + 1.., j);
|
let mut col = matrix.slice_range_mut(j + 1.., j);
|
||||||
col /= denom;
|
col /= denom;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The diagonal element is either zero or its square root could not
|
||||||
|
// be taken (e.g. for negative real numbers).
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> + Allocator<N, DimD
|
||||||
/// 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
|
||||||
/// hessenberg matrix.
|
/// hessenberg matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unpack(self) -> (MatrixN<N, D>, MatrixN<N, D>)
|
pub fn unpack(self) -> (MatrixN<N, D>, MatrixN<N, D>) {
|
||||||
where ShapeConstraint: DimEq<Dynamic, DimDiff<D, U1>> {
|
|
||||||
let q = self.q();
|
let q = self.q();
|
||||||
|
|
||||||
(q, self.unpack_h())
|
(q, self.unpack_h())
|
||||||
|
@ -101,13 +100,12 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> + Allocator<N, DimD
|
||||||
|
|
||||||
/// Retrieves the upper trapezoidal submatrix `H` of this decomposition.
|
/// Retrieves the upper trapezoidal submatrix `H` of this decomposition.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unpack_h(mut self) -> MatrixN<N, D>
|
pub fn unpack_h(mut self) -> MatrixN<N, D> {
|
||||||
where ShapeConstraint: DimEq<Dynamic, DimDiff<D, U1>> {
|
|
||||||
let dim = self.hess.nrows();
|
let dim = self.hess.nrows();
|
||||||
self.hess.fill_lower_triangle(N::zero(), 2);
|
self.hess.fill_lower_triangle(N::zero(), 2);
|
||||||
self.hess
|
self.hess
|
||||||
.slice_mut((1, 0), (dim - 1, dim - 1))
|
.slice_mut((1, 0), (dim - 1, dim - 1))
|
||||||
.set_diagonal(&self.subdiag.map(|e| N::from_real(e.modulus())));
|
.set_partial_diagonal(self.subdiag.iter().map(|e| N::from_real(e.modulus())));
|
||||||
self.hess
|
self.hess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +114,12 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> + Allocator<N, DimD
|
||||||
///
|
///
|
||||||
/// 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]
|
||||||
pub fn h(&self) -> MatrixN<N, D>
|
pub fn h(&self) -> MatrixN<N, D> {
|
||||||
where ShapeConstraint: DimEq<Dynamic, DimDiff<D, U1>> {
|
|
||||||
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(N::zero(), 2);
|
res.fill_lower_triangle(N::zero(), 2);
|
||||||
res.slice_mut((1, 0), (dim - 1, dim - 1))
|
res.slice_mut((1, 0), (dim - 1, dim - 1))
|
||||||
.set_diagonal(&self.subdiag.map(|e| N::from_real(e.modulus())));
|
.set_partial_diagonal(self.subdiag.iter().map(|e| N::from_real(e.modulus())));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,12 +79,10 @@ where DefaultAllocator: Allocator<N, R, C> + Allocator<N, R> + Allocator<N, DimM
|
||||||
pub fn r(&self) -> MatrixMN<N, DimMinimum<R, C>, C>
|
pub fn r(&self) -> MatrixMN<N, DimMinimum<R, C>, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, DimMinimum<R, C>, C>,
|
DefaultAllocator: Allocator<N, DimMinimum<R, C>, C>,
|
||||||
// FIXME: the following bound is ugly.
|
|
||||||
DimMinimum<R, C>: DimMin<C, Output = DimMinimum<R, C>>,
|
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.data.shape();
|
||||||
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_diagonal(&self.diag.map(|e| N::from_real(e.modulus())));
|
res.set_partial_diagonal(self.diag.iter().map(|e| N::from_real(e.modulus())));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,13 +93,11 @@ where DefaultAllocator: Allocator<N, R, C> + Allocator<N, R> + Allocator<N, DimM
|
||||||
pub fn unpack_r(self) -> MatrixMN<N, DimMinimum<R, C>, C>
|
pub fn unpack_r(self) -> MatrixMN<N, DimMinimum<R, C>, C>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Reallocator<N, R, C, DimMinimum<R, C>, C>,
|
DefaultAllocator: Reallocator<N, R, C, DimMinimum<R, C>, C>,
|
||||||
// FIXME: the following bound is ugly (needed by `set_diagonal`).
|
|
||||||
DimMinimum<R, C>: DimMin<C, Output = DimMinimum<R, C>>,
|
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.qr.data.shape();
|
let (nrows, ncols) = self.qr.data.shape();
|
||||||
let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, N::zero());
|
let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, N::zero());
|
||||||
res.fill_lower_triangle(N::zero(), 1);
|
res.fill_lower_triangle(N::zero(), 1);
|
||||||
res.set_diagonal(&self.diag.map(|e| N::from_real(e.modulus())));
|
res.set_partial_diagonal(self.diag.iter().map(|e| N::from_real(e.modulus())));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ where
|
||||||
impl<N: Complex, D: Dim> Schur<N, D>
|
impl<N: Complex, D: Dim> Schur<N, D>
|
||||||
where
|
where
|
||||||
D: DimSub<U1>, // For Hessenberg.
|
D: DimSub<U1>, // For Hessenberg.
|
||||||
ShapeConstraint: DimEq<Dynamic, DimDiff<D, U1>>, // For Hessenberg.
|
|
||||||
DefaultAllocator: Allocator<N, D, DimDiff<D, U1>>
|
DefaultAllocator: Allocator<N, D, DimDiff<D, U1>>
|
||||||
+ Allocator<N, DimDiff<D, U1>>
|
+ Allocator<N, DimDiff<D, U1>>
|
||||||
+ Allocator<N, D, D>
|
+ Allocator<N, D, D>
|
||||||
|
@ -341,7 +340,7 @@ where
|
||||||
while n > 0 {
|
while n > 0 {
|
||||||
let m = n - 1;
|
let m = n - 1;
|
||||||
|
|
||||||
if t[(n, m)].modulus() <= eps * (t[(n, n)].modulus() + t[(m, m)].modulus()) {
|
if t[(n, m)].norm1() <= eps * (t[(n, n)].norm1() + t[(m, m)].norm1()) {
|
||||||
t[(n, m)] = N::zero();
|
t[(n, m)] = N::zero();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -360,7 +359,7 @@ where
|
||||||
|
|
||||||
let off_diag = t[(new_start, m)];
|
let off_diag = t[(new_start, m)];
|
||||||
if off_diag.is_zero()
|
if off_diag.is_zero()
|
||||||
|| off_diag.modulus() <= eps * (t[(new_start, new_start)].modulus() + t[(m, m)].modulus())
|
|| off_diag.norm1() <= eps * (t[(new_start, new_start)].norm1() + t[(m, m)].norm1())
|
||||||
{
|
{
|
||||||
t[(new_start, m)] = N::zero();
|
t[(new_start, m)] = N::zero();
|
||||||
break;
|
break;
|
||||||
|
@ -479,7 +478,7 @@ fn compute_2x2_basis<N: Complex, S: Storage<N, U2, U2>>(
|
||||||
// NOTE: Choose the one that yields a larger x component.
|
// NOTE: Choose the one that yields a larger x component.
|
||||||
// This is necessary for numerical stability of the normalization of the complex
|
// This is necessary for numerical stability of the normalization of the complex
|
||||||
// number.
|
// number.
|
||||||
if x1.modulus() > x2.modulus() {
|
if x1.norm1() > x2.norm1() {
|
||||||
Some(GivensRotation::new(x1, h10).0)
|
Some(GivensRotation::new(x1, h10).0)
|
||||||
} else {
|
} else {
|
||||||
Some(GivensRotation::new(x2, h10).0)
|
Some(GivensRotation::new(x2, h10).0)
|
||||||
|
@ -492,7 +491,6 @@ fn compute_2x2_basis<N: Complex, S: Storage<N, U2, U2>>(
|
||||||
impl<N: Complex, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S>
|
impl<N: Complex, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S>
|
||||||
where
|
where
|
||||||
D: DimSub<U1>, // For Hessenberg.
|
D: DimSub<U1>, // For Hessenberg.
|
||||||
ShapeConstraint: DimEq<Dynamic, DimDiff<D, U1>>, // For Hessenberg.
|
|
||||||
DefaultAllocator: Allocator<N, D, DimDiff<D, U1>>
|
DefaultAllocator: Allocator<N, D, DimDiff<D, U1>>
|
||||||
+ Allocator<N, DimDiff<D, U1>>
|
+ Allocator<N, DimDiff<D, U1>>
|
||||||
+ Allocator<N, D, D>
|
+ Allocator<N, D, D>
|
||||||
|
|
|
@ -316,17 +316,17 @@ where
|
||||||
let m = n - 1;
|
let m = n - 1;
|
||||||
|
|
||||||
if off_diagonal[m].is_zero()
|
if off_diagonal[m].is_zero()
|
||||||
|| off_diagonal[m].modulus() <= eps * (diagonal[n].modulus() + diagonal[m].modulus())
|
|| off_diagonal[m].norm1() <= eps * (diagonal[n].norm1() + diagonal[m].norm1())
|
||||||
{
|
{
|
||||||
off_diagonal[m] = N::Real::zero();
|
off_diagonal[m] = N::Real::zero();
|
||||||
} else if diagonal[m].modulus() <= eps {
|
} else if diagonal[m].norm1() <= eps {
|
||||||
diagonal[m] = N::Real::zero();
|
diagonal[m] = N::Real::zero();
|
||||||
Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, m + 1);
|
Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, m + 1);
|
||||||
|
|
||||||
if m != 0 {
|
if m != 0 {
|
||||||
Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1);
|
Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1);
|
||||||
}
|
}
|
||||||
} else if diagonal[n].modulus() <= eps {
|
} else if diagonal[n].norm1() <= eps {
|
||||||
diagonal[n] = N::Real::zero();
|
diagonal[n] = N::Real::zero();
|
||||||
Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m);
|
Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m);
|
||||||
} else {
|
} else {
|
||||||
|
@ -344,13 +344,13 @@ where
|
||||||
while new_start > 0 {
|
while new_start > 0 {
|
||||||
let m = new_start - 1;
|
let m = new_start - 1;
|
||||||
|
|
||||||
if off_diagonal[m].modulus() <= eps * (diagonal[new_start].modulus() + diagonal[m].modulus())
|
if off_diagonal[m].norm1() <= eps * (diagonal[new_start].norm1() + diagonal[m].norm1())
|
||||||
{
|
{
|
||||||
off_diagonal[m] = N::Real::zero();
|
off_diagonal[m] = N::Real::zero();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// FIXME: write a test that enters this case.
|
// FIXME: write a test that enters this case.
|
||||||
else if diagonal[m].modulus() <= eps {
|
else if diagonal[m].norm1() <= eps {
|
||||||
diagonal[m] = N::Real::zero();
|
diagonal[m] = N::Real::zero();
|
||||||
Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, n);
|
Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, n);
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N::Real, D>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if off_diag[m].modulus() <= eps * (diag[m].modulus() + diag[n].modulus()) {
|
if off_diag[m].norm1() <= eps * (diag[m].norm1() + diag[n].norm1()) {
|
||||||
end -= 1;
|
end -= 1;
|
||||||
}
|
}
|
||||||
} else if subdim == 2 {
|
} else if subdim == 2 {
|
||||||
|
@ -240,7 +240,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N::Real, D>
|
||||||
while n > 0 {
|
while n > 0 {
|
||||||
let m = n - 1;
|
let m = n - 1;
|
||||||
|
|
||||||
if off_diag[m].modulus() > eps * (diag[n].modulus() + diag[m].modulus()) {
|
if off_diag[m].norm1() > eps * (diag[n].norm1() + diag[m].norm1()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N::Real, D>
|
||||||
let m = new_start - 1;
|
let m = new_start - 1;
|
||||||
|
|
||||||
if off_diag[m].is_zero()
|
if off_diag[m].is_zero()
|
||||||
|| off_diag[m].modulus() <= eps * (diag[new_start].modulus() + diag[m].modulus())
|
|| off_diag[m].norm1() <= eps * (diag[new_start].norm1() + diag[m].norm1())
|
||||||
{
|
{
|
||||||
off_diag[m] = N::Real::zero();
|
off_diag[m] = N::Real::zero();
|
||||||
break;
|
break;
|
||||||
|
@ -277,7 +277,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N::Real, D>
|
||||||
let val = self.eigenvalues[i];
|
let val = self.eigenvalues[i];
|
||||||
u_t.column_mut(i).scale_mut(val);
|
u_t.column_mut(i).scale_mut(val);
|
||||||
}
|
}
|
||||||
u_t.conjugate_transpose_mut();
|
u_t.adjoint_mut();
|
||||||
&self.eigenvectors * u_t
|
&self.eigenvectors * u_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,8 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>
|
||||||
let mut p = p.rows_range_mut(i..);
|
let mut p = p.rows_range_mut(i..);
|
||||||
|
|
||||||
p.hegemv(::convert(2.0), &m, &axis, N::zero());
|
p.hegemv(::convert(2.0), &m, &axis, N::zero());
|
||||||
let dot = axis.dotc(&p);
|
|
||||||
|
|
||||||
// p.axpy(-dot, &axis.conjugate(), N::one());
|
let dot = axis.dotc(&p);
|
||||||
m.hegerc(-N::one(), &p, &axis, N::one());
|
m.hegerc(-N::one(), &p, &axis, N::one());
|
||||||
m.hegerc(-N::one(), &axis, &p, N::one());
|
m.hegerc(-N::one(), &axis, &p, N::one());
|
||||||
m.hegerc(dot * ::convert(2.0), &axis, &axis, N::one());
|
m.hegerc(dot * ::convert(2.0), &axis, &axis, N::one());
|
||||||
|
|
Loading…
Reference in New Issue