Fix matrix inversion algorithm.

This commit is contained in:
Sébastien Crozet 2013-05-31 18:35:48 +02:00
parent f264b75ce6
commit 4146385e09
3 changed files with 39 additions and 27 deletions

View File

@ -2,6 +2,7 @@ use core::num::{One, Zero};
use core::vec::{from_elem, swap, all, all2, len}; use core::vec::{from_elem, swap, all, all2, len};
use core::cmp::ApproxEq; use core::cmp::ApproxEq;
use traits::inv::Inv; use traits::inv::Inv;
use traits::division_ring::DivisionRing;
use traits::transpose::Transpose; use traits::transpose::Transpose;
use traits::workarounds::rlmul::{RMul, LMul}; use traits::workarounds::rlmul::{RMul, LMul};
use ndim::dvec::{DVec, zero_vec_with_dim}; use ndim::dvec::{DVec, zero_vec_with_dim};
@ -41,12 +42,19 @@ impl<T: Copy> DMat<T>
assert!(j < self.dim); assert!(j < self.dim);
self.mij[self.offset(i, j)] = *t self.mij[self.offset(i, j)] = *t
} }
pub fn at(&self, i: uint, j: uint) -> T
{
assert!(i < self.dim);
assert!(j < self.dim);
self.mij[self.offset(i, j)]
}
} }
impl<T: Copy> Index<(uint, uint), T> for DMat<T> impl<T: Copy> Index<(uint, uint), T> for DMat<T>
{ {
fn index(&self, &(i, j): &(uint, uint)) -> T fn index(&self, &(i, j): &(uint, uint)) -> T
{ self.mij[self.offset(i, j)] } { self.at(i, j) }
} }
impl<T: Copy + Mul<T, T> + Add<T, T> + Zero> impl<T: Copy + Mul<T, T> + Add<T, T> + Zero>
@ -63,10 +71,10 @@ Mul<DMat<T>, DMat<T>> for DMat<T>
{ {
for uint::range(0u, dim) |j| for uint::range(0u, dim) |j|
{ {
let mut acc: T = Zero::zero(); let mut acc = Zero::zero::<T>();
for uint::range(0u, dim) |k| for uint::range(0u, dim) |k|
{ acc += self[(i, k)] * other[(k, j)]; } { acc += self.at(i, k) * other.at(k, j); }
res.set(i, j, &acc); res.set(i, j, &acc);
} }
@ -89,7 +97,7 @@ RMul<DVec<T>> for DMat<T>
for uint::range(0u, dim) |i| for uint::range(0u, dim) |i|
{ {
for uint::range(0u, dim) |j| for uint::range(0u, dim) |j|
{ res.at[i] = res.at[i] + other.at[j] * self[(i, j)]; } { res.at[i] = res.at[i] + other.at[j] * self.at(i, j); }
} }
res res
@ -109,15 +117,14 @@ LMul<DVec<T>> for DMat<T>
for uint::range(0u, dim) |i| for uint::range(0u, dim) |i|
{ {
for uint::range(0u, dim) |j| for uint::range(0u, dim) |j|
{ res.at[i] = res.at[i] + other.at[j] * self[(j, i)]; } { res.at[i] = res.at[i] + other.at[j] * self.at(j, i); }
} }
res res
} }
} }
impl<T: Clone + Copy + Eq + One + Zero + impl<T: Clone + Copy + Eq + DivisionRing>
Mul<T, T> + Div<T, T> + Sub<T, T> + Neg<T>>
Inv for DMat<T> Inv for DMat<T>
{ {
fn inverse(&self) -> DMat<T> fn inverse(&self) -> DMat<T>
@ -142,14 +149,11 @@ Inv for DMat<T>
// FIXME: would it be worth it to spend some more time searching for the // FIXME: would it be worth it to spend some more time searching for the
// max instead? // max instead?
// FIXME: this is kind of uggly… let mut n0 = k; // index of a non-zero entry
// … but we cannot use position_between since we are iterating on one
// columns
let mut n0 = 0u; // index of a non-zero entry
while (n0 != dim) while (n0 != dim)
{ {
if (self[(n0, k)] != _0T) if (self.at(n0, k) != _0T)
{ break; } { break; }
n0 += 1; n0 += 1;
@ -170,16 +174,17 @@ Inv for DMat<T>
} }
} }
let pivot = self[(k, k)]; let pivot = self.at(k, k);
for uint::range(k, dim) |j| for uint::range(k, dim) |j|
{ {
// FIXME: not to putting selfal exression directly on the nuction call let selfval = &(self.at(k, j) / pivot);
// is uggly but does not seem to compile any more…
let selfval = &(self[(k, j)] / pivot);
let resval = &(res[(k, j)] / pivot);
self.set(k, j, selfval); self.set(k, j, selfval);
}
for uint::range(0u, dim) |j|
{
let resval = &(res.at(k, j) / pivot);
res.set(k, j, resval); res.set(k, j, resval);
} }
@ -187,19 +192,24 @@ Inv for DMat<T>
{ {
if (l != k) if (l != k)
{ {
let normalizer = self[(l, k)] / pivot; let normalizer = self.at(l, k);
for uint::range(k, dim) |j| for uint::range(k, dim) |j|
{ {
let selfval = &(self[(l, j)] - self[(k, j)] * normalizer); let selfval = &(self.at(l, j) - self.at(k, j) * normalizer);
let resval = &(res[(l, j)] - res[(k, j)] * normalizer); self.set(l, j, selfval);
}
self.set(k, j, selfval); for uint::range(0u, dim) |j|
res.set(k, j, resval); {
let resval = &(res.at(l, j) - res.at(k, j) * normalizer);
res.set(l, j, resval);
} }
} }
} }
} }
*self = res;
} }
} }

View File

@ -3,6 +3,7 @@ use core::rand::{Rand, Rng, RngUtil};
use core::cmp::ApproxEq; use core::cmp::ApproxEq;
use traits::dim::Dim; use traits::dim::Dim;
use traits::inv::Inv; use traits::inv::Inv;
use traits::division_ring::DivisionRing;
use traits::transpose::Transpose; use traits::transpose::Transpose;
use traits::workarounds::rlmul::{RMul, LMul}; use traits::workarounds::rlmul::{RMul, LMul};
use ndim::dmat::{DMat, one_mat_with_dim, zero_mat_with_dim, is_zero_mat}; use ndim::dmat::{DMat, one_mat_with_dim, zero_mat_with_dim, is_zero_mat};
@ -113,9 +114,7 @@ LMul<NVec<D, T>> for NMat<D, T>
} }
} }
impl<D: Dim, impl<D: Dim, T: Clone + Copy + Eq + DivisionRing>
T: Clone + Copy + Eq + One + Zero +
Mul<T, T> + Div<T, T> + Sub<T, T> + Neg<T>>
Inv for NMat<D, T> Inv for NMat<D, T>
{ {
fn inverse(&self) -> NMat<D, T> fn inverse(&self) -> NMat<D, T>

View File

@ -8,6 +8,8 @@ use core::cmp::ApproxEq;
use traits::inv::Inv; use traits::inv::Inv;
#[test] #[test]
use traits::rotation::Rotation; use traits::rotation::Rotation;
// #[test]
// use traits::dim::d7;
#[test] #[test]
use dim1::vec1::vec1; use dim1::vec1::vec1;
#[test] #[test]
@ -16,6 +18,8 @@ use dim1::mat1::Mat1;
use dim2::mat2::Mat2; use dim2::mat2::Mat2;
#[test] #[test]
use dim3::mat3::Mat3; use dim3::mat3::Mat3;
// #[test]
// use ndim::nmat::NMat;
#[test] #[test]
use adaptors::rotmat::Rotmat; use adaptors::rotmat::Rotmat;
@ -42,7 +46,6 @@ fn test_inv_mat2()
fn test_inv_mat3() fn test_inv_mat3()
{ test_inv_mat_impl!(Mat3<f64>); } { test_inv_mat_impl!(Mat3<f64>); }
// FIXME: this one fails with an ICE: node_id_to_type: no type for node [...]
// #[test] // #[test]
// fn test_inv_nmat() // fn test_inv_nmat()
// { test_inv_mat_impl!(NMat<d7, f64>); } // { test_inv_mat_impl!(NMat<d7, f64>); }