pub const MAX_BASIS_DIM: usize = 128;
pub(crate) fn grade_k_masks(n: usize, k: usize) -> impl Iterator<Item = u128> {
let mut current = if k == 0 {
Some(0)
} else if k > n {
None
} else {
assert!(n <= u128::BITS as usize, "basis masks fit in u128");
Some(if k == u128::BITS as usize {
u128::MAX
} else {
(1u128 << k) - 1
})
};
let limit = (n < u128::BITS as usize).then(|| 1u128 << n);
std::iter::from_fn(move || {
let c = current?;
if c == 0 {
current = None;
return Some(c);
}
let u = c & c.wrapping_neg();
let v = c.checked_add(u);
current = match v {
Some(v) if v != 0 => {
let next = v + (((v ^ c) / u) >> 2);
if limit.is_some_and(|lim| next >= lim) {
None
} else {
Some(next)
}
}
_ => None,
};
Some(c)
})
}
pub(crate) fn bit_indices(mut mask: u128) -> impl Iterator<Item = usize> {
std::iter::from_fn(move || {
if mask == 0 {
return None;
}
let index = mask.trailing_zeros() as usize;
mask &= mask - 1;
Some(index)
})
}
pub fn bits(mask: u128) -> Vec<usize> {
bit_indices(mask).collect()
}
pub fn grade(mask: u128) -> usize {
mask.count_ones() as usize
}
pub(super) fn wedge_is_negative(a: u128, b: u128) -> bool {
let mut prefix_parity = b;
prefix_parity ^= prefix_parity << 1;
prefix_parity ^= prefix_parity << 2;
prefix_parity ^= prefix_parity << 4;
prefix_parity ^= prefix_parity << 8;
prefix_parity ^= prefix_parity << 16;
prefix_parity ^= prefix_parity << 32;
prefix_parity ^= prefix_parity << 64;
(a & (prefix_parity << 1)).count_ones() & 1 == 1
}