use crate::{
polynomial::{DivisorIsOne, PolynomialCoefficient, PolynomialReducingFactorSupported},
traits::{
AlwaysExactDiv, AlwaysExactDivAssign, ExactDiv, ExactDivAssign, ExtendedGCD,
ExtendedGCDResult, GCD,
},
util::BaseAndExponent,
};
use num_bigint::{BigInt, BigUint};
use num_integer::Integer;
use num_traits::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, One, ToPrimitive, Zero,
};
use std::{
borrow::{Borrow, Cow},
convert::{identity, TryInto},
fmt,
hash::Hash,
ops::{Add, AddAssign, Deref, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
pub trait ModularReduce: Clone + Eq {
fn modular_reduce_assign<M: Modulus<Self>>(&mut self, modulus: M);
#[inline]
fn modular_reduce<M: Modulus<Self>>(mut self, modulus: M) -> Self {
self.modular_reduce_assign(modulus);
self
}
fn modular_add_ref_assign<M: Modulus<Self>>(&mut self, rhs: &Self, modulus: M);
#[inline]
fn modular_add_move_assign<M: Modulus<Self>>(&mut self, rhs: Self, modulus: M) {
self.modular_add_ref_assign(&rhs, modulus);
}
#[inline]
fn modular_add_ref_ref<M: Modulus<Self>>(&self, rhs: &Self, modulus: M) -> Self {
self.clone().modular_add_move_ref(rhs, modulus)
}
#[inline]
fn modular_add_move_ref<M: Modulus<Self>>(mut self, rhs: &Self, modulus: M) -> Self {
self.modular_add_ref_assign(rhs, modulus);
self
}
#[inline]
fn modular_add_ref_move<M: Modulus<Self>>(&self, rhs: Self, modulus: M) -> Self {
self.clone().modular_add_move_move(rhs, modulus)
}
#[inline]
fn modular_add_move_move<M: Modulus<Self>>(mut self, rhs: Self, modulus: M) -> Self {
self.modular_add_move_assign(rhs, modulus);
self
}
fn modular_neg_assign<M: Modulus<Self>>(&mut self, modulus: M);
#[inline]
fn modular_neg_ref<M: Modulus<Self>>(&self, modulus: M) -> Self {
self.clone().modular_neg_move(modulus)
}
#[inline]
fn modular_neg_move<M: Modulus<Self>>(mut self, modulus: M) -> Self {
self.modular_neg_assign(modulus);
self
}
#[inline]
fn modular_sub_ref_assign<M: Modulus<Self>>(&mut self, rhs: &Self, modulus: M) {
self.modular_add_move_assign(rhs.modular_neg_ref(&modulus), modulus);
}
#[inline]
fn modular_sub_move_assign<M: Modulus<Self>>(&mut self, rhs: Self, modulus: M) {
self.modular_sub_ref_assign(&rhs, modulus);
}
#[inline]
fn modular_sub_ref_ref<M: Modulus<Self>>(&self, rhs: &Self, modulus: M) -> Self {
self.clone().modular_sub_move_ref(rhs, modulus)
}
#[inline]
fn modular_sub_move_ref<M: Modulus<Self>>(mut self, rhs: &Self, modulus: M) -> Self {
self.modular_sub_ref_assign(rhs, modulus);
self
}
#[inline]
fn modular_sub_ref_move<M: Modulus<Self>>(&self, rhs: Self, modulus: M) -> Self {
self.clone().modular_sub_move_move(rhs, modulus)
}
#[inline]
fn modular_sub_move_move<M: Modulus<Self>>(mut self, rhs: Self, modulus: M) -> Self {
self.modular_sub_move_assign(rhs, modulus);
self
}
fn modular_mul_ref_assign<M: Modulus<Self>>(&mut self, rhs: &Self, modulus: M);
#[inline]
fn modular_mul_move_assign<M: Modulus<Self>>(&mut self, rhs: Self, modulus: M) {
self.modular_mul_ref_assign(&rhs, modulus);
}
#[inline]
fn modular_mul_ref_ref<M: Modulus<Self>>(&self, rhs: &Self, modulus: M) -> Self {
self.clone().modular_mul_move_ref(rhs, modulus)
}
#[inline]
fn modular_mul_move_ref<M: Modulus<Self>>(mut self, rhs: &Self, modulus: M) -> Self {
self.modular_mul_ref_assign(rhs, modulus);
self
}
#[inline]
fn modular_mul_ref_move<M: Modulus<Self>>(&self, rhs: Self, modulus: M) -> Self {
self.clone().modular_mul_move_move(rhs, modulus)
}
#[inline]
fn modular_mul_move_move<M: Modulus<Self>>(mut self, rhs: Self, modulus: M) -> Self {
self.modular_mul_move_assign(rhs, modulus);
self
}
fn modular_reduce_from_bigint<M: Modulus<Self>>(v: &BigInt, modulus: M) -> Self;
#[inline]
fn modular_reduce_from_biguint<M: Modulus<Self>>(v: &BigUint, modulus: M) -> Self {
Self::modular_reduce_from_bigint(&v.clone().into(), modulus)
}
#[inline]
fn modular_reduce_from_u8<M: Modulus<Self>>(v: u8, modulus: M) -> Self {
Self::modular_reduce_from_u16(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_u16<M: Modulus<Self>>(v: u16, modulus: M) -> Self {
Self::modular_reduce_from_u32(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_u32<M: Modulus<Self>>(v: u32, modulus: M) -> Self {
Self::modular_reduce_from_u64(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_u64<M: Modulus<Self>>(v: u64, modulus: M) -> Self {
Self::modular_reduce_from_u128(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_u128<M: Modulus<Self>>(v: u128, modulus: M) -> Self {
Self::modular_reduce_from_biguint(&v.into(), modulus)
}
#[inline]
fn modular_reduce_from_usize<M: Modulus<Self>>(v: usize, modulus: M) -> Self {
Self::modular_reduce_from_u128(v as _, modulus)
}
#[inline]
fn modular_reduce_from_i8<M: Modulus<Self>>(v: i8, modulus: M) -> Self {
Self::modular_reduce_from_i16(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_i16<M: Modulus<Self>>(v: i16, modulus: M) -> Self {
Self::modular_reduce_from_i32(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_i32<M: Modulus<Self>>(v: i32, modulus: M) -> Self {
Self::modular_reduce_from_i64(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_i64<M: Modulus<Self>>(v: i64, modulus: M) -> Self {
Self::modular_reduce_from_i128(v.into(), modulus)
}
#[inline]
fn modular_reduce_from_i128<M: Modulus<Self>>(v: i128, modulus: M) -> Self {
Self::modular_reduce_from_bigint(&v.into(), modulus)
}
#[inline]
fn modular_reduce_from_isize<M: Modulus<Self>>(v: isize, modulus: M) -> Self {
Self::modular_reduce_from_i128(v as _, modulus)
}
}
pub trait ModularReducePow<E = Self>: ModularReduce {
fn pow_modular_reduce<M: Modulus<Self>>(&self, exponent: &E, modulus: M) -> Self;
}
pub trait Modulus<Value: Clone + Eq>: Clone + Eq {
fn to_modulus(&self) -> Cow<Value>;
#[inline]
fn into_modulus(self) -> Value {
self.to_modulus().into_owned()
}
}
impl<T: Modulus<Value>, Value: Clone + Eq> Modulus<Value> for &'_ T {
#[inline]
fn to_modulus(&self) -> Cow<Value> {
(**self).to_modulus()
}
}
pub trait StaticModulus<Value: Clone + Eq>: Modulus<Value> + 'static + Copy + Default {
#[inline]
fn get_modulus() -> Value {
Self::default().into_modulus()
}
}
pub trait PrimePowerModulus<Value: Integer + Clone>: Modulus<Value> {
fn base_and_exponent(&self) -> BaseAndExponent<Value>;
}
pub trait PrimeModulus<Value: Integer + Clone>: PrimePowerModulus<Value> {}
pub trait OddModulus<Value: Integer + Clone>: Modulus<Value> {}
pub trait OddPrimePowerModulus<Value: Integer + Clone>:
PrimePowerModulus<Value> + OddModulus<Value>
{
}
impl<T: PrimePowerModulus<Value> + OddModulus<Value>, Value: Integer + Clone>
OddPrimePowerModulus<Value> for T
{
}
pub trait OddPrimeModulus<Value: Integer + Clone>:
PrimeModulus<Value> + OddPrimePowerModulus<Value>
{
}
impl<T: PrimeModulus<Value> + OddPrimePowerModulus<Value>, Value: Integer + Clone>
OddPrimeModulus<Value> for T
{
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
pub struct KnownPrime<T>(T);
impl<T> KnownPrime<T> {
#[inline]
pub fn new_unsafe(prime: T) -> Self {
KnownPrime(prime)
}
#[inline]
pub fn unwrap(self) -> T {
self.0
}
}
impl<T> Deref for KnownPrime<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.0
}
}
impl<T: Modulus<Value>, Value: Eq + Clone> Modulus<Value> for KnownPrime<T> {
#[inline]
fn to_modulus(&self) -> Cow<Value> {
self.0.to_modulus()
}
#[inline]
fn into_modulus(self) -> Value {
self.0.into_modulus()
}
}
impl<T: Modulus<Value>, Value: Integer + Clone> PrimePowerModulus<Value> for KnownPrime<T> {
#[inline]
fn base_and_exponent(&self) -> BaseAndExponent<Value> {
BaseAndExponent {
base: self.clone().into_modulus(),
exponent: One::one(),
}
}
}
impl<T: Modulus<Value>, Value: Integer + Clone> PrimeModulus<Value> for KnownPrime<T> {}
impl<T: OddModulus<Value>, Value: Integer + Clone> OddModulus<Value> for KnownPrime<T> {}
impl<T: StaticModulus<Value>, Value: Integer + Clone> StaticModulus<Value> for KnownPrime<T> {
#[inline]
fn get_modulus() -> Value {
T::get_modulus()
}
}
impl<T: fmt::Display> fmt::Display for KnownPrime<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
pub type KnownOddPrime<T> = KnownOdd<KnownPrime<T>>;
impl<T> KnownOddPrime<T> {
#[inline]
pub fn new_odd_prime_unsafe(value: T) -> Self {
KnownOdd::new_unsafe(KnownPrime::new_unsafe(value))
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
pub struct KnownOdd<T>(T);
impl<T> KnownOdd<T> {
#[inline]
pub fn new_unsafe(odd: T) -> Self {
KnownOdd(odd)
}
#[inline]
pub fn unwrap(self) -> T {
self.0
}
}
impl<T> Deref for KnownOdd<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.0
}
}
impl<T: Modulus<Value>, Value: Eq + Clone> Modulus<Value> for KnownOdd<T> {
#[inline]
fn to_modulus(&self) -> Cow<Value> {
self.0.to_modulus()
}
#[inline]
fn into_modulus(self) -> Value {
self.0.into_modulus()
}
}
impl<T: PrimePowerModulus<Value>, Value: Integer + Clone> PrimePowerModulus<Value> for KnownOdd<T> {
#[inline]
fn base_and_exponent(&self) -> BaseAndExponent<Value> {
self.0.base_and_exponent()
}
}
impl<T: PrimeModulus<Value>, Value: Integer + Clone> PrimeModulus<Value> for KnownOdd<T> {}
impl<T: Modulus<Value>, Value: Integer + Clone> OddModulus<Value> for KnownOdd<T> {}
impl<T: StaticModulus<Value>, Value: Integer + Clone> StaticModulus<Value> for KnownOdd<T> {
#[inline]
fn get_modulus() -> Value {
T::get_modulus()
}
}
impl<T: fmt::Display> fmt::Display for KnownOdd<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
macro_rules! impl_int_modulus {
($t:ty, $wide:ty, $to_wide:expr, $from_wide:expr, $from_bigint:ident) => {
impl Modulus<Self> for $t {
#[inline]
fn to_modulus(&self) -> Cow<Self> {
Cow::Borrowed(self)
}
#[inline]
fn into_modulus(self) -> Self {
self
}
}
impl ModularReduce for $t {
#[inline]
fn modular_reduce_assign<M: Modulus<Self>>(&mut self, modulus: M) {
let modulus = modulus.to_modulus();
if !modulus.is_zero() {
*self = self.mod_floor(&modulus);
}
}
#[inline]
fn modular_reduce<M: Modulus<Self>>(self, modulus: M) -> Self {
let modulus = modulus.to_modulus();
if !modulus.is_zero() {
self.mod_floor(&modulus)
} else {
self
}
}
#[inline]
fn modular_add_ref_assign<M: Modulus<Self>>(&mut self, rhs: &Self, modulus: M) {
let mut wide = $to_wide(self.clone());
wide += $to_wide(rhs.clone());
wide %= $to_wide(modulus.to_modulus().into_owned());
*self = $from_wide(wide);
}
#[inline]
fn modular_neg_assign<M: Modulus<Self>>(&mut self, modulus: M) {
let modulus = modulus.to_modulus();
*self = &*modulus.to_modulus() - self.clone();
if *self == *modulus {
self.set_zero();
}
}
#[inline]
fn modular_mul_ref_assign<M: Modulus<Self>>(&mut self, rhs: &Self, modulus: M) {
let mut wide = $to_wide(self.clone());
wide *= $to_wide(rhs.clone());
wide %= $to_wide(modulus.to_modulus().into_owned());
*self = $from_wide(wide);
}
#[inline]
fn modular_reduce_from_bigint<M: Modulus<Self>>(v: &BigInt, modulus: M) -> Self {
v.mod_floor(&modulus.into_modulus().into())
.$from_bigint()
.expect(concat!(stringify!($from_bigint), " failed"))
}
}
};
}
macro_rules! impl_prim_int_modulus {
($t:ty, $wide:ty, $to_wide:expr, $from_wide:expr, $from_bigint:ident) => {
impl_int_modulus!($t, $wide, $to_wide, $from_wide, $from_bigint);
impl<E: Integer + Clone + FromPrimitive> ModularReducePow<E> for $t {
fn pow_modular_reduce<M: Modulus<Self>>(&self, exponent: &E, modulus: M) -> Self {
if exponent.is_zero() {
return One::one();
}
let modulus = *modulus.to_modulus();
let mut base = *self;
base.modular_reduce_assign(modulus);
if exponent.is_one() {
return base;
}
let mut exponent = exponent.clone();
let mut retval = None;
loop {
if exponent.is_odd() {
match &mut retval {
None => retval = Some(base.clone()),
Some(retval) => {
retval.modular_mul_move_assign(base, modulus);
}
}
}
exponent = exponent / E::from_u8(2).expect("2 doesn't fit in exponent type");
if exponent.is_zero() {
break;
}
base.modular_mul_move_assign(base, modulus);
}
retval.unwrap_or_else(|| unreachable!())
}
}
};
}
macro_rules! impl_bigint_modulus {
($t:ty, $from_bigint:ident) => {
impl_int_modulus!($t, $t, identity, identity, $from_bigint);
impl<E: Clone + Into<$t>> ModularReducePow<E> for $t {
#[inline]
fn pow_modular_reduce<M: Modulus<Self>>(&self, exponent: &E, modulus: M) -> Self {
self.modpow(&exponent.clone().into(), &modulus.to_modulus())
}
}
};
}
#[inline]
fn convert_to<I: TryInto<O>, O>(v: I) -> O
where
I::Error: fmt::Debug,
{
v.try_into().unwrap()
}
#[inline]
fn convert_to_i128(v: BigInt) -> i128 {
v.to_i128().expect("can't convert to i128")
}
#[inline]
fn convert_to_u128(v: BigUint) -> u128 {
v.to_u128().expect("can't convert to u128")
}
trait BigIntToOptionBigInt: Sized {
#[inline]
fn bigint_to_option_bigint(self) -> Option<Self> {
Some(self)
}
}
impl BigIntToOptionBigInt for BigInt {}
impl_prim_int_modulus!(i8, i16, i16::from, convert_to, to_i8);
impl_prim_int_modulus!(u8, u16, u16::from, convert_to, to_u8);
impl_prim_int_modulus!(i16, i32, i32::from, convert_to, to_i16);
impl_prim_int_modulus!(u16, u32, u32::from, convert_to, to_u16);
impl_prim_int_modulus!(i32, i64, i64::from, convert_to, to_i32);
impl_prim_int_modulus!(u32, u64, u64::from, convert_to, to_u32);
impl_prim_int_modulus!(i64, i128, i128::from, convert_to, to_i64);
impl_prim_int_modulus!(u64, u128, u128::from, convert_to, to_u64);
impl_prim_int_modulus!(i128, BigInt, BigInt::from, convert_to_i128, to_i128);
impl_prim_int_modulus!(u128, BigUint, BigUint::from, convert_to_u128, to_u128);
impl_prim_int_modulus!(isize, i128, convert_to::<isize, i128>, convert_to, to_isize);
impl_prim_int_modulus!(usize, u128, convert_to::<usize, u128>, convert_to, to_usize);
impl_bigint_modulus!(BigInt, bigint_to_option_bigint);
impl_bigint_modulus!(BigUint, to_biguint);
macro_rules! impl_static_modulus {
($n:ident, $v:expr, [$($t:ty),+], []) => {
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
pub struct $n;
impl fmt::Display for $n {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&$v, f)
}
}
$(
impl Modulus<$t> for $n {
#[inline]
fn to_modulus(&self) -> Cow<$t> {
Cow::Owned($n.into_modulus())
}
#[inline]
fn into_modulus(self) -> $t {
<$t>::from_u128($v).expect(concat!("can't convert ", stringify!($v), " to ", stringify!($t)))
}
}
impl StaticModulus<$t> for $n {}
)+
};
($n:ident, $v:expr, [$($t:ty),+], [prime_power($base:expr, $exponent:expr)]) => {
impl_static_modulus!($n, $v, [$($t),+], []);
$(
impl PrimePowerModulus<$t> for $n {
#[inline]
fn base_and_exponent(&self) -> BaseAndExponent<$t> {
BaseAndExponent {
base: <$t>::from_u128($base).expect(concat!("can't convert ", stringify!($v), " to ", stringify!($t))),
exponent: $exponent,
}
}
}
)+
};
($n:ident, $v:expr, [$($t:ty),+], [prime]) => {
impl_static_modulus!($n, $v, [$($t),+], [prime_power($v, 1)]);
$(
impl PrimeModulus<$t> for $n {}
)+
};
($n:ident, $v:expr, [$($t:ty),+], [odd]) => {
impl_static_modulus!($n, $v, [$($t),+], []);
$(
impl OddModulus<$t> for $n {}
)+
};
($n:ident, $v:expr, [$($t:ty),+], [odd, $($opts:tt)*]) => {
impl_static_modulus!($n, $v, [$($t),+], [$($opts)*]);
$(
impl OddModulus<$t> for $n {}
)+
};
($n:ident, $v:expr, .., $opts:tt) => {
impl_static_modulus!($n, $v, [i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, BigInt, BigUint], $opts);
};
}
impl_static_modulus!(Mod1, 1, .., [odd]);
impl_static_modulus!(Mod2, 2, .., [prime]);
impl_static_modulus!(Mod3, 3, .., [odd, prime]);
impl_static_modulus!(Mod4, 4, .., [prime_power(2, 2)]);
impl_static_modulus!(Mod5, 5, .., [odd, prime]);
impl_static_modulus!(Mod6, 6, .., []);
impl_static_modulus!(Mod7, 7, .., [odd, prime]);
impl_static_modulus!(Mod8, 8, .., [prime_power(2, 3)]);
impl_static_modulus!(Mod9, 9, .., [odd, prime_power(3, 2)]);
impl_static_modulus!(Mod10, 10, .., []);
impl_static_modulus!(Mod11, 11, .., [odd, prime]);
impl_static_modulus!(Mod12, 12, .., []);
impl_static_modulus!(Mod13, 13, .., [odd, prime]);
impl_static_modulus!(Mod14, 14, .., []);
impl_static_modulus!(Mod15, 15, .., [odd]);
impl_static_modulus!(Mod16, 16, .., [prime_power(2, 4)]);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct ModularInteger<V, M> {
value: V,
modulus: M,
}
impl<V, M> ModularInteger<V, M> {
pub fn value(&self) -> &V {
&self.value
}
pub fn modulus(&self) -> &M {
&self.modulus
}
}
impl<V: fmt::Display, M: fmt::Display> fmt::Display for ModularInteger<V, M> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "mod_int({}, {})", self.value, self.modulus)
}
}
impl<V, M: PartialEq> ModularInteger<V, M> {
pub fn has_matching_moduli(&self, rhs: &Self) -> bool {
self.modulus == rhs.modulus
}
fn require_matching_moduli(&self, rhs: &Self) {
assert!(self.has_matching_moduli(rhs), "moduli don't match");
}
}
impl<V, M> Into<(V, M)> for ModularInteger<V, M> {
fn into(self) -> (V, M) {
(self.value, self.modulus)
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> ModularInteger<V, M> {
pub fn new(value: V, modulus: M) -> Self {
let value = value.modular_reduce(&modulus);
Self { value, modulus }
}
pub fn neg_assign(&mut self) {
V::modular_neg_assign(&mut self.value, &self.modulus);
}
pub fn from_u8(value: u8, modulus: M) -> Self {
let value = V::modular_reduce_from_u8(value, &modulus);
Self { value, modulus }
}
pub fn from_i8(value: i8, modulus: M) -> Self {
let value = V::modular_reduce_from_i8(value, &modulus);
Self { value, modulus }
}
pub fn from_u16(value: u16, modulus: M) -> Self {
let value = V::modular_reduce_from_u16(value, &modulus);
Self { value, modulus }
}
pub fn from_i16(value: i16, modulus: M) -> Self {
let value = V::modular_reduce_from_i16(value, &modulus);
Self { value, modulus }
}
pub fn from_u32(value: u32, modulus: M) -> Self {
let value = V::modular_reduce_from_u32(value, &modulus);
Self { value, modulus }
}
pub fn from_i32(value: i32, modulus: M) -> Self {
let value = V::modular_reduce_from_i32(value, &modulus);
Self { value, modulus }
}
pub fn from_u64(value: u64, modulus: M) -> Self {
let value = V::modular_reduce_from_u64(value, &modulus);
Self { value, modulus }
}
pub fn from_i64(value: i64, modulus: M) -> Self {
let value = V::modular_reduce_from_i64(value, &modulus);
Self { value, modulus }
}
pub fn from_u128(value: u128, modulus: M) -> Self {
let value = V::modular_reduce_from_u128(value, &modulus);
Self { value, modulus }
}
pub fn from_i128(value: i128, modulus: M) -> Self {
let value = V::modular_reduce_from_i128(value, &modulus);
Self { value, modulus }
}
pub fn from_usize(value: usize, modulus: M) -> Self {
let value = V::modular_reduce_from_usize(value, &modulus);
Self { value, modulus }
}
pub fn from_isize(value: isize, modulus: M) -> Self {
let value = V::modular_reduce_from_isize(value, &modulus);
Self { value, modulus }
}
pub fn from_bigint(value: &BigInt, modulus: M) -> Self {
let value = V::modular_reduce_from_bigint(value, &modulus);
Self { value, modulus }
}
pub fn from_biguint(value: &BigUint, modulus: M) -> Self {
let value = V::modular_reduce_from_biguint(value, &modulus);
Self { value, modulus }
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> From<(V, M)> for ModularInteger<V, M> {
fn from((value, modulus): (V, M)) -> Self {
Self::new(value, modulus)
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> Add for ModularInteger<V, M> {
type Output = ModularInteger<V, M>;
fn add(self, rhs: Self) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_add_move_move(rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> AddAssign for ModularInteger<V, M> {
fn add_assign(&mut self, rhs: Self) {
self.require_matching_moduli(&rhs);
self.value.modular_add_move_assign(rhs.value, &self.modulus);
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> AddAssign<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
fn add_assign(&mut self, rhs: &Self) {
self.require_matching_moduli(&rhs);
self.value.modular_add_ref_assign(&rhs.value, &self.modulus);
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> Add<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn add(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(rhs);
ModularInteger {
value: self.value.modular_add_move_ref(&rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<'l, V: ModularReduce + Eq, M: Modulus<V>> Add<ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn add(self, rhs: ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_add_ref_move(rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<'l, 'r, V: ModularReduce + Eq, M: Modulus<V>> Add<&'r ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn add(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(rhs);
ModularInteger {
value: self.value.modular_add_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> CheckedAdd for ModularInteger<V, M> {
fn checked_add(&self, rhs: &Self) -> Option<Self> {
if !self.has_matching_moduli(rhs) {
return None;
}
Some(ModularInteger {
value: self.value.modular_add_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
})
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> Neg for ModularInteger<V, M> {
type Output = ModularInteger<V, M>;
fn neg(mut self) -> Self::Output {
self.value = self.value.modular_neg_move(&self.modulus);
self
}
}
impl<'a, V: ModularReduce + Eq, M: Modulus<V>> Neg for &'a ModularInteger<V, M> {
type Output = ModularInteger<V, M>;
fn neg(self) -> Self::Output {
let value = self.value.modular_neg_ref(&self.modulus);
ModularInteger {
value,
modulus: self.modulus.clone(),
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> Sub<ModularInteger<V, M>> for ModularInteger<V, M> {
type Output = ModularInteger<V, M>;
fn sub(self, rhs: ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_sub_move_move(rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> Sub<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn sub(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_sub_move_ref(&rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<'l, V: ModularReduce + Eq, M: Modulus<V>> Sub<ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn sub(self, rhs: ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_sub_ref_move(rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<'l, 'r, V: ModularReduce + Eq, M: Modulus<V>> Sub<&'r ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn sub(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_sub_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> SubAssign<ModularInteger<V, M>>
for ModularInteger<V, M>
{
fn sub_assign(&mut self, rhs: Self) {
self.require_matching_moduli(&rhs);
self.value.modular_sub_move_assign(rhs.value, &self.modulus);
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> SubAssign<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
fn sub_assign(&mut self, rhs: &Self) {
self.require_matching_moduli(&rhs);
self.value.modular_sub_ref_assign(&rhs.value, &self.modulus);
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> CheckedSub for ModularInteger<V, M> {
fn checked_sub(&self, rhs: &Self) -> Option<Self> {
if !self.has_matching_moduli(rhs) {
return None;
}
Some(ModularInteger {
value: self.value.modular_sub_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
})
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> Mul for ModularInteger<V, M> {
type Output = ModularInteger<V, M>;
fn mul(self, rhs: Self) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_mul_move_move(rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> MulAssign for ModularInteger<V, M> {
fn mul_assign(&mut self, rhs: Self) {
self.require_matching_moduli(&rhs);
self.value.modular_mul_move_assign(rhs.value, &self.modulus);
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> MulAssign<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
fn mul_assign(&mut self, rhs: &Self) {
self.require_matching_moduli(&rhs);
self.value.modular_mul_ref_assign(&rhs.value, &self.modulus);
}
}
impl<'r, V: ModularReduce + Eq, M: Modulus<V>> Mul<&'r ModularInteger<V, M>>
for ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn mul(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_mul_move_ref(&rhs.value, &self.modulus),
modulus: self.modulus,
}
}
}
impl<'l, V: ModularReduce + Eq, M: Modulus<V>> Mul<ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn mul(self, rhs: ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_mul_ref_move(rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<'l, 'r, V: ModularReduce + Eq, M: Modulus<V>> Mul<&'r ModularInteger<V, M>>
for &'l ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn mul(self, rhs: &ModularInteger<V, M>) -> Self::Output {
self.require_matching_moduli(&rhs);
ModularInteger {
value: self.value.modular_mul_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
}
}
}
impl<V: ModularReduce + Eq, M: Modulus<V>> CheckedMul for ModularInteger<V, M> {
fn checked_mul(&self, rhs: &Self) -> Option<Self> {
if !self.has_matching_moduli(rhs) {
return None;
}
Some(ModularInteger {
value: self.value.modular_mul_ref_ref(&rhs.value, &self.modulus),
modulus: self.modulus.clone(),
})
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>>
ModularInteger<V, M>
{
pub fn checked_inverse(&self) -> Option<Self> {
if self.value.is_zero() {
return None;
}
let ExtendedGCDResult { gcd, x, .. } = self.value.extended_gcd(&*self.modulus.to_modulus());
if gcd.is_one() {
Some(ModularInteger::new(x, self.modulus.clone()))
} else {
None
}
}
pub fn inverse(&self) -> Self {
self.checked_inverse()
.expect("value has no modular inverse")
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>> DivAssign
for ModularInteger<V, M>
{
fn div_assign(&mut self, rhs: ModularInteger<V, M>) {
self.mul_assign(rhs.inverse())
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>>
DivAssign<&'_ ModularInteger<V, M>> for ModularInteger<V, M>
{
fn div_assign(&mut self, rhs: &ModularInteger<V, M>) {
self.mul_assign(rhs.inverse())
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>> Div
for ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn div(self, rhs: ModularInteger<V, M>) -> ModularInteger<V, M> {
self.mul(rhs.inverse())
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>>
Div<ModularInteger<V, M>> for &'_ ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn div(self, rhs: ModularInteger<V, M>) -> ModularInteger<V, M> {
self.mul(&rhs.inverse())
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>>
Div<&'_ ModularInteger<V, M>> for ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn div(self, rhs: &ModularInteger<V, M>) -> ModularInteger<V, M> {
self.mul(rhs.inverse())
}
}
impl<'a, 'b, V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>>
Div<&'a ModularInteger<V, M>> for &'b ModularInteger<V, M>
{
type Output = ModularInteger<V, M>;
fn div(self, rhs: &ModularInteger<V, M>) -> ModularInteger<V, M> {
self.mul(&rhs.inverse())
}
}
impl<V: ModularReduce + Eq + One + Zero + GCD<Output = V> + ExtendedGCD, M: Modulus<V>> CheckedDiv
for ModularInteger<V, M>
{
fn checked_div(&self, rhs: &Self) -> Option<Self> {
self.checked_mul(&rhs.checked_inverse()?)
}
}
macro_rules! impl_exact_div {
(($($lifetimes:tt),*), $v:ident, $m:ident, $lhs:ty, $rhs:ty) => {
impl<$($lifetimes,)* $v, $m> ExactDiv<$rhs> for $lhs
where
$v: ModularReduce + Eq + One + Zero + GCD<Output = $v> + ExtendedGCD, $m: Modulus<$v>
{
type Output = ModularInteger<$v, $m>;
fn exact_div(self, rhs: $rhs) -> Self::Output {
self.div(rhs)
}
fn checked_exact_div(self, rhs: $rhs) -> Option<Self::Output> {
self.checked_div(rhs.borrow())
}
}
impl<$($lifetimes,)* $v, $m> AlwaysExactDiv<$rhs> for $lhs
where
$v: ModularReduce + Integer + GCD<Output = $v> + ExtendedGCD,
$m: PrimeModulus<$v>,
{
}
};
(assign ($($lifetimes:tt),*), $v:ident, $m:ident, $lhs:ty, $rhs:ty) => {
impl_exact_div!(($($lifetimes),*), $v, $m, $lhs, $rhs);
impl<$($lifetimes,)* $v, $m> ExactDivAssign<$rhs> for $lhs
where
$v: ModularReduce + Eq + One + Zero + GCD<Output = $v> + ExtendedGCD, $m: Modulus<$v>
{
fn exact_div_assign(&mut self, rhs: $rhs) {
self.div_assign(rhs);
}
fn checked_exact_div_assign(&mut self, rhs: $rhs) -> Result<(), ()> {
(&*self)
.checked_exact_div(rhs)
.map(|v| {
*self = v;
})
.ok_or(())
}
}
impl<$($lifetimes,)* $v, $m> AlwaysExactDivAssign<$rhs> for $lhs
where
$v: ModularReduce + Integer + GCD<Output = $v> + ExtendedGCD,
$m: PrimeModulus<$v>,
{
}
};
}
impl_exact_div!(assign (), V, M, ModularInteger<V, M>, ModularInteger<V, M>);
impl_exact_div!(assign ('r), V, M, ModularInteger<V, M>, &'r ModularInteger<V, M>);
impl_exact_div!(('l), V, M, &'l ModularInteger<V, M>, ModularInteger<V, M>);
impl_exact_div!(('l, 'r), V, M, &'l ModularInteger<V, M>, &'r ModularInteger<V, M>);
impl<V, M> PolynomialCoefficient for ModularInteger<V, M>
where
V: ModularReducePow<usize> + Eq + One + Zero + fmt::Debug + Hash,
M: Modulus<V> + fmt::Debug + Hash,
{
type Element = Self;
type Divisor = DivisorIsOne;
const NESTING_DEPTH: usize = 0;
fn is_element_zero(element: &Self::Element) -> bool {
element.value.is_zero()
}
fn is_element_one(element: &Self::Element) -> bool {
element.value.is_one()
}
fn is_coefficient_zero(coefficient: &Self) -> bool {
coefficient.value.is_zero()
}
fn is_coefficient_one(coefficient: &Self) -> bool {
coefficient.value.is_one()
}
fn set_element_zero(element: &mut Self::Element) {
element.value.set_zero();
}
fn set_element_one(element: &mut Self::Element) {
element.value = V::modular_reduce(V::one(), &element.modulus);
}
fn set_coefficient_zero(coefficient: &mut Self) {
Self::set_element_zero(coefficient);
}
fn set_coefficient_one(coefficient: &mut Self) {
Self::set_element_one(coefficient);
}
fn make_zero_element(element: Cow<Self::Element>) -> Self::Element {
let modulus = match element {
Cow::Borrowed(element) => element.modulus.clone(),
Cow::Owned(element) => element.modulus,
};
Self::new(V::zero(), modulus)
}
fn make_one_element(element: Cow<Self::Element>) -> Self::Element {
let modulus = match element {
Cow::Borrowed(element) => element.modulus.clone(),
Cow::Owned(element) => element.modulus,
};
Self::new(V::one(), modulus)
}
fn make_zero_coefficient_from_element(element: Cow<Self::Element>) -> Self {
Self::make_zero_element(element)
}
fn make_one_coefficient_from_element(element: Cow<Self::Element>) -> Self {
Self::make_one_element(element)
}
fn make_zero_coefficient_from_coefficient(coefficient: Cow<Self>) -> Self {
Self::make_zero_element(coefficient)
}
fn make_one_coefficient_from_coefficient(coefficient: Cow<Self>) -> Self {
Self::make_one_element(coefficient)
}
fn negate_element(element: &mut Self::Element) {
element.neg_assign();
}
fn mul_element_by_usize(element: Cow<Self::Element>, multiplier: usize) -> Self::Element {
let mut element = element.into_owned();
Self::mul_assign_element_by_usize(&mut element, multiplier);
element
}
fn mul_assign_element_by_usize(element: &mut Self::Element, multiplier: usize) {
element.value.modular_mul_move_assign(
V::modular_reduce_from_usize(multiplier, &element.modulus),
&element.modulus,
);
}
fn divisor_to_element(
_v: Cow<Self::Divisor>,
other_element: Cow<Self::Element>,
) -> Self::Element {
Self::make_one_element(other_element)
}
fn coefficients_to_elements(coefficients: Cow<[Self]>) -> (Vec<Self::Element>, Self::Divisor) {
(coefficients.into_owned(), One::one())
}
fn make_coefficient(element: Cow<Self::Element>, _divisor: Cow<Self::Divisor>) -> Self {
element.into_owned()
}
fn reduce_divisor(_elements: &mut [Self::Element], _divisor: &mut Self::Divisor) {}
fn get_reduced_divisor(
elements: &[Self::Element],
_divisor: &Self::Divisor,
) -> (Vec<Self::Element>, Self::Divisor) {
(elements.to_vec(), One::one())
}
fn coefficient_to_element(coefficient: Cow<Self>) -> (Self::Element, Self::Divisor) {
(coefficient.into_owned(), One::one())
}
fn divisor_pow_usize(_base: Self::Divisor, _exponent: usize) -> Self::Divisor {
One::one()
}
fn element_pow_usize(base: Self::Element, exponent: usize) -> Self::Element {
let ModularInteger { value, modulus } = base;
let value = value.pow_modular_reduce(&exponent, &modulus);
ModularInteger { value, modulus }
}
}
impl<V, M> PolynomialReducingFactorSupported for ModularInteger<V, M>
where
V: ModularReducePow<usize> + Integer + fmt::Debug + Hash,
M: PrimeModulus<V> + fmt::Debug + Hash,
{
fn get_nonzero_reducing_factor(
elements: &[Self::Element],
_divisor: &Self::Divisor,
) -> Option<Self> {
Some(elements.last()?.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::tests::{test_op_helper, test_unary_op_helper};
fn test_overflow_for_type<
T: Modulus<T> + ModularReduce + Sub<Output = T> + Copy + Into<BigInt> + fmt::Debug,
BigIntToT: Fn(&BigInt) -> Option<T>,
>(
modulus: T,
big_int_to_t: BigIntToT,
) where
i32: TryInto<T>,
<i32 as TryInto<T>>::Error: fmt::Debug,
{
let index_to_t = |index: i32| -> T {
if index < 0 {
modulus - (-index).try_into().unwrap()
} else {
index.try_into().unwrap()
}
};
for a in -5..=5 {
for b in -5..=5 {
let lhs = index_to_t(a);
let rhs = index_to_t(b);
let big_modulus: BigInt = modulus.into();
let big_lhs: BigInt = lhs.into();
let big_rhs: BigInt = rhs.into();
let add_result = big_int_to_t(&((&big_lhs + &big_rhs) % &big_modulus))
.expect("can't convert BigInt to T");
let neg_result = big_int_to_t(&((&big_modulus - &big_rhs) % &big_modulus))
.expect("can't convert BigInt to T");
let sub_result =
big_int_to_t(&((&big_lhs + &big_modulus - &big_rhs) % &big_modulus))
.expect("can't convert BigInt to T");
let mul_result = big_int_to_t(&((&big_lhs * &big_rhs) % &big_modulus))
.expect("can't convert BigInt to T");
test_op_helper(
ModularInteger::<T, T>::new(lhs, modulus),
ModularInteger::new(rhs, modulus),
&ModularInteger::new(add_result, modulus),
|l, r| *l += r,
|l, r| *l += r,
|l, r| l + r,
|l, r| l + r,
|l, r| l + r,
|l, r| l + r,
);
test_unary_op_helper(
ModularInteger::<T, T>::new(rhs, modulus),
&ModularInteger::new(neg_result, modulus),
|v| -v,
|v| -v,
);
test_op_helper(
ModularInteger::<T, T>::new(lhs, modulus),
ModularInteger::new(rhs, modulus),
&ModularInteger::new(sub_result, modulus),
|l, r| *l -= r,
|l, r| *l -= r,
|l, r| l - r,
|l, r| l - r,
|l, r| l - r,
|l, r| l - r,
);
test_op_helper(
ModularInteger::<T, T>::new(lhs, modulus),
ModularInteger::new(rhs, modulus),
&ModularInteger::new(mul_result, modulus),
|l, r| *l *= r,
|l, r| *l *= r,
|l, r| l * r,
|l, r| l * r,
|l, r| l * r,
|l, r| l * r,
);
}
}
}
#[test]
fn test_overflow() {
test_overflow_for_type(251u8, BigInt::to_u8);
test_overflow_for_type(127i8, BigInt::to_i8);
test_overflow_for_type(65521u16, BigInt::to_u16);
test_overflow_for_type(32749i16, BigInt::to_i16);
test_overflow_for_type(4_294_967_291u32, BigInt::to_u32);
test_overflow_for_type(2_147_483_647i32, BigInt::to_i32);
test_overflow_for_type(18_446_744_073_709_551_557u64, BigInt::to_u64);
test_overflow_for_type(9_223_372_036_854_775_783i64, BigInt::to_i64);
test_overflow_for_type(
340_282_366_920_938_463_463_374_607_431_768_211_297u128,
BigInt::to_u128,
);
test_overflow_for_type(
170_141_183_460_469_231_731_687_303_715_884_105_727i128,
BigInt::to_i128,
);
}
#[test]
fn test_add() {
let test = |l: ModularInteger<i32, i32>,
r: ModularInteger<i32, i32>,
expected: &ModularInteger<i32, i32>| {
test_op_helper(
l,
r,
expected,
|l, r| *l += r,
|l, r| *l += r,
|l, r| l + r,
|l, r| l + r,
|l, r| l + r,
|l, r| l + r,
);
};
for m in 0..10 {
for a in 0..m {
for b in 0..m {
let mut expected = a + b;
if m != 0 {
expected %= m;
}
test((a, m).into(), (b, m).into(), &(expected, m).into());
}
}
}
}
#[test]
fn test_sub() {
let test = |l: ModularInteger<i32, i32>,
r: ModularInteger<i32, i32>,
expected: &ModularInteger<i32, i32>| {
test_op_helper(
l,
r,
expected,
|l, r| *l -= r,
|l, r| *l -= r,
|l, r| l - r,
|l, r| l - r,
|l, r| l - r,
|l, r| l - r,
);
};
for m in 0..10 {
for a in 0..m {
for b in 0..m {
let mut expected = a - b;
if m != 0 {
expected %= m;
if expected < 0 {
expected += m;
}
}
test((a, m).into(), (b, m).into(), &(expected, m).into());
}
}
}
}
#[test]
fn test_mul() {
let test = |l: ModularInteger<i32, i32>,
r: ModularInteger<i32, i32>,
expected: &ModularInteger<i32, i32>| {
test_op_helper(
l,
r,
expected,
|l, r| *l *= r,
|l, r| *l *= r,
|l, r| l * r,
|l, r| l * r,
|l, r| l * r,
|l, r| l * r,
);
};
for m in 0..10 {
for a in 0..m {
for b in 0..m {
let mut expected = a * b;
if m != 0 {
expected %= m;
}
test((a, m).into(), (b, m).into(), &(expected, m).into());
}
}
}
}
#[test]
fn test_div() {
let test = |l: i64, r: i64, expected: Option<i64>, modulus: i64| {
dbg!((l, r, expected, modulus));
assert_eq!(
ModularInteger::new(l, modulus).checked_div(&ModularInteger::new(r, modulus)),
expected.map(|expected| ModularInteger::new(expected, modulus))
);
let expected = match expected {
None => return,
Some(expected) => expected,
};
test_op_helper(
ModularInteger::new(l, modulus),
ModularInteger::new(r, modulus),
&ModularInteger::new(expected, modulus),
|l, r| *l /= r,
|l, r| *l /= r,
|l, r| l / r,
|l, r| l / r,
|l, r| l / r,
|l, r| l / r,
);
};
test(0, 0, None, 1);
test(0, 0, None, 2);
test(0, 1, Some(0), 2);
test(1, 0, None, 2);
test(1, 1, Some(1), 2);
test(0, 0, None, 3);
test(0, 1, Some(0), 3);
test(0, 2, Some(0), 3);
test(1, 0, None, 3);
test(1, 1, Some(1), 3);
test(1, 2, Some(2), 3);
test(2, 0, None, 3);
test(2, 1, Some(2), 3);
test(2, 2, Some(1), 3);
test(0, 0, None, 4);
test(0, 1, Some(0), 4);
test(0, 2, None, 4);
test(0, 3, Some(0), 4);
test(1, 0, None, 4);
test(1, 1, Some(1), 4);
test(1, 2, None, 4);
test(1, 3, Some(3), 4);
test(2, 0, None, 4);
test(2, 1, Some(2), 4);
test(2, 2, None, 4);
test(2, 3, Some(2), 4);
test(3, 0, None, 4);
test(3, 1, Some(3), 4);
test(3, 2, None, 4);
test(3, 3, Some(1), 4);
test(0, 0, None, 5);
test(0, 1, Some(0), 5);
test(0, 2, Some(0), 5);
test(0, 3, Some(0), 5);
test(0, 4, Some(0), 5);
test(1, 0, None, 5);
test(1, 1, Some(1), 5);
test(1, 2, Some(3), 5);
test(1, 3, Some(2), 5);
test(1, 4, Some(4), 5);
test(2, 0, None, 5);
test(2, 1, Some(2), 5);
test(2, 2, Some(1), 5);
test(2, 3, Some(4), 5);
test(2, 4, Some(3), 5);
test(3, 0, None, 5);
test(3, 1, Some(3), 5);
test(3, 2, Some(4), 5);
test(3, 3, Some(1), 5);
test(3, 4, Some(2), 5);
test(4, 0, None, 5);
test(4, 1, Some(4), 5);
test(4, 2, Some(2), 5);
test(4, 3, Some(3), 5);
test(4, 4, Some(1), 5);
test(0, 0, None, 6);
test(0, 1, Some(0), 6);
test(0, 2, None, 6);
test(0, 3, None, 6);
test(0, 4, None, 6);
test(0, 5, Some(0), 6);
test(1, 0, None, 6);
test(1, 1, Some(1), 6);
test(1, 2, None, 6);
test(1, 3, None, 6);
test(1, 4, None, 6);
test(1, 5, Some(5), 6);
test(2, 0, None, 6);
test(2, 1, Some(2), 6);
test(2, 2, None, 6);
test(2, 3, None, 6);
test(2, 4, None, 6);
test(2, 5, Some(4), 6);
test(3, 0, None, 6);
test(3, 1, Some(3), 6);
test(3, 2, None, 6);
test(3, 3, None, 6);
test(3, 4, None, 6);
test(3, 5, Some(3), 6);
test(4, 0, None, 6);
test(4, 1, Some(4), 6);
test(4, 2, None, 6);
test(4, 3, None, 6);
test(4, 4, None, 6);
test(4, 5, Some(2), 6);
test(5, 0, None, 6);
test(5, 1, Some(5), 6);
test(5, 2, None, 6);
test(5, 3, None, 6);
test(5, 4, None, 6);
test(5, 5, Some(1), 6);
test(0, 0, None, 7);
test(0, 1, Some(0), 7);
test(0, 2, Some(0), 7);
test(0, 3, Some(0), 7);
test(0, 4, Some(0), 7);
test(0, 5, Some(0), 7);
test(0, 6, Some(0), 7);
test(1, 0, None, 7);
test(1, 1, Some(1), 7);
test(1, 2, Some(4), 7);
test(1, 3, Some(5), 7);
test(1, 4, Some(2), 7);
test(1, 5, Some(3), 7);
test(1, 6, Some(6), 7);
test(2, 0, None, 7);
test(2, 1, Some(2), 7);
test(2, 2, Some(1), 7);
test(2, 3, Some(3), 7);
test(2, 4, Some(4), 7);
test(2, 5, Some(6), 7);
test(2, 6, Some(5), 7);
test(3, 0, None, 7);
test(3, 1, Some(3), 7);
test(3, 2, Some(5), 7);
test(3, 3, Some(1), 7);
test(3, 4, Some(6), 7);
test(3, 5, Some(2), 7);
test(3, 6, Some(4), 7);
test(4, 0, None, 7);
test(4, 1, Some(4), 7);
test(4, 2, Some(2), 7);
test(4, 3, Some(6), 7);
test(4, 4, Some(1), 7);
test(4, 5, Some(5), 7);
test(4, 6, Some(3), 7);
test(5, 0, None, 7);
test(5, 1, Some(5), 7);
test(5, 2, Some(6), 7);
test(5, 3, Some(4), 7);
test(5, 4, Some(3), 7);
test(5, 5, Some(1), 7);
test(5, 6, Some(2), 7);
test(6, 0, None, 7);
test(6, 1, Some(6), 7);
test(6, 2, Some(3), 7);
test(6, 3, Some(2), 7);
test(6, 4, Some(5), 7);
test(6, 5, Some(4), 7);
test(6, 6, Some(1), 7);
test(0, 0, None, 8);
test(0, 1, Some(0), 8);
test(0, 2, None, 8);
test(0, 3, Some(0), 8);
test(0, 4, None, 8);
test(0, 5, Some(0), 8);
test(0, 6, None, 8);
test(0, 7, Some(0), 8);
test(1, 0, None, 8);
test(1, 1, Some(1), 8);
test(1, 2, None, 8);
test(1, 3, Some(3), 8);
test(1, 4, None, 8);
test(1, 5, Some(5), 8);
test(1, 6, None, 8);
test(1, 7, Some(7), 8);
test(2, 0, None, 8);
test(2, 1, Some(2), 8);
test(2, 2, None, 8);
test(2, 3, Some(6), 8);
test(2, 4, None, 8);
test(2, 5, Some(2), 8);
test(2, 6, None, 8);
test(2, 7, Some(6), 8);
test(3, 0, None, 8);
test(3, 1, Some(3), 8);
test(3, 2, None, 8);
test(3, 3, Some(1), 8);
test(3, 4, None, 8);
test(3, 5, Some(7), 8);
test(3, 6, None, 8);
test(3, 7, Some(5), 8);
test(4, 0, None, 8);
test(4, 1, Some(4), 8);
test(4, 2, None, 8);
test(4, 3, Some(4), 8);
test(4, 4, None, 8);
test(4, 5, Some(4), 8);
test(4, 6, None, 8);
test(4, 7, Some(4), 8);
test(5, 0, None, 8);
test(5, 1, Some(5), 8);
test(5, 2, None, 8);
test(5, 3, Some(7), 8);
test(5, 4, None, 8);
test(5, 5, Some(1), 8);
test(5, 6, None, 8);
test(5, 7, Some(3), 8);
test(6, 0, None, 8);
test(6, 1, Some(6), 8);
test(6, 2, None, 8);
test(6, 3, Some(2), 8);
test(6, 4, None, 8);
test(6, 5, Some(6), 8);
test(6, 6, None, 8);
test(6, 7, Some(2), 8);
test(7, 0, None, 8);
test(7, 1, Some(7), 8);
test(7, 2, None, 8);
test(7, 3, Some(5), 8);
test(7, 4, None, 8);
test(7, 5, Some(3), 8);
test(7, 6, None, 8);
test(7, 7, Some(1), 8);
test(0, 0, None, 9);
test(0, 1, Some(0), 9);
test(0, 2, Some(0), 9);
test(0, 3, None, 9);
test(0, 4, Some(0), 9);
test(0, 5, Some(0), 9);
test(0, 6, None, 9);
test(0, 7, Some(0), 9);
test(0, 8, Some(0), 9);
test(1, 0, None, 9);
test(1, 1, Some(1), 9);
test(1, 2, Some(5), 9);
test(1, 3, None, 9);
test(1, 4, Some(7), 9);
test(1, 5, Some(2), 9);
test(1, 6, None, 9);
test(1, 7, Some(4), 9);
test(1, 8, Some(8), 9);
test(2, 0, None, 9);
test(2, 1, Some(2), 9);
test(2, 2, Some(1), 9);
test(2, 3, None, 9);
test(2, 4, Some(5), 9);
test(2, 5, Some(4), 9);
test(2, 6, None, 9);
test(2, 7, Some(8), 9);
test(2, 8, Some(7), 9);
test(3, 0, None, 9);
test(3, 1, Some(3), 9);
test(3, 2, Some(6), 9);
test(3, 3, None, 9);
test(3, 4, Some(3), 9);
test(3, 5, Some(6), 9);
test(3, 6, None, 9);
test(3, 7, Some(3), 9);
test(3, 8, Some(6), 9);
test(4, 0, None, 9);
test(4, 1, Some(4), 9);
test(4, 2, Some(2), 9);
test(4, 3, None, 9);
test(4, 4, Some(1), 9);
test(4, 5, Some(8), 9);
test(4, 6, None, 9);
test(4, 7, Some(7), 9);
test(4, 8, Some(5), 9);
test(5, 0, None, 9);
test(5, 1, Some(5), 9);
test(5, 2, Some(7), 9);
test(5, 3, None, 9);
test(5, 4, Some(8), 9);
test(5, 5, Some(1), 9);
test(5, 6, None, 9);
test(5, 7, Some(2), 9);
test(5, 8, Some(4), 9);
test(6, 0, None, 9);
test(6, 1, Some(6), 9);
test(6, 2, Some(3), 9);
test(6, 3, None, 9);
test(6, 4, Some(6), 9);
test(6, 5, Some(3), 9);
test(6, 6, None, 9);
test(6, 7, Some(6), 9);
test(6, 8, Some(3), 9);
test(7, 0, None, 9);
test(7, 1, Some(7), 9);
test(7, 2, Some(8), 9);
test(7, 3, None, 9);
test(7, 4, Some(4), 9);
test(7, 5, Some(5), 9);
test(7, 6, None, 9);
test(7, 7, Some(1), 9);
test(7, 8, Some(2), 9);
test(8, 0, None, 9);
test(8, 1, Some(8), 9);
test(8, 2, Some(4), 9);
test(8, 3, None, 9);
test(8, 4, Some(2), 9);
test(8, 5, Some(7), 9);
test(8, 6, None, 9);
test(8, 7, Some(5), 9);
test(8, 8, Some(1), 9);
test(0, 0, None, 10);
test(0, 1, Some(0), 10);
test(0, 2, None, 10);
test(0, 3, Some(0), 10);
test(0, 4, None, 10);
test(0, 5, None, 10);
test(0, 6, None, 10);
test(0, 7, Some(0), 10);
test(0, 8, None, 10);
test(0, 9, Some(0), 10);
test(1, 0, None, 10);
test(1, 1, Some(1), 10);
test(1, 2, None, 10);
test(1, 3, Some(7), 10);
test(1, 4, None, 10);
test(1, 5, None, 10);
test(1, 6, None, 10);
test(1, 7, Some(3), 10);
test(1, 8, None, 10);
test(1, 9, Some(9), 10);
test(2, 0, None, 10);
test(2, 1, Some(2), 10);
test(2, 2, None, 10);
test(2, 3, Some(4), 10);
test(2, 4, None, 10);
test(2, 5, None, 10);
test(2, 6, None, 10);
test(2, 7, Some(6), 10);
test(2, 8, None, 10);
test(2, 9, Some(8), 10);
test(3, 0, None, 10);
test(3, 1, Some(3), 10);
test(3, 2, None, 10);
test(3, 3, Some(1), 10);
test(3, 4, None, 10);
test(3, 5, None, 10);
test(3, 6, None, 10);
test(3, 7, Some(9), 10);
test(3, 8, None, 10);
test(3, 9, Some(7), 10);
test(4, 0, None, 10);
test(4, 1, Some(4), 10);
test(4, 2, None, 10);
test(4, 3, Some(8), 10);
test(4, 4, None, 10);
test(4, 5, None, 10);
test(4, 6, None, 10);
test(4, 7, Some(2), 10);
test(4, 8, None, 10);
test(4, 9, Some(6), 10);
test(5, 0, None, 10);
test(5, 1, Some(5), 10);
test(5, 2, None, 10);
test(5, 3, Some(5), 10);
test(5, 4, None, 10);
test(5, 5, None, 10);
test(5, 6, None, 10);
test(5, 7, Some(5), 10);
test(5, 8, None, 10);
test(5, 9, Some(5), 10);
test(6, 0, None, 10);
test(6, 1, Some(6), 10);
test(6, 2, None, 10);
test(6, 3, Some(2), 10);
test(6, 4, None, 10);
test(6, 5, None, 10);
test(6, 6, None, 10);
test(6, 7, Some(8), 10);
test(6, 8, None, 10);
test(6, 9, Some(4), 10);
test(7, 0, None, 10);
test(7, 1, Some(7), 10);
test(7, 2, None, 10);
test(7, 3, Some(9), 10);
test(7, 4, None, 10);
test(7, 5, None, 10);
test(7, 6, None, 10);
test(7, 7, Some(1), 10);
test(7, 8, None, 10);
test(7, 9, Some(3), 10);
test(8, 0, None, 10);
test(8, 1, Some(8), 10);
test(8, 2, None, 10);
test(8, 3, Some(6), 10);
test(8, 4, None, 10);
test(8, 5, None, 10);
test(8, 6, None, 10);
test(8, 7, Some(4), 10);
test(8, 8, None, 10);
test(8, 9, Some(2), 10);
test(9, 0, None, 10);
test(9, 1, Some(9), 10);
test(9, 2, None, 10);
test(9, 3, Some(3), 10);
test(9, 4, None, 10);
test(9, 5, None, 10);
test(9, 6, None, 10);
test(9, 7, Some(7), 10);
test(9, 8, None, 10);
test(9, 9, Some(1), 10);
}
}