chalk 0.1.1

A computational algebra library
Documentation
use crate as chalk;
use crate::chalk;
use crate::AddIdentity;
use crate::Binary;
use crate::MulIdentity;

#[derive(Copy, Clone, Default, Eq, PartialEq)]
#[chalk(
  |> Ring
)]
pub struct ZMod<const N: usize>(usize);

impl<const N: usize> Binary for ZMod<N> {
  type Rhs = Self;
  fn into_rhs(&self) -> &Self {
    self
  }
}

impl<const N: usize> From<usize> for ZMod<N> {
  fn from(n: usize) -> ZMod<N> {
    ZMod(n)
  }
}

impl<const N: usize> ZMod<N> {
  fn reduce(&mut self) {
    match const { Algorithm::choose(N, 0) } {
      Algorithm::Add(exponent, power) => {
        if self.0 >= power {
          self.0 = (self.0 >> exponent) + (self.0 & (power - 1))
        }
      }
      Algorithm::Mod => {
        self.0 %= N;
      }
    }
  }
}

enum Algorithm {
  Add(usize, usize),
  Mod,
}

impl Algorithm {
  const fn choose(n: usize, i: usize) -> Algorithm {
    if i == 32 {
      Algorithm::Mod
    } else if (1 << i) % n == 1 {
      Algorithm::Add(i, 1 << i)
    } else {
      Algorithm::choose(n, i + 1)
    }
  }
}

impl<'a, const N: usize> std::ops::AddAssign<&'a ZMod<N>> for ZMod<N> {
  fn add_assign(&mut self, ZMod(rhs): &'a ZMod<N>) {
    self.0 += rhs;
    self.reduce()
  }
}

impl<'a, const N: usize> std::ops::SubAssign<&'a ZMod<N>> for ZMod<N> {
  fn sub_assign(&mut self, ZMod(rhs): &'a ZMod<N>) {
    self.0 += N - rhs;
    self.reduce()
  }
}

impl<'a, const N: usize> std::ops::MulAssign<&'a ZMod<N>> for ZMod<N> {
  fn mul_assign(&mut self, ZMod(rhs): &'a ZMod<N>) {
    self.0 *= rhs;
    self.reduce()
  }
}

impl<const N: usize> AddIdentity for ZMod<N> {
  fn add_id() -> ZMod<N> {
    Default::default()
  }
}

impl<const N: usize> MulIdentity for ZMod<N> {
  fn mul_id() -> ZMod<N> {
    ZMod(1)
  }
}