forked from M-Labs/nalgebra
Make blas, matrix, norm, and ops.rs compatible with SoA Simd.
This commit is contained in:
parent
73af0f9179
commit
002e735c76
178
src/base/blas.rs
178
src/base/blas.rs
@ -1,3 +1,4 @@
|
|||||||
|
use crate::SimdComplexField;
|
||||||
use alga::general::{ClosedAdd, ClosedMul, ComplexField};
|
use alga::general::{ClosedAdd, ClosedMul, ComplexField};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use matrixmultiply;
|
use matrixmultiply;
|
||||||
@ -11,8 +12,9 @@ use crate::base::constraint::{
|
|||||||
};
|
};
|
||||||
use crate::base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
|
use crate::base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
|
||||||
use crate::base::storage::{Storage, StorageMut};
|
use crate::base::storage::{Storage, StorageMut};
|
||||||
use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, DVectorSlice, VectorSliceN};
|
use crate::base::{
|
||||||
|
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSliceN,
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: find a way to avoid code duplication just for complex number support.
|
// FIXME: find a way to avoid code duplication just for complex number support.
|
||||||
impl<N: ComplexField, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: ComplexField, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
@ -229,7 +231,6 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// Computes the index of the matrix component with the largest absolute value.
|
/// Computes the index of the matrix component with the largest absolute value.
|
||||||
///
|
///
|
||||||
@ -267,7 +268,11 @@ impl<N, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
|
|||||||
where N: Scalar + Zero + ClosedAdd + ClosedMul
|
where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn dotx<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>, conjugate: impl Fn(N) -> N) -> N
|
fn dotx<R2: Dim, C2: Dim, SB>(
|
||||||
|
&self,
|
||||||
|
rhs: &Matrix<N, R2, C2, SB>,
|
||||||
|
conjugate: impl Fn(N) -> N,
|
||||||
|
) -> N
|
||||||
where
|
where
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
@ -281,27 +286,36 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
// because the `for` loop below won't be very efficient on those.
|
// because the `for` loop below won't be very efficient on those.
|
||||||
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone()) * rhs.get_unchecked((0, 0)).inlined_clone();
|
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
|
||||||
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone()) * rhs.get_unchecked((1, 0)).inlined_clone();
|
* rhs.get_unchecked((0, 0)).inlined_clone();
|
||||||
|
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((1, 0)).inlined_clone();
|
||||||
|
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone()) * rhs.get_unchecked((0, 0)).inlined_clone();
|
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
|
||||||
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone()) * rhs.get_unchecked((1, 0)).inlined_clone();
|
* rhs.get_unchecked((0, 0)).inlined_clone();
|
||||||
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone()) * rhs.get_unchecked((2, 0)).inlined_clone();
|
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((1, 0)).inlined_clone();
|
||||||
|
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((2, 0)).inlined_clone();
|
||||||
|
|
||||||
return a + b + c;
|
return a + b + c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut a = conjugate(self.get_unchecked((0, 0)).inlined_clone()) * rhs.get_unchecked((0, 0)).inlined_clone();
|
let mut a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
|
||||||
let mut b = conjugate(self.get_unchecked((1, 0)).inlined_clone()) * rhs.get_unchecked((1, 0)).inlined_clone();
|
* rhs.get_unchecked((0, 0)).inlined_clone();
|
||||||
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone()) * rhs.get_unchecked((2, 0)).inlined_clone();
|
let mut b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
|
||||||
let d = conjugate(self.get_unchecked((3, 0)).inlined_clone()) * rhs.get_unchecked((3, 0)).inlined_clone();
|
* rhs.get_unchecked((1, 0)).inlined_clone();
|
||||||
|
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((2, 0)).inlined_clone();
|
||||||
|
let d = conjugate(self.get_unchecked((3, 0)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((3, 0)).inlined_clone();
|
||||||
|
|
||||||
a += c;
|
a += c;
|
||||||
b += d;
|
b += d;
|
||||||
@ -341,14 +355,38 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
acc7 = N::zero();
|
acc7 = N::zero();
|
||||||
|
|
||||||
while self.nrows() - i >= 8 {
|
while self.nrows() - i >= 8 {
|
||||||
acc0 += unsafe { conjugate(self.get_unchecked((i + 0, j)).inlined_clone()) * rhs.get_unchecked((i + 0, j)).inlined_clone() };
|
acc0 += unsafe {
|
||||||
acc1 += unsafe { conjugate(self.get_unchecked((i + 1, j)).inlined_clone()) * rhs.get_unchecked((i + 1, j)).inlined_clone() };
|
conjugate(self.get_unchecked((i + 0, j)).inlined_clone())
|
||||||
acc2 += unsafe { conjugate(self.get_unchecked((i + 2, j)).inlined_clone()) * rhs.get_unchecked((i + 2, j)).inlined_clone() };
|
* rhs.get_unchecked((i + 0, j)).inlined_clone()
|
||||||
acc3 += unsafe { conjugate(self.get_unchecked((i + 3, j)).inlined_clone()) * rhs.get_unchecked((i + 3, j)).inlined_clone() };
|
};
|
||||||
acc4 += unsafe { conjugate(self.get_unchecked((i + 4, j)).inlined_clone()) * rhs.get_unchecked((i + 4, j)).inlined_clone() };
|
acc1 += unsafe {
|
||||||
acc5 += unsafe { conjugate(self.get_unchecked((i + 5, j)).inlined_clone()) * rhs.get_unchecked((i + 5, j)).inlined_clone() };
|
conjugate(self.get_unchecked((i + 1, j)).inlined_clone())
|
||||||
acc6 += unsafe { conjugate(self.get_unchecked((i + 6, j)).inlined_clone()) * rhs.get_unchecked((i + 6, j)).inlined_clone() };
|
* rhs.get_unchecked((i + 1, j)).inlined_clone()
|
||||||
acc7 += unsafe { conjugate(self.get_unchecked((i + 7, j)).inlined_clone()) * rhs.get_unchecked((i + 7, j)).inlined_clone() };
|
};
|
||||||
|
acc2 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 2, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 2, j)).inlined_clone()
|
||||||
|
};
|
||||||
|
acc3 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 3, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 3, j)).inlined_clone()
|
||||||
|
};
|
||||||
|
acc4 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 4, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 4, j)).inlined_clone()
|
||||||
|
};
|
||||||
|
acc5 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 5, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 5, j)).inlined_clone()
|
||||||
|
};
|
||||||
|
acc6 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 6, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 6, j)).inlined_clone()
|
||||||
|
};
|
||||||
|
acc7 += unsafe {
|
||||||
|
conjugate(self.get_unchecked((i + 7, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((i + 7, j)).inlined_clone()
|
||||||
|
};
|
||||||
i += 8;
|
i += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,14 +396,16 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
res += acc3 + acc7;
|
res += acc3 + acc7;
|
||||||
|
|
||||||
for k in i..self.nrows() {
|
for k in i..self.nrows() {
|
||||||
res += unsafe { conjugate(self.get_unchecked((k, j)).inlined_clone()) * rhs.get_unchecked((k, j)).inlined_clone() }
|
res += unsafe {
|
||||||
|
conjugate(self.get_unchecked((k, j)).inlined_clone())
|
||||||
|
* rhs.get_unchecked((k, j)).inlined_clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The dot product between two vectors or matrices (seen as vectors).
|
/// The dot product between two vectors or matrices (seen as vectors).
|
||||||
///
|
///
|
||||||
/// This is equal to `self.transpose() * rhs`. For the sesquilinear complex dot product, use
|
/// This is equal to `self.transpose() * rhs`. For the sesquilinear complex dot product, use
|
||||||
@ -420,11 +460,11 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
|
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
|
||||||
where
|
where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
{
|
{
|
||||||
self.dotx(rhs, ComplexField::conjugate)
|
self.dotx(rhs, N::simd_conjugate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The dot product between the transpose of `self` and `rhs`.
|
/// The dot product between the transpose of `self` and `rhs`.
|
||||||
@ -460,7 +500,10 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
|
|
||||||
for j in 0..self.nrows() {
|
for j in 0..self.nrows() {
|
||||||
for i in 0..self.ncols() {
|
for i in 0..self.ncols() {
|
||||||
res += unsafe { self.get_unchecked((j, i)).inlined_clone() * rhs.get_unchecked((i, j)).inlined_clone() }
|
res += unsafe {
|
||||||
|
self.get_unchecked((j, i)).inlined_clone()
|
||||||
|
* rhs.get_unchecked((i, j)).inlined_clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,12 +511,25 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_axcpy<N>(y: &mut [N], a: N, x: &[N], c: N, beta: N, stride1: usize, stride2: usize, len: usize)
|
fn array_axcpy<N>(
|
||||||
where N: Scalar + Zero + ClosedAdd + ClosedMul {
|
y: &mut [N],
|
||||||
|
a: N,
|
||||||
|
x: &[N],
|
||||||
|
c: N,
|
||||||
|
beta: N,
|
||||||
|
stride1: usize,
|
||||||
|
stride2: usize,
|
||||||
|
len: usize,
|
||||||
|
) where
|
||||||
|
N: Scalar + Zero + ClosedAdd + ClosedMul,
|
||||||
|
{
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
let y = y.get_unchecked_mut(i * stride1);
|
let y = y.get_unchecked_mut(i * stride1);
|
||||||
*y = a.inlined_clone() * x.get_unchecked(i * stride2).inlined_clone() * c.inlined_clone() + beta.inlined_clone() * y.inlined_clone();
|
*y = a.inlined_clone()
|
||||||
|
* x.get_unchecked(i * stride2).inlined_clone()
|
||||||
|
* c.inlined_clone()
|
||||||
|
+ beta.inlined_clone() * y.inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,7 +538,9 @@ fn array_axc<N>(y: &mut [N], a: N, x: &[N], c: N, stride1: usize, stride2: usize
|
|||||||
where N: Scalar + Zero + ClosedAdd + ClosedMul {
|
where N: Scalar + Zero + ClosedAdd + ClosedMul {
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
*y.get_unchecked_mut(i * stride1) = a.inlined_clone() * x.get_unchecked(i * stride2).inlined_clone() * c.inlined_clone();
|
*y.get_unchecked_mut(i * stride1) = a.inlined_clone()
|
||||||
|
* x.get_unchecked(i * stride2).inlined_clone()
|
||||||
|
* c.inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,7 +671,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn xxgemv<D2: Dim, D3: Dim, SB, SC>(
|
fn xxgemv<D2: Dim, D3: Dim, SB, SC>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -621,7 +678,10 @@ 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,
|
||||||
dot: 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>,
|
||||||
@ -660,8 +720,11 @@ where
|
|||||||
val = x.vget_unchecked(j).inlined_clone();
|
val = x.vget_unchecked(j).inlined_clone();
|
||||||
*self.vget_unchecked_mut(j) += alpha.inlined_clone() * dot;
|
*self.vget_unchecked_mut(j) += alpha.inlined_clone() * dot;
|
||||||
}
|
}
|
||||||
self.rows_range_mut(j + 1..)
|
self.rows_range_mut(j + 1..).axpy(
|
||||||
.axpy(alpha.inlined_clone() * val, &col2.rows_range(j + 1..), N::one());
|
alpha.inlined_clone() * val,
|
||||||
|
&col2.rows_range(j + 1..),
|
||||||
|
N::one(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +828,7 @@ where
|
|||||||
x: &Vector<N, D3, SC>,
|
x: &Vector<N, D3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, D2, D2>,
|
SB: Storage<N, D2, D2>,
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
|
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
|
||||||
@ -773,7 +836,6 @@ where
|
|||||||
self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b))
|
self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn gemv_xx<R2: Dim, C2: Dim, D3: Dim, SB, SC>(
|
fn gemv_xx<R2: Dim, C2: Dim, D3: Dim, SB, SC>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -809,12 +871,12 @@ where
|
|||||||
} else {
|
} else {
|
||||||
for j in 0..ncols2 {
|
for j in 0..ncols2 {
|
||||||
let val = unsafe { self.vget_unchecked_mut(j) };
|
let val = unsafe { self.vget_unchecked_mut(j) };
|
||||||
*val = alpha.inlined_clone() * dot(&a.column(j), x) + beta.inlined_clone() * val.inlined_clone();
|
*val = alpha.inlined_clone() * dot(&a.column(j), x)
|
||||||
|
+ beta.inlined_clone() * val.inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and
|
/// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and
|
||||||
/// `alpha, beta` two scalars.
|
/// `alpha, beta` two scalars.
|
||||||
///
|
///
|
||||||
@ -876,7 +938,7 @@ where
|
|||||||
x: &Vector<N, D3, SC>,
|
x: &Vector<N, D3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>,
|
ShapeConstraint: DimEq<D, C2> + AreMultipliable<C2, R2, D3, U1>,
|
||||||
@ -914,7 +976,8 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
for j in 0..ncols1 {
|
for j in 0..ncols1 {
|
||||||
// FIXME: avoid bound checks.
|
// FIXME: avoid bound checks.
|
||||||
let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) };
|
let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) };
|
||||||
self.column_mut(j).axpy(alpha.inlined_clone() * val, x, beta.inlined_clone());
|
self.column_mut(j)
|
||||||
|
.axpy(alpha.inlined_clone() * val, x, beta.inlined_clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,12 +1038,12 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
y: &Vector<N, D3, SC>,
|
y: &Vector<N, D3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, D2>,
|
SB: Storage<N, D2>,
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
||||||
{
|
{
|
||||||
self.gerx(alpha, x, y, beta, ComplexField::conjugate)
|
self.gerx(alpha, x, y, beta, SimdComplexField::simd_conjugate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices.
|
/// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices.
|
||||||
@ -1032,7 +1095,8 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
|| R2::is::<Dynamic>()
|
|| R2::is::<Dynamic>()
|
||||||
|| C2::is::<Dynamic>()
|
|| C2::is::<Dynamic>()
|
||||||
|| R3::is::<Dynamic>()
|
|| R3::is::<Dynamic>()
|
||||||
|| C3::is::<Dynamic>() {
|
|| C3::is::<Dynamic>()
|
||||||
|
{
|
||||||
// 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();
|
||||||
@ -1125,10 +1189,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for j1 in 0..ncols1 {
|
for j1 in 0..ncols1 {
|
||||||
// FIXME: avoid bound checks.
|
// FIXME: avoid bound checks.
|
||||||
self.column_mut(j1).gemv(alpha.inlined_clone(), a, &b.column(j1), beta.inlined_clone());
|
self.column_mut(j1).gemv(
|
||||||
|
alpha.inlined_clone(),
|
||||||
|
a,
|
||||||
|
&b.column(j1),
|
||||||
|
beta.inlined_clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1185,11 +1253,15 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
|
|
||||||
for j1 in 0..ncols1 {
|
for j1 in 0..ncols1 {
|
||||||
// FIXME: avoid bound checks.
|
// FIXME: avoid bound checks.
|
||||||
self.column_mut(j1).gemv_tr(alpha.inlined_clone(), a, &b.column(j1), beta.inlined_clone());
|
self.column_mut(j1).gemv_tr(
|
||||||
|
alpha.inlined_clone(),
|
||||||
|
a,
|
||||||
|
&b.column(j1),
|
||||||
|
beta.inlined_clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices.
|
/// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices.
|
||||||
/// `alpha` and `beta` are scalar.
|
/// `alpha` and `beta` are scalar.
|
||||||
///
|
///
|
||||||
@ -1220,7 +1292,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
b: &Matrix<N, R3, C3, SC>,
|
b: &Matrix<N, R3, C3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
SC: Storage<N, R3, C3>,
|
SC: Storage<N, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, C2>
|
ShapeConstraint: SameNumberOfRows<R1, C2>
|
||||||
@ -1386,12 +1458,12 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
|||||||
y: &Vector<N, D3, SC>,
|
y: &Vector<N, D3, SC>,
|
||||||
beta: N,
|
beta: N,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, D2>,
|
SB: Storage<N, D2>,
|
||||||
SC: Storage<N, D3>,
|
SC: Storage<N, D3>,
|
||||||
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
|
||||||
{
|
{
|
||||||
self.xxgerx(alpha, x, y, beta, ComplexField::conjugate)
|
self.xxgerx(alpha, x, y, beta, SimdComplexField::simd_conjugate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1534,11 +1606,13 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
|
|||||||
DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>,
|
DimEq<D3, R4> + DimEq<D1, C4> + DimEq<D2, D3> + AreMultipliable<C4, R4, D2, U1>,
|
||||||
{
|
{
|
||||||
work.gemv(N::one(), mid, &rhs.column(0), N::zero());
|
work.gemv(N::one(), mid, &rhs.column(0), N::zero());
|
||||||
self.column_mut(0).gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone());
|
self.column_mut(0)
|
||||||
|
.gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone());
|
||||||
|
|
||||||
for j in 1..rhs.ncols() {
|
for j in 1..rhs.ncols() {
|
||||||
work.gemv(N::one(), mid, &rhs.column(j), N::zero());
|
work.gemv(N::one(), mid, &rhs.column(j), N::zero());
|
||||||
self.column_mut(j).gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone());
|
self.column_mut(j)
|
||||||
|
.gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,16 +16,20 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use abomonation::Abomonation;
|
use abomonation::Abomonation;
|
||||||
|
|
||||||
use alga::general::{ClosedAdd, ClosedMul, ClosedSub, RealField, Ring, ComplexField, Field};
|
use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Field, RealField, Ring};
|
||||||
|
use alga::simd::SimdPartialOrd;
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
||||||
use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
|
use crate::base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
|
||||||
use crate::base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
|
use crate::base::iter::{
|
||||||
|
ColumnIter, ColumnIterMut, MatrixIter, MatrixIterMut, RowIter, RowIterMut,
|
||||||
|
};
|
||||||
use crate::base::storage::{
|
use crate::base::storage::{
|
||||||
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
|
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
|
||||||
};
|
};
|
||||||
use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN};
|
use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN};
|
||||||
|
use crate::{SimdComplexField, SimdRealField};
|
||||||
|
|
||||||
/// A square matrix.
|
/// A square matrix.
|
||||||
pub type SquareMatrix<N, D, S> = Matrix<N, D, D, S>;
|
pub type SquareMatrix<N, D, S> = Matrix<N, D, D, S>;
|
||||||
@ -431,6 +435,25 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure.
|
||||||
|
///
|
||||||
|
/// The initialization closure is given the first component of this matrix:
|
||||||
|
/// - If the matrix has no component (0 rows or 0 columns) then `init_f` is called with `None`
|
||||||
|
/// and its return value is the value returned by this method.
|
||||||
|
/// - If the matrix has has least one component, then `init_f` is called with the first component
|
||||||
|
/// to compute the initial value. Folding then continues on all the remaining components of the matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn fold_with<N2>(
|
||||||
|
&self,
|
||||||
|
init_f: impl FnOnce(Option<&N>) -> N2,
|
||||||
|
f: impl FnMut(N2, &N) -> N2,
|
||||||
|
) -> N2
|
||||||
|
{
|
||||||
|
let mut it = self.iter();
|
||||||
|
let init = init_f(it.next());
|
||||||
|
it.fold(init, f)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
|
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
|
||||||
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
|
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -553,13 +576,18 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
|
|
||||||
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
|
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zip_fold<N2, R2, C2, S2, Acc>(&self, rhs: &Matrix<N2, R2, C2, S2>, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc
|
pub fn zip_fold<N2, R2, C2, S2, Acc>(
|
||||||
|
&self,
|
||||||
|
rhs: &Matrix<N2, R2, C2, S2>,
|
||||||
|
init: Acc,
|
||||||
|
mut f: impl FnMut(Acc, N, N2) -> Acc,
|
||||||
|
) -> Acc
|
||||||
where
|
where
|
||||||
N2: Scalar,
|
N2: Scalar,
|
||||||
R2: Dim,
|
R2: Dim,
|
||||||
C2: Dim,
|
C2: Dim,
|
||||||
S2: Storage<N2, R2, C2>,
|
S2: Storage<N2, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
{
|
{
|
||||||
let (nrows, ncols) = self.data.shape();
|
let (nrows, ncols) = self.data.shape();
|
||||||
|
|
||||||
@ -718,7 +746,8 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut((i, j)) = slice.get_unchecked(i + j * nrows).inlined_clone();
|
*self.get_unchecked_mut((i, j)) =
|
||||||
|
slice.get_unchecked(i + j * nrows).inlined_clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -774,7 +803,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
// FIXME: rename `apply` to `apply_mut` and `apply_into` to `apply`?
|
// FIXME: rename `apply` to `apply_mut` and `apply_into` to `apply`?
|
||||||
/// Returns `self` with each of its components replaced by the result of a closure `f` applied on it.
|
/// Returns `self` with each of its components replaced by the result of a closure `f` applied on it.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply_into<F: FnMut(N) -> N>(mut self, f: F) -> Self{
|
pub fn apply_into<F: FnMut(N) -> N>(mut self, f: F) -> Self {
|
||||||
self.apply(f);
|
self.apply(f);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -797,12 +826,17 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
||||||
/// joined with the components from `rhs`.
|
/// joined with the components from `rhs`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zip_apply<N2, R2, C2, S2>(&mut self, rhs: &Matrix<N2, R2, C2, S2>, mut f: impl FnMut(N, N2) -> N)
|
pub fn zip_apply<N2, R2, C2, S2>(
|
||||||
where N2: Scalar,
|
&mut self,
|
||||||
|
rhs: &Matrix<N2, R2, C2, S2>,
|
||||||
|
mut f: impl FnMut(N, N2) -> N,
|
||||||
|
) where
|
||||||
|
N2: Scalar,
|
||||||
R2: Dim,
|
R2: Dim,
|
||||||
C2: Dim,
|
C2: Dim,
|
||||||
S2: Storage<N2, R2, C2>,
|
S2: Storage<N2, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@ -821,12 +855,16 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
||||||
/// joined with the components from `b` and `c`.
|
/// joined with the components from `b` and `c`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(&mut self, b: &Matrix<N2, R2, C2, S2>, c: &Matrix<N3, R3, C3, S3>, mut f: impl FnMut(N, N2, N3) -> N)
|
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(
|
||||||
where N2: Scalar,
|
&mut self,
|
||||||
|
b: &Matrix<N2, R2, C2, S2>,
|
||||||
|
c: &Matrix<N3, R3, C3, S3>,
|
||||||
|
mut f: impl FnMut(N, N2, N3) -> N,
|
||||||
|
) where
|
||||||
|
N2: Scalar,
|
||||||
R2: Dim,
|
R2: Dim,
|
||||||
C2: Dim,
|
C2: Dim,
|
||||||
S2: Storage<N2, R2, C2>,
|
S2: Storage<N2, R2, C2>,
|
||||||
@ -835,7 +873,8 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
C3: Dim,
|
C3: Dim,
|
||||||
S3: Storage<N3, R3, C3>,
|
S3: Storage<N3, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
{
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@ -914,7 +953,7 @@ impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`.
|
/// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn adjoint_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
pub fn adjoint_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
||||||
@ -934,7 +973,7 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
unsafe {
|
unsafe {
|
||||||
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conjugate();
|
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).simd_conjugate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -981,47 +1020,47 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
#[must_use = "Did you mean to use conjugate_mut()?"]
|
#[must_use = "Did you mean to use conjugate_mut()?"]
|
||||||
pub fn conjugate(&self) -> MatrixMN<N, R, C>
|
pub fn conjugate(&self) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
self.map(|e| e.conjugate())
|
self.map(|e| e.simd_conjugate())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides each component of the complex matrix `self` by the given real.
|
/// Divides each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "Did you mean to use unscale_mut()?"]
|
#[must_use = "Did you mean to use unscale_mut()?"]
|
||||||
pub fn unscale(&self, real: N::RealField) -> MatrixMN<N, R, C>
|
pub fn unscale(&self, real: N::SimdRealField) -> 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.simd_unscale(real))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiplies each component of the complex matrix `self` by the given real.
|
/// Multiplies each component of the complex matrix `self` by the given real.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "Did you mean to use scale_mut()?"]
|
#[must_use = "Did you mean to use scale_mut()?"]
|
||||||
pub fn scale(&self, real: N::RealField) -> MatrixMN<N, R, C>
|
pub fn scale(&self, real: N::SimdRealField) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
self.map(|e| e.scale(real))
|
self.map(|e| e.simd_scale(real))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// The conjugate of the complex matrix `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.simd_conjugate())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divides each component of the complex matrix `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::RealField) {
|
pub fn unscale_mut(&mut self, real: N::SimdRealField) {
|
||||||
self.apply(|e| e.unscale(real))
|
self.apply(|e| e.simd_unscale(real))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiplies each component of the complex matrix `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::RealField) {
|
pub fn scale_mut(&mut self, real: N::SimdRealField) {
|
||||||
self.apply(|e| e.scale(real))
|
self.apply(|e| e.simd_scale(real))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
impl<N: SimdComplexField, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
/// Sets `self` to its adjoint.
|
/// Sets `self` to its adjoint.
|
||||||
#[deprecated(note = "Renamed to `self.adjoint_mut()`.")]
|
#[deprecated(note = "Renamed to `self.adjoint_mut()`.")]
|
||||||
pub fn conjugate_transform_mut(&mut self) {
|
pub fn conjugate_transform_mut(&mut self) {
|
||||||
@ -1042,8 +1081,8 @@ impl<N: ComplexField, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
|||||||
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;
|
||||||
let ref_ji = self.get_unchecked_mut((j, i)) as *mut N;
|
let ref_ji = self.get_unchecked_mut((j, i)) as *mut N;
|
||||||
let conj_ij = (*ref_ij).conjugate();
|
let conj_ij = (*ref_ij).simd_conjugate();
|
||||||
let conj_ji = (*ref_ji).conjugate();
|
let conj_ji = (*ref_ji).simd_conjugate();
|
||||||
*ref_ij = conj_ji;
|
*ref_ij = conj_ji;
|
||||||
*ref_ji = conj_ij;
|
*ref_ji = conj_ij;
|
||||||
}
|
}
|
||||||
@ -1051,7 +1090,7 @@ impl<N: ComplexField, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let diag = unsafe { self.get_unchecked_mut((i, i)) };
|
let diag = unsafe { self.get_unchecked_mut((i, i)) };
|
||||||
*diag = diag.conjugate();
|
*diag = diag.simd_conjugate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1108,12 +1147,15 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
impl<N: SimdComplexField, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
/// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`.
|
/// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn symmetric_part(&self) -> MatrixMN<N, D, D>
|
pub fn symmetric_part(&self) -> MatrixMN<N, D, D>
|
||||||
where DefaultAllocator: Allocator<N, D, D> {
|
where DefaultAllocator: Allocator<N, D, D> {
|
||||||
assert!(self.is_square(), "Cannot compute the symmetric part of a non-square matrix.");
|
assert!(
|
||||||
|
self.is_square(),
|
||||||
|
"Cannot compute the symmetric part of a non-square matrix."
|
||||||
|
);
|
||||||
let mut tr = self.transpose();
|
let mut tr = self.transpose();
|
||||||
tr += self;
|
tr += self;
|
||||||
tr *= crate::convert::<_, N>(0.5);
|
tr *= crate::convert::<_, N>(0.5);
|
||||||
@ -1124,7 +1166,10 @@ impl<N: ComplexField, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn hermitian_part(&self) -> MatrixMN<N, D, D>
|
pub fn hermitian_part(&self) -> MatrixMN<N, D, D>
|
||||||
where DefaultAllocator: Allocator<N, D, D> {
|
where DefaultAllocator: Allocator<N, D, D> {
|
||||||
assert!(self.is_square(), "Cannot compute the hermitian part of a non-square matrix.");
|
assert!(
|
||||||
|
self.is_square(),
|
||||||
|
"Cannot compute the hermitian part of a non-square matrix."
|
||||||
|
);
|
||||||
|
|
||||||
let mut tr = self.adjoint();
|
let mut tr = self.adjoint();
|
||||||
tr += self;
|
tr += self;
|
||||||
@ -1133,20 +1178,24 @@ impl<N: ComplexField, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + Zero + One, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>> Matrix<N, D, D, S> {
|
impl<N: Scalar + Zero + One, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>>
|
||||||
|
Matrix<N, D, D, S>
|
||||||
|
{
|
||||||
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
|
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
|
||||||
/// and setting the diagonal element to `1`.
|
/// and setting the diagonal element to `1`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
|
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
|
||||||
where DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>> {
|
where DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>> {
|
||||||
assert!(self.is_square(), "Only square matrices can currently be transformed to homogeneous coordinates.");
|
assert!(
|
||||||
|
self.is_square(),
|
||||||
|
"Only square matrices can currently be transformed to homogeneous coordinates."
|
||||||
|
);
|
||||||
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
|
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
|
||||||
let mut res = MatrixN::identity_generic(dim, dim);
|
let mut res = MatrixN::identity_generic(dim, dim);
|
||||||
res.generic_slice_mut::<D, D>((0, 0), self.data.shape()).copy_from(&self);
|
res.generic_slice_mut::<D, D>((0, 0), self.data.shape())
|
||||||
|
.copy_from(&self);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
@ -1347,7 +1396,8 @@ impl<N, R: Dim, C: Dim, S> Eq for Matrix<N, R, C, S>
|
|||||||
where
|
where
|
||||||
N: Scalar + Eq,
|
N: Scalar + Eq,
|
||||||
S: Storage<N, R, C>,
|
S: Storage<N, R, C>,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<N, R, R2, C, C2, S, S2> PartialEq<Matrix<N, R2, C2, S2>> for Matrix<N, R, C, S>
|
impl<N, R, R2, C, C2, S, S2> PartialEq<Matrix<N, R2, C2, S2>> for Matrix<N, R, C, S>
|
||||||
where
|
where
|
||||||
@ -1357,7 +1407,7 @@ where
|
|||||||
R: Dim,
|
R: Dim,
|
||||||
R2: Dim,
|
R2: Dim,
|
||||||
S: Storage<N, R, C>,
|
S: Storage<N, R, C>,
|
||||||
S2: Storage<N, R2, C2>
|
S2: Storage<N, R2, C2>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, right: &Matrix<N, R2, C2, S2>) -> bool {
|
fn eq(&self, right: &Matrix<N, R2, C2, S2>) -> bool {
|
||||||
@ -1377,7 +1427,9 @@ macro_rules! impl_fmt {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
fn val_width<N: Scalar + $trait>(val: &N, f: &mut fmt::Formatter) -> usize {
|
fn val_width<N: Scalar + $trait>(val: &N, f: &mut fmt::Formatter) -> usize {
|
||||||
match f.precision() {
|
match f.precision() {
|
||||||
Some(precision) => format!($fmt_str_with_precision, val, precision).chars().count(),
|
Some(precision) => format!($fmt_str_with_precision, val, precision)
|
||||||
|
.chars()
|
||||||
|
.count(),
|
||||||
None => format!($fmt_str_without_precision, val).chars().count(),
|
None => format!($fmt_str_without_precision, val).chars().count(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1421,7 +1473,9 @@ macro_rules! impl_fmt {
|
|||||||
let pad = max_length_with_space - number_length;
|
let pad = max_length_with_space - number_length;
|
||||||
write!(f, " {:>thepad$}", "", thepad = pad)?;
|
write!(f, " {:>thepad$}", "", thepad = pad)?;
|
||||||
match f.precision() {
|
match f.precision() {
|
||||||
Some(precision) => write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)?,
|
Some(precision) => {
|
||||||
|
write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)?
|
||||||
|
}
|
||||||
None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?,
|
None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1451,13 +1505,16 @@ impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}");
|
|||||||
#[test]
|
#[test]
|
||||||
fn lower_exp() {
|
fn lower_exp() {
|
||||||
let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.);
|
let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.);
|
||||||
assert_eq!(format!("{:e}", test), r"
|
assert_eq!(
|
||||||
|
format!("{:e}", test),
|
||||||
|
r"
|
||||||
┌ ┐
|
┌ ┐
|
||||||
│ 1e6 2e5 │
|
│ 1e6 2e5 │
|
||||||
│ 2e-5 1e0 │
|
│ 2e-5 1e0 │
|
||||||
└ ┘
|
└ ┘
|
||||||
|
|
||||||
")
|
"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
@ -1477,7 +1534,8 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_unchecked((0, 0)).inlined_clone() * b.get_unchecked((1, 0)).inlined_clone()
|
self.get_unchecked((0, 0)).inlined_clone() * b.get_unchecked((1, 0)).inlined_clone()
|
||||||
- self.get_unchecked((1, 0)).inlined_clone() * b.get_unchecked((0, 0)).inlined_clone()
|
- self.get_unchecked((1, 0)).inlined_clone()
|
||||||
|
* b.get_unchecked((0, 0)).inlined_clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1520,9 +1578,12 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
let by = b.get_unchecked((1, 0));
|
let by = b.get_unchecked((1, 0));
|
||||||
let bz = b.get_unchecked((2, 0));
|
let bz = b.get_unchecked((2, 0));
|
||||||
|
|
||||||
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() - az.inlined_clone() * by.inlined_clone();
|
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone()
|
||||||
*res.get_unchecked_mut((1, 0)) = az.inlined_clone() * bx.inlined_clone() - ax.inlined_clone() * bz.inlined_clone();
|
- az.inlined_clone() * by.inlined_clone();
|
||||||
*res.get_unchecked_mut((2, 0)) = ax.inlined_clone() * by.inlined_clone() - ay.inlined_clone() * bx.inlined_clone();
|
*res.get_unchecked_mut((1, 0)) = az.inlined_clone() * bx.inlined_clone()
|
||||||
|
- ax.inlined_clone() * bz.inlined_clone();
|
||||||
|
*res.get_unchecked_mut((2, 0)) = ax.inlined_clone() * by.inlined_clone()
|
||||||
|
- ay.inlined_clone() * bx.inlined_clone();
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@ -1541,9 +1602,12 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
let by = b.get_unchecked((0, 1));
|
let by = b.get_unchecked((0, 1));
|
||||||
let bz = b.get_unchecked((0, 2));
|
let bz = b.get_unchecked((0, 2));
|
||||||
|
|
||||||
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() - az.inlined_clone() * by.inlined_clone();
|
*res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone()
|
||||||
*res.get_unchecked_mut((0, 1)) = az.inlined_clone() * bx.inlined_clone() - ax.inlined_clone() * bz.inlined_clone();
|
- az.inlined_clone() * by.inlined_clone();
|
||||||
*res.get_unchecked_mut((0, 2)) = ax.inlined_clone() * by.inlined_clone() - ay.inlined_clone() * bx.inlined_clone();
|
*res.get_unchecked_mut((0, 1)) = az.inlined_clone() * bx.inlined_clone()
|
||||||
|
- ax.inlined_clone() * bz.inlined_clone();
|
||||||
|
*res.get_unchecked_mut((0, 2)) = ax.inlined_clone() * by.inlined_clone()
|
||||||
|
- ay.inlined_clone() * bx.inlined_clone();
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@ -1571,10 +1635,10 @@ where DefaultAllocator: Allocator<N, U3>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// The smallest angle between two vectors.
|
/// The smallest angle between two vectors.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn angle<R2: Dim, C2: Dim, SB>(&self, other: &Matrix<N, R2, C2, SB>) -> N::RealField
|
pub fn angle<R2: Dim, C2: Dim, SB>(&self, other: &Matrix<N, R2, C2, SB>) -> N::SimdRealField
|
||||||
where
|
where
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
|
||||||
@ -1584,17 +1648,11 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
let n2 = other.norm();
|
let n2 = other.norm();
|
||||||
|
|
||||||
if n1.is_zero() || n2.is_zero() {
|
if n1.is_zero() || n2.is_zero() {
|
||||||
N::RealField::zero()
|
N::SimdRealField::zero()
|
||||||
} else {
|
} else {
|
||||||
let cang = prod.real() / (n1 * n2);
|
let cang = prod.simd_real() / (n1 * n2);
|
||||||
|
cang.simd_clamp(-N::SimdRealField::one(), N::SimdRealField::one())
|
||||||
if cang > N::RealField::one() {
|
.simd_acos()
|
||||||
N::RealField::zero()
|
|
||||||
} else if cang < -N::RealField::one() {
|
|
||||||
N::RealField::pi()
|
|
||||||
} else {
|
|
||||||
cang.acos()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
243
src/base/norm.rs
243
src/base/norm.rs
@ -1,24 +1,36 @@
|
|||||||
use num::Zero;
|
use num::Zero;
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::{RealField, ComplexField};
|
use crate::base::{DefaultAllocator, Dim, Matrix, MatrixMN};
|
||||||
|
use crate::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::storage::{Storage, StorageMut};
|
use crate::storage::{Storage, StorageMut};
|
||||||
use crate::base::{DefaultAllocator, Matrix, Dim, MatrixMN};
|
use crate::{ComplexField, RealField, SimdComplexField, SimdRealField};
|
||||||
use crate::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint};
|
use alga::simd::SimdPartialOrd;
|
||||||
|
|
||||||
|
|
||||||
// FIXME: this should be be a trait on alga?
|
// FIXME: this should be be a trait on alga?
|
||||||
/// A trait for abstract matrix norms.
|
/// A trait for abstract matrix norms.
|
||||||
///
|
///
|
||||||
/// This may be moved to the alga crate in the future.
|
/// This may be moved to the alga crate in the future.
|
||||||
pub trait Norm<N: ComplexField> {
|
pub trait Norm<N: SimdComplexField> {
|
||||||
/// Apply this norm to the given matrix.
|
/// Apply this norm to the given matrix.
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::RealField
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::SimdRealField
|
||||||
where R: Dim, C: Dim, S: Storage<N, R, C>;
|
where
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<N, R, C>;
|
||||||
/// Use the metric induced by this norm to compute the metric distance between the two given matrices.
|
/// Use the metric induced by this norm to compute the metric distance between the two given matrices.
|
||||||
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N::RealField
|
fn metric_distance<R1, C1, S1, R2, C2, S2>(
|
||||||
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
|
&self,
|
||||||
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
m1: &Matrix<N, R1, C1, S1>,
|
||||||
|
m2: &Matrix<N, R2, C2, S2>,
|
||||||
|
) -> N::SimdRealField
|
||||||
|
where
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
S1: Storage<N, R1, C1>,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>;
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,81 +41,123 @@ pub struct LpNorm(pub i32);
|
|||||||
/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm.
|
/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm.
|
||||||
pub struct UniformNorm;
|
pub struct UniformNorm;
|
||||||
|
|
||||||
impl<N: ComplexField> Norm<N> for EuclideanNorm {
|
impl<N: SimdComplexField> Norm<N> for EuclideanNorm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::RealField
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::SimdRealField
|
||||||
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
where
|
||||||
m.norm_squared().sqrt()
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<N, R, C>,
|
||||||
|
{
|
||||||
|
m.norm_squared().simd_sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N::RealField
|
fn metric_distance<R1, C1, S1, R2, C2, S2>(
|
||||||
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
|
&self,
|
||||||
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
m1: &Matrix<N, R1, C1, S1>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
m2: &Matrix<N, R2, C2, S2>,
|
||||||
m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| {
|
) -> N::SimdRealField
|
||||||
|
where
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
S1: Storage<N, R1, C1>,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
|
{
|
||||||
|
m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| {
|
||||||
let diff = a - b;
|
let diff = a - b;
|
||||||
acc + diff.modulus_squared()
|
acc + diff.simd_modulus_squared()
|
||||||
}).sqrt()
|
})
|
||||||
|
.simd_sqrt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField> Norm<N> for LpNorm {
|
impl<N: SimdComplexField> Norm<N> for LpNorm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::RealField
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::SimdRealField
|
||||||
where R: Dim, C: Dim, S: Storage<N, R, C> {
|
where
|
||||||
m.fold(N::RealField::zero(), |a, b| {
|
R: Dim,
|
||||||
a + b.modulus().powi(self.0)
|
C: Dim,
|
||||||
}).powf(crate::convert(1.0 / (self.0 as f64)))
|
S: Storage<N, R, C>,
|
||||||
|
{
|
||||||
|
m.fold(N::SimdRealField::zero(), |a, b| {
|
||||||
|
a + b.simd_modulus().simd_powi(self.0)
|
||||||
|
})
|
||||||
|
.simd_powf(crate::convert(1.0 / (self.0 as f64)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N::RealField
|
fn metric_distance<R1, C1, S1, R2, C2, S2>(
|
||||||
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
|
&self,
|
||||||
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
m1: &Matrix<N, R1, C1, S1>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
m2: &Matrix<N, R2, C2, S2>,
|
||||||
m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| {
|
) -> N::SimdRealField
|
||||||
|
where
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
S1: Storage<N, R1, C1>,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
|
{
|
||||||
|
m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| {
|
||||||
let diff = a - b;
|
let diff = a - b;
|
||||||
acc + diff.modulus().powi(self.0)
|
acc + diff.simd_modulus().simd_powi(self.0)
|
||||||
}).powf(crate::convert(1.0 / (self.0 as f64)))
|
})
|
||||||
|
.simd_powf(crate::convert(1.0 / (self.0 as f64)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: ComplexField> Norm<N> for UniformNorm {
|
impl<N: SimdComplexField> Norm<N> for UniformNorm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::RealField
|
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N::SimdRealField
|
||||||
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
|
// NOTE: we don't use `m.amax()` here because for the complex
|
||||||
// numbers this will return the max norm1 instead of the modulus.
|
// numbers this will return the max norm1 instead of the modulus.
|
||||||
m.fold(N::RealField::zero(), |acc, a| acc.max(a.modulus()))
|
m.fold(N::SimdRealField::zero(), |acc, a| {
|
||||||
|
acc.simd_max(a.simd_modulus())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N::RealField
|
fn metric_distance<R1, C1, S1, R2, C2, S2>(
|
||||||
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
|
&self,
|
||||||
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
m1: &Matrix<N, R1, C1, S1>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
|
m2: &Matrix<N, R2, C2, S2>,
|
||||||
m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| {
|
) -> N::SimdRealField
|
||||||
let val = (a - b).modulus();
|
where
|
||||||
if val > acc {
|
R1: Dim,
|
||||||
val
|
C1: Dim,
|
||||||
} else {
|
S1: Storage<N, R1, C1>,
|
||||||
acc
|
R2: Dim,
|
||||||
}
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
|
||||||
|
{
|
||||||
|
m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| {
|
||||||
|
let val = (a - b).simd_modulus();
|
||||||
|
acc.simd_max(val)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|
||||||
/// The squared L2 norm of this vector.
|
/// The squared L2 norm of this vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn norm_squared(&self) -> N::RealField {
|
pub fn norm_squared(&self) -> N::SimdRealField {
|
||||||
let mut res = N::RealField::zero();
|
let mut res = N::SimdRealField::zero();
|
||||||
|
|
||||||
for i in 0..self.ncols() {
|
for i in 0..self.ncols() {
|
||||||
let col = self.column(i);
|
let col = self.column(i);
|
||||||
res += col.dotc(&col).real()
|
res += col.dotc(&col).simd_real()
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
@ -113,17 +167,21 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
///
|
///
|
||||||
/// Use `.apply_norm` to apply a custom norm.
|
/// Use `.apply_norm` to apply a custom norm.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn norm(&self) -> N::RealField {
|
pub fn norm(&self) -> N::SimdRealField {
|
||||||
self.norm_squared().sqrt()
|
self.norm_squared().simd_sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm.
|
/// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm.
|
||||||
///
|
///
|
||||||
/// Use `.apply_metric_distance` to apply a custom norm.
|
/// Use `.apply_metric_distance` to apply a custom norm.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>) -> N::RealField
|
pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>) -> N::SimdRealField
|
||||||
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
where
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
{
|
||||||
self.apply_metric_distance(rhs, &EuclideanNorm)
|
self.apply_metric_distance(rhs, &EuclideanNorm)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +198,7 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm());
|
/// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply_norm(&self, norm: &impl Norm<N>) -> N::RealField {
|
pub fn apply_norm(&self, norm: &impl Norm<N>) -> N::SimdRealField {
|
||||||
norm.norm(self)
|
norm.norm(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +217,17 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm());
|
/// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply_metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>, norm: &impl Norm<N>) -> N::RealField
|
pub fn apply_metric_distance<R2, C2, S2>(
|
||||||
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
|
&self,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
rhs: &Matrix<N, R2, C2, S2>,
|
||||||
|
norm: &impl Norm<N>,
|
||||||
|
) -> N::SimdRealField
|
||||||
|
where
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
{
|
||||||
norm.metric_distance(self, rhs)
|
norm.metric_distance(self, rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +237,7 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
///
|
///
|
||||||
/// This function is simply implemented as a call to `norm()`
|
/// This function is simply implemented as a call to `norm()`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn magnitude(&self) -> N::RealField {
|
pub fn magnitude(&self) -> N::SimdRealField {
|
||||||
self.norm()
|
self.norm()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,11 +247,34 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
///
|
///
|
||||||
/// This function is simply implemented as a call to `norm_squared()`
|
/// This function is simply implemented as a call to `norm_squared()`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn magnitude_squared(&self) -> N::RealField {
|
pub fn magnitude_squared(&self) -> N::SimdRealField {
|
||||||
self.norm_squared()
|
self.norm_squared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the magnitude of this vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_magnitude(&mut self, magnitude: N::SimdRealField)
|
||||||
|
where S: StorageMut<N, R, C> {
|
||||||
|
let n = self.norm();
|
||||||
|
self.scale_mut(magnitude / n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a normalized version of this matrix.
|
||||||
|
#[inline]
|
||||||
|
#[must_use = "Did you mean to use normalize_mut()?"]
|
||||||
|
pub fn normalize(&self) -> MatrixMN<N, R, C>
|
||||||
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
|
self.unscale(self.norm())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Lp norm of this matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn lp_norm(&self, p: i32) -> N::SimdRealField {
|
||||||
|
self.apply_norm(&LpNorm(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// Sets the magnitude of this vector unless it is smaller than `min_magnitude`.
|
/// Sets the magnitude of this vector unless it is smaller than `min_magnitude`.
|
||||||
///
|
///
|
||||||
/// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged.
|
/// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged.
|
||||||
@ -200,14 +289,6 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a normalized version of this matrix.
|
|
||||||
#[inline]
|
|
||||||
#[must_use = "Did you mean to use normalize_mut()?"]
|
|
||||||
pub fn normalize(&self) -> MatrixMN<N, R, C>
|
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
|
||||||
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`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "Did you mean to use try_normalize_mut()?"]
|
#[must_use = "Did you mean to use try_normalize_mut()?"]
|
||||||
@ -221,30 +302,26 @@ impl<N: ComplexField, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
Some(self.unscale(n))
|
Some(self.unscale(n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Lp norm of this matrix.
|
|
||||||
#[inline]
|
|
||||||
pub fn lp_norm(&self, p: i32) -> N::RealField {
|
|
||||||
self.apply_norm(&LpNorm(p))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: SimdComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
impl<N: ComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|
||||||
/// Normalizes this matrix in-place and returns its norm.
|
/// Normalizes this matrix in-place and returns its norm.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize_mut(&mut self) -> N::RealField {
|
pub fn normalize_mut(&mut self) -> N::SimdRealField {
|
||||||
let n = self.norm();
|
let n = self.norm();
|
||||||
self.unscale_mut(n);
|
self.unscale_mut(n);
|
||||||
|
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: ComplexField, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
|
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
|
||||||
///
|
///
|
||||||
/// If the normalization succeeded, returns the old norm of this matrix.
|
/// If the normalization succeeded, returns the old norm of this matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option<N::RealField> {
|
pub fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option<N::RealField>
|
||||||
|
where N: ComplexField {
|
||||||
let n = self.norm();
|
let n = self.norm();
|
||||||
|
|
||||||
if n <= min_norm {
|
if n <= min_norm {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use num::{One, Signed, Zero};
|
use num::{One, Signed, Zero};
|
||||||
use std::cmp::{PartialOrd, Ordering};
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::{
|
use std::ops::{
|
||||||
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
|
||||||
use alga::general::{ComplexField, ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
|
use alga::general::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
|
||||||
|
use alga::simd::{SimdPartialOrd, SimdSigned};
|
||||||
|
|
||||||
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
||||||
use crate::base::constraint::{
|
use crate::base::constraint::{
|
||||||
@ -14,6 +15,7 @@ use crate::base::constraint::{
|
|||||||
use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
|
use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
|
||||||
use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut};
|
use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut};
|
||||||
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar, VectorSliceN};
|
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar, VectorSliceN};
|
||||||
|
use crate::SimdComplexField;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -445,7 +447,9 @@ where
|
|||||||
/// # use nalgebra::DMatrix;
|
/// # use nalgebra::DMatrix;
|
||||||
/// iter::empty::<&DMatrix<f64>>().sum::<DMatrix<f64>>(); // panics!
|
/// iter::empty::<&DMatrix<f64>>().sum::<DMatrix<f64>>(); // panics!
|
||||||
/// ```
|
/// ```
|
||||||
fn sum<I: Iterator<Item = &'a MatrixMN<N, Dynamic, C>>>(mut iter: I) -> MatrixMN<N, Dynamic, C> {
|
fn sum<I: Iterator<Item = &'a MatrixMN<N, Dynamic, C>>>(
|
||||||
|
mut iter: I,
|
||||||
|
) -> MatrixMN<N, Dynamic, C> {
|
||||||
if let Some(first) = iter.next() {
|
if let Some(first) = iter.next() {
|
||||||
iter.fold(first.clone(), |acc, x| acc + x)
|
iter.fold(first.clone(), |acc, x| acc + x)
|
||||||
} else {
|
} else {
|
||||||
@ -693,7 +697,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn ad_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixMN<N, C1, C2>
|
pub fn ad_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixMN<N, C1, C2>
|
||||||
where
|
where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
DefaultAllocator: Allocator<N, C1, C2>,
|
DefaultAllocator: Allocator<N, C1, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
ShapeConstraint: SameNumberOfRows<R1, R2>,
|
||||||
@ -710,7 +714,10 @@ where
|
|||||||
&self,
|
&self,
|
||||||
rhs: &Matrix<N, R2, C2, SB>,
|
rhs: &Matrix<N, R2, C2, SB>,
|
||||||
out: &mut Matrix<N, R3, C3, SC>,
|
out: &mut Matrix<N, R3, C3, SC>,
|
||||||
dot: impl Fn(&VectorSliceN<N, R1, SA::RStride, SA::CStride>, &VectorSliceN<N, R2, SB::RStride, SB::CStride>) -> N,
|
dot: impl Fn(
|
||||||
|
&VectorSliceN<N, R1, SA::RStride, SA::CStride>,
|
||||||
|
&VectorSliceN<N, R2, SB::RStride, SB::CStride>,
|
||||||
|
) -> N,
|
||||||
) where
|
) where
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
SC: StorageMut<N, R3, C3>,
|
SC: StorageMut<N, R3, C3>,
|
||||||
@ -760,7 +767,7 @@ where
|
|||||||
rhs: &Matrix<N, R2, C2, SB>,
|
rhs: &Matrix<N, R2, C2, SB>,
|
||||||
out: &mut Matrix<N, R3, C3, SC>,
|
out: &mut Matrix<N, R3, C3, SC>,
|
||||||
) where
|
) where
|
||||||
N: ComplexField,
|
N: SimdComplexField,
|
||||||
SB: Storage<N, R2, C2>,
|
SB: Storage<N, R2, C2>,
|
||||||
SC: StorageMut<N, R3, C3>,
|
SC: StorageMut<N, R3, C3>,
|
||||||
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
|
||||||
@ -813,7 +820,8 @@ where
|
|||||||
let coeff = self.get_unchecked((i1, j1)).inlined_clone();
|
let coeff = self.get_unchecked((i1, j1)).inlined_clone();
|
||||||
|
|
||||||
for i2 in 0..nrows2.value() {
|
for i2 in 0..nrows2.value() {
|
||||||
*data_res = coeff.inlined_clone() * rhs.get_unchecked((i2, j2)).inlined_clone();
|
*data_res = coeff.inlined_clone()
|
||||||
|
* rhs.get_unchecked((i2, j2)).inlined_clone();
|
||||||
data_res = data_res.offset(1);
|
data_res = data_res.offset(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -868,23 +876,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
#[inline(always)]
|
|
||||||
fn xcmp<N2>(&self, abs: impl Fn(N) -> N2, ordering: Ordering) -> N2
|
|
||||||
where N2: Scalar + PartialOrd + Zero {
|
|
||||||
let mut iter = self.iter();
|
|
||||||
let mut max = iter.next().cloned().map_or(N2::zero(), &abs);
|
|
||||||
|
|
||||||
for e in iter {
|
|
||||||
let ae = abs(e.inlined_clone());
|
|
||||||
|
|
||||||
if ae.partial_cmp(&max) == Some(ordering) {
|
|
||||||
max = ae;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
max
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the absolute value of the component with the largest absolute value.
|
/// Returns the absolute value of the component with the largest absolute value.
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
@ -894,8 +885,11 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn amax(&self) -> N
|
pub fn amax(&self) -> N
|
||||||
where N: PartialOrd + Signed {
|
where N: Zero + SimdSigned + SimdPartialOrd {
|
||||||
self.xcmp(|e| e.abs(), Ordering::Greater)
|
self.fold_with(
|
||||||
|
|e| e.unwrap_or(&N::zero()).simd_abs(),
|
||||||
|
|a, b| a.simd_max(b.simd_abs()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the the 1-norm of the complex component with the largest 1-norm.
|
/// Returns the the 1-norm of the complex component with the largest 1-norm.
|
||||||
@ -908,9 +902,12 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// Complex::new(1.0, 3.0)).camax(), 5.0);
|
/// Complex::new(1.0, 3.0)).camax(), 5.0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn camax(&self) -> N::RealField
|
pub fn camax(&self) -> N::SimdRealField
|
||||||
where N: ComplexField {
|
where N: SimdComplexField {
|
||||||
self.xcmp(|e| e.norm1(), Ordering::Greater)
|
self.fold_with(
|
||||||
|
|e| e.unwrap_or(&N::zero()).simd_norm1(),
|
||||||
|
|a, b| a.simd_max(b.simd_norm1()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the component with the largest value.
|
/// Returns the component with the largest value.
|
||||||
@ -923,8 +920,11 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max(&self) -> N
|
pub fn max(&self) -> N
|
||||||
where N: PartialOrd + Zero {
|
where N: SimdPartialOrd + Zero {
|
||||||
self.xcmp(|e| e, Ordering::Greater)
|
self.fold_with(
|
||||||
|
|e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()),
|
||||||
|
|a, b| a.simd_max(b.inlined_clone()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the absolute value of the component with the smallest absolute value.
|
/// Returns the absolute value of the component with the smallest absolute value.
|
||||||
@ -936,8 +936,11 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn amin(&self) -> N
|
pub fn amin(&self) -> N
|
||||||
where N: PartialOrd + Signed {
|
where N: Zero + SimdPartialOrd + SimdSigned {
|
||||||
self.xcmp(|e| e.abs(), Ordering::Less)
|
self.fold_with(
|
||||||
|
|e| e.map(|e| e.simd_abs()).unwrap_or(N::zero()),
|
||||||
|
|a, b| a.simd_min(b.simd_abs()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the the 1-norm of the complex component with the smallest 1-norm.
|
/// Returns the the 1-norm of the complex component with the smallest 1-norm.
|
||||||
@ -950,9 +953,15 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// Complex::new(1.0, 3.0)).camin(), 3.0);
|
/// Complex::new(1.0, 3.0)).camin(), 3.0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn camin(&self) -> N::RealField
|
pub fn camin(&self) -> N::SimdRealField
|
||||||
where N: ComplexField {
|
where N: SimdComplexField {
|
||||||
self.xcmp(|e| e.norm1(), Ordering::Less)
|
self.fold_with(
|
||||||
|
|e| {
|
||||||
|
e.map(|e| e.simd_norm1())
|
||||||
|
.unwrap_or(N::SimdRealField::zero())
|
||||||
|
},
|
||||||
|
|a, b| a.simd_min(b.simd_norm1()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the component with the smallest value.
|
/// Returns the component with the smallest value.
|
||||||
@ -965,7 +974,10 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min(&self) -> N
|
pub fn min(&self) -> N
|
||||||
where N: PartialOrd + Zero {
|
where N: SimdPartialOrd + Zero {
|
||||||
self.xcmp(|e| e, Ordering::Less)
|
self.fold_with(
|
||||||
|
|e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()),
|
||||||
|
|a, b| a.simd_min(b.inlined_clone()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/lib.rs
19
src/lib.rs
@ -110,8 +110,8 @@ extern crate generic_array;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
extern crate matrixmultiply;
|
extern crate matrixmultiply;
|
||||||
extern crate num_complex;
|
extern crate num_complex;
|
||||||
extern crate num_traits as num;
|
|
||||||
extern crate num_rational;
|
extern crate num_rational;
|
||||||
|
extern crate num_traits as num;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
extern crate rand_distr;
|
extern crate rand_distr;
|
||||||
@ -141,30 +141,31 @@ pub mod linalg;
|
|||||||
#[cfg(feature = "sparse")]
|
#[cfg(feature = "sparse")]
|
||||||
pub mod sparse;
|
pub mod sparse;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[deprecated(
|
|
||||||
note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate."
|
|
||||||
)]
|
|
||||||
pub use base as core;
|
|
||||||
pub use crate::base::*;
|
pub use crate::base::*;
|
||||||
pub use crate::geometry::*;
|
pub use crate::geometry::*;
|
||||||
pub use crate::linalg::*;
|
pub use crate::linalg::*;
|
||||||
#[cfg(feature = "sparse")]
|
#[cfg(feature = "sparse")]
|
||||||
pub use crate::sparse::*;
|
pub use crate::sparse::*;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[deprecated(
|
||||||
|
note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate."
|
||||||
|
)]
|
||||||
|
pub use base as core;
|
||||||
|
|
||||||
use std::cmp::{self, Ordering, PartialOrd};
|
use std::cmp::{self, Ordering, PartialOrd};
|
||||||
|
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice,
|
Additive, AdditiveGroup, Identity, JoinSemilattice, Lattice, MeetSemilattice, Multiplicative,
|
||||||
Multiplicative, SupersetOf,
|
SupersetOf, TwoSidedInverse,
|
||||||
};
|
};
|
||||||
use alga::linear::SquareMatrix as AlgaSquareMatrix;
|
use alga::linear::SquareMatrix as AlgaSquareMatrix;
|
||||||
use alga::linear::{EuclideanSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace};
|
use alga::linear::{EuclideanSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace};
|
||||||
use num::Signed;
|
use num::Signed;
|
||||||
|
|
||||||
pub use alga::general::{Id, RealField, ComplexField};
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use alga::general::Real;
|
pub use alga::general::Real;
|
||||||
|
pub use alga::general::{ComplexField, Id, RealField};
|
||||||
|
pub use alga::simd::{SimdComplexField, SimdRealField};
|
||||||
pub use num_complex::Complex;
|
pub use num_complex::Complex;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user