use num::Zero;
use general::{Module, Field, Real, Identity, Additive};
pub trait VectorSpace : Module<Ring = <Self as VectorSpace>::Field> {
type Field: Field;
}
pub trait NormedSpace: VectorSpace {
fn norm_squared(&self) -> Self::Field;
fn norm(&self) -> Self::Field;
fn normalize(&self) -> Self;
fn normalize_mut(&mut self) -> Self::Field;
fn try_normalize(&self, eps: &Self::Field) -> Option<Self>;
fn try_normalize_mut(&mut self, eps: &Self::Field) -> Option<Self::Field>;
}
pub trait InnerSpace : NormedSpace<Field = <Self as InnerSpace>::Real> {
type Real: Real;
fn inner_product(&self, other: &Self) -> Self::Real;
#[inline]
fn angle(&self, other: &Self) -> Self::Real {
let prod = self.inner_product(other);
let n1 = self.norm();
let n2 = self.norm();
let zero: Self::Real = Identity::<Additive>::id();
if n1 == Zero::zero() || n2 == Zero::zero() {
zero
}
else {
let cang = prod / (n1 * n2);
cang.acos()
}
}
}
pub trait FiniteDimVectorSpace : VectorSpace {
fn dimension() -> usize;
fn canonical_basis<F: FnOnce(&[Self])>(f: F);
fn component(&self, i: usize) -> Self::Field;
unsafe fn component_unchecked(&self, i: usize) -> Self::Field;
}
pub trait FiniteDimInnerSpace: InnerSpace + FiniteDimVectorSpace<Field = <Self as InnerSpace>::Real> {
}
impl<T> FiniteDimInnerSpace for T
where T: InnerSpace + FiniteDimVectorSpace<Field = <T as InnerSpace>::Real> {
}
pub trait AffineSpace: Sized + Clone {
type Translation: VectorSpace;
fn translate_by(&self, t: &Self::Translation) -> Self;
fn subtract(&self, other: &Self) -> Self::Translation;
}
pub trait EuclideanSpace: AffineSpace<Translation = <Self as EuclideanSpace>::Vector> {
type Vector: FiniteDimInnerSpace<Real = Self::Real>;
type Real: Real;
#[inline]
fn distance_squared(&self, b: &Self) -> Self::Real {
let ab = self.subtract(b);
ab.norm_squared()
}
#[inline]
fn distance(&self, b: &Self) -> Self::Real {
let ab = self.subtract(b);
ab.norm()
}
}