use num;
use std::ops::{Add, Sub, Mul, Div, MulAssign, DivAssign, Neg};
use general::{ClosedDiv, Module, Field, Real};
pub trait VectorSpace: Module<Ring = <Self as VectorSpace>::Field> +
ClosedDiv<<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 = other.norm();
if n1 == num::zero() || n2 == num::zero() {
num::zero()
}
else {
let cang = prod / (n1 * n2);
if cang > num::one() {
num::zero()
}
else if cang < -num::one::<Self::Real>() {
Self::Real::pi()
}
else {
cang.acos()
}
}
}
}
pub trait FiniteDimVectorSpace: VectorSpace {
fn dimension() -> usize;
fn canonical_basis<F: FnMut(&Self) -> bool>(mut f: F) {
for i in 0 .. Self::dimension() {
if !f(&Self::canonical_basis_element(i)) {
break;
}
}
}
fn canonical_basis_element(i: usize) -> Self;
fn component(&self, i: usize) -> Self::Field;
fn dot(&self, other: &Self) -> Self::Field;
unsafe fn component_unchecked(&self, i: usize) -> Self::Field;
}
pub trait FiniteDimInnerSpace: InnerSpace + FiniteDimVectorSpace<Field = <Self as InnerSpace>::Real> {
fn orthonormalize(vs: &mut [Self]) -> usize;
fn orthonormal_subspace_basis<F: FnMut(&Self) -> bool>(vs: &[Self], f: F);
}
pub trait AffineSpace: Sized + Clone + PartialEq +
Sub<Self, Output = <Self as AffineSpace>::Translation> +
Add<<Self as AffineSpace>::Translation, Output = Self> {
type Translation: VectorSpace;
fn translate_by(&self, t: &Self::Translation) -> Self {
self.clone() + t.clone()
}
fn subtract(&self, right: &Self) -> Self::Translation {
self.clone() - right.clone()
}
}
pub trait EuclideanSpace: AffineSpace<Translation = <Self as EuclideanSpace>::Vector> {
type Vector: FiniteDimInnerSpace<Real = Self::Real> +
Mul<Self::Real, Output = Self::Vector> +
MulAssign<Self::Real> +
Div<Self::Real, Output = Self::Vector> +
DivAssign<Self::Real> +
Neg<Output = Self::Vector>;
type Real: Real;
fn origin() -> Self;
fn scale_by(&self, s: Self::Real) -> Self {
Self::origin().translate_by(&(self.coordinates() * s))
}
#[inline]
fn coordinates(&self) -> Self::Vector {
self.subtract(&Self::origin())
}
#[inline]
fn distance_squared(&self, b: &Self) -> Self::Real {
self.subtract(b).norm_squared()
}
#[inline]
fn distance(&self, b: &Self) -> Self::Real {
self.subtract(b).norm()
}
}