pub fn blade_product(
p: usize,
q: usize,
_r: usize,
dim: usize,
i: usize,
j: usize,
) -> (usize, f64) {
let k = i ^ j;
let mut sign = 1.0f64;
let mut swap_count = 0u32;
let mut remaining_i = i;
for bit in 0..dim {
if (j >> bit) & 1 == 1 {
let higher_bits = (remaining_i >> (bit + 1)).count_ones();
swap_count += higher_bits;
}
remaining_i &= !(1 << bit);
}
if swap_count % 2 == 1 {
sign = -sign;
}
let common = i & j;
for bit in 0..dim {
if (common >> bit) & 1 == 1 {
if bit < p {
} else if bit < p + q {
sign = -sign;
} else {
return (k, 0.0);
}
}
}
(k, sign)
}
pub fn generic_geometric_product(p: usize, q: usize, r: usize, a: &[f64], b: &[f64]) -> Vec<f64> {
let dim = p + q + r;
let basis_count = 1 << dim;
let mut result = vec![0.0; basis_count];
for (i, &ai) in a.iter().enumerate() {
if ai.abs() < f64::MIN_POSITIVE {
continue;
}
for (j, &bj) in b.iter().enumerate() {
if bj.abs() < f64::MIN_POSITIVE {
continue;
}
let (k, sign) = blade_product(p, q, r, dim, i, j);
if sign != 0.0 {
result[k] += sign * ai * bj;
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Multivector;
#[test]
fn test_blade_product_e1_e1_cl300() {
let (k, sign) = blade_product(3, 0, 0, 3, 1, 1);
assert_eq!(k, 0); assert!((sign - 1.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_e1_e2_cl300() {
let (k, sign) = blade_product(3, 0, 0, 3, 1, 2);
assert_eq!(k, 3); assert!((sign - 1.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_e2_e1_cl300() {
let (k, sign) = blade_product(3, 0, 0, 3, 2, 1);
assert_eq!(k, 3);
assert!((sign + 1.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_e3_e3_cl210() {
let (k, sign) = blade_product(2, 1, 0, 3, 4, 4);
assert_eq!(k, 0);
assert!((sign + 1.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_null_signature() {
let (k, sign) = blade_product(0, 0, 1, 1, 1, 1);
assert_eq!(k, 0);
assert!((sign - 0.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_e12_e1_cl300() {
let (k, sign) = blade_product(3, 0, 0, 3, 3, 1);
assert_eq!(k, 2); assert!((sign + 1.0).abs() < 1e-10);
}
#[test]
fn test_blade_product_scalar_scalar() {
let (k, sign) = blade_product(3, 0, 0, 3, 0, 0);
assert_eq!(k, 0);
assert!((sign - 1.0).abs() < 1e-10);
}
#[test]
fn test_generic_gp_matches_const_generic_cl300() {
let mv_a = Multivector::<3, 0, 0>::basis_vector(0);
let mv_b = Multivector::<3, 0, 0>::basis_vector(1);
let expected = mv_a.geometric_product(&mv_b);
let a_coeffs: Vec<f64> = (0..8).map(|i| mv_a.get(i)).collect();
let b_coeffs: Vec<f64> = (0..8).map(|i| mv_b.get(i)).collect();
let result = generic_geometric_product(3, 0, 0, &a_coeffs, &b_coeffs);
for i in 0..8 {
assert!(
(result[i] - expected.get(i)).abs() < 1e-10,
"Coefficient {} differs: {} vs {}",
i,
result[i],
expected.get(i)
);
}
}
#[test]
fn test_generic_gp_matches_const_generic_cl210() {
let mv_a = Multivector::<2, 1, 0>::basis_vector(2);
let mv_b = Multivector::<2, 1, 0>::basis_vector(2);
let expected = mv_a.geometric_product(&mv_b);
let a_coeffs: Vec<f64> = (0..8).map(|i| mv_a.get(i)).collect();
let b_coeffs: Vec<f64> = (0..8).map(|i| mv_b.get(i)).collect();
let result = generic_geometric_product(2, 1, 0, &a_coeffs, &b_coeffs);
for i in 0..8 {
assert!(
(result[i] - expected.get(i)).abs() < 1e-10,
"Coefficient {} differs: {} vs {}",
i,
result[i],
expected.get(i)
);
}
}
#[test]
fn test_generic_gp_random_cl410() {
let a_coeffs: Vec<f64> = (0..32).map(|i| ((i as f64) * 0.137) % 1.5 - 0.75).collect();
let b_coeffs: Vec<f64> = (0..32)
.map(|i| ((i as f64 + 17.0) * 0.097) % 1.5 - 0.75)
.collect();
let mv_a = Multivector::<4, 1, 0>::from_coefficients(a_coeffs.clone());
let mv_b = Multivector::<4, 1, 0>::from_coefficients(b_coeffs.clone());
let expected = mv_a.geometric_product(&mv_b);
let result = generic_geometric_product(4, 1, 0, &a_coeffs, &b_coeffs);
for i in 0..32 {
assert!(
(result[i] - expected.get(i)).abs() < 1e-8,
"Coefficient {} differs: {} vs {}",
i,
result[i],
expected.get(i)
);
}
}
#[test]
fn test_generic_gp_scalar_only() {
let a = vec![2.0];
let b = vec![3.0];
let result = generic_geometric_product(0, 0, 0, &a, &b);
assert_eq!(result.len(), 1);
assert!((result[0] - 6.0).abs() < 1e-10);
}
}