use num_traits::{Float, One, Zero};
use std::marker::PhantomData;
#[cfg(feature = "formal-verification")]
use creusot_contracts::macros::{ensures, requires};
pub struct Signature<const P: usize, const Q: usize, const R: usize>;
pub struct Grade<const G: usize>;
pub struct Dim<const D: usize>;
#[derive(Debug, Clone)]
pub struct VerifiedMultivector<T, const P: usize, const Q: usize, const R: usize>
where
T: Float + Zero + One,
{
pub(crate) coefficients: Vec<T>,
_signature: PhantomData<Signature<P, Q, R>>,
}
impl<T, const P: usize, const Q: usize, const R: usize> VerifiedMultivector<T, P, Q, R>
where
T: Float + Zero + One,
{
pub const DIM: usize = P + Q + R;
pub const BASIS_SIZE: usize = 1 << (P + Q + R);
#[cfg_attr(feature = "formal-verification",
requires(coefficients.len() == Self::BASIS_SIZE))]
pub fn new(coefficients: Vec<T>) -> Result<Self, &'static str> {
if coefficients.len() != Self::BASIS_SIZE {
return Err("Coefficient array size must equal 2^(P+Q+R)");
}
Ok(Self {
coefficients,
_signature: PhantomData,
})
}
#[cfg_attr(feature = "formal-verification",
ensures(result.is_scalar()),
ensures(result.coefficients[0] == value),
ensures(result.coefficients.len() == Self::BASIS_SIZE))]
pub fn scalar(value: T) -> Self {
let mut coefficients = vec![T::zero(); Self::BASIS_SIZE];
coefficients[0] = value;
Self {
coefficients,
_signature: PhantomData,
}
}
#[cfg_attr(feature = "formal-verification",
requires(index < Self::DIM),
ensures(result.grade() == 1))]
pub fn basis_vector(index: usize) -> Result<Self, &'static str> {
if index >= Self::DIM {
return Err("Basis vector index exceeds dimension");
}
let mut coefficients = vec![T::zero(); Self::BASIS_SIZE];
coefficients[1 << index] = T::one();
Ok(Self {
coefficients,
_signature: PhantomData,
})
}
#[cfg_attr(feature = "formal-verification",
ensures(result == (self.coefficients[1..].iter().all(|c| c.is_zero()))))]
pub fn is_scalar(&self) -> bool {
self.coefficients[1..].iter().all(|c| c.is_zero())
}
#[cfg_attr(feature = "formal-verification",
ensures(result <= Self::DIM))]
pub fn grade(&self) -> usize {
for (i, coeff) in self.coefficients.iter().enumerate().rev() {
if !coeff.is_zero() {
return i.count_ones() as usize;
}
}
0
}
#[cfg_attr(feature = "formal-verification",
ensures(result.coefficients.len() == self.coefficients.len()))]
pub fn add(&self, other: &Self) -> Self {
let coefficients: Vec<T> = self
.coefficients
.iter()
.zip(&other.coefficients)
.map(|(a, b)| *a + *b)
.collect();
Self {
coefficients,
_signature: PhantomData,
}
}
#[cfg_attr(feature = "formal-verification",
requires(self.coefficients.len() == Self::BASIS_SIZE),
requires(other.coefficients.len() == Self::BASIS_SIZE),
ensures(result.coefficients.len() == Self::BASIS_SIZE))]
pub fn geometric_product(&self, other: &Self) -> Self {
let mut result = vec![T::zero(); Self::BASIS_SIZE];
for i in 0..Self::BASIS_SIZE {
for j in 0..Self::BASIS_SIZE {
let sign = self.compute_product_sign(i, j);
let target_index = i ^ j; result[target_index] = result[target_index]
+ self.coefficients[i] * other.coefficients[j] * T::from(sign).unwrap();
}
}
Self {
coefficients: result,
_signature: PhantomData,
}
}
fn compute_product_sign(&self, blade1: usize, blade2: usize) -> i32 {
let swaps = self.count_swaps(blade1, blade2);
let mut sign: i32 = if swaps.is_multiple_of(2) { 1 } else { -1 };
let shared = blade1 & blade2;
for i in 0..Self::DIM {
if shared & (1 << i) != 0 {
if i >= P + Q {
return 0;
} else if i >= P {
sign = -sign;
}
}
}
sign
}
fn count_swaps(&self, blade1: usize, blade2: usize) -> usize {
let mut count = 0;
for i in 0..Self::DIM {
if blade1 & (1 << i) != 0 {
for j in 0..i {
if blade2 & (1 << j) != 0 {
count += 1;
}
}
}
}
count
}
}
pub struct KVector<T, const K: usize, const P: usize, const Q: usize, const R: usize>
where
T: Float + Zero + One,
{
multivector: VerifiedMultivector<T, P, Q, R>,
_grade: PhantomData<Grade<K>>,
}
impl<T, const K: usize, const P: usize, const Q: usize, const R: usize> KVector<T, K, P, Q, R>
where
T: Float + Zero + One,
{
#[cfg_attr(feature = "formal-verification",
requires(K <= P + Q + R),
ensures(result.grade() == K))]
pub fn from_multivector(mv: VerifiedMultivector<T, P, Q, R>) -> Self {
let mut coefficients = vec![T::zero(); VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE];
for (i, coeff) in mv.coefficients.iter().enumerate() {
if i.count_ones() as usize == K {
coefficients[i] = *coeff;
}
}
Self {
multivector: VerifiedMultivector {
coefficients,
_signature: PhantomData,
},
_grade: PhantomData,
}
}
pub const fn grade(&self) -> usize {
K
}
pub fn inner_product(&self, other: &Self) -> T {
self.multivector
.coefficients
.iter()
.zip(&other.multivector.coefficients)
.map(|(a, b)| *a * *b)
.fold(T::zero(), |acc, x| acc + x)
}
}
pub trait OuterProduct<T, const J: usize, const P: usize, const Q: usize, const R: usize>
where
T: Float + Zero + One,
{
type Output;
fn outer_product(&self, other: &KVector<T, J, P, Q, R>) -> Self::Output;
}
impl<T, const P: usize, const Q: usize, const R: usize> OuterProduct<T, 1, P, Q, R>
for KVector<T, 1, P, Q, R>
where
T: Float + Zero + One,
{
type Output = KVector<T, 2, P, Q, R>;
fn outer_product(&self, other: &KVector<T, 1, P, Q, R>) -> Self::Output {
let mut coefficients = vec![T::zero(); VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE];
for i in 0..VerifiedMultivector::<T, P, Q, R>::DIM {
for j in i + 1..VerifiedMultivector::<T, P, Q, R>::DIM {
let blade_i = 1 << i;
let blade_j = 1 << j;
let blade_ij = blade_i | blade_j;
coefficients[blade_ij] = self.multivector.coefficients[blade_i]
* other.multivector.coefficients[blade_j]
- self.multivector.coefficients[blade_j]
* other.multivector.coefficients[blade_i];
}
}
KVector {
multivector: VerifiedMultivector {
coefficients,
_signature: PhantomData,
},
_grade: PhantomData,
}
}
}
impl<T, const P: usize, const Q: usize, const R: usize> OuterProduct<T, 2, P, Q, R>
for KVector<T, 1, P, Q, R>
where
T: Float + Zero + One,
{
type Output = KVector<T, 3, P, Q, R>;
fn outer_product(&self, other: &KVector<T, 2, P, Q, R>) -> Self::Output {
let dim = VerifiedMultivector::<T, P, Q, R>::DIM;
let basis_size = VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE;
let mut coefficients = vec![T::zero(); basis_size];
for i in 0..dim {
let blade_i = 1usize << i;
for j in 0..basis_size {
if j.count_ones() != 2 {
continue;
}
if blade_i & j == 0 {
let target = blade_i | j;
let mut swaps = 0;
for k in 0..i {
if j & (1 << k) != 0 {
swaps += 1;
}
}
let sign = if swaps % 2 == 0 { T::one() } else { -T::one() };
coefficients[target] = coefficients[target]
+ sign
* self.multivector.coefficients[blade_i]
* other.multivector.coefficients[j];
}
}
}
KVector {
multivector: VerifiedMultivector {
coefficients,
_signature: PhantomData,
},
_grade: PhantomData,
}
}
}
impl<T, const P: usize, const Q: usize, const R: usize> OuterProduct<T, 1, P, Q, R>
for KVector<T, 2, P, Q, R>
where
T: Float + Zero + One,
{
type Output = KVector<T, 3, P, Q, R>;
fn outer_product(&self, other: &KVector<T, 1, P, Q, R>) -> Self::Output {
let dim = VerifiedMultivector::<T, P, Q, R>::DIM;
let basis_size = VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE;
let mut coefficients = vec![T::zero(); basis_size];
for i in 0..basis_size {
if i.count_ones() != 2 {
continue;
}
for j in 0..dim {
let blade_j = 1usize << j;
if i & blade_j == 0 {
let target = i | blade_j;
let mut swaps = 0;
for k in (j + 1)..dim {
if i & (1 << k) != 0 {
swaps += 1;
}
}
let sign = if swaps % 2 == 0 { T::one() } else { -T::one() };
coefficients[target] = coefficients[target]
+ sign
* self.multivector.coefficients[i]
* other.multivector.coefficients[blade_j];
}
}
}
KVector {
multivector: VerifiedMultivector {
coefficients,
_signature: PhantomData,
},
_grade: PhantomData,
}
}
}
pub struct VerifiedRotor<T, const P: usize, const Q: usize, const R: usize>
where
T: Float + Zero + One,
{
multivector: VerifiedMultivector<T, P, Q, R>,
_rotor_invariant: PhantomData<()>,
}
impl<T, const P: usize, const Q: usize, const R: usize> VerifiedRotor<T, P, Q, R>
where
T: Float + Zero + One,
{
#[cfg_attr(feature = "formal-verification",
requires(mv.is_even_grade()),
requires((mv.norm() - T::one()).abs() < T::from(0.0001).unwrap()),
ensures(result.is_ok()))]
pub fn new(mv: VerifiedMultivector<T, P, Q, R>) -> Result<Self, &'static str> {
if !Self::is_even_grade(&mv) {
return Err("Rotor must have even grade");
}
let norm = Self::compute_norm(&mv);
if (norm - T::one()).abs() > T::from(0.0001).unwrap() {
return Err("Rotor must have unit norm");
}
Ok(Self {
multivector: mv,
_rotor_invariant: PhantomData,
})
}
fn is_even_grade(mv: &VerifiedMultivector<T, P, Q, R>) -> bool {
for (i, coeff) in mv.coefficients.iter().enumerate() {
let grade = i.count_ones() as usize;
if !grade.is_multiple_of(2) && !coeff.is_zero() {
return false;
}
}
true
}
fn compute_norm(mv: &VerifiedMultivector<T, P, Q, R>) -> T {
mv.coefficients
.iter()
.map(|c| *c * *c)
.fold(T::zero(), |acc, x| acc + x)
.sqrt()
}
#[cfg_attr(feature = "formal-verification",
ensures(Self::compute_norm(&result.multivector) == T::one()))]
pub fn compose(&self, other: &Self) -> Self {
let composed = self.multivector.geometric_product(&other.multivector);
let norm = Self::compute_norm(&composed);
let normalized = VerifiedMultivector {
coefficients: composed.coefficients.iter().map(|c| *c / norm).collect(),
_signature: PhantomData,
};
Self {
multivector: normalized,
_rotor_invariant: PhantomData,
}
}
pub fn apply_to_multivector(
&self,
v: &VerifiedMultivector<T, P, Q, R>,
) -> VerifiedMultivector<T, P, Q, R> {
let mut rev_coeffs = self.multivector.coefficients.clone();
for (i, coeff) in rev_coeffs.iter_mut().enumerate() {
let grade = i.count_ones() as usize;
if grade >= 2 && (grade * (grade - 1) / 2) % 2 == 1 {
*coeff = -*coeff;
}
}
let r_rev = VerifiedMultivector::<T, P, Q, R> {
coefficients: rev_coeffs,
_signature: PhantomData,
};
let rv = self.multivector.geometric_product(v);
rv.geometric_product(&r_rev)
}
}
pub struct Vector<T, const D: usize>
where
T: Float + Zero + One,
{
pub(crate) data: Vec<T>,
_dim: PhantomData<Dim<D>>,
}
impl<T, const D: usize> Vector<T, D>
where
T: Float + Zero + One,
{
#[cfg_attr(feature = "formal-verification",
requires(data.len() == D),
ensures(result.dimension() == D))]
pub fn new(data: Vec<T>) -> Result<Self, &'static str> {
if data.len() != D {
return Err("Vector data length must match dimension");
}
Ok(Self {
data,
_dim: PhantomData,
})
}
pub const fn dimension(&self) -> usize {
D
}
#[cfg_attr(feature = "formal-verification",
ensures(result >= T::zero()))] pub fn dot(&self, other: &Self) -> T {
self.data
.iter()
.zip(&other.data)
.map(|(a, b)| *a * *b)
.fold(T::zero(), |acc, x| acc + x)
}
pub fn add(&self, other: &Self) -> Self {
Self {
data: self
.data
.iter()
.zip(&other.data)
.map(|(a, b)| *a + *b)
.collect(),
_dim: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_phantom_type_dimension_safety() {
let v1 = Vector::<f64, 3>::new(vec![1.0, 2.0, 3.0]).unwrap();
let v2 = Vector::<f64, 3>::new(vec![4.0, 5.0, 6.0]).unwrap();
let _v3 = v1.add(&v2);
}
#[test]
fn test_signature_type_safety() {
let mv1 = VerifiedMultivector::<f64, 3, 0, 0>::scalar(2.0);
let mv2 = VerifiedMultivector::<f64, 3, 0, 0>::scalar(3.0);
let _mv3 = mv1.add(&mv2);
}
#[test]
fn test_grade_preservation() {
let bivector =
KVector::<f64, 2, 3, 0, 0>::from_multivector(VerifiedMultivector::scalar(1.0));
assert_eq!(bivector.grade(), 2);
}
#[test]
fn test_outer_product_type_safety() {
use super::OuterProduct;
let v1 = KVector::<f64, 1, 3, 0, 0>::from_multivector(
VerifiedMultivector::basis_vector(0).unwrap(),
);
let v2 = KVector::<f64, 1, 3, 0, 0>::from_multivector(
VerifiedMultivector::basis_vector(1).unwrap(),
);
let bivector: KVector<f64, 2, 3, 0, 0> = v1.outer_product(&v2);
assert_eq!(bivector.grade(), 2);
}
}