Add the ability to stop the basis internal itertors.

This commit is contained in:
Sébastien Crozet 2013-08-17 10:48:45 +02:00
parent d8db04cce5
commit 344d761be5
5 changed files with 38 additions and 25 deletions

View File

@ -80,10 +80,14 @@ macro_rules! test_basis_impl(
do 10000.times { do 10000.times {
do Basis::canonical_basis::<$t> |e1| { do Basis::canonical_basis::<$t> |e1| {
do Basis::canonical_basis::<$t> |e2| { do Basis::canonical_basis::<$t> |e2| {
assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero()));
true
} }
assert!(e1.norm().approx_eq(&One::one())); assert!(e1.norm().approx_eq(&One::one()));
true
} }
} }
); );
@ -102,8 +106,12 @@ macro_rules! test_subspace_basis_impl(
assert!(e1.norm().approx_eq(&One::one())); assert!(e1.norm().approx_eq(&One::one()));
// check vectors form an ortogonal basis // check vectors form an ortogonal basis
do v1.orthonormal_subspace_basis() |e2| { do v1.orthonormal_subspace_basis() |e2| {
assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero()));
true
} }
true
} }
} }
); );

View File

@ -1,17 +1,20 @@
// FIXME: return an iterator instead
/// Traits of objecs which can form a basis. /// Traits of objecs which can form a basis.
pub trait Basis { pub trait Basis {
/// Iterate through the canonical basis of the space in which this object lives. /// Iterate through the canonical basis of the space in which this object lives.
fn canonical_basis(&fn(Self)); fn canonical_basis(&fn(Self) -> bool);
/// Iterate through a basis of the subspace orthogonal to `self`. /// Iterate through a basis of the subspace orthogonal to `self`.
fn orthonormal_subspace_basis(&self, &fn(Self)); fn orthonormal_subspace_basis(&self, &fn(Self) -> bool);
/// Creates the canonical basis of the space in which this object lives. /// Creates the canonical basis of the space in which this object lives.
fn canonical_basis_list() -> ~[Self] { fn canonical_basis_list() -> ~[Self] {
let mut res = ~[]; let mut res = ~[];
do Basis::canonical_basis::<Self> |elem| { do Basis::canonical_basis::<Self> |elem| {
res.push(elem) res.push(elem);
true
} }
res res
@ -22,7 +25,9 @@ pub trait Basis {
let mut res = ~[]; let mut res = ~[];
do self.orthonormal_subspace_basis |elem| { do self.orthonormal_subspace_basis |elem| {
res.push(elem) res.push(elem);
true
} }
res res

View File

@ -72,10 +72,10 @@ impl<N> Dim for vec::Vec0<N> {
impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for vec::Vec0<N> { impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for vec::Vec0<N> {
#[inline(always)] #[inline(always)]
fn canonical_basis(_: &fn(vec::Vec0<N>)) { } fn canonical_basis(_: &fn(vec::Vec0<N>) -> bool) { }
#[inline(always)] #[inline(always)]
fn orthonormal_subspace_basis(&self, _: &fn(vec::Vec0<N>)) { } fn orthonormal_subspace_basis(&self, _: &fn(vec::Vec0<N>) -> bool) { }
} }
impl<N: Clone + Add<N,N>> Add<vec::Vec0<N>, vec::Vec0<N>> for vec::Vec0<N> { impl<N: Clone + Add<N,N>> Add<vec::Vec0<N>, vec::Vec0<N>> for vec::Vec0<N> {

View File

@ -185,18 +185,18 @@ macro_rules! basis_impl(
($t: ident, $dim: expr) => ( ($t: ident, $dim: expr) => (
impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for $t<N> { impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for $t<N> {
#[inline] #[inline]
fn canonical_basis(f: &fn($t<N>)) { fn canonical_basis(f: &fn($t<N>) -> bool) {
for i in range(0u, $dim) { for i in range(0u, $dim) {
let mut basis_element : $t<N> = Zero::zero(); let mut basis_element : $t<N> = Zero::zero();
basis_element.set(i, One::one()); basis_element.set(i, One::one());
f(basis_element); if !f(basis_element) { return }
} }
} }
#[inline] #[inline]
fn orthonormal_subspace_basis(&self, f: &fn($t<N>)) { fn orthonormal_subspace_basis(&self, f: &fn($t<N>) -> bool) {
// compute the basis of the orthogonal subspace using Gram-Schmidt // compute the basis of the orthogonal subspace using Gram-Schmidt
// orthogonalization algorithm // orthogonalization algorithm
let mut basis: ~[$t<N>] = ~[]; let mut basis: ~[$t<N>] = ~[];
@ -221,7 +221,7 @@ macro_rules! basis_impl(
if !elt.sqnorm().approx_eq(&Zero::zero()) { if !elt.sqnorm().approx_eq(&Zero::zero()) {
let new_element = elt.normalized(); let new_element = elt.normalized();
f(new_element.clone()); if !f(new_element.clone()) { return };
basis.push(new_element); basis.push(new_element);
} }

View File

@ -26,38 +26,38 @@ impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec3<N>> for Vec3<N> {
impl<N: One> Basis for Vec1<N> { impl<N: One> Basis for Vec1<N> {
#[inline(always)] #[inline(always)]
fn canonical_basis(f: &fn(Vec1<N>)) { fn canonical_basis(f: &fn(Vec1<N>) -> bool) {
f(Vec1::new(One::one())) f(Vec1::new(One::one()));
} }
#[inline(always)] #[inline(always)]
fn orthonormal_subspace_basis(&self, _: &fn(Vec1<N>)) { } fn orthonormal_subspace_basis(&self, _: &fn(Vec1<N>) -> bool ) { }
} }
impl<N: Clone + One + Zero + Neg<N>> Basis for Vec2<N> { impl<N: Clone + One + Zero + Neg<N>> Basis for Vec2<N> {
#[inline] #[inline(always)]
fn canonical_basis(f: &fn(Vec2<N>)) { fn canonical_basis(f: &fn(Vec2<N>) -> bool) {
f(Vec2::new(One::one(), Zero::zero())); if !f(Vec2::new(One::one(), Zero::zero())) { return };
f(Vec2::new(Zero::zero(), One::one())); f(Vec2::new(Zero::zero(), One::one()));
} }
#[inline] #[inline]
fn orthonormal_subspace_basis(&self, f: &fn(Vec2<N>)) { fn orthonormal_subspace_basis(&self, f: &fn(Vec2<N>) -> bool) {
f(Vec2::new(-self.y, self.x.clone())) f(Vec2::new(-self.y, self.x.clone()));
} }
} }
impl<N: Clone + DivisionRing + Ord + Algebraic + Signed> impl<N: Clone + DivisionRing + Ord + Algebraic + Signed>
Basis for Vec3<N> { Basis for Vec3<N> {
#[inline(always)] #[inline(always)]
fn canonical_basis(f: &fn(Vec3<N>)) { fn canonical_basis(f: &fn(Vec3<N>) -> bool) {
f(Vec3::new(One::one(), Zero::zero(), Zero::zero())); if !f(Vec3::new(One::one(), Zero::zero(), Zero::zero())) { return };
f(Vec3::new(Zero::zero(), One::one(), Zero::zero())); if !f(Vec3::new(Zero::zero(), One::one(), Zero::zero())) { return };
f(Vec3::new(Zero::zero(), Zero::zero(), One::one())); f(Vec3::new(Zero::zero(), Zero::zero(), One::one()));
} }
#[inline(always)] #[inline(always)]
fn orthonormal_subspace_basis(&self, f: &fn(Vec3<N>)) { fn orthonormal_subspace_basis(&self, f: &fn(Vec3<N>) -> bool) {
let a = let a =
if self.x.clone().abs() > self.y.clone().abs() { if self.x.clone().abs() > self.y.clone().abs() {
Vec3::new(self.z.clone(), Zero::zero(), -self.x).normalized() Vec3::new(self.z.clone(), Zero::zero(), -self.x).normalized()
@ -66,7 +66,7 @@ Basis for Vec3<N> {
Vec3::new(Zero::zero(), -self.z, self.y.clone()).normalized() Vec3::new(Zero::zero(), -self.z, self.y.clone()).normalized()
}; };
f(a.cross(self)); if !f(a.cross(self)) { return };
f(a); f(a);
} }
} }