use geoit::algebra::blade_new::{grade, BladeMask};
use geoit::algebra::mv::Mv;
use geoit::algebra::signature::Signature;
use geoit::scalar::Rat;
pub struct TestRng {
state: u64,
}
impl TestRng {
pub fn new(seed: u64) -> Self {
TestRng { state: seed }
}
pub fn next_u64(&mut self) -> u64 {
self.state ^= self.state << 13;
self.state ^= self.state >> 7;
self.state ^= self.state << 17;
self.state
}
pub fn next_i64(&mut self, range: i64) -> i64 {
let v = self.next_u64();
((v % (2 * range as u64 + 1)) as i64) - range
}
pub fn next_nonzero_i64(&mut self, range: i64) -> i64 {
loop {
let v = self.next_i64(range);
if v != 0 {
return v;
}
}
}
}
pub fn random_mv(sig: &Signature, max_terms: usize, coeff_range: i64, rng: &mut TestRng) -> Mv {
let n = sig.n();
let dim = 1u64 << n;
let num_terms = ((rng.next_u64() % max_terms as u64) + 1) as usize;
let mut terms = Vec::new();
for _ in 0..num_terms {
let mask = rng.next_u64() % dim;
let coeff = rng.next_nonzero_i64(coeff_range);
terms.push((mask as BladeMask, Rat::from(coeff)));
}
Mv::from_rat_terms(&terms)
}
pub fn random_mv_at_grades(
sig: &Signature,
grades: &[u8],
max_terms: usize,
coeff_range: i64,
rng: &mut TestRng,
) -> Mv {
let n = sig.n();
let mut allowed: Vec<BladeMask> = Vec::new();
for mask in 0..(1u64 << n) {
if grades.contains(&grade(mask)) {
allowed.push(mask);
}
}
if allowed.is_empty() {
return Mv::new();
}
let num_terms = ((rng.next_u64() % max_terms as u64) + 1).min(allowed.len() as u64) as usize;
let mut terms = Vec::new();
for _ in 0..num_terms {
let idx = (rng.next_u64() as usize) % allowed.len();
let coeff = rng.next_nonzero_i64(coeff_range);
terms.push((allowed[idx], Rat::from(coeff)));
}
Mv::from_rat_terms(&terms)
}
pub fn assert_mv_eq(a: &Mv, b: &Mv, context: &str) {
if a == b {
return;
}
let mut diffs = Vec::new();
let mut all_masks: Vec<BladeMask> = Vec::new();
for (m, _) in a.blades() {
all_masks.push(m);
}
for (m, _) in b.blades() {
if !all_masks.contains(&m) {
all_masks.push(m);
}
}
all_masks.sort();
for mask in &all_masks {
let ca = a.coefficient(*mask);
let cb = b.coefficient(*mask);
if ca != cb {
diffs.push(format!(
" blade {:#b} (grade {}): left={}, right={}",
mask,
grade(*mask),
ca,
cb
));
}
}
panic!("Mv mismatch [{}]:\n{}", context, diffs.join("\n"));
}
pub fn all_signatures() -> Vec<(&'static str, Signature)> {
vec![
("VGA2", Signature::new(0, 0, 2).unwrap()),
("VGA3", Signature::new(0, 0, 3).unwrap()),
("PGA2", Signature::new(0, 1, 2).unwrap()),
("PGA3", Signature::new(0, 1, 3).unwrap()),
("CGA2", Signature::new(1, 0, 3).unwrap()),
("CGA3", Signature::new(1, 0, 4).unwrap()),
("STA-WC", Signature::new(3, 0, 1).unwrap()),
("STA-EC", Signature::new(1, 0, 3).unwrap()),
("QGA3", Signature::new(3, 0, 6).unwrap()),
("VGA5", Signature::new(0, 0, 5).unwrap()),
]
}