use super::verified::VerifiedMultivector;
use creusot_contracts::macros::requires;
use num_traits::{Float, One, Zero};
#[requires(scalar != T::zero())]
#[ensures(result.coefficients.len() == mv.coefficients.len())]
#[ensures(result.coefficients[0] == scalar * mv.coefficients[0])]
pub fn verified_scalar_mult<T, const P: usize, const Q: usize, const R: usize>(
scalar: T,
mv: &VerifiedMultivector<T, P, Q, R>,
) -> VerifiedMultivector<T, P, Q, R>
where
T: Float + Zero + One + Copy,
{
let mut coefficients = Vec::with_capacity(mv.coefficients.len());
for &coeff in &mv.coefficients {
coefficients.push(scalar * coeff);
}
VerifiedMultivector::new(coefficients).unwrap()
}
#[requires(a.coefficients.len() == b.coefficients.len())]
#[ensures(result.coefficients.len() == a.coefficients.len())]
#[ensures(forall(|i: usize| i < result.coefficients.len() ==>
result.coefficients[i] == a.coefficients[i] + b.coefficients[i]
))]
pub fn verified_addition<T, const P: usize, const Q: usize, const R: usize>(
a: &VerifiedMultivector<T, P, Q, R>,
b: &VerifiedMultivector<T, P, Q, R>,
) -> VerifiedMultivector<T, P, Q, R>
where
T: Float + Zero + One + Copy,
{
a.add(b)
}
#[requires(!mv.coefficients.is_empty())]
#[ensures(result >= T::zero())]
pub fn verified_norm<T, const P: usize, const Q: usize, const R: usize>(
mv: &VerifiedMultivector<T, P, Q, R>,
) -> T
where
T: Float + Zero + One + Copy,
{
mv.coefficients
.iter()
.map(|&c| c * c)
.fold(T::zero(), |acc, x| acc + x)
.sqrt()
}
#[requires(!mv.coefficients.is_empty())]
#[ensures(result <= P + Q + R)]
pub fn verified_grade<T, const P: usize, const Q: usize, const R: usize>(
mv: &VerifiedMultivector<T, P, Q, R>,
) -> usize
where
T: Float + Zero + One,
{
mv.grade()
}
#[requires(mv.coefficients.len() == VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE)]
#[ensures(result.coefficients.len() == mv.coefficients.len())]
#[ensures(forall(|i: usize| i < result.coefficients.len() ==>
result.coefficients[i] == mv.coefficients[i]
))]
pub fn verify_scalar_identity<T, const P: usize, const Q: usize, const R: usize>(
mv: &VerifiedMultivector<T, P, Q, R>,
) -> VerifiedMultivector<T, P, Q, R>
where
T: Float + Zero + One + Copy,
{
let identity = VerifiedMultivector::scalar(T::one());
mv.geometric_product(&identity)
}
#[requires(mv.coefficients.len() == VerifiedMultivector::<T, P, Q, R>::BASIS_SIZE)]
#[ensures(result.coefficients.len() == mv.coefficients.len())]
#[ensures(forall(|i: usize| i < result.coefficients.len() ==>
result.coefficients[i] == mv.coefficients[i]
))]
pub fn verify_zero_addition<T, const P: usize, const Q: usize, const R: usize>(
mv: &VerifiedMultivector<T, P, Q, R>,
) -> VerifiedMultivector<T, P, Q, R>
where
T: Float + Zero + One + Copy,
{
let zero = VerifiedMultivector::scalar(T::zero());
mv.add(&zero)
}
#[requires(index < P + Q + R)]
#[ensures(
(index < P ==> (result - T::one()).abs() < T::from(0.0001).unwrap()) &&
(P <= index && index < P + Q ==> (result + T::one()).abs() < T::from(0.0001).unwrap()) &&
(P + Q <= index ==> result.abs() < T::from(0.0001).unwrap())
)]
pub fn verify_basis_vector_square<T, const P: usize, const Q: usize, const R: usize>(
index: usize,
) -> T
where
T: Float + Zero + One + Copy,
{
let basis = VerifiedMultivector::<T, P, Q, R>::basis_vector(index).unwrap();
let square = basis.geometric_product(&basis);
square.coefficients[0]
}
#[cfg(test)]
mod contract_tests {
use super::*;
#[test]
fn test_verified_scalar_multiplication() {
let mv = VerifiedMultivector::<f64, 3, 0, 0>::scalar(2.0);
let result = verified_scalar_mult(3.0, &mv);
assert_eq!(result.coefficients[0], 6.0);
assert_eq!(result.coefficients.len(), mv.coefficients.len());
}
#[test]
fn test_verified_addition_properties() {
let mv1 = VerifiedMultivector::<f64, 3, 0, 0>::scalar(2.0);
let mv2 = VerifiedMultivector::<f64, 3, 0, 0>::scalar(3.0);
let result = verified_addition(&mv1, &mv2);
assert_eq!(result.coefficients[0], 5.0);
}
#[test]
fn test_verified_identity_laws() {
let mv = VerifiedMultivector::<f64, 3, 0, 0>::scalar(5.0);
let result = verify_scalar_identity(&mv);
assert_eq!(result.coefficients[0], mv.coefficients[0]);
let result = verify_zero_addition(&mv);
assert_eq!(result.coefficients[0], mv.coefficients[0]);
}
#[test]
fn test_signature_verification() {
for i in 0..3 {
let square = verify_basis_vector_square::<f64, 3, 0, 0>(i);
assert!((square - 1.0).abs() < 0.0001);
}
}
}