use crate::scalar::Scalar;
pub const MAX_BASIS_DIM: usize = 128;
pub(crate) fn grade_k_masks(n: usize, k: usize) -> Vec<u128> {
if k == 0 {
return vec![0];
}
if k > n {
return vec![];
}
assert!(n <= u128::BITS as usize, "basis masks fit in u128");
if k == u128::BITS as usize {
return vec![u128::MAX];
}
let mut out = Vec::new();
let mut c: u128 = (1u128 << k) - 1;
let limit = (n < u128::BITS as usize).then(|| 1u128 << n);
loop {
out.push(c);
let u = c & c.wrapping_neg();
let v = c.checked_add(u);
match v {
Some(v) if v != 0 => {
let next = v + (((v ^ c) / u) >> 2);
if limit.is_some_and(|lim| next >= lim) {
break;
}
c = next;
}
_ => break,
}
}
out
}
pub fn bits(mask: u128) -> Vec<usize> {
let mut v = Vec::new();
let mut m = mask;
while m != 0 {
let i = m.trailing_zeros() as usize;
v.push(i);
m &= m - 1;
}
v
}
pub fn grade(mask: u128) -> usize {
mask.count_ones() as usize
}
pub(super) fn wedge_sign<S: Scalar>(a: u128, b: u128) -> S {
let mut swaps = 0usize;
let mut aa = a;
while aa != 0 {
let i = aa.trailing_zeros() as usize;
aa &= aa - 1;
let below = b & ((1u128 << i) - 1);
swaps += below.count_ones() as usize;
}
if swaps & 1 == 0 {
S::one()
} else {
S::one().neg()
}
}