use itertools::Itertools;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::ops::AddAssign;
use nimber::FiniteNimber;
fn lowest_set_bit(n: &FiniteNimber) -> Option<usize> {
for (i, word) in n.as_slice().iter().cloned().enumerate() {
if word != 0 {
let tz: usize = word.trailing_zeros().try_into().expect(
"a number of leading zeros can't be too big to fit in a usize",
);
return Some(i * 64 + tz);
}
}
None
}
#[derive(Clone, Debug)]
struct Polynomial(Vec<u64>);
impl Polynomial {
fn monomial(index: usize) -> Self {
Self(
std::iter::repeat(0)
.take(index / 64)
.chain([1u64 << (index % 64)].iter().cloned())
.collect(),
)
}
}
impl AddAssign<&Polynomial> for Polynomial {
fn add_assign(&mut self, other: &Polynomial) {
self.0 = self
.0
.iter()
.cloned()
.zip_longest(other.0.iter().cloned())
.map(|pair| pair.reduce(|a, b| a ^ b))
.collect();
}
}
impl Display for Polynomial {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(f, "0x")?;
let mut started = false;
for v in self.0.iter().rev() {
if started {
write!(f, "{:016x}", v)?;
} else if *v != 0 {
write!(f, "{:x}", v)?;
started = true;
}
}
if !started {
write!(f, "0")?;
}
Ok(())
}
}
fn minimal_polynomial(n: &FiniteNimber) -> Polynomial {
let mut map = HashMap::new();
let mut exp = 0;
let mut power = FiniteNimber::from(1);
loop {
let mut comb = Polynomial::monomial(exp);
let mut val = power.clone();
loop {
let bit = match lowest_set_bit(&val) {
Some(bit) => bit,
None => return comb,
};
match map.entry(bit) {
Entry::Occupied(e) => {
let e: &(FiniteNimber, Polynomial) = e.get();
val += &e.0;
comb += &e.1;
}
Entry::Vacant(e) => {
e.insert((val.clone(), comb));
break;
}
}
}
power *= n;
exp += 1;
}
}
fn largest_nimber_in_subfield(level: usize) -> FiniteNimber {
match level.checked_sub(6) {
None => FiniteNimber::from((1 << (1 << level)) - 1),
Some(wordlevel) => {
let words = 1 << wordlevel;
let v: Vec<_> =
std::iter::repeat(0xffffffffffffffff).take(words).collect();
FiniteNimber::from(v)
}
}
}
fn main() {
println!("Min poly of nimbers up to 2^8:");
for n in (0..256).map(FiniteNimber::from) {
println!("{} has minimal polynomial {}", &n, minimal_polynomial(&n));
}
println!();
println!("Min poly of largest nimber in each subfield (https://oeis.org/A382121):");
for level in 0..13 {
let n = largest_nimber_in_subfield(level);
println!(
"level {}: *(2^{}-1) = {} has minimal polynomial {}",
level,
1 << level,
&n,
minimal_polynomial(&n)
);
}
}