Skip to content

Commit

Permalink
WIP use Complex instead of Real whenever possible on the linalg module.
Browse files Browse the repository at this point in the history
  • Loading branch information
sebcrozet committed Mar 2, 2019
1 parent 7c91f2e commit 77f048b
Show file tree
Hide file tree
Showing 34 changed files with 914 additions and 445 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
abomonation-serialize = [ "abomonation" ]
sparse = [ ]
debug = [ ]
debug = [ "approx/num-complex", "rand/std" ]
alloc = [ ]
io = [ "pest", "pest_derive" ]

Expand All @@ -53,3 +53,6 @@ rand_xorshift = "0.1"

[workspace]
members = [ "nalgebra-lapack", "nalgebra-glm" ]

[patch.crates-io]
alga = { path = "../alga/alga" }
118 changes: 118 additions & 0 deletions src/base/blas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,39 @@ use base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};


// FIXME: find a way to avoid code duplication just for complex number support.
impl<N: Complex, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index of the vector component with the largest complex or real absolute value.
///
/// # Examples:
///
/// ```
/// # use num_complex::Complex;
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(Complex::new(11.0, 3.0), Complex::new(-15.0, 0.0), Complex::new(13.0, 5.0));
/// assert_eq!(vec.icamax(), 2);
/// ```
#[inline]
pub fn icamax(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty.");

let mut the_max = unsafe { self.vget_unchecked(0).asum() };
let mut the_i = 0;

for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i).asum() };

if val > the_max {
the_max = val;
the_i = i;
}
}

the_i
}
}

impl<N: Scalar + PartialOrd, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index and value of the vector component with the largest value.
///
Expand Down Expand Up @@ -157,6 +190,41 @@ impl<N: Scalar + PartialOrd, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
}
}

// FIXME: find a way to avoid code duplication just for complex number support.
impl<N: Complex, 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.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix2x3;
/// let mat = Matrix2x3::new(Complex::new(11.0, 1.0), Complex::new(-12.0, 2.0), Complex::new(13.0, 3.0),
/// Complex::new(21.0, 43.0), Complex::new(22.0, 5.0), Complex::new(-23.0, 0.0);
/// assert_eq!(mat.iamax_full(), (1, 0));
/// ```
#[inline]
pub fn icamax_full(&self) -> (usize, usize) {
assert!(!self.is_empty(), "The input matrix must not be empty.");

let mut the_max = unsafe { self.get_unchecked((0, 0)).asum() };
let mut the_ij = (0, 0);

for j in 0..self.ncols() {
for i in 0..self.nrows() {
let val = unsafe { self.get_unchecked((i, j)).asum() };

if val > the_max {
the_max = val;
the_ij = (i, j);
}
}
}

the_ij
}
}


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.
///
Expand Down Expand Up @@ -705,6 +773,56 @@ where
}
}

// FIXME: duplicate code
impl<N, R1: Dim, C1: Dim, S: StorageMut<N, R1, C1>> Matrix<N, R1, C1, S>
where N: Complex + Zero + ClosedAdd + ClosedMul
{
/// Computes `self = alpha * x * y.transpose() + beta * self`.
///
/// If `beta` is zero, `self` is never read.
///
/// # Examples:
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector2, Vector3};
/// let mut mat = Matrix2x3::repeat(4.0);
/// let vec1 = Vector2::new(1.0, 2.0);
/// let vec2 = Vector3::new(0.1, 0.2, 0.3);
/// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0;
///
/// mat.ger(10.0, &vec1, &vec2, 5.0);
/// assert_eq!(mat, expected);
/// ```
#[inline]
pub fn gerc<D2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: N,
x: &Vector<N, D2, SB>,
y: &Vector<N, D3, SC>,
beta: N,
) where
N: One,
SB: Storage<N, D2>,
SC: Storage<N, D3>,
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3>,
{
let (nrows1, ncols1) = self.shape();
let dim2 = x.nrows();
let dim3 = y.nrows();

assert!(
nrows1 == dim2 && ncols1 == dim3,
"ger: dimensions mismatch."
);

for j in 0..ncols1 {
// FIXME: avoid bound checks.
let val = unsafe { y.vget_unchecked(j).conjugate() };
self.column_mut(j).axpy(alpha * val, x, beta);
}
}
}

impl<N, R1: Dim, C1: Dim, S: StorageMut<N, R1, C1>> Matrix<N, R1, C1, S>
where N: Scalar + Zero + ClosedAdd + ClosedMul
{
Expand Down
73 changes: 71 additions & 2 deletions src/base/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,47 @@ impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res
}
}

/// The conjugate of `self`.
#[inline]
pub fn conjugate(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self.map(|e| e.conjugate())
}

/// Divides each component of `self` by the given real.
#[inline]
pub fn unscale(&self, real: N::Real) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self.map(|e| e.unscale(real))
}

/// Multiplies each component of `self` by the given real.
#[inline]
pub fn scale(&self, real: N::Real) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self.map(|e| e.scale(real))
}
}

impl<N: Complex, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// The conjugate of `self` computed in-place.
#[inline]
pub fn conjugate_mut(&mut self) {
self.apply(|e| e.conjugate())
}

/// Divides each component of `self` by the given real.
#[inline]
pub fn unscale_mut(&mut self, real: N::Real) {
self.apply(|e| e.unscale(real))
}

/// Multiplies each component of `self` by the given real.
#[inline]
pub fn scale_mut(&mut self, real: N::Real) {
self.apply(|e| e.scale(real))
}
}

impl<N: Complex, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
Expand Down Expand Up @@ -975,7 +1016,7 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
#[inline]
pub fn diagonal(&self) -> VectorN<N, D>
where DefaultAllocator: Allocator<N, D> {
where DefaultAllocator: Allocator<N, D> {
assert!(
self.is_square(),
"Unable to get the diagonal of a non-square matrix."
Expand All @@ -996,7 +1037,7 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
/// Computes a trace of a square matrix, i.e., the sum of its diagonal elements.
#[inline]
pub fn trace(&self) -> N
where N: Ring {
where N: Ring {
assert!(
self.is_square(),
"Cannot compute the trace of non-square matrix."
Expand All @@ -1013,6 +1054,34 @@ impl<N: Scalar, 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> {
/// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`.
#[inline]
pub fn symmetric_part(&self) -> MatrixMN<N, D, D>
where DefaultAllocator: Allocator<N, D, D> {
assert!(self.is_square(), "Cannot compute the symmetric part of a non-square matrix.");
let mut tr = self.transpose();
tr += self;
tr *= ::convert::<_, N>(0.5);
tr
}

/// The hermitian part of `self`, i.e., `0.5 * (self + self.conjugate_transpose())`.
#[inline]
pub fn hermitian_part(&self) -> MatrixMN<N, D, D>
where DefaultAllocator: Allocator<N, D, D> {
assert!(self.is_square(), "Cannot compute the hermitian part of a non-square matrix.");
let nrows = self.data.shape().0;

unsafe {
let mut tr = self.conjugate_transpose();
tr += self;
tr *= ::convert::<_, N>(0.5);
tr
}
}
}

impl<N: Scalar + One + Zero, 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
Expand Down
21 changes: 20 additions & 1 deletion src/base/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};

use alga::general::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use alga::general::{Complex, ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};

use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use base::constraint::{
Expand Down Expand Up @@ -760,6 +760,25 @@ where
}
}

// XXX: avoid code duplication.
impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns the absolute value of the component with the largest absolute value.
#[inline]
pub fn camax(&self) -> N::Real {
let mut max = N::Real::zero();

for e in self.iter() {
let ae = e.asum();

if ae > max {
max = ae;
}
}

max
}
}

impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns the absolute value of the component with the largest absolute value.
#[inline]
Expand Down
17 changes: 10 additions & 7 deletions src/base/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use approx::RelativeEq;
use num::{One, Zero};

use alga::general::{ClosedAdd, ClosedMul, Real};
use alga::general::{ClosedAdd, ClosedMul, Real, Complex};

use base::allocator::Allocator;
use base::dimension::{Dim, DimMin};
Expand Down Expand Up @@ -82,20 +82,23 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {

true
}
}

impl<N: Complex, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Checks that `Mᵀ × M = Id`.
///
/// In this definition `Id` is approximately equal to the identity matrix with a relative error
/// equal to `eps`.
#[inline]
pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool
where
N: Zero + One + ClosedAdd + ClosedMul + RelativeEq,
S: Storage<N, R, C>,
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, C, C>,
where
N: Zero + One + ClosedAdd + ClosedMul + RelativeEq,
S: Storage<N, R, C>,
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, R, C> + Allocator<N, C, C>,
{
(self.tr_mul(self)).is_identity(eps)
// FIXME: add a conjugate-transpose-mul
(self.conjugate().tr_mul(self)).is_identity(eps)
}
}

Expand Down
13 changes: 7 additions & 6 deletions src/geometry/reflection.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alga::general::Real;
use alga::general::Complex;
use base::allocator::Allocator;
use base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
use base::{DefaultAllocator, Matrix, Scalar, Unit, Vector};
Expand All @@ -13,15 +13,15 @@ pub struct Reflection<N: Scalar, D: Dim, S: Storage<N, D>> {
bias: N,
}

impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
impl<N: Complex, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
/// Creates a new reflection wrt the plane orthogonal to the given axis and bias.
///
/// The bias is the position of the plane on the axis. In particular, a bias equal to zero
/// represents a plane that passes through the origin.
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Self {
Self {
axis: axis.into_inner(),
bias: bias,
bias,
}
}

Expand All @@ -35,7 +35,7 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
D: DimName,
DefaultAllocator: Allocator<N, D>,
{
let bias = pt.coords.dot(axis.as_ref());
let bias = axis.cdot(&pt.coords);
Self::new(axis, bias)
}

Expand All @@ -56,7 +56,7 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
// dot product, and then mutably. Somehow, this allows significantly
// better optimizations of the dot product from the compiler.
let m_two: N = ::convert(-2.0f64);
let factor = (rhs.column(i).dot(&self.axis) - self.bias) * m_two;
let factor = (self.axis.cdot(&rhs.column(i)) - self.bias) * m_two;
rhs.column_mut(i).axpy(factor, &self.axis, N::one());
}
}
Expand All @@ -70,8 +70,9 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
S2: StorageMut<N, R2, C2>,
S3: StorageMut<N, R2>,
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1>,
DefaultAllocator: Allocator<N, D>
{
rhs.mul_to(&self.axis, work);
rhs.mul_to(&self.axis.conjugate(), work);

if !self.bias.is_zero() {
work.add_scalar_mut(-self.bias);
Expand Down
Loading

0 comments on commit 77f048b

Please sign in to comment.