chiark / gitweb /
First attempt at making the example program work
authorSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 08:54:12 +0000 (09:54 +0100)
committerSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 08:54:12 +0000 (09:54 +0100)
examples/a382121.rs
src/lib.rs

index a5e602f538a8c8ec7022267bb3c6b0b3bb3b603c..da22eb158e0f435916c144479a12c288bcd0c42d 100644 (file)
@@ -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<usize> {
+    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<u64>);
+
+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));
 }
index bc692dc1f8f71faa90e5998ce3e2ef53bd98e965..ed6ff493ba1a4ebeeaf1de478e958fc42478b53f 100644 (file)
@@ -1,3 +1,4 @@
 mod finitenimber;
 
+pub use finitenimber::Word;
 pub use finitenimber::FiniteNimber;