use core::cmp::Ordering;
use core::fmt;
use alloc::rc::Rc;
use crate::int::Int;
use crate::nat::{Nat, Reciprocal};
struct Ring {
modulus: Nat,
recip: Reciprocal,
}
#[derive(Clone)]
pub struct ModInt {
value: Nat,
ring: Rc<Ring>,
}
impl ModInt {
pub fn new(value: Int, modulus: Int) -> ModInt {
assert!(modulus > Int::ONE, "ModInt: modulus must be >= 2");
let m = modulus.magnitude();
let ring = Rc::new(Ring {
recip: Reciprocal::new(&m),
modulus: m,
});
let residue = value.rem_euclid(&modulus).magnitude();
ModInt {
value: residue,
ring,
}
}
pub fn of(&self, value: Int) -> ModInt {
let residue = value
.rem_euclid(&Int::from(self.ring.modulus.clone()))
.magnitude();
ModInt {
value: residue,
ring: self.ring.clone(),
}
}
#[inline]
pub fn residue(&self) -> &Nat {
&self.value
}
#[inline]
pub fn to_int(&self) -> Int {
Int::from(self.value.clone())
}
#[inline]
pub fn modulus(&self) -> Int {
Int::from(self.ring.modulus.clone())
}
#[inline]
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
fn same_ring(&self, other: &ModInt) {
debug_assert!(
Rc::ptr_eq(&self.ring, &other.ring) || self.ring.modulus == other.ring.modulus,
"ModInt: operands have different moduli"
);
}
fn wrap(&self, value: Nat) -> ModInt {
ModInt {
value,
ring: self.ring.clone(),
}
}
pub fn add(&self, rhs: &ModInt) -> ModInt {
self.same_ring(rhs);
let s = self.value.add(&rhs.value);
let m = &self.ring.modulus;
let v = if s.cmp(m) != Ordering::Less {
s.checked_sub(m).unwrap()
} else {
s
};
self.wrap(v)
}
pub fn sub(&self, rhs: &ModInt) -> ModInt {
self.same_ring(rhs);
let m = &self.ring.modulus;
let v = if self.value.cmp(&rhs.value) != Ordering::Less {
self.value.checked_sub(&rhs.value).unwrap()
} else {
self.value.add(m).checked_sub(&rhs.value).unwrap()
};
self.wrap(v)
}
pub fn mul(&self, rhs: &ModInt) -> ModInt {
self.same_ring(rhs);
self.wrap(self.ring.recip.reduce(&self.value.mul(&rhs.value)))
}
pub fn neg(&self) -> ModInt {
if self.value.is_zero() {
self.clone()
} else {
self.wrap(self.ring.modulus.checked_sub(&self.value).unwrap())
}
}
pub fn inv(&self) -> Option<ModInt> {
let inv = self.to_int().modinv(&self.modulus())?;
Some(self.wrap(inv.magnitude()))
}
pub fn div(&self, rhs: &ModInt) -> ModInt {
self.mul(&rhs.inv().expect("ModInt::div: divisor is not invertible"))
}
pub fn pow(&self, exp: &Int) -> ModInt {
if exp.is_negative() {
return self
.inv()
.expect("ModInt::pow: base not invertible for a negative exponent")
.pow(&exp.abs());
}
self.wrap(self.value.modpow(&exp.magnitude(), &self.ring.modulus))
}
}
impl PartialEq for ModInt {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.ring.modulus == other.ring.modulus
}
}
impl Eq for ModInt {}
impl fmt::Display for ModInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
impl fmt::Debug for ModInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ModInt({} mod {})", self.value, self.ring.modulus)
}
}
macro_rules! mod_binop {
($tr:ident, $m:ident, $atr:ident, $am:ident) => {
impl core::ops::$tr for ModInt {
type Output = ModInt;
#[inline]
fn $m(self, rhs: ModInt) -> ModInt {
ModInt::$m(&self, &rhs)
}
}
impl core::ops::$tr<&ModInt> for &ModInt {
type Output = ModInt;
#[inline]
fn $m(self, rhs: &ModInt) -> ModInt {
ModInt::$m(self, rhs)
}
}
impl core::ops::$atr for ModInt {
#[inline]
fn $am(&mut self, rhs: ModInt) {
*self = ModInt::$m(self, &rhs);
}
}
};
}
mod_binop!(Add, add, AddAssign, add_assign);
mod_binop!(Sub, sub, SubAssign, sub_assign);
mod_binop!(Mul, mul, MulAssign, mul_assign);
mod_binop!(Div, div, DivAssign, div_assign);
impl core::ops::Neg for ModInt {
type Output = ModInt;
#[inline]
fn neg(self) -> ModInt {
ModInt::neg(&self)
}
}