use crate::*;
use proptest::prelude::*;
#[cfg(not(feature = "std"))]
use alloc::format;
#[cfg(feature = "std")]
use std::f64::consts;
#[cfg(not(feature = "std"))]
use core::f64::consts;
fn multivector_coefficients() -> impl Strategy<Value = Vec<f64>> {
prop::collection::vec(-100.0..100.0, 8..=8) }
fn non_zero_scalar() -> impl Strategy<Value = f64> {
(-100.0..-0.001).prop_union(0.001..100.0)
}
fn basis_index() -> impl Strategy<Value = usize> {
0..3usize }
fn create_multivector(coeffs: Vec<f64>) -> Multivector<3, 0, 0> {
Multivector::from_coefficients(coeffs)
}
proptest! {
#[test]
fn prop_addition_commutative(
a_coeffs in multivector_coefficients(),
b_coeffs in multivector_coefficients()
) {
let a = create_multivector(a_coeffs);
let b = create_multivector(b_coeffs);
let ab = &a + &b;
let ba = &b + &a;
for i in 0..8 {
prop_assert!((ab.get(i) - ba.get(i)).abs() < 1e-10);
}
}
#[test]
fn prop_addition_associative(
a_coeffs in multivector_coefficients(),
b_coeffs in multivector_coefficients(),
c_coeffs in multivector_coefficients()
) {
let a = create_multivector(a_coeffs);
let b = create_multivector(b_coeffs);
let c = create_multivector(c_coeffs);
let ab_c = &(&a + &b) + &c;
let a_bc = &a + &(&b + &c);
for i in 0..8 {
prop_assert!((ab_c.get(i) - a_bc.get(i)).abs() < 1e-10);
}
}
#[test]
fn prop_additive_identity(a_coeffs in multivector_coefficients()) {
let a = create_multivector(a_coeffs);
let zero = Multivector::zero();
let result = &a + &zero;
for i in 0..8 {
prop_assert!((a.get(i) - result.get(i)).abs() < 1e-10);
}
}
#[test]
fn prop_geometric_product_associative(
a_coeffs in multivector_coefficients(),
b_coeffs in multivector_coefficients(),
c_coeffs in multivector_coefficients()
) {
let a = create_multivector(a_coeffs);
let b = create_multivector(b_coeffs);
let c = create_multivector(c_coeffs);
let ab_c = a.geometric_product(&b).geometric_product(&c);
let a_bc = a.geometric_product(&b.geometric_product(&c));
for i in 0..8 {
prop_assert!((ab_c.get(i) - a_bc.get(i)).abs() < 1e-8);
}
}
#[test]
fn prop_multiplicative_identity(a_coeffs in multivector_coefficients()) {
let a = create_multivector(a_coeffs);
let one = Multivector::scalar(1.0);
let result = a.geometric_product(&one);
for i in 0..8 {
prop_assert!((a.get(i) - result.get(i)).abs() < 1e-10);
}
}
#[test]
fn prop_scalar_multiplication_commutative(
a_coeffs in multivector_coefficients(),
scalar in non_zero_scalar()
) {
let a = create_multivector(a_coeffs);
let s = Multivector::scalar(scalar);
let sa = s.geometric_product(&a);
let as_result = a.geometric_product(&s);
for i in 0..8 {
prop_assert!((sa.get(i) - as_result.get(i)).abs() < 1e-10);
}
}
#[test]
fn prop_left_distributivity(
a_coeffs in multivector_coefficients(),
b_coeffs in multivector_coefficients(),
c_coeffs in multivector_coefficients()
) {
let a = create_multivector(a_coeffs);
let b = create_multivector(b_coeffs);
let c = create_multivector(c_coeffs);
let a_bc = a.geometric_product(&(&b + &c));
let ab_ac = &a.geometric_product(&b) + &a.geometric_product(&c);
for i in 0..8 {
prop_assert!((a_bc.get(i) - ab_ac.get(i)).abs() < 1e-8);
}
}
#[test]
fn prop_basis_vector_squares(i in basis_index()) {
let ei = Multivector::<3, 0, 0>::basis_vector(i);
let ei_squared = ei.geometric_product(&ei);
prop_assert!((ei_squared.scalar_part() - 1.0).abs() < 1e-10);
for j in 1..8 {
prop_assert!(ei_squared.get(j).abs() < 1e-10);
}
}
#[test]
fn prop_basis_anticommutativity(i in basis_index(), j in basis_index()) {
prop_assume!(i != j);
let ei = Multivector::<3, 0, 0>::basis_vector(i);
let ej = Multivector::<3, 0, 0>::basis_vector(j);
let eij = ei.geometric_product(&ej);
let eji = ej.geometric_product(&ei);
for k in 0..8 {
prop_assert!((eij.get(k) + eji.get(k)).abs() < 1e-10);
}
}
#[test]
fn prop_outer_product_antisymmetric(i in basis_index(), j in basis_index()) {
prop_assume!(i != j);
let ei = Multivector::<3, 0, 0>::basis_vector(i);
let ej = Multivector::<3, 0, 0>::basis_vector(j);
let ei_ej = ei.outer_product(&ej);
let ej_ei = ej.outer_product(&ei);
for k in 0..8 {
prop_assert!((ei_ej.get(k) + ej_ei.get(k)).abs() < 1e-10);
}
}
#[test]
fn prop_outer_product_self_zero(i in basis_index()) {
let ei = Multivector::<3, 0, 0>::basis_vector(i);
let ei_ei = ei.outer_product(&ei);
prop_assert!(ei_ei.is_zero());
}
#[test]
fn prop_reverse_antiautomorphism(
a_coeffs in multivector_coefficients(),
b_coeffs in multivector_coefficients()
) {
let a = create_multivector(a_coeffs);
let b = create_multivector(b_coeffs);
let ab = a.geometric_product(&b);
let ab_rev = ab.reverse();
let a_rev = a.reverse();
let b_rev = b.reverse();
let ba_rev = b_rev.geometric_product(&a_rev);
for i in 0..8 {
prop_assert!((ab_rev.get(i) - ba_rev.get(i)).abs() < 1e-8);
}
}
#[test]
fn prop_norm_via_reverse(a_coeffs in multivector_coefficients()) {
let a = create_multivector(a_coeffs);
let a_rev = a.reverse();
let norm_squared_mv = a.geometric_product(&a_rev);
let norm_squared_direct = a.norm_squared();
let norm_squared_via_reverse = norm_squared_mv.scalar_part();
prop_assert!((norm_squared_direct - norm_squared_via_reverse).abs() < 1e-8);
}
#[test]
fn prop_rotor_preserves_norm(
vector_coeffs in prop::collection::vec(-10.0..10.0, 3..=3), angle in -consts::PI..consts::PI
) {
let v = Multivector::<3, 0, 0>::from_vector(&Vector::from_components(
vector_coeffs[0], vector_coeffs[1], vector_coeffs[2]
));
let e1 = Multivector::<3, 0, 0>::basis_vector(0);
let e2 = Multivector::<3, 0, 0>::basis_vector(1);
let bivector = e1.outer_product(&e2) * (angle / 2.0);
let rotor = bivector.exp();
let rotated = rotor.geometric_product(&v).geometric_product(&rotor.reverse());
let original_norm = v.norm();
let rotated_norm = rotated.norm();
prop_assert!((original_norm - rotated_norm).abs() < 1e-6);
}
}
#[cfg(test)]
mod unit_property_tests {
use super::*;
#[test]
fn test_property_framework() {
let a = Multivector::<3, 0, 0>::scalar(2.0);
let b = Multivector::<3, 0, 0>::scalar(3.0);
let sum = &a + &b;
assert_eq!(sum.scalar_part(), 5.0);
}
}