From: Simon Tatham Date: Sat, 12 Apr 2025 08:54:12 +0000 (+0100) Subject: First attempt at making the example program work X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=5949ae5e53c1cafce6dfc93b767b4fcd4b2676dd;p=nimber.git First attempt at making the example program work --- diff --git a/examples/a382121.rs b/examples/a382121.rs index a5e602f..da22eb1 100644 --- a/examples/a382121.rs +++ b/examples/a382121.rs @@ -1,6 +1,106 @@ +use itertools::Itertools; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::ops::Add; + use nimber::FiniteNimber; +fn lowest_set_bit(n: &FiniteNimber) -> Option { + let words: &[nimber::Word] = n.borrow(); + + for (i, word) in words.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); + +impl Polynomial { + fn monomial(index: usize) -> Self { + Self( + std::iter::repeat(0) + .take(index / 64) + .chain([1u64 << (index % 64)].iter().cloned()) + .collect(), + ) + } +} + +impl Add<&Polynomial> for Polynomial { + type Output = Polynomial; + + fn add(self, other: &Polynomial) -> Self { + Self( + self.0 + .into_iter() + .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 { + // Maps (lowest set bit) -> (nimber, combination of powers it's made of) + let mut map = HashMap::new(); + + let mut exp = 0; + let mut val = FiniteNimber::from(1); + + loop { + let mut comb = Polynomial::monomial(exp); + 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 = val + &e.0; + comb = comb + &e.1; + } + Entry::Vacant(e) => { + e.insert((val.clone(), comb)); + break; + } + } + } + val = val * n; + exp += 1; + } +} + fn main() { - let n = FiniteNimber::from(1234); - println!("{}", n); + let n = FiniteNimber::from(0xff); + println!("{} -> {}", &n, minimal_polynomial(&n)); } diff --git a/src/lib.rs b/src/lib.rs index bc692dc..ed6ff49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ mod finitenimber; +pub use finitenimber::Word; pub use finitenimber::FiniteNimber;