use batch_impl::{batch_impl_only, batch_trait};
use crate::complex::Complex;
use crate::op::{Additive, Multiplicative};
use crate::tower::{
AffineSpace, BilinearForm, BooleanAlgebra, ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg,
ClosedRem, ClosedSub, ComplementedLattice, DistributiveLattice, EuclideanSpace,
FiniteDimInnerSpace, FiniteDimVectorSpace, Group, InnerSpace, JoinSemilattice, Lattice, Magma,
MeetSemilattice, Module, Monoid, NormedSpace, OrderedField, PositiveDefinite, Real, SubsetOf,
SymmetricBilinearForm, VectorSpace,
};
#[batch_impl_only(
[
SubsetOf<u16> u8,
SubsetOf<u32> u16,
SubsetOf<u64> u32,
SubsetOf<u128> u64,
SubsetOf<i16> i8,
SubsetOf<i32> i16,
SubsetOf<i64> i32,
SubsetOf<i128> i64,
SubsetOf<i16> u8,
SubsetOf<i32> u16,
SubsetOf<i64> u32,
SubsetOf<i128> u64,
SubsetOf<f64> [@u*, @i*]
] #to_superset{*self as T}
#is_in_subset{(*element as Self) as T == *element}
#from_superset_unchecked{*element as Self},
SubsetOf<Complex<f64>> f64 #to_superset{Complex::new(*self, 0.)}
#is_in_subset{*element.im() == 0.}
#from_superset_unchecked{*element.re()},
SubsetOf<Complex<f64>> f32 #to_superset{Complex::new(*self as f64, 0.)}
#is_in_subset{*element.im() == 0.}
#from_superset_unchecked{*element.re() as f32},
)]
trait SubsetOf<T>: Sized {
fn to_superset(&self) -> T;
fn is_in_subset(element: &T) -> bool;
fn from_superset(element: &T) -> Option<Self>;
fn from_superset_unchecked(element: &T) -> Self;
}
batch_trait! {
@with=Additive, Multiplicative;
@trait_with=@trait<@with>;
MeetSemilattice:[@num,bool]{
fn meet(&self, other: &Self) -> Self {
(*self).min(*other)
}
};
JoinSemilattice: [@num,bool]{
fn join(&self, other: &Self) -> Self {
(*self).max(*other)
}
};
Lattice: @num, bool;
ClosedAdd:@num;
ClosedSub:@num;
ClosedMul:@num;
ClosedDiv:@num;
ClosedRem:@num;
FiniteDimInnerSpace:@trait_with [@f*,Complex<f64>,Complex<f32>];
ClosedNeg:[@i*, @f*];
DistributiveLattice: @num, bool;
ComplementedLattice: bool {
fn complement(&self) -> Self { !*self }
};
BooleanAlgebra: bool;
OrderedField: @trait_with @f*;
Real: @f* {
fn sqrt(self) -> Self { self.sqrt() }
fn abs(self) -> Self { self.abs() }
fn acos(self) -> Self { self.acos() }
};
NormedSpace: @trait_with @f*{
type RealField = Self;
fn norm_squared(&self) -> Self { *self * *self }
fn scale_real(&self, r: Self) -> Self { *self * r }
}, @trait_with <T: Real + ClosedAdd + ClosedMul + Copy> Complex<T>{
type RealField = T;
fn norm_squared(&self) -> T { *self.re() * *self.re() + *self.im() * *self.im() }
fn scale_real(&self, r: T) -> Self {
<Complex<T> as Module<Additive, Multiplicative>>::scale(&r, *self)
}
};
InnerSpace: @trait_with [@f*{
fn inner_product(&self, other: &Self) -> Self { *self * *other }
},
<T: Real + ClosedAdd + ClosedMul + Copy> Complex<T>{
fn inner_product(&self, other: &Self) -> T {
*self.re() * *other.re() + *self.im() * *other.im()
}
}];
FiniteDimVectorSpace: @trait_with [@f*{
fn dimension() -> usize { 1 }
fn canonical_basis_element(_i: usize) -> Self { 1. }
fn dot(&self, other: &Self) -> Self { *self * *other }
}, <T: Real + ClosedAdd + ClosedMul + Copy> Complex<T>{
fn dimension() -> usize { 2 }
fn canonical_basis_element(_i: usize) -> Self {
if _i == 0 {
Complex::new(
<T as Monoid<Multiplicative>>::identity(),
<T as Monoid>::identity(),
)
} else {
Complex::new(
<T as Monoid>::identity(),
<T as Monoid<Multiplicative>>::identity(),
)
}
}
fn dot(&self, other: &Self) -> T {
*self.re() * *other.re() + *self.im() * *other.im()
}
}];
BilinearForm: <T: Real + Copy> T where
T: VectorSpace<@with, Scalar = T>,
{
type Space = T;
type Scalar = T;
fn apply(&self, u: &T, v: &T) -> T { *u * *v }
};
SymmetricBilinearForm: <T: Real + Copy> T where
T: VectorSpace<@with, Scalar = T>,
;
PositiveDefinite: <T: Real + Copy> T where
T: VectorSpace<@with, Scalar = T>,
T: OrderedField<@with>,
;
EuclideanSpace: @f* {
type Coordinates = Self;
fn origin() -> Self { 0. }
fn from_coordinates(coords: Self) -> Self { coords }
fn coordinates(&self) -> Self { *self }
}, (f64,).1..=12 impl{(A@..,)}{
type Coordinates = (@(f64,)..);
fn origin() -> Self { (@(0.,)..) }
fn from_coordinates(coords: Self::Coordinates) -> Self { coords }
fn coordinates(&self) -> Self::Coordinates { *self }
};
AffineSpace: @f*{
type Translation = Self; fn origin() -> Self { 0. }
fn from_point_translation(origin: &Self, translation: &Self) -> Self {
<Self as Magma>::combine(origin, translation)
}
fn translate_by(&self, t: &Self) -> Self {
<Self as Magma>::combine(self, t)
}
fn translation(&self, other: &Self) -> Self {
<Self as Magma>::combine(other, &<Self as Group>::inverse(self))
}
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tower::{
AffineSpace, EuclideanSpace, FiniteDimInnerSpace, FiniteDimVectorSpace, InnerSpace,
JoinSemilattice, MeetSemilattice, NormedSpace, SubsetOf,
};
#[test]
fn numeric_lattice() {
assert_eq!(3u8.meet(&5), 3);
assert_eq!(3u8.join(&5), 5);
assert_eq!(3.5f64.meet(&-1.0), -1.0);
assert_eq!((3u8, 7u8).meet(&(5, 2)), (3, 2));
assert_eq!((3u8, 7u8).join(&(5, 2)), (5, 7));
}
#[test]
fn subset_embedding() {
let up: u16 = 3u8.to_superset();
assert_eq!(up, 3u16);
assert_eq!(<u8 as SubsetOf<u16>>::from_superset(&300u16), None);
assert_eq!(<u8 as SubsetOf<u16>>::from_superset(&3u16), Some(3u8));
assert!(<u64 as SubsetOf<f64>>::is_in_subset(&42.0));
assert!(!<u64 as SubsetOf<f64>>::is_in_subset(&1e30));
let z: Complex<f64> = 2.0f64.to_superset();
assert_eq!(z, Complex::new(2.0, 0.0));
}
#[test]
fn reals() {
assert_eq!(9.0f64.sqrt(), 3.0);
assert_eq!((-5.0f64).abs(), 5.0);
assert_eq!(1.0f64.acos(), 0.0);
}
#[test]
fn euclidean_norms() {
assert_eq!(3.0f64.norm_squared(), 9.0);
assert_eq!((-4.0f64).norm(), 4.0);
let v = (3.0f64, 4.0f64);
assert_eq!(v.norm_squared(), 25.0);
assert_eq!(v.norm(), 5.0);
let n = v.normalize();
assert!((n.norm() - 1.0).abs() < 1e-12);
assert_eq!((1.0f64, 2.0f64).inner_product(&(3.0, 4.0)), 11.0);
let z = Complex::new(3.0f64, 4.0);
assert_eq!(z.norm(), 5.0);
}
#[test]
fn finite_dimension_and_basis() {
assert_eq!(<f64 as FiniteDimVectorSpace<Additive, Multiplicative>>::dimension(), 1);
assert_eq!(<(f64, f64) as FiniteDimVectorSpace<Additive, Multiplicative>>::dimension(), 2);
let e0 =
<(f64, f64) as FiniteDimVectorSpace<Additive, Multiplicative>>::canonical_basis_element(
0,
);
assert_eq!(e0, (1.0, 0.0));
assert_eq!((1.0f64, 2.0).dot(&(3.0, 4.0)), 11.0);
}
#[test]
fn gram_schmidt_orthonormalizes() {
let mut vs = [(1.0f64, 0.0), (1.0, 1.0)];
let n =
<(f64, f64) as FiniteDimInnerSpace<Additive, Multiplicative>>::orthonormalize(&mut vs);
assert_eq!(n, 2);
assert!((vs[0].norm() - 1.0).abs() < 1e-12);
assert!((vs[1].norm() - 1.0).abs() < 1e-12);
assert!(vs[0].inner_product(&vs[1]).abs() < 1e-12);
}
#[test]
fn euclidean_distance_and_affine() {
assert_eq!(1.0f64.distance(&4.0), 3.0);
assert_eq!((0.0f64, 0.0).distance(&(3.0, 4.0)), 5.0);
assert_eq!(1.0f64.translate_by(&2.0), 3.0);
}
#[test]
fn euclidean_space_tuples_to_12() {
let v: (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) =
(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0);
assert_eq!(
<(f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) as EuclideanSpace>::origin(),
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
);
assert_eq!(
<(f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) as EuclideanSpace>::coordinates(&v),
v
);
}
#[test]
fn complex_finite_dim_is_two() {
assert_eq!(
<Complex<f64> as FiniteDimVectorSpace<Additive, Multiplicative>>::dimension(),
2
);
let e0 =
<Complex<f64> as FiniteDimVectorSpace<Additive, Multiplicative>>::canonical_basis_element(
0,
);
let e1 =
<Complex<f64> as FiniteDimVectorSpace<Additive, Multiplicative>>::canonical_basis_element(
1,
);
assert_eq!(e0, Complex::new(1.0, 0.0));
assert_eq!(e1, Complex::new(0.0, 1.0));
assert_eq!(
<Complex<f32> as FiniteDimVectorSpace<Additive, Multiplicative>>::dimension(),
2
);
assert_eq!(
<Complex<f32> as NormedSpace<Additive, Multiplicative>>::norm_squared(&Complex::new(
3.0f32, 4.0
)),
25.0
);
}
#[test]
fn complex_subset_checks_imag_part() {
assert!(<f64 as SubsetOf<Complex<f64>>>::is_in_subset(&Complex::new(1.0, 0.0)));
assert!(!<f64 as SubsetOf<Complex<f64>>>::is_in_subset(&Complex::new(1.0, 2.0)));
assert_eq!(<f64 as SubsetOf<Complex<f64>>>::from_superset(&Complex::new(1.0, 2.0)), None);
assert_eq!(
<f64 as SubsetOf<Complex<f64>>>::from_superset(&Complex::new(1.0, 0.0)),
Some(1.0)
);
assert!(!<f32 as SubsetOf<Complex<f64>>>::is_in_subset(&Complex::new(1.0, 2.0)));
}
#[test]
fn multiplication_is_a_bilinear_form() {
use crate::tower::{BilinearForm, PositiveDefinite, SymmetricBilinearForm};
let form = 1.0f64;
assert_eq!(form.apply(&2.0, &3.0), 6.0);
fn assert_sym<F: SymmetricBilinearForm<Space = f64, Scalar = f64>>() {}
fn assert_pd<F: PositiveDefinite<Space = f64, Scalar = f64>>() {}
assert_sym::<f64>();
assert_pd::<f64>();
}
}