#![forbid(unsafe_code)]
use self::ffi::Mpz;
use super::ffi;
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct CongruenceContext {
pub g: Mpz,
pub d: Mpz,
pub q: Mpz,
pub r: Mpz,
}
impl Default for CongruenceContext {
fn default() -> Self {
Self {
g: Mpz::new(),
d: Mpz::new(),
q: Mpz::new(),
r: Mpz::new(),
}
}
}
impl CongruenceContext {
pub fn solve_linear_congruence(
&mut self,
mu: &mut Mpz,
v: Option<&mut Mpz>,
a: &Mpz,
b: &Mpz,
m: &Mpz,
) {
ffi::mpz_gcdext(&mut self.g, &mut self.d, mu, a, m);
if cfg!(test) {
println!(
"g = {}, d = {}, e = {}, a = {}, m = {}",
self.g, self.d, mu, a, m
);
}
if cfg!(debug_assertions) {
ffi::mpz_fdiv_qr(&mut self.q, &mut self.r, b, &self.g);
debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!");
} else {
ffi::mpz_divexact(&mut self.q, b, &self.g)
}
ffi::mpz_mul(&mut self.r, &self.q, &self.d);
ffi::mpz_tdiv_r(mu, &self.r, m);
if let Some(v) = v {
if cfg!(debug_assertions) {
ffi::mpz_fdiv_qr(v, &mut self.r, &m, &self.g);
debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!");
} else {
ffi::mpz_divexact(v, &m, &self.g)
}
}
}
}