Merge pull request #6 from vbarrielle/master
Implementation of QR factorizarion
This commit is contained in:
commit
43a6c96d33
@ -119,6 +119,7 @@ extern crate test;
|
||||
pub mod na;
|
||||
mod structs;
|
||||
mod traits;
|
||||
mod linalg;
|
||||
|
||||
// mod lower_triangular;
|
||||
// mod chol;
|
||||
|
58
src/linalg/decompositions.rs
Normal file
58
src/linalg/decompositions.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use std::num::{Zero, Float};
|
||||
use na::DVec;
|
||||
use na::DMat;
|
||||
use traits::operations::Transpose;
|
||||
use traits::structure::ColSlice;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
qk
|
||||
};
|
||||
|
||||
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() {
|
||||
-Norm::norm(&v)
|
||||
}
|
||||
else {
|
||||
Norm::norm(&v)
|
||||
};
|
||||
unsafe {
|
||||
let x = v.at_fast(0);
|
||||
v.set_fast(0, x - alpha);
|
||||
}
|
||||
let _ = v.normalize();
|
||||
let qk = subtract_reflection(v);
|
||||
r = qk * r;
|
||||
q = q * Transpose::transpose_cpy(&qk);
|
||||
}
|
||||
|
||||
(q, r)
|
||||
}
|
||||
|
4
src/linalg/mod.rs
Normal file
4
src/linalg/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
pub use self::decompositions::decomp_qr;
|
||||
|
||||
mod decompositions;
|
@ -39,7 +39,8 @@ pub use traits::{
|
||||
Transpose,
|
||||
UniformSphereSample,
|
||||
AnyVec,
|
||||
VecExt
|
||||
VecExt,
|
||||
ColSlice, RowSlice
|
||||
};
|
||||
|
||||
pub use structs::{
|
||||
@ -52,6 +53,10 @@ pub use structs::{
|
||||
Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6
|
||||
};
|
||||
|
||||
pub use linalg::{
|
||||
decomp_qr
|
||||
};
|
||||
|
||||
/// Traits to work around the language limitations related to operator overloading.
|
||||
///
|
||||
/// The trait names are formed by:
|
||||
|
@ -9,7 +9,8 @@ use traits::operations::ApproxEq;
|
||||
use std::mem;
|
||||
use structs::dvec::{DVec, DVecMulRhs};
|
||||
use traits::operations::{Inv, Transpose, Mean, Cov};
|
||||
use traits::structure::Cast;
|
||||
use traits::structure::{Cast, ColSlice, RowSlice};
|
||||
use std::fmt::{Show, Formatter, Result};
|
||||
|
||||
#[doc(hidden)]
|
||||
mod metal;
|
||||
@ -494,6 +495,39 @@ impl<N: Clone + Num + Cast<f32> + DMatDivRhs<N, DMat<N>> + ToStr > Cov<DMat<N>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Clone> ColSlice<DVec<N>> for DMat<N> {
|
||||
fn col_slice(&self, col_id :uint, row_start: uint, row_end: uint) -> DVec<N> {
|
||||
assert!(col_id < self.ncols);
|
||||
assert!(row_start < row_end);
|
||||
assert!(row_end <= self.nrows);
|
||||
// we can init from slice thanks to the matrix being column major
|
||||
let start= self.offset(row_start, col_id);
|
||||
let stop = self.offset(row_end, col_id);
|
||||
let slice = DVec::from_vec(
|
||||
row_end - row_start, self.mij.slice(start, stop));
|
||||
slice
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Clone> RowSlice<DVec<N>> for DMat<N> {
|
||||
fn row_slice(&self, row_id :uint, col_start: uint, col_end: uint) -> DVec<N> {
|
||||
assert!(row_id < self.nrows);
|
||||
assert!(col_start < col_end);
|
||||
assert!(col_end <= self.ncols);
|
||||
let mut slice : DVec<N> = unsafe {
|
||||
DVec::new_uninitialized(self.nrows)
|
||||
};
|
||||
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_idx += 1;
|
||||
}
|
||||
slice
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: ApproxEq<N>> ApproxEq<N> for DMat<N> {
|
||||
#[inline]
|
||||
fn approx_epsilon(_: Option<DMat<N>>) -> N {
|
||||
@ -515,6 +549,18 @@ impl<N: ApproxEq<N>> ApproxEq<N> for DMat<N> {
|
||||
}
|
||||
}
|
||||
|
||||
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.buf, "\n");
|
||||
}
|
||||
write!(form.buf, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! scalar_mul_impl (
|
||||
($n: ident) => (
|
||||
impl DMatMulRhs<$n, DMat<$n>> for $n {
|
||||
|
@ -2,6 +2,7 @@ use std::num::{Float, abs};
|
||||
use rand::random;
|
||||
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable};
|
||||
use na;
|
||||
use na::decomp_qr;
|
||||
|
||||
macro_rules! test_inv_mat_impl(
|
||||
($t: ty) => (
|
||||
@ -206,3 +207,23 @@ fn test_dmat_from_vec() {
|
||||
|
||||
assert!(mat1 == mat2);
|
||||
}
|
||||
|
||||
#[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
|
||||
]
|
||||
);
|
||||
|
||||
let (q, r) = decomp_qr(&mat);
|
||||
let mat_ = q * r;
|
||||
|
||||
assert!(na::approx_eq(&mat_, &mat));
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneou
|
||||
Transform, Transformation, Translate, Translation, UniformSphereSample};
|
||||
|
||||
pub use self::structure::{FloatVec, FloatVecExt, Basis, Cast, Col, Dim, Indexable,
|
||||
Iterable, IterableMut, Mat, Row, AnyVec, VecExt};
|
||||
Iterable, IterableMut, Mat, Row, AnyVec, VecExt,
|
||||
ColSlice, RowSlice};
|
||||
|
||||
pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, PartialOrd, RMul,
|
||||
ScalarAdd, ScalarSub, Transpose};
|
||||
|
@ -244,6 +244,7 @@ pub trait Mean<N> {
|
||||
fn mean(&Self) -> N;
|
||||
}
|
||||
|
||||
|
||||
// /// Cholesky decomposition.
|
||||
// pub trait Chol {
|
||||
// /// Performs the cholesky decomposition on `self`. The resulting upper-triangular matrix is
|
||||
|
@ -91,6 +91,18 @@ pub trait Col<C> {
|
||||
// a lot of operations.
|
||||
}
|
||||
|
||||
/// Trait to access part of a column of a matrix
|
||||
pub trait ColSlice<C> {
|
||||
/// Returns a view to a slice of a column of a matrix.
|
||||
fn col_slice(&self, col_id: uint, row_start: uint, row_end: uint) -> C;
|
||||
}
|
||||
|
||||
/// Trait to access part of a row of a matrix
|
||||
pub trait RowSlice<R> {
|
||||
/// Returns a view to a slice of a row of a matrix.
|
||||
fn row_slice(&self, row_id: uint, col_start: uint, col_end: uint) -> R;
|
||||
}
|
||||
|
||||
/// Trait of objects having a spacial dimension known at compile time.
|
||||
pub trait Dim {
|
||||
/// The dimension of the object.
|
||||
|
Loading…
Reference in New Issue
Block a user