#![cfg_attr(not(test), no_std)]
use core::cmp::Ordering;
use core::fmt::{Debug, Display, Formatter};
use core::mem;
use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Range, RangeInclusive, Sub, SubAssign,
};
use num::traits::{Pow, SaturatingAdd, SaturatingSub};
use num::{FromPrimitive, Integer, NumCast, One, Signed, Zero};
pub trait NumType:
Default
+ Copy
+ Clone
+ Integer
+ Display
+ Debug
+ NumCast
+ FromPrimitive
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
{
}
impl<
T: Default
+ Copy
+ Clone
+ Integer
+ Display
+ Debug
+ NumCast
+ FromPrimitive
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign,
> NumType for T
{
}
pub trait MNum: Copy + Eq + PartialEq {
type Num: NumType;
fn a(&self) -> Self::Num;
fn m(&self) -> Self::Num;
fn with(&self, new_a: Self::Num) -> Self;
fn replace(&mut self, new_a: Self::Num) {
*self = self.with(new_a);
}
fn egcd(a: Self::Num, b: Self::Num) -> (Self::Num, Self::Num, Self::Num)
where
Self::Num: Signed,
{
if b == Self::Num::zero() {
(a.signum() * a, a.signum(), Self::Num::zero())
} else {
let (g, x, y) = Self::egcd(b, a.mod_floor(&b));
(g, y, x - (a / b) * y)
}
}
fn inverse(&self) -> Option<Self>
where
Self::Num: Signed,
{
let (g, _, inv) = Self::egcd(self.m(), self.a());
if g == Self::Num::one() {
Some(self.with(inv))
} else {
None
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ModNum<N> {
num: N,
modulo: N,
}
impl<N: NumType> MNum for ModNum<N> {
type Num = N;
fn a(&self) -> N {
self.num
}
fn m(&self) -> N {
self.modulo
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a, self.m())
}
}
impl<N: NumType> ModNum<N> {
pub fn new(a: N, m: N) -> Self {
ModNum {
num: a.mod_floor(&m),
modulo: m,
}
}
pub fn iter(&self) -> ModNumIterator<N, Self> {
ModNumIterator::new(*self)
}
}
impl<N: NumType + Signed> ModNum<N> {
pub fn chinese_remainder(&self, other: ModNum<N>) -> ModNum<N> {
let (g, u, v) = ModNum::egcd(self.m(), other.m());
let c = (self.a() * other.m() * v + other.a() * self.m() * u).div_floor(&g);
ModNum::new(c, self.m() * other.m())
}
pub fn chinese_remainder_system<I: Iterator<Item = ModNum<N>>>(
mut modnums: I,
) -> Option<ModNum<N>> {
modnums
.next()
.map(|start_num| modnums.fold(start_num, |a, b| a.chinese_remainder(b)))
}
}
macro_rules! derive_assign {
($name:ty, $implname:ty, $rhs_type:ty, $methodname:ident {$symbol:tt} {$($generic:tt)*} {$($num_type_suffix:ident)?} {$($unwrap:tt)*}) => {
impl <N: NumType + $($num_type_suffix)?,$($generic)*> $implname for $name {
fn $methodname(&mut self, rhs: $rhs_type) {
*self = (*self $symbol rhs)$($unwrap)*;
}
}
}
}
macro_rules! derive_basic_modulo_arithmetic {
($name:ty {$($generic:tt)*}) => {
impl <N:NumType,$($generic)*> PartialEq<N> for $name {
fn eq(&self, other: &N) -> bool {
self.a() == self.with(*other).a()
}
}
impl <N:NumType,$($generic)*> PartialOrd<N> for $name {
fn partial_cmp(&self, other: &N) -> Option<Ordering> {
self.a().partial_cmp(other)
}
}
impl <N: NumType,$($generic)*> Add<N> for $name {
type Output = Self;
fn add(self, rhs: N) -> Self::Output {
self.with(self.a() + rhs)
}
}
impl <N: NumType,$($generic)*> Add<$name> for $name {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self + rhs.a()
}
}
}
}
macro_rules! derive_core_modulo_arithmetic {
($name:ty {$($generic:tt)*}) => {
derive_basic_modulo_arithmetic! {
$name
{$($generic)*}
}
impl <N: NumType,$($generic)*> Mul<N> for $name {
type Output = Self;
fn mul(self, rhs: N) -> Self::Output {
self.with(self.a() * rhs)
}
}
impl <N: NumType,$($generic)*> Mul<$name> for $name {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
assert_eq!(self.m(), rhs.m());
self * rhs.a()
}
}
impl <N: NumType + Signed,$($generic)*> Div<N> for $name {
type Output = Option<Self>;
fn div(self, rhs: N) -> Self::Output {
self.with(rhs).inverse().map(|inv| self * inv.a())
}
}
impl <N: NumType + Signed,$($generic)*> Div<$name> for $name {
type Output = Option<Self>;
fn div(self, rhs: Self) -> Self::Output {
self / rhs.a()
}
}
impl <N: NumType,$($generic)*> Pow<N> for $name {
type Output = Self;
fn pow(self, rhs: N) -> Self::Output {
if rhs < N::zero() {
panic!("Negative exponentiation undefined for ModNum.pow(). Try .pow_signed() instead.")
} else if rhs == N::zero() {
self.with(N::one())
} else {
let mut r = self.pow(rhs.div_floor(&(N::one() + N::one())));
r *= r;
if rhs.is_odd() {
r *= self;
}
r
}
}
}
impl <N: NumType,$($generic)*> Pow<$name> for $name {
type Output = Self;
fn pow(self, rhs: Self) -> Self::Output {
self.pow(rhs.a())
}
}
impl <N: NumType + Signed,$($generic)*> $name {
pub fn pow_signed(&self, rhs: N) -> Option<Self> {
if rhs < N::zero() {
self.pow(-rhs).inverse()
} else {
Some(self.pow(rhs))
}
}
}
}
}
macro_rules! derive_add_assign_sub {
($name:ty {$($generic:tt)*}) => {
derive_assign! {
$name, AddAssign<N>, N, add_assign {+} {$($generic)*} {} {}
}
derive_assign! {
$name, AddAssign<$name>, $name, add_assign {+} {$($generic)*} {} {}
}
impl <N: NumType,$($generic)*> Neg for $name {
type Output = Self;
fn neg(self) -> Self::Output {
self.with(self.m() - self.num)
}
}
impl <N: NumType,$($generic)*> Sub<N> for $name {
type Output = Self;
fn sub(self, rhs: N) -> Self::Output {
let offset = rhs.mod_floor(&self.m());
let negated_offset = self.m() - offset;
self + negated_offset
}
}
impl <N: NumType,$($generic)*> Sub<$name> for $name {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self - rhs.a()
}
}
derive_assign! {
$name, SubAssign<N>, N, sub_assign {-} {$($generic)*} {} {}
}
derive_assign! {
$name, SubAssign<$name>, $name, sub_assign {-} {$($generic)*} {} {}
}
}
}
macro_rules! derive_modulo_arithmetic {
($name:ty {$($generic:tt)*}) => {
derive_core_modulo_arithmetic! {
$name
{$($generic)*}
}
impl <N:NumType,$($generic)*> Display for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{} (mod {})", self.a(), self.m())
}
}
derive_add_assign_sub! {
$name
{$($generic)*}
}
derive_assign! {
$name, MulAssign<N>, N, mul_assign {*} {$($generic)*} {} {}
}
derive_assign! {
$name, MulAssign<$name>, $name, mul_assign {*} {$($generic)*} {} {}
}
derive_assign! {
$name, DivAssign<N>, N, div_assign {/} {$($generic)*} {Signed} {.unwrap()}
}
derive_assign! {
$name, DivAssign<$name>, $name, div_assign {/} {$($generic)*} {Signed} {.unwrap()}
}
impl <N: NumType, $($generic)*> SaturatingAdd for $name {
fn saturating_add(&self, v: &Self) -> Self {
if self.a() + v.a() >= self.m() {
self.with(self.m() - N::one())
} else {
*self + *v
}
}
}
impl <N: NumType, $($generic)*> SaturatingSub for $name {
fn saturating_sub(&self, v: &Self) -> Self {
if self.a() < v.a() {
self.with(N::zero())
} else {
*self - *v
}
}
}
}
}
derive_modulo_arithmetic! {
ModNum<N> {}
}
#[derive(Debug)]
pub struct ModNumIterator<N: NumType, M: MNum<Num = N> + Add<N, Output = M> + Sub<N, Output = M>> {
next: M,
next_back: M,
finished: bool,
}
impl<N: NumType, M: MNum<Num = N> + Add<N, Output = M> + Sub<N, Output = M>> ModNumIterator<N, M> {
pub fn new(mn: M) -> Self {
ModNumIterator {
next: mn,
next_back: mn - N::one(),
finished: false,
}
}
}
fn update<
N: NumType,
M: MNum<Num = N> + Add<N, Output = M> + Sub<N, Output = M>,
F: Fn(&M, N) -> M,
>(
finished: &mut bool,
update: &mut M,
updater: F,
target: M,
) -> Option<<ModNumIterator<N, M> as Iterator>::Item> {
if *finished {
None
} else {
let mut future = updater(update, N::one());
if future == updater(&target, N::one()) {
*finished = true;
}
mem::swap(&mut future, update);
Some(future)
}
}
impl<N: NumType, M: MNum<Num = N> + Add<N, Output = M> + Sub<N, Output = M>> Iterator
for ModNumIterator<N, M>
{
type Item = M;
fn next(&mut self) -> Option<Self::Item> {
update(
&mut self.finished,
&mut self.next,
|m, u| *m + u,
self.next_back,
)
}
}
impl<N: NumType, M: MNum<Num = N> + Add<N, Output = M> + Sub<N, Output = M>> DoubleEndedIterator
for ModNumIterator<N, M>
{
fn next_back(&mut self) -> Option<Self::Item> {
update(
&mut self.finished,
&mut self.next_back,
|m, u| *m - u,
self.next,
)
}
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ModNumC<N: FromPrimitive, const M: usize> {
num: N,
}
impl<N: NumType, const M: usize> MNum for ModNumC<N, M> {
type Num = N;
fn a(&self) -> Self::Num {
self.num
}
fn m(&self) -> Self::Num {
N::from_usize(M).unwrap()
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a)
}
}
impl<N: NumType, const M: usize> ModNumC<N, M> {
pub fn new(num: N) -> Self {
let mut result = ModNumC { num };
result.num = result.num.mod_floor(&result.m());
result
}
pub fn iter(&self) -> ModNumIterator<N, Self> {
ModNumIterator::new(*self)
}
}
derive_modulo_arithmetic! {
ModNumC<N,M> {const M: usize}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct WrapCountNum<N: NumType> {
num: N,
modulo: N,
wraps: N,
}
impl<N: NumType> MNum for WrapCountNum<N> {
type Num = N;
fn a(&self) -> Self::Num {
self.num
}
fn m(&self) -> Self::Num {
self.modulo
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a, self.m())
}
}
impl<N: NumType> WrapCountNum<N> {
pub fn new(a: N, modulo: N) -> Self {
let (wraps, num) = a.div_mod_floor(&modulo);
WrapCountNum { num, modulo, wraps }
}
pub fn with_wraps(&self, a: N, wraps: N) -> Self {
WrapCountNum {
num: a,
modulo: self.modulo,
wraps,
}
}
}
macro_rules! derive_wrap_assign {
($name:ty, $implname:ty, $rhs_type:ty, $methodname:ident {$symbol:tt} {$($generic:tt)*} {$($num_type_suffix:ident)?} {$($unwrap:tt)*}) => {
impl <N: NumType + $($num_type_suffix)?,$($generic)*> $implname for $name {
fn $methodname(&mut self, rhs: $rhs_type) {
let result = (*self $symbol rhs)$($unwrap)*;
self.num = result.num;
self.wraps += result.wraps;
}
}
}
}
macro_rules! derive_wrap_modulo_arithmetic {
($name:ty {$($generic:tt)*}) => {
derive_core_modulo_arithmetic! {$name {$($generic)*}}
impl <N: NumType,$($generic)*> $name {
pub fn wraps(&self) -> N {
self.wraps
}
pub fn pow_assign(&mut self, rhs: N) {
let result = self.pow(rhs);
self.num = result.num;
self.wraps += result.wraps;
}
}
impl <N: NumType + Signed,$($generic)*> $name {
pub fn iter(&self) -> ModNumIterator<N,Self> {
ModNumIterator::new(*self)
}
pub fn pow_assign_signed(&mut self, rhs: N) {
let result = self.pow_signed(rhs);
if let Some(result) = result {
self.num = result.num;
self.wraps += result.wraps;
}
}
}
impl <N: NumType,$($generic)*> Display for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{} (mod {}) (wrap {})", self.a(), self.m(), self.wraps)
}
}
impl <N: NumType + Signed,$($generic)*> Neg for $name {
type Output = Self;
fn neg(self) -> Self::Output {
self.with_wraps(-self.num, -self.wraps)
}
}
impl <N: NumType + Signed,$($generic)*> Sub<N> for $name {
type Output = Self;
fn sub(self, rhs: N) -> Self::Output {
self.with(self.num - rhs)
}
}
impl <N: NumType + Signed,$($generic)*> Sub<$name> for $name {
type Output = Self;
fn sub(self, rhs: $name) -> Self::Output {
self - rhs.a()
}
}
derive_wrap_assign! {
$name, AddAssign<N>, N, add_assign {+} {$($generic)*} {} {}
}
derive_wrap_assign! {
$name, AddAssign<$name>, $name, add_assign {+} {$($generic)*} {} {}
}
derive_wrap_assign! {
$name, SubAssign<N>, N, sub_assign {-} {$($generic)*} {Signed} {}
}
derive_wrap_assign! {
$name, SubAssign<$name>, $name, sub_assign {-} {$($generic)*} {Signed} {}
}
derive_wrap_assign! {
$name, MulAssign<N>, N, mul_assign {*} {$($generic)*} {} {}
}
derive_wrap_assign! {
$name, MulAssign<$name>, $name, mul_assign {*} {$($generic)*} {} {}
}
derive_wrap_assign! {
$name, DivAssign<N>, N, div_assign {/} {$($generic)*} {Signed} {.unwrap()}
}
derive_wrap_assign! {
$name, DivAssign<$name>, $name, div_assign {/} {$($generic)*} {Signed} {.unwrap()}
}
}
}
derive_wrap_modulo_arithmetic! {
WrapCountNum<N> {}
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct WrapCountNumC<N: FromPrimitive, const M: usize> {
num: N,
wraps: N,
}
impl<N: NumType, const M: usize> MNum for WrapCountNumC<N, M> {
type Num = N;
fn a(&self) -> Self::Num {
self.num
}
fn m(&self) -> Self::Num {
N::from_usize(M).unwrap()
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a)
}
}
impl<N: NumType, const M: usize> WrapCountNumC<N, M> {
pub fn new(a: N) -> Self {
let mut result = WrapCountNumC {
num: a,
wraps: N::zero(),
};
let (wraps, num) = a.div_mod_floor(&result.m());
result.num = num;
result.wraps = wraps;
result
}
pub fn with_wraps(&self, a: N, wraps: N) -> Self {
WrapCountNumC { num: a, wraps }
}
}
derive_wrap_modulo_arithmetic! {
WrapCountNumC<N,M> {const M: usize}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct OffsetNum<N: FromPrimitive> {
num: N,
modulo: N,
offset: N,
}
fn offset_init<N: NumType>(num: N, modulo: N, offset: N) -> N {
let mut num = num;
while num < offset {
num += modulo;
}
num - offset
}
impl<N: NumType> OffsetNum<N> {
pub fn new(num: N, modulo: N, offset: N) -> Self {
let num = offset_init(num, modulo, offset);
let mut result = OffsetNum {
num,
modulo,
offset,
};
result.num = result.num.mod_floor(&result.m());
result
}
pub fn iter(&self) -> ModNumIterator<N, Self> {
ModNumIterator::new(*self)
}
pub fn min_max(&self) -> (N, N) {
(self.offset, self.offset + self.modulo - N::one())
}
}
impl<N: NumType> From<RangeInclusive<N>> for OffsetNum<N> {
fn from(r: RangeInclusive<N>) -> Self {
Self::new(*r.start(), *r.end() - *r.start() + N::one(), *r.start())
}
}
impl<N: NumType> From<Range<N>> for OffsetNum<N> {
fn from(r: Range<N>) -> Self {
Self::new(r.start, r.end - r.start, r.start)
}
}
impl<N: NumType> MNum for OffsetNum<N> {
type Num = N;
fn a(&self) -> N {
self.num + self.offset
}
fn m(&self) -> N {
self.modulo
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a, self.m(), self.offset)
}
}
derive_basic_modulo_arithmetic! {
OffsetNum<N> {}
}
derive_add_assign_sub! {
OffsetNum<N> {}
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct OffsetNumC<N: FromPrimitive, const M: usize, const O: isize> {
num: N,
}
impl<N: NumType, const M: usize, const O: isize> MNum for OffsetNumC<N, M, O> {
type Num = N;
fn a(&self) -> Self::Num {
self.num + N::from_isize(O).unwrap()
}
fn m(&self) -> Self::Num {
N::from_usize(M).unwrap()
}
fn with(&self, new_a: Self::Num) -> Self {
Self::new(new_a)
}
}
impl<N: NumType, const M: usize, const O: isize> OffsetNumC<N, M, O> {
pub fn new(num: N) -> Self {
let num = offset_init(num, N::from_usize(M).unwrap(), N::from_isize(O).unwrap());
let mut result = OffsetNumC { num };
result.num = result.num.mod_floor(&result.m());
result
}
pub fn iter(&self) -> ModNumIterator<N, Self> {
ModNumIterator::new(*self)
}
pub fn min_max(&self) -> (N, N) {
(
N::from_isize(O).unwrap(),
N::from_isize(O + isize::from_usize(M).unwrap() - 1).unwrap(),
)
}
}
derive_basic_modulo_arithmetic! {
OffsetNumC<N,M,O> {const M: usize, const O: isize}
}
derive_add_assign_sub! {
OffsetNumC<N,M,O> {const M: usize, const O: isize}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn test_neg() {
let m = ModNum::new(-2, 5);
assert_eq!(m, ModNum::new(3, 5));
}
#[test]
fn test_negation() {
for n in 0..5 {
let m = ModNum::new(n, 5);
let n = -m;
assert_eq!(m + n.a(), 0);
}
}
#[test]
fn test_sub() {
for (n, m, sub, target) in vec![(1, 5, 2, 4)] {
assert_eq!(ModNum::new(n, m) - sub, ModNum::new(target, m));
}
}
#[test]
fn test_neg_c() {
let m: ModNumC<i32, 5> = ModNumC::new(-2);
assert_eq!(m, ModNumC::new(3));
}
#[test]
fn test_negation_c() {
let s: ModNumC<i32, 5> = ModNumC::new(0);
for m in s.iter() {
let n = -m;
assert_eq!(m + n, 0);
}
}
#[test]
fn test_sub_c() {
for (n, sub, target) in vec![(1, 2, 4), (2, 1, 1), (4, 1, 3), (4, 4, 0), (2, 5, 2)] {
let n: ModNumC<i32, 5> = ModNumC::new(n);
assert_eq!(n - sub, target);
}
}
#[test]
fn test_congruence_c() {
let m: ModNumC<i32, 5> = ModNumC::new(2);
for c in (-13..13).step_by(5) {
assert_eq!(m, c);
for i in -2..=2 {
if i == 0 {
assert_eq!(m, c);
} else {
assert_ne!(m, c + i);
}
}
}
}
#[test]
fn test_iter_up() {
assert_eq!(
vec![2, 3, 4, 0, 1],
ModNum::new(2, 5)
.iter()
.map(|m: ModNum<usize>| m.a())
.collect::<Vec<usize>>()
)
}
#[test]
fn test_iter_down() {
assert_eq!(
vec![1, 0, 4, 3, 2],
ModNum::new(2, 5)
.iter()
.rev()
.map(|m: ModNum<usize>| m.a())
.collect::<Vec<usize>>()
)
}
#[test]
fn test_iter_up_w() {
assert_eq!(
vec![2, 3, 4, 0, 1],
WrapCountNumC::<isize, 5>::new(2)
.iter()
.map(|m: WrapCountNumC<isize, 5>| m.a())
.collect::<Vec<isize>>()
)
}
#[test]
fn test_iter_down_w() {
assert_eq!(
vec![1, 0, 4, 3, 2],
WrapCountNumC::<isize, 5>::new(2)
.iter()
.rev()
.map(|m: WrapCountNumC<isize, 5>| m.a())
.collect::<Vec<isize>>()
)
}
#[test]
fn test_inverse() {
for a in 0..13 {
let m = ModNum::new(a, 13);
let inv = m.inverse();
if a == 0 {
assert!(inv.is_none());
} else {
assert_eq!(m * inv.unwrap().a(), 1);
}
}
}
#[test]
fn test_assign() {
let mut m = ModNum::new(2, 5);
m += 2;
assert_eq!(m, ModNum::new(4, 5));
m += 2;
assert_eq!(m, ModNum::new(1, 5));
m -= 3;
assert_eq!(m, ModNum::new(3, 5));
m *= 2;
assert_eq!(m, ModNum::new(1, 5));
m *= 2;
assert_eq!(m, ModNum::new(2, 5));
m *= 2;
assert_eq!(m, ModNum::new(4, 5));
m *= 2;
assert_eq!(m, ModNum::new(3, 5));
}
#[test]
fn test_assign_2() {
let mut m = ModNum::new(2, 5);
m += ModNum::new(2, 5);
assert_eq!(m, ModNum::new(4, 5));
m += ModNum::new(2, 5);
assert_eq!(m, ModNum::new(1, 5));
m -= ModNum::new(3, 5);
assert_eq!(m, ModNum::new(3, 5));
m *= ModNum::new(2, 5);
assert_eq!(m, ModNum::new(1, 5));
m *= ModNum::new(2, 5);
assert_eq!(m, ModNum::new(2, 5));
m *= ModNum::new(2, 5);
assert_eq!(m, ModNum::new(4, 5));
m *= ModNum::new(2, 5);
assert_eq!(m, ModNum::new(3, 5));
}
#[test]
fn test_chinese_remainder() {
let x = ModNum::new(2, 5);
let y = ModNum::new(3, 7);
assert_eq!(x.chinese_remainder(y), ModNum::new(17, 35));
}
#[test]
fn test_chinese_systems() {
let systems = vec![
(vec![(2, 5), (3, 7), (4, 9)], 157),
(vec![(0, 17), (-2, 13), (-3, 19)], 3417),
(vec![(0, 67), (-1, 7), (-2, 59), (-3, 61)], 754018),
(vec![(0, 67), (-2, 7), (-3, 59), (-4, 61)], 779210),
(vec![(0, 67), (-1, 7), (-3, 59), (-4, 61)], 1261476),
(vec![(0, 1789), (-1, 37), (-2, 47), (-3, 1889)], 1202161486),
];
for (system, goal) in systems {
let mut equations = system
.iter()
.copied()
.map(|(a, m)| ModNum::<i128>::new(a, m));
assert_eq!(
ModNum::chinese_remainder_system(&mut equations)
.unwrap()
.a(),
goal
);
}
}
#[test]
fn test_congruence() {
let m = ModNum::new(2, 5);
for c in (-13..13).step_by(5) {
assert_eq!(m, c);
for i in -2..=2 {
if i == 0 {
assert_eq!(m, c);
} else {
assert_ne!(m, c + i);
}
}
}
}
#[test]
fn test_division() {
let m = ModNum::new(6, 11);
for undefined in [0, 11].iter() {
assert_eq!(m / *undefined, None);
}
for (divisor, quotient) in [(1, 6), (2, 3), (4, 7), (5, 10), (8, 9)].iter() {
for (d, q) in [(divisor, quotient), (quotient, divisor)].iter() {
let result = (m / **d).unwrap();
assert_eq!(result * **d, m);
assert_eq!(result.a(), **q);
}
}
}
#[test]
fn test_pow() {
let m = ModNum::new(2, 5);
for (exp, result) in (2..).zip([4, 3, 1, 2].iter().cycle()).take(20) {
assert_eq!(m.pow(exp).a(), *result);
}
}
#[test]
fn test_big() {
let mut values = [
(0, 23),
(28, 41),
(20, 37),
(398, 421),
(11, 17),
(15, 19),
(6, 29),
(433, 487),
(11, 13),
(5, 137),
(19, 49),
]
.iter()
.copied()
.map(|(a, m)| ModNum::new(a, m));
let solution = ModNum::<i128>::chinese_remainder_system(&mut values)
.unwrap()
.a();
assert_eq!(solution, 762009420388013796);
}
#[test]
fn test_negative_exp() {
let m = ModNum::new(2, 5);
for (exp, result) in (2..).map(|n| -n).zip([4, 2, 1, 3].iter().cycle()).take(20) {
assert_eq!(m.pow_signed(exp).unwrap().a(), *result);
}
}
#[test]
fn test_wrapping() {
let mut w: WrapCountNumC<usize, 5> = WrapCountNumC::new(4);
w *= 4;
assert_eq!(w, 1);
assert_eq!(w.wraps(), 3);
w += 9;
assert_eq!(w, 0);
assert_eq!(w.wraps(), 5);
}
#[test]
fn test_offset() {
let mut off = OffsetNumC::<i16, 7, 5>::new(3);
assert_eq!(off.a(), 10);
off += 1;
assert_eq!(off.a(), 11);
off += 1;
assert_eq!(off.a(), 5);
off += 1;
assert_eq!(off.a(), 6);
}
#[test]
fn test_offset_2() {
let off = OffsetNumC::<usize, 5, 2>::new(1);
assert_eq!(off.a(), 6);
for test in [507, 512, 502, 497, 22] {
let bigoff = OffsetNumC::<usize, 5, 502>::new(test);
assert_eq!(bigoff.a(), 502);
}
}
#[test]
fn test_offset_3() {
let mut off = OffsetNum::<usize>::from(1..=10);
for i in 1..=10 {
assert_eq!(off.a(), i);
off += 1;
println!("{off:?}");
}
assert_eq!(off.a(), 1);
}
#[test]
fn test_offset_4() {
let mut off = OffsetNumC::<usize, 10, 1>::new(1);
for i in 1..=10 {
assert_eq!(off.a(), i);
off += 1;
println!("{off:?}");
}
assert_eq!(off.a(), 1);
}
#[test]
fn test_offset_5() {
let mut off = OffsetNum::<usize>::from(1..=10);
assert_eq!(off.a(), 1);
assert_eq!(off, 1);
assert_eq!(off, 11); assert_eq!(off.min_max(), (1, 10));
for i in 1..=10 {
assert_eq!(off.a(), i);
off += 1;
}
assert_eq!(off.a(), 1);
for (i, n) in off.iter().enumerate() {
assert_eq!(n.a(), i + 1);
}
off -= 1;
for i in (1..=10).rev() {
assert_eq!(off.a(), i);
off -= 1;
}
assert_eq!(off.a(), 10);
}
#[test]
fn test_offset_6() {
let x = OffsetNum::new(5, 9, 1);
let one = OffsetNum::new(1, 9, 1);
let y = x + one;
let z = x - one;
assert_eq!(x.a() + 1, y.a());
assert_eq!(x.a() - 1, z.a());
}
}