-use std::fmt::Debug;
-use std::ops::BitXor;
+use std::ops::Add;
-pub trait FiniteNimberBase:
- BitXor<Output = Self::Owned> + Eq + Debug + Sized
-{
- type Cheap<'a>: FiniteNimberBase where Self: 'a;
- type Owned: FiniteNimberBase + Clone;
+type Word = u64; // element type of the vectors we use
+const WORDLEVELS: usize = 6; // 2^{2^6} = 64 = size of Word
- fn to_cheap<'a>(&'a self) -> Self::Cheap<'a>;
- fn to_owned(self) -> Self::Owned;
-}
-
-impl FiniteNimberBase for u64 {
- type Cheap<'a> = Self where Self: 'a;
- type Owned = Self;
-
- fn to_cheap<'a>(&'a self) -> Self::Cheap<'a> {
- *self
- }
-
- fn to_owned(self) -> Self::Owned {
- self
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct IntVector(pub Vec<u64>);
-
-#[derive(PartialEq, Eq, Debug)]
-pub struct IntSlice<'a>(pub &'a [u64]);
-
-impl BitXor for IntVector {
- type Output = Self;
-
- fn bitxor(self, other: Self) -> Self {
- Self(
- self.0
- .into_iter()
- .zip(other.0.into_iter())
- .map(|(a, b)| a ^ b)
- .collect(),
- )
- }
-}
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub struct FiniteNimber(Vec<Word>);
-impl BitXor for IntSlice<'_> {
- type Output = IntVector;
-
- fn bitxor(self, other: Self) -> IntVector {
- IntVector(
+impl Add<&FiniteNimber> for &FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: &FiniteNimber) -> FiniteNimber {
+ FiniteNimber(
self.0
.iter()
.zip(other.0.iter())
}
}
-impl FiniteNimberBase for IntVector {
- type Cheap<'a> = IntSlice<'a> where Self: 'a;
- type Owned = IntVector;
-
- fn to_cheap<'a>(&'a self) -> Self::Cheap<'a> {
- IntSlice(&self.0)
+impl Add<&FiniteNimber> for FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: &FiniteNimber) -> FiniteNimber {
+ (&self) + other
}
+}
- fn to_owned(self) -> Self::Owned {
- self
+impl Add<FiniteNimber> for &FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: FiniteNimber) -> FiniteNimber {
+ self + (&other)
}
}
-impl<'a> FiniteNimberBase for IntSlice<'a> {
- type Cheap<'b> = IntSlice<'b> where Self: 'b;
- type Owned = IntVector;
-
- fn to_cheap<'b>(&'b self) -> Self::Cheap<'b> {
- IntSlice(self.0)
+impl Add<FiniteNimber> for FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: FiniteNimber) -> FiniteNimber {
+ (&self) + (&other)
}
+}
- fn to_owned(self) -> Self::Owned {
- IntVector(self.0.into())
+impl From<Word> for FiniteNimber {
+ fn from(val: Word) -> FiniteNimber {
+ FiniteNimber(vec![val])
}
}
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FiniteNimber<T: FiniteNimberBase> {
- n: T,
+#[derive(Clone, Copy, Debug)]
+pub enum FiniteNimberRef<'a> {
+ OneWord(Word),
+ Slice(&'a [Word]),
}
+use FiniteNimberRef::*;
-impl<T: FiniteNimberBase> FiniteNimber<T> {
- pub fn new(n: T) -> Self {
- Self { n }
+impl<'a> FiniteNimberRef<'a> {
+ fn zero() -> Self {
+ OneWord(0)
}
-}
-impl<T: FiniteNimberBase> std::ops::Add<FiniteNimber<T>> for FiniteNimber<T> {
- type Output = FiniteNimber<T::Owned>;
+ fn low_word(self) -> Word {
+ match self {
+ OneWord(v) => v,
+ Slice(s) => {
+ *(s.first().expect("FiniteNimberRef::Slice is never empty"))
+ }
+ }
+ }
+
+ fn as_slice<'b, 'c>(&'b self) -> &'c [Word]
+ where
+ 'a: 'c,
+ 'b: 'c,
+ {
+ match self {
+ OneWord(v) => std::slice::from_ref(v),
+ Slice(s) => s,
+ }
+ }
- fn add(self, other: Self) -> Self::Output {
- Self::Output::new(self.n ^ other.n)
+ fn split(
+ self,
+ level: usize,
+ ) -> (FiniteNimberRef<'a>, FiniteNimberRef<'a>) {
+ match level.checked_sub(WORDLEVELS) {
+ None => {
+ // If level < WORDLEVELS then we can cast to Word any old way
+ let bits = 1 << (level as Word);
+ let mask = bits - 1;
+ let v = self.low_word();
+ return (OneWord(v & mask), OneWord((v >> bits) & mask));
+ }
+ Some(wordlevel) => match self {
+ OneWord(v) => (OneWord(v), Self::zero()),
+ Slice(s) => {
+ match wordlevel
+ .try_into()
+ .ok()
+ .and_then(|w| 1usize.checked_shl(w))
+ {
+ Some(words) => {
+ let mut iter = s.chunks(words);
+ let lo = iter.next().expect(
+ "FiniteNimberRef::Slice is never empty",
+ );
+ match iter.next() {
+ Some(hi) => (Slice(lo), Slice(hi)),
+ None => (Slice(lo), Self::zero()),
+ }
+ }
+ None => (self.clone(), Self::zero()),
+ }
+ }
+ },
+ }
}
}
mod finitenimber;
pub use finitenimber::FiniteNimber;
-pub use finitenimber::IntSlice;
-pub use finitenimber::IntVector;
#[cfg(test)]
mod tests {
#[test]
fn addition() {
- let a = FiniteNimber::new(0b1100u64);
- let b = FiniteNimber::new(0b1010u64);
- assert_eq!(a + b, FiniteNimber::new(0b0110u64));
-
- let a = FiniteNimber::new(IntVector(vec![1, 1, 0, 0]));
- let b = FiniteNimber::new(IntVector(vec![1, 0, 1, 0]));
- assert_eq!(a + b, FiniteNimber::new(IntVector(vec![0, 1, 1, 0])));
-
- let a = FiniteNimber::new(IntSlice(&[1, 1, 0, 0]));
- let b = FiniteNimber::new(IntSlice(&[1, 0, 1, 0]));
- assert_eq!(a + b, FiniteNimber::new(IntVector(vec![0, 1, 1, 0])));
+ let a = FiniteNimber::from(0b1100);
+ let b = FiniteNimber::from(0b1010);
+ assert_eq!(a + b, FiniteNimber::from(0b0110));
}
}