+use core::fmt::{Debug, Formatter};
use core::ops::Add;
type Word = u64; // element type of the vectors we use
const WORDLEVELS: usize = 6; // 2^{2^6} = 64 = size of Word
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct FiniteNimber(Vec<Word>);
-impl Add<&FiniteNimber> for &FiniteNimber {
- type Output = FiniteNimber;
- fn add(self, other: &FiniteNimber) -> FiniteNimber {
- FiniteNimber(
- self.0
- .iter()
- .zip(other.0.iter())
- .map(|(a, b)| a ^ b)
- .collect(),
- )
- }
-}
-
-impl Add<&FiniteNimber> for FiniteNimber {
- type Output = FiniteNimber;
- fn add(self, other: &FiniteNimber) -> FiniteNimber {
- (&self) + other
- }
-}
-
-impl Add<FiniteNimber> for &FiniteNimber {
- type Output = FiniteNimber;
- fn add(self, other: FiniteNimber) -> FiniteNimber {
- self + (&other)
- }
+#[derive(Clone, Copy)]
+pub enum FiniteNimberRef<'a> {
+ OneWord(Word),
+ Slice(&'a [Word]),
}
+use FiniteNimberRef::*;
-impl Add<FiniteNimber> for FiniteNimber {
- type Output = FiniteNimber;
- fn add(self, other: FiniteNimber) -> FiniteNimber {
- (&self) + (&other)
+impl Debug for FiniteNimber {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
+ write!(f, "FiniteNimber[")?;
+ let mut sep: &str = "";
+ for v in &self.0 {
+ write!(f, "{}0x{:016x}", sep, v)?;
+ sep = ", ";
+ }
+ write!(f, "]")
}
}
-impl From<Word> for FiniteNimber {
- fn from(val: Word) -> FiniteNimber {
- FiniteNimber(vec![val])
+impl Debug for FiniteNimberRef<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
+ match self {
+ OneWord(v) => write!(f, "FiniteNimberRef::OneWord(0x{:16x})", v),
+ Slice(s) => {
+ write!(f, "FiniteNimberRef::Slice[")?;
+ let mut sep: &str = "";
+ for v in *s {
+ write!(f, "{}0x{:016x}", sep, v)?;
+ sep = ", ";
+ }
+ write!(f, "]")
+ }
+ }
}
}
-#[derive(Clone, Copy, Debug)]
-pub enum FiniteNimberRef<'a> {
- OneWord(Word),
- Slice(&'a [Word]),
-}
-use FiniteNimberRef::*;
-
impl<'a> FiniteNimberRef<'a> {
fn zero() -> Self {
OneWord(0)
None => {
// If level < WORDLEVELS then we can cast to Word any old way
let bits = 1 << (level as Word);
- let mask = bits - 1;
+ let mask = (1 << bits) - 1;
let v = self.low_word();
return (OneWord(v & mask), OneWord((v >> bits) & mask));
}
None => {
// If level < WORDLEVELS then we can cast to Word any old way
let bits = 1 << (level as Word);
- let mask = bits - 1;
+ let mask = (1 << bits) - 1;
let vlo = self.low_word();
let vhi = hi.low_word();
((vlo & mask) | ((vhi & mask) << bits)).into()
}
}
+impl FiniteNimber {
+ fn to_ref(&self) -> FiniteNimberRef {
+ match self.0.len() {
+ 0 => FiniteNimberRef::zero(),
+ _ => Slice(&self.0),
+ }
+ }
+}
+
impl<'a> From<&'a FiniteNimber> for FiniteNimberRef<'a> {
fn from(n: &'a FiniteNimber) -> Self {
- match n.0.len() {
- 0 => Self::zero(),
- _ => Slice(&n.0),
+ n.to_ref()
+ }
+}
+
+impl From<FiniteNimberRef<'_>> for FiniteNimber {
+ fn from(n: FiniteNimberRef) -> Self {
+ FiniteNimber(n.as_slice().into())
+ }
+}
+
+impl From<Word> for FiniteNimber {
+ fn from(val: Word) -> FiniteNimber {
+ FiniteNimber(vec![val])
+ }
+}
+
+impl<'a, 'b> Add<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
+ type Output = FiniteNimber;
+ fn add(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
+ FiniteNimber(
+ self.as_slice()
+ .iter()
+ .zip(other.as_slice().iter())
+ .map(|(a, b)| a ^ b)
+ .collect(),
+ )
+ }
+}
+
+impl Add<&FiniteNimber> for FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: &FiniteNimber) -> FiniteNimber {
+ let aref: FiniteNimberRef = (&self).into();
+ let bref: FiniteNimberRef = other.into();
+ aref + bref
+ }
+}
+
+impl Add<FiniteNimber> for &FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: FiniteNimber) -> FiniteNimber {
+ let aref: FiniteNimberRef = self.into();
+ let bref: FiniteNimberRef = (&other).into();
+ aref + bref
+ }
+}
+
+impl Add<FiniteNimber> for FiniteNimber {
+ type Output = FiniteNimber;
+ fn add(self, other: FiniteNimber) -> FiniteNimber {
+ let aref: FiniteNimberRef = (&self).into();
+ let bref: FiniteNimberRef = (&other).into();
+ aref + bref
+ }
+}
+
+impl<'a> FiniteNimberRef<'a> {
+ fn mul_by_h(self, level: usize) -> FiniteNimber {
+ match level.checked_sub(1) {
+ Some(sublevel) => {
+ let (lo, hi) = self.split(sublevel);
+ hi.mul_by_h(sublevel)
+ .to_ref()
+ .mul_by_h(sublevel)
+ .to_ref()
+ .join(
+ (lo + hi).to_ref().mul_by_h(sublevel).to_ref(),
+ sublevel,
+ )
+ }
+
+ // At level 0, h = 1, so multiplying by h is a no-op.
+ None => self.into(),
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn split() {
+ let a = FiniteNimber(vec![
+ 0x8786858483828180,
+ 0x9796959493929190,
+ 0xa7a6a5a4a3a2a1a0,
+ 0xb7b6b5b4b3b2b1b0,
+ 0xc7c6c5c4c3c2c1c0,
+ 0xd7d6d5d4d3d2d1d0,
+ ]);
+
+ let (loref, hiref) = a.to_ref().split(4);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![0x8180]));
+ assert_eq!(hi, FiniteNimber(vec![0x8382]));
+
+ let (loref, hiref) = a.to_ref().split(5);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![0x83828180]));
+ assert_eq!(hi, FiniteNimber(vec![0x87868584]));
+
+ let (loref, hiref) = a.to_ref().split(6);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![0x8786858483828180]));
+ assert_eq!(hi, FiniteNimber(vec![0x9796959493929190]));
+
+ let (loref, hiref) = a.to_ref().split(7);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(
+ lo,
+ FiniteNimber(vec![0x8786858483828180, 0x9796959493929190])
+ );
+ assert_eq!(
+ hi,
+ FiniteNimber(vec![0xa7a6a5a4a3a2a1a0, 0xb7b6b5b4b3b2b1b0,])
+ );
+
+ let (loref, hiref) = a.to_ref().split(8);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(
+ lo,
+ FiniteNimber(vec![
+ 0x8786858483828180,
+ 0x9796959493929190,
+ 0xa7a6a5a4a3a2a1a0,
+ 0xb7b6b5b4b3b2b1b0
+ ])
+ );
+ assert_eq!(
+ hi,
+ FiniteNimber(vec![0xc7c6c5c4c3c2c1c0, 0xd7d6d5d4d3d2d1d0])
+ );
+
+ let (loref, hiref) = a.to_ref().split(9);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(
+ lo,
+ FiniteNimber(vec![
+ 0x8786858483828180,
+ 0x9796959493929190,
+ 0xa7a6a5a4a3a2a1a0,
+ 0xb7b6b5b4b3b2b1b0,
+ 0xc7c6c5c4c3c2c1c0,
+ 0xd7d6d5d4d3d2d1d0
+ ])
+ );
+ assert_eq!(hi, FiniteNimber(vec![0]));
+
+ let a = FiniteNimber(vec![0xFF]);
+
+ let (loref, hiref) = a.to_ref().split(0);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![1]));
+ assert_eq!(hi, FiniteNimber(vec![1]));
+
+ let (loref, hiref) = a.to_ref().split(1);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![3]));
+ assert_eq!(hi, FiniteNimber(vec![3]));
+
+ let (loref, hiref) = a.to_ref().split(2);
+ let lo: FiniteNimber = loref.into();
+ let hi: FiniteNimber = hiref.into();
+ assert_eq!(lo, FiniteNimber(vec![0xf]));
+ assert_eq!(hi, FiniteNimber(vec![0xf]));
+ }
+
+ #[test]
+ fn join() {
+ let a = FiniteNimber::from(0x5);
+ let b = FiniteNimber::from(0xa);
+ assert_eq!(a.to_ref().join(b.to_ref(), 0), FiniteNimber::from(0b01));
+ assert_eq!(b.to_ref().join(a.to_ref(), 0), FiniteNimber::from(0b10));
+ assert_eq!(a.to_ref().join(b.to_ref(), 1), FiniteNimber::from(0b1001));
+ assert_eq!(b.to_ref().join(a.to_ref(), 1), FiniteNimber::from(0b0110));
+ assert_eq!(a.to_ref().join(b.to_ref(), 2), FiniteNimber::from(0xa5));
+ assert_eq!(b.to_ref().join(a.to_ref(), 2), FiniteNimber::from(0x5a));
+ assert_eq!(
+ a.to_ref().join(b.to_ref(), 5),
+ FiniteNimber::from(0xa00000005)
+ );
+ assert_eq!(
+ a.to_ref().join(b.to_ref(), 6),
+ FiniteNimber(vec![0x5, 0xa])
+ );
+ assert_eq!(
+ a.to_ref().join(b.to_ref(), 8),
+ FiniteNimber(vec![0x5, 0, 0, 0, 0xa])
+ );
+ }
+
+ #[test]
+ fn addition() {
+ let a = FiniteNimber::from(0b1100);
+ let b = FiniteNimber::from(0b1010);
+ assert_eq!(a + b, FiniteNimber::from(0b0110));
+
+ let a = FiniteNimber(vec![1, 1, 0, 0]);
+ let b = FiniteNimber(vec![1, 0, 1, 0]);
+ assert_eq!(a + b, FiniteNimber(vec![0, 1, 1, 0]));
+ }
+
+ #[test]
+ fn mul_by_h() {
+ let a = FiniteNimber::from(1);
+ assert_eq!(a.to_ref().mul_by_h(0), FiniteNimber::from(1));
+ assert_eq!(a.to_ref().mul_by_h(1), FiniteNimber::from(2));
+ assert_eq!(a.to_ref().mul_by_h(2), FiniteNimber::from(8));
+ assert_eq!(a.to_ref().mul_by_h(3), FiniteNimber::from(128));
+ assert_eq!(
+ a.to_ref().mul_by_h(8),
+ FiniteNimber(vec![0, 0, 0, 0x8000000000000000])
+ );
+
+ assert_eq!(
+ a.to_ref().mul_by_h(3).to_ref().mul_by_h(3),
+ FiniteNimber::from(0xde)
+ );
+ assert_eq!(
+ a.to_ref().mul_by_h(8).to_ref().mul_by_h(8),
+ FiniteNimber(vec![
+ 0xa92181714b010a1a,
+ 0x4a88a921e2208b6b,
+ 0xe3a92850a9218171,
+ 0xde4ae3a94a88a921
+ ])
+ );
+ }
+}