Merge pull request #9 from vbarrielle/genericQR

Generic QR factorization
This commit is contained in:
Sébastien Crozet 2014-05-16 21:16:07 +02:00
commit cfa18252bc
17 changed files with 331 additions and 121 deletions

View File

@ -50,6 +50,7 @@ and keeps an optimized set of tools for computational graphics and physics. Thos
* Dynamically sized vector: `DVec`.
* Dynamically sized (square or rectangular) matrix: `DMat`.
* A few methods for data analysis: `Cov`, `Mean`.
* Some matrix factorization algorithms: QR decomposition, ...
* Almost one trait per functionality: useful for generic programming.
* Operator overloading using the double trait dispatch
[trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/).

View File

@ -1,54 +1,65 @@
use std::num::{Zero, Float};
use na::DVec;
use na::DMat;
use traits::operations::Transpose;
use traits::structure::ColSlice;
use traits::structure::{ColSlice, Eye, Indexable};
use traits::geometry::Norm;
use std::cmp::min;
/// QR decomposition using Householder reflections
/// # Arguments
/// * `m` - matrix to decompose
pub fn decomp_qr<N: Clone + Float>(m: &DMat<N>) -> (DMat<N>, DMat<N>) {
let rows = m.nrows();
let cols = m.ncols();
assert!(rows >= cols);
let mut q : DMat<N> = DMat::new_identity(rows);
let mut r = m.clone();
let subtract_reflection = |vec: DVec<N>| -> DMat<N> {
// FIXME: we don't handle the complex case here
let mut qk : DMat<N> = DMat::new_identity(rows);
let start = rows - vec.at.len();
for j in range(start, rows) {
for i in range(start, rows) {
/// Get the householder matrix corresponding to a reflexion to the hyperplane
/// defined by `vec̀ . It can be a reflexion contained in a subspace.
///
/// # Arguments
/// * `dim` - the dimension of the space the resulting matrix operates in
/// * `start` - the starting dimension of the subspace of the reflexion
/// * `vec` - the vector defining the reflection.
pub fn householder_matrix<N: Float,
M: Eye + Indexable<(uint, uint), N>,
V: Indexable<uint, N>>
(dim: uint, start: uint, vec: V) -> M {
let mut qk : M = Eye::new_identity(dim);
let stop = start + vec.shape();
assert!(stop <= dim);
for j in range(start, stop) {
for i in range(start, stop) {
unsafe {
let vv = vec.at_fast(i - start) * vec.at_fast(j - start);
let qkij = qk.at_fast(i, j);
qk.set_fast(i, j, qkij - vv - vv);
let vv = vec.unsafe_at(i) * vec.unsafe_at(j);
let qkij = qk.unsafe_at((i, j));
qk.unsafe_set((i, j), qkij - vv - vv);
}
}
}
qk
};
}
/// QR decomposition using Householder reflections
/// # Arguments
/// * `m` - matrix to decompose
pub fn decomp_qr<N: Float,
V: Indexable<uint, N> + Norm<N>,
M: Clone + Eye + ColSlice<V> + Transpose
+ Indexable<(uint, uint), N> + Mul<M, M>>
(m: &M) -> (M, M) {
let (rows, cols) = m.shape();
assert!(rows >= cols);
let mut q : M = Eye::new_identity(rows);
let mut r = m.clone();
let iterations = min(rows - 1, cols);
for ite in range(0u, iterations) {
let mut v = r.col_slice(ite, ite, rows);
let alpha =
if unsafe { v.at_fast(ite) } >= Zero::zero() {
if unsafe { v.unsafe_at(ite) } >= Zero::zero() {
-Norm::norm(&v)
}
else {
Norm::norm(&v)
};
unsafe {
let x = v.at_fast(0);
v.set_fast(0, x - alpha);
let x = v.unsafe_at(0);
v.unsafe_set(0, x - alpha);
}
let _ = v.normalize();
let qk = subtract_reflection(v);
let qk: M = householder_matrix(rows, 0, v);
r = qk * r;
q = q * Transpose::transpose_cpy(&qk);
}

View File

@ -1,4 +1,4 @@
pub use self::decompositions::decomp_qr;
pub use self::decompositions::{decomp_qr, householder_matrix};
mod decompositions;

View File

@ -1,6 +1,6 @@
//! **nalgebra** prelude.
use std::num::{Zero, One};
use std::num::{Zero, One, FloatMath};
use std::cmp;
pub use traits::{PartialLess, PartialEqual, PartialGreater, NotComparable};
pub use traits::{
@ -40,7 +40,8 @@ pub use traits::{
UniformSphereSample,
AnyVec,
VecExt,
ColSlice, RowSlice
ColSlice, RowSlice,
Eye
};
pub use structs::{
@ -54,7 +55,8 @@ pub use structs::{
};
pub use linalg::{
decomp_qr
decomp_qr,
householder_matrix
};
/// Traits to work around the language limitations related to operator overloading.
@ -215,7 +217,7 @@ pub fn one<T: One>() -> T {
*/
/// Computes a projection matrix given the frustrum near plane width, height, the field of
/// view, and the distance to the clipping planes (`znear` and `zfar`).
pub fn perspective3d<N: Float + Cast<f32> + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4<N> {
pub fn perspective3d<N: FloatMath + Cast<f32> + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4<N> {
let aspect = width / height;
let _1: N = one();
@ -720,6 +722,10 @@ pub fn mean<N, M: Mean<N>>(observations: &M) -> N {
//
//
/// Construct the identity matrix for a given dimension
#[inline(always)]
pub fn new_identity<M: Eye>(dim: uint) -> M { Eye::new_identity(dim) }
/*
* Basis
*/

View File

@ -9,7 +9,7 @@ use traits::operations::ApproxEq;
use std::mem;
use structs::dvec::{DVec, DVecMulRhs};
use traits::operations::{Inv, Transpose, Mean, Cov};
use traits::structure::{Cast, ColSlice, RowSlice};
use traits::structure::{Cast, ColSlice, RowSlice, Eye, Indexable};
use std::fmt::{Show, Formatter, Result};
#[doc(hidden)]
@ -181,19 +181,19 @@ impl<N> DMat<N> {
// FIXME: add a function to modify the dimension (to avoid useless allocations)?
impl<N: One + Zero + Clone> DMat<N> {
impl<N: One + Zero + Clone> Eye for DMat<N> {
/// Builds an identity matrix.
///
/// # Arguments
/// * `dim` - The dimension of the matrix. A `dim`-dimensional matrix contains `dim * dim`
/// components.
#[inline]
pub fn new_identity(dim: uint) -> DMat<N> {
fn new_identity(dim: uint) -> DMat<N> {
let mut res = DMat::new_zeros(dim, dim);
for i in range(0u, dim) {
let _1: N = One::one();
res.set(i, i, _1);
res.set((i, i), _1);
}
res
@ -206,13 +206,16 @@ impl<N: Clone> DMat<N> {
i + j * self.nrows
}
}
impl<N: Clone> Indexable<(uint, uint), N> for DMat<N> {
/// Changes the value of a component of the matrix.
///
/// # Arguments
/// * `row` - 0-based index of the line to be changed
/// * `col` - 0-based index of the column to be changed
/// * `rowcol` - 0-based tuple (row, col) to be changed
#[inline]
pub fn set(&mut self, row: uint, col: uint, val: N) {
fn set(&mut self, rowcol: (uint, uint), val: N) {
let (row, col) = rowcol;
assert!(row < self.nrows);
assert!(col < self.ncols);
@ -222,7 +225,8 @@ impl<N: Clone> DMat<N> {
/// Just like `set` without bounds checking.
#[inline]
pub unsafe fn set_fast(&mut self, row: uint, col: uint, val: N) {
unsafe fn unsafe_set(&mut self, rowcol: (uint, uint), val: N) {
let (row, col) = rowcol;
let offset = self.offset(row, col);
*self.mij.as_mut_slice().unsafe_mut_ref(offset) = val
}
@ -230,20 +234,38 @@ impl<N: Clone> DMat<N> {
/// Reads the value of a component of the matrix.
///
/// # Arguments
/// * `row` - 0-based index of the line to be read
/// * `col` - 0-based index of the column to be read
/// * `rowcol` - 0-based tuple (row, col) to be read
#[inline]
pub fn at(&self, row: uint, col: uint) -> N {
fn at(&self, rowcol: (uint, uint)) -> N {
let (row, col) = rowcol;
assert!(row < self.nrows);
assert!(col < self.ncols);
unsafe { self.at_fast(row, col) }
unsafe { self.unsafe_at((row, col)) }
}
/// Just like `at` without bounds checking.
#[inline]
pub unsafe fn at_fast(&self, row: uint, col: uint) -> N {
unsafe fn unsafe_at(&self, rowcol: (uint, uint)) -> N {
let (row, col) = rowcol;
(*self.mij.as_slice().unsafe_ref(self.offset(row, col))).clone()
}
#[inline]
fn swap(&mut self, rowcol1: (uint, uint), rowcol2: (uint, uint)) {
let (row1, col1) = rowcol1;
let (row2, col2) = rowcol2;
let offset1 = self.offset(row1, col1);
let offset2 = self.offset(row2, col2);
let count = self.mij.len();
assert!(offset1 < count);
assert!(offset2 < count);
self.mij.as_mut_slice().swap(offset1, offset2);
}
fn shape(&self) -> (uint, uint) {
(self.nrows, self.ncols)
}
}
impl<N: Clone + Mul<N, N> + Add<N, N> + Zero> DMatMulRhs<N, DMat<N>> for DMat<N> {
@ -258,10 +280,11 @@ impl<N: Clone + Mul<N, N> + Add<N, N> + Zero> DMatMulRhs<N, DMat<N>> for DMat<N>
unsafe {
for k in range(0u, left.ncols) {
acc = acc + left.at_fast(i, k) * right.at_fast(k, j);
acc = acc
+ left.unsafe_at((i, k)) * right.unsafe_at((k, j));
}
res.set_fast(i, j, acc);
res.unsafe_set((i, j), acc);
}
}
}
@ -282,7 +305,7 @@ DMatMulRhs<N, DVec<N>> for DVec<N> {
for j in range(0u, left.ncols) {
unsafe {
acc = acc + left.at_fast(i, j) * right.at_fast(j);
acc = acc + left.unsafe_at((i, j)) * right.unsafe_at(j);
}
}
@ -306,7 +329,7 @@ DVecMulRhs<N, DVec<N>> for DMat<N> {
for j in range(0u, right.nrows) {
unsafe {
acc = acc + left.at_fast(j) * right.at_fast(j, i);
acc = acc + left.unsafe_at(j) * right.unsafe_at((j, i));
}
}
@ -335,7 +358,7 @@ Inv for DMat<N> {
assert!(self.nrows == self.ncols);
let dim = self.nrows;
let mut res: DMat<N> = DMat::new_identity(dim);
let mut res: DMat<N> = Eye::new_identity(dim);
let _0T: N = Zero::zero();
// inversion using Gauss-Jordan elimination
@ -347,7 +370,7 @@ Inv for DMat<N> {
let mut n0 = k; // index of a non-zero entry
while n0 != dim {
if unsafe { self.at_fast(n0, k) } != _0T {
if unsafe { self.unsafe_at((n0, k)) } != _0T {
break;
}
@ -370,30 +393,30 @@ Inv for DMat<N> {
}
unsafe {
let pivot = self.at_fast(k, k);
let pivot = self.unsafe_at((k, k));
for j in range(k, dim) {
let selfval = self.at_fast(k, j) / pivot;
self.set_fast(k, j, selfval);
let selfval = self.unsafe_at((k, j)) / pivot;
self.unsafe_set((k, j), selfval);
}
for j in range(0u, dim) {
let resval = res.at_fast(k, j) / pivot;
res.set_fast(k, j, resval);
let resval = res.unsafe_at((k, j)) / pivot;
res.unsafe_set((k, j), resval);
}
for l in range(0u, dim) {
if l != k {
let normalizer = self.at_fast(l, k);
let normalizer = self.unsafe_at((l, k));
for j in range(k, dim) {
let selfval = self.at_fast(l, j) - self.at_fast(k, j) * normalizer;
self.set_fast(l, j, selfval);
let selfval = self.unsafe_at((l, j)) - self.unsafe_at((k, j)) * normalizer;
self.unsafe_set((l, j), selfval);
}
for j in range(0u, dim) {
let resval = res.at_fast(l, j) - res.at_fast(k, j) * normalizer;
res.set_fast(l, j, resval);
let resval = res.unsafe_at((l, j)) - res.unsafe_at((k, j)) * normalizer;
res.unsafe_set((l, j), resval);
}
}
}
@ -422,7 +445,7 @@ impl<N: Clone> Transpose for DMat<N> {
for i in range(0u, m.nrows) {
for j in range(0u, m.ncols) {
unsafe {
res.set_fast(j, i, m.at_fast(i, j))
res.unsafe_set((j, i), m.unsafe_at((i, j)))
}
}
}
@ -460,8 +483,8 @@ impl<N: Num + Cast<f32> + Clone> Mean<DVec<N>> for DMat<N> {
for i in range(0u, m.nrows) {
for j in range(0u, m.ncols) {
unsafe {
let acc = res.at_fast(j) + m.at_fast(i, j) * normalizer;
res.set_fast(j, acc);
let acc = res.unsafe_at(j) + m.unsafe_at((i, j)) * normalizer;
res.unsafe_set(j, acc);
}
}
}
@ -482,7 +505,7 @@ impl<N: Clone + Num + Cast<f32> + DMatDivRhs<N, DMat<N>> + ToStr > Cov<DMat<N>>
for i in range(0u, m.nrows) {
for j in range(0u, m.ncols) {
unsafe {
centered.set_fast(i, j, m.at_fast(i, j) - mean.at_fast(j));
centered.unsafe_set((i, j), m.unsafe_at((i, j)) - mean.unsafe_at(j));
}
}
}
@ -520,7 +543,7 @@ impl<N: Clone> RowSlice<DVec<N>> for DMat<N> {
let mut slice_idx = 0u;
for col_id in range(col_start, col_end) {
unsafe {
slice.set_fast(slice_idx, self.at_fast(row_id, col_id));
slice.unsafe_set(slice_idx, self.unsafe_at((row_id, col_id)));
}
slice_idx += 1;
}
@ -553,11 +576,11 @@ impl<N: Show + Clone> Show for DMat<N> {
fn fmt(&self, form:&mut Formatter) -> Result {
for i in range(0u, self.nrows()) {
for j in range(0u, self.ncols()) {
let _ = write!(form.buf, "{} ", self.at(i, j));
let _ = write!(form, "{} ", self.at((i, j)));
}
let _ = write!(form.buf, "\n");
let _ = write!(form, "\n");
}
write!(form.buf, "\n")
write!(form, "\n")
}
}

View File

@ -9,7 +9,7 @@ use std::slice::{Items, MutItems};
use traits::operations::ApproxEq;
use std::iter::FromIterator;
use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut};
use traits::structure::{Iterable, IterableMut, Indexable};
#[doc(hidden)]
mod metal;
@ -48,11 +48,42 @@ impl<N: Zero + Clone> DVec<N> {
}
}
impl<N: Clone> DVec<N> {
/// Indexing without bounds checking.
pub unsafe fn at_fast(&self, i: uint) -> N {
impl<N: Clone> Indexable<uint, N> for DVec<N> {
fn at(&self, i: uint) -> N {
assert!(i < self.at.len());
unsafe {
self.unsafe_at(i)
}
}
fn set(&mut self, i: uint, val: N) {
assert!(i < self.at.len());
unsafe {
self.unsafe_set(i, val);
}
}
fn swap(&mut self, i: uint, j: uint) {
assert!(i < self.at.len());
assert!(j < self.at.len());
self.at.as_mut_slice().swap(i, j);
}
fn shape(&self) -> uint {
self.at.len()
}
#[inline]
unsafe fn unsafe_at(&self, i: uint) -> N {
(*self.at.as_slice().unsafe_ref(i)).clone()
}
#[inline]
unsafe fn unsafe_set(&mut self, i: uint, val: N) {
*self.at.as_mut_slice().unsafe_mut_ref(i) = val
}
}
impl<N: One + Clone> DVec<N> {
@ -86,11 +117,6 @@ impl<N> DVec<N> {
}
}
#[inline]
pub unsafe fn set_fast(&mut self, i: uint, val: N) {
*self.at.as_mut_slice().unsafe_mut_ref(i) = val
}
/// Gets a reference to of this vector data.
#[inline]
pub fn as_vec<'r>(&'r self) -> &'r [N] {
@ -172,7 +198,7 @@ impl<N> FromIterator<N> for DVec<N> {
}
}
impl<N: Clone + Num + Float + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> {
impl<N: Clone + Float + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> {
/// Computes the canonical basis for the given dimension. A canonical basis is a set of
/// vectors, mutually orthogonal, with all its component equal to 0.0 except one which is equal
/// to 1.0.
@ -261,7 +287,7 @@ impl<N: Num + Clone> Dot<N> for DVec<N> {
let mut res: N = Zero::zero();
for i in range(0u, a.at.len()) {
res = res + unsafe { a.at_fast(i) * b.at_fast(i) };
res = res + unsafe { a.unsafe_at(i) * b.unsafe_at(i) };
}
res
@ -272,14 +298,14 @@ impl<N: Num + Clone> Dot<N> for DVec<N> {
let mut res: N = Zero::zero();
for i in range(0u, a.at.len()) {
res = res + unsafe { (a.at_fast(i) - b.at_fast(i)) * c.at_fast(i) };
res = res + unsafe { (a.unsafe_at(i) - b.unsafe_at(i)) * c.unsafe_at(i) };
}
res
}
}
impl<N: Num + Float + Clone> Norm<N> for DVec<N> {
impl<N: Float + Clone> Norm<N> for DVec<N> {
#[inline]
fn sqnorm(v: &DVec<N>) -> N {
Dot::dot(v, v)

View File

@ -51,7 +51,7 @@ pub struct Iso4<N> {
pub translation: Vec4<N>
}
impl<N: Clone + Num + Float> Iso3<N> {
impl<N: Clone + Float> Iso3<N> {
/// Reorient and translate this transformation such that its local `x` axis points to a given
/// direction. Note that the usually known `look_at` function does the same thing but with the
/// `z` axis. See `look_at_z` for that.

View File

@ -2,7 +2,7 @@
macro_rules! iso_impl(
($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => (
impl<N: Clone + Float + Float + Num> $t<N> {
impl<N: Clone + FloatMath + Num> $t<N> {
/// Creates a new isometry from a rotation matrix and a vector.
#[inline]
pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>) -> $t<N> {
@ -26,7 +26,7 @@ macro_rules! iso_impl(
macro_rules! rotation_matrix_impl(
($t: ident, $trot: ident, $tlv: ident, $tav: ident) => (
impl<N: Cast<f32> + Float + Float + Num + Clone>
impl<N: Cast<f32> + FloatMath + Num + Clone>
RotationMatrix<$tlv<N>, $tav<N>, $trot<N>> for $t<N> {
#[inline]
fn to_rot_mat(&self) -> $trot<N> {
@ -50,7 +50,7 @@ macro_rules! dim_impl(
macro_rules! one_impl(
($t: ident) => (
impl<N: Float + Float + Num + Clone> One for $t<N> {
impl<N: FloatMath + Clone> One for $t<N> {
#[inline]
fn one() -> $t<N> {
$t::new_with_rotmat(Zero::zero(), One::one())
@ -61,7 +61,7 @@ macro_rules! one_impl(
macro_rules! iso_mul_iso_impl(
($t: ident, $tmul: ident) => (
impl<N: Num + Float + Float + Clone> $tmul<N, $t<N>> for $t<N> {
impl<N: FloatMath + Clone> $tmul<N, $t<N>> for $t<N> {
#[inline]
fn binop(left: &$t<N>, right: &$t<N>) -> $t<N> {
$t::new_with_rotmat(
@ -96,7 +96,7 @@ macro_rules! vec_mul_iso_impl(
macro_rules! translation_impl(
($t: ident, $tv: ident) => (
impl<N: Float + Num + Float + Clone> Translation<$tv<N>> for $t<N> {
impl<N: FloatMath + Clone> Translation<$tv<N>> for $t<N> {
#[inline]
fn translation(&self) -> $tv<N> {
self.translation.clone()
@ -153,7 +153,7 @@ macro_rules! translate_impl(
macro_rules! rotation_impl(
($t: ident, $trot: ident, $tav: ident) => (
impl<N: Cast<f32> + Num + Float + Float + Clone> Rotation<$tav<N>> for $t<N> {
impl<N: Cast<f32> + FloatMath + Clone> Rotation<$tav<N>> for $t<N> {
#[inline]
fn rotation(&self) -> $tav<N> {
self.rotation.rotation()
@ -220,7 +220,7 @@ macro_rules! rotate_impl(
macro_rules! transformation_impl(
($t: ident) => (
impl<N: Num + Float + Float + Clone> Transformation<$t<N>> for $t<N> {
impl<N: FloatMath + Clone> Transformation<$t<N>> for $t<N> {
fn transformation(&self) -> $t<N> {
self.clone()
}
@ -336,7 +336,7 @@ macro_rules! approx_eq_impl(
macro_rules! rand_impl(
($t: ident) => (
impl<N: Rand + Clone + Float + Float + Num> Rand for $t<N> {
impl<N: Rand + Clone + FloatMath> Rand for $t<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> $t<N> {
$t::new(rng.gen(), rng.gen())

View File

@ -8,8 +8,10 @@ use traits::operations::ApproxEq;
use std::slice::{Items, MutItems};
use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1MulRhs, Vec4MulRhs,
Vec5MulRhs, Vec6MulRhs};
use structs::dvec::DVec;
use traits::structure::{Cast, Row, Col, Iterable, IterableMut, Dim, Indexable};
use traits::structure::{Cast, Row, Col, Iterable, IterableMut, Dim, Indexable,
Eye, ColSlice, RowSlice};
use traits::operations::{Absolute, Transpose, Inv, Outer};
use traits::geometry::{ToHomogeneous, FromHomogeneous};
@ -34,6 +36,8 @@ pub struct Mat1<N> {
pub m11: N
}
eye_impl!(Mat1, 1, m11)
double_dispatch_binop_decl_trait!(Mat1, Mat1MulRhs)
double_dispatch_binop_decl_trait!(Mat1, Mat1DivRhs)
double_dispatch_binop_decl_trait!(Mat1, Mat1AddRhs)
@ -116,6 +120,8 @@ transpose_impl!(Mat1, 1)
approx_eq_impl!(Mat1)
row_impl!(Mat1, Vec1, 1)
col_impl!(Mat1, Vec1, 1)
col_slice_impl!(Mat1, Vec1, 1)
row_slice_impl!(Mat1, Vec1, 1)
to_homogeneous_impl!(Mat1, Mat2, 1, 2)
from_homogeneous_impl!(Mat1, Mat2, 1, 2)
outer_impl!(Vec1, Mat1)
@ -127,6 +133,8 @@ pub struct Mat2<N> {
pub m12: N, pub m22: N
}
eye_impl!(Mat2, 2, m11, m22)
double_dispatch_binop_decl_trait!(Mat2, Mat2MulRhs)
double_dispatch_binop_decl_trait!(Mat2, Mat2DivRhs)
double_dispatch_binop_decl_trait!(Mat2, Mat2AddRhs)
@ -213,6 +221,8 @@ transpose_impl!(Mat2, 2)
approx_eq_impl!(Mat2)
row_impl!(Mat2, Vec2, 2)
col_impl!(Mat2, Vec2, 2)
col_slice_impl!(Mat2, Vec2, 2)
row_slice_impl!(Mat2, Vec2, 2)
to_homogeneous_impl!(Mat2, Mat3, 2, 3)
from_homogeneous_impl!(Mat2, Mat3, 2, 3)
outer_impl!(Vec2, Mat2)
@ -225,6 +235,8 @@ pub struct Mat3<N> {
pub m13: N, pub m23: N, pub m33: N
}
eye_impl!(Mat3, 3, m11, m22, m33)
double_dispatch_binop_decl_trait!(Mat3, Mat3MulRhs)
double_dispatch_binop_decl_trait!(Mat3, Mat3DivRhs)
double_dispatch_binop_decl_trait!(Mat3, Mat3AddRhs)
@ -324,6 +336,8 @@ transpose_impl!(Mat3, 3)
approx_eq_impl!(Mat3)
// (specialized) row_impl!(Mat3, Vec3, 3)
// (specialized) col_impl!(Mat3, Vec3, 3)
col_slice_impl!(Mat3, Vec3, 3)
row_slice_impl!(Mat3, Vec3, 3)
to_homogeneous_impl!(Mat3, Mat4, 3, 4)
from_homogeneous_impl!(Mat3, Mat4, 3, 4)
outer_impl!(Vec3, Mat3)
@ -337,6 +351,8 @@ pub struct Mat4<N> {
pub m14: N, pub m24: N, pub m34: N, pub m44: N
}
eye_impl!(Mat4, 4, m11, m22, m33, m44)
double_dispatch_binop_decl_trait!(Mat4, Mat4MulRhs)
double_dispatch_binop_decl_trait!(Mat4, Mat4DivRhs)
double_dispatch_binop_decl_trait!(Mat4, Mat4AddRhs)
@ -487,6 +503,8 @@ transpose_impl!(Mat4, 4)
approx_eq_impl!(Mat4)
row_impl!(Mat4, Vec4, 4)
col_impl!(Mat4, Vec4, 4)
col_slice_impl!(Mat4, Vec4, 4)
row_slice_impl!(Mat4, Vec4, 4)
to_homogeneous_impl!(Mat4, Mat5, 4, 5)
from_homogeneous_impl!(Mat4, Mat5, 4, 5)
outer_impl!(Vec4, Mat4)
@ -501,6 +519,8 @@ pub struct Mat5<N> {
pub m15: N, pub m25: N, pub m35: N, pub m45: N, pub m55: N
}
eye_impl!(Mat5, 5, m11, m22, m33, m44, m55)
double_dispatch_binop_decl_trait!(Mat5, Mat5MulRhs)
double_dispatch_binop_decl_trait!(Mat5, Mat5DivRhs)
double_dispatch_binop_decl_trait!(Mat5, Mat5AddRhs)
@ -666,6 +686,8 @@ transpose_impl!(Mat5, 5)
approx_eq_impl!(Mat5)
row_impl!(Mat5, Vec5, 5)
col_impl!(Mat5, Vec5, 5)
col_slice_impl!(Mat5, Vec5, 5)
row_slice_impl!(Mat5, Vec5, 5)
to_homogeneous_impl!(Mat5, Mat6, 5, 6)
from_homogeneous_impl!(Mat5, Mat6, 5, 6)
outer_impl!(Vec5, Mat5)
@ -681,6 +703,8 @@ pub struct Mat6<N> {
pub m16: N, pub m26: N, pub m36: N, pub m46: N, pub m56: N, pub m66: N
}
eye_impl!(Mat6, 6, m11, m22, m33, m44, m55, m66)
double_dispatch_binop_decl_trait!(Mat6, Mat6MulRhs)
double_dispatch_binop_decl_trait!(Mat6, Mat6DivRhs)
double_dispatch_binop_decl_trait!(Mat6, Mat6AddRhs)
@ -897,4 +921,6 @@ transpose_impl!(Mat6, 6)
approx_eq_impl!(Mat6)
row_impl!(Mat6, Vec6, 6)
col_impl!(Mat6, Vec6, 6)
col_slice_impl!(Mat6, Vec6, 6)
row_slice_impl!(Mat6, Vec6, 6)
outer_impl!(Vec6, Mat6)

View File

@ -98,6 +98,20 @@ macro_rules! scalar_add_impl(
)
)
macro_rules! eye_impl(
($t: ident, $ndim: expr, $($comp_diagN: ident),+) => (
impl<N: Zero + One> Eye for $t<N> {
fn new_identity(dim: uint) -> $t<N> {
assert!(dim == $ndim);
let mut eye: $t<N> = Zero::zero();
$(eye.$comp_diagN = One::one();)+
eye
}
}
)
)
macro_rules! scalar_sub_impl(
($t: ident, $n: ident, $trhs: ident, $comp0: ident $(,$compN: ident)*) => (
impl $trhs<$n, $t<$n>> for $n {
@ -193,6 +207,11 @@ macro_rules! indexable_impl(
}
}
#[inline]
fn shape(&self) -> (uint, uint) {
($dim, $dim)
}
#[inline]
unsafe fn unsafe_at(&self, (i, j): (uint, uint)) -> N {
(*mem::transmute::<&$t<N>, &[N, ..$dim * $dim]>(self).unsafe_ref(i + j * $dim)).clone()
@ -206,6 +225,26 @@ macro_rules! indexable_impl(
)
)
macro_rules! col_slice_impl(
($t: ident, $tv: ident, $dim: expr) => (
impl<N: Clone + Zero> ColSlice<DVec<N>> for $t<N> {
fn col_slice(& self, cid: uint, rstart: uint, rend: uint) -> DVec<N> {
assert!(cid < $dim);
assert!(rstart < rend);
assert!(rend <= $dim);
let col = self.col(cid);
let res = DVec::from_vec(
rend - rstart,
unsafe {
mem::transmute::<&$tv<N>, & [N, ..$dim]>
(&col).slice(rstart, rend)
});
res
}
}
)
)
macro_rules! row_impl(
($t: ident, $tv: ident, $dim: expr) => (
impl<N: Clone + Zero> Row<$tv<N>> for $t<N> {
@ -235,6 +274,26 @@ macro_rules! row_impl(
)
)
macro_rules! row_slice_impl(
($t: ident, $tv: ident, $dim: expr) => (
impl<N: Clone + Zero> RowSlice<DVec<N>> for $t<N> {
fn row_slice(& self, rid: uint, cstart: uint, cend: uint) -> DVec<N> {
assert!(rid < $dim);
assert!(cstart < cend);
assert!(cend <= $dim);
let row = self.row(rid);
let res = DVec::from_vec(
cend - cstart,
unsafe {
mem::transmute::<&$tv<N>, & [N, ..$dim]>
(&row).slice(cstart, cend)
});
res
}
}
)
)
macro_rules! col_impl(
($t: ident, $tv: ident, $dim: expr) => (
impl<N: Clone + Zero> Col<$tv<N>> for $t<N> {

View File

@ -20,7 +20,7 @@ pub struct Rot2<N> {
submat: Mat2<N>
}
impl<N: Clone + Float + Neg<N>> Rot2<N> {
impl<N: Clone + FloatMath + Neg<N>> Rot2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian.
pub fn new(angle: Vec1<N>) -> Rot2<N> {
let (sia, coa) = angle.x.sin_cos();
@ -31,7 +31,7 @@ impl<N: Clone + Float + Neg<N>> Rot2<N> {
}
}
impl<N: Float + Num + Clone>
impl<N: FloatMath + Clone>
Rotation<Vec1<N>> for Rot2<N> {
#[inline]
fn rotation(&self) -> Vec1<N> {
@ -69,7 +69,7 @@ Rotation<Vec1<N>> for Rot2<N> {
}
}
impl<N: Clone + Rand + Float + Neg<N>> Rand for Rot2<N> {
impl<N: Clone + Rand + FloatMath + Neg<N>> Rand for Rot2<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot2<N> {
Rot2::new(rng.gen())
@ -99,7 +99,7 @@ pub struct Rot3<N> {
}
impl<N: Clone + Float + Num + Float> Rot3<N> {
impl<N: Clone + FloatMath> Rot3<N> {
/// Builds a 3 dimensional rotation matrix from an axis and an angle.
///
/// # Arguments
@ -140,7 +140,7 @@ impl<N: Clone + Float + Num + Float> Rot3<N> {
}
}
impl<N: Clone + Num + Float> Rot3<N> {
impl<N: Clone + Float> Rot3<N> {
/// Reorient this matrix such that its local `x` axis points to a given point. Note that the
/// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z`
/// for that.
@ -180,7 +180,7 @@ impl<N: Clone + Num + Float> Rot3<N> {
}
}
impl<N: Clone + Float + Num + Float + Cast<f32>>
impl<N: Clone + FloatMath + Cast<f32>>
Rotation<Vec3<N>> for Rot3<N> {
#[inline]
fn rotation(&self) -> Vec3<N> {
@ -245,7 +245,7 @@ Rotation<Vec3<N>> for Rot3<N> {
}
}
impl<N: Clone + Rand + Float + Num + Float>
impl<N: Clone + Rand + FloatMath>
Rand for Rot3<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot3<N> {
@ -309,7 +309,7 @@ impl<N: Signed> AbsoluteRotate<Vec4<N>> for Rot4<N> {
}
}
impl<N: Float + Num + Clone>
impl<N: Float + Clone>
Rotation<Vec4<N>> for Rot4<N> {
#[inline]
fn rotation(&self) -> Vec4<N> {

View File

@ -56,7 +56,7 @@ macro_rules! dim_impl(
macro_rules! rotation_matrix_impl(
($t: ident, $tlv: ident, $tav: ident) => (
impl<N: Cast<f32> + Float + Float + Num + Clone>
impl<N: Cast<f32> + FloatMath + Clone>
RotationMatrix<$tlv<N>, $tav<N>, $t<N>> for $t<N> {
#[inline]
fn to_rot_mat(&self) -> $t<N> {

View File

@ -25,6 +25,11 @@ impl<N> Indexable<uint, N> for vec::Vec0<N> {
fn set(&mut self, _: uint, _: N) {
}
#[inline]
fn shape(&self) -> uint {
0
}
#[inline]
fn swap(&mut self, _: uint, _: uint) {
}
@ -159,7 +164,7 @@ impl<N: Clone + Add<N, N> + Neg<N>> Translation<vec::Vec0<N>> for vec::Vec0<N> {
}
}
impl<N: Num + Float> Norm<N> for vec::Vec0<N> {
impl<N: Float> Norm<N> for vec::Vec0<N> {
#[inline]
fn sqnorm(_: &vec::Vec0<N>) -> N {
Zero::zero()

View File

@ -38,7 +38,7 @@ macro_rules! at_fast_impl(
// However, f32/f64 does not implement TotalOrd…
macro_rules! ord_impl(
($t: ident, $comp0: ident $(,$compN: ident)*) => (
impl<N: Float + Eq + Clone> PartialOrd for $t<N> {
impl<N: FloatMath + Eq + Clone> PartialOrd for $t<N> {
#[inline]
fn inf(a: &$t<N>, b: &$t<N>) -> $t<N> {
$t::new(a.$comp0.min(b.$comp0.clone())
@ -165,6 +165,11 @@ macro_rules! indexable_impl(
}
}
#[inline]
fn shape(&self) -> uint {
$dim
}
#[inline]
fn swap(&mut self, i1: uint, i2: uint) {
unsafe {
@ -250,7 +255,7 @@ macro_rules! container_impl(
macro_rules! basis_impl(
($t: ident, $trhs: ident, $dim: expr) => (
impl<N: Clone + Num + Float + ApproxEq<N> + $trhs<N, $t<N>>> Basis for $t<N> {
impl<N: Clone + Float + ApproxEq<N> + $trhs<N, $t<N>>> Basis for $t<N> {
#[inline]
fn canonical_basis(f: |$t<N>| -> bool) {
for i in range(0u, $dim) {
@ -460,7 +465,7 @@ macro_rules! translation_impl(
macro_rules! norm_impl(
($t: ident, $comp0: ident $(,$compN: ident)*) => (
impl<N: Clone + Num + Float> Norm<N> for $t<N> {
impl<N: Clone + Float> Norm<N> for $t<N> {
#[inline]
fn sqnorm(v: &$t<N>) -> N {
Dot::dot(v, v)

View File

@ -3,6 +3,7 @@ use rand::random;
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable};
use na;
use na::decomp_qr;
use std::cmp::{min, max};
macro_rules! test_inv_mat_impl(
($t: ty) => (
@ -24,6 +25,19 @@ macro_rules! test_transpose_mat_impl(
);
)
macro_rules! test_decomp_qr_impl(
($t: ty) => (
for _ in range(0, 10000) {
let randmat : $t = random();
let (q, r) = decomp_qr(&randmat);
let recomp = q * r;
assert!(na::approx_eq(&randmat, &recomp));
}
);
)
#[test]
fn test_transpose_mat1() {
test_transpose_mat_impl!(Mat1<f64>);
@ -210,20 +224,45 @@ fn test_dmat_from_vec() {
#[test]
fn test_decomp_qr() {
let mat = DMat::from_row_vec(
5,
3,
[
4.0, 2.0, 0.60,
4.2, 2.1, 0.59,
3.9, 2.0, 0.58,
4.3, 2.1, 0.62,
4.1, 2.2, 0.63
]
);
for _ in range(0, 10) {
let dim1: uint = random();
let dim2: uint = random();
let rows = min(40, max(dim1, dim2));
let cols = min(40, min(dim1, dim2));
let randmat: DMat<f64> = DMat::new_random(rows, cols);
let (q, r) = decomp_qr(&randmat);
let recomp = q * r;
let (q, r) = decomp_qr(&mat);
let mat_ = q * r;
assert!(na::approx_eq(&mat_, &mat));
assert!(na::approx_eq(&randmat, &recomp));
}
}
#[test]
fn test_decomp_qr_mat1() {
test_decomp_qr_impl!(Mat1<f64>);
}
#[test]
fn test_decomp_qr_mat2() {
test_decomp_qr_impl!(Mat2<f64>);
}
#[test]
fn test_decomp_qr_mat3() {
test_decomp_qr_impl!(Mat3<f64>);
}
#[test]
fn test_decomp_qr_mat4() {
test_decomp_qr_impl!(Mat4<f64>);
}
#[test]
fn test_decomp_qr_mat5() {
test_decomp_qr_impl!(Mat5<f64>);
}
#[test]
fn test_decomp_qr_mat6() {
test_decomp_qr_impl!(Mat6<f64>);
}

View File

@ -6,7 +6,7 @@ pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneou
pub use self::structure::{FloatVec, FloatVecExt, Basis, Cast, Col, Dim, Indexable,
Iterable, IterableMut, Mat, Row, AnyVec, VecExt,
ColSlice, RowSlice};
ColSlice, RowSlice, Eye};
pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, PartialOrd, RMul,
ScalarAdd, ScalarSub, Transpose};

View File

@ -19,6 +19,12 @@ pub trait Mat<R, C> : Row<R> + Col<C> + RMul<R> + LMul<C> { }
impl<M: Row<R> + Col<C> + RMul<R> + LMul<C>, R, C> Mat<R, C> for M {
}
/// Trait for constructing the identity matrix
pub trait Eye {
/// Return the identity matrix of specified dimension
fn new_identity(dim: uint) -> Self;
}
// XXX: we keep ScalarAdd and ScalarSub here to avoid trait impl conflict (overriding) between the
// different Add/Sub traits. This is _so_ unfortunate…
@ -126,6 +132,9 @@ pub trait Indexable<Index, Res> {
/// Swaps the `i`-th element of `self` with its `j`-th element.
fn swap(&mut self, i: Index, j: Index);
/// Returns the shape of the iterable range
fn shape(&self) -> Index;
/// Reads the `i`-th element of `self`.
///
/// `i` is not checked.