use super::super::MatZ;
use crate::{
integer::Z,
integer_mod_q::Modulus,
macros::{
arithmetics::{arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned},
for_others::implement_for_others,
},
traits::MatrixDimensions,
};
use flint_sys::{fmpz::fmpz_mod, fmpz_mat::fmpz_mat_entry, fmpz_mod::fmpz_mod_set_fmpz};
use std::ops::Rem;
impl Rem<&Z> for &MatZ {
type Output = MatZ;
fn rem(self, modulus: &Z) -> Self::Output {
assert!(modulus > &1, "Modulus can not be smaller than 2.");
let out = self.clone();
for i in 0..out.get_num_rows() {
for j in 0..out.get_num_columns() {
let entry = unsafe { fmpz_mat_entry(&out.matrix, i, j) };
unsafe { fmpz_mod(entry, entry, &modulus.value) }
}
}
out
}
}
impl Rem<&Modulus> for &MatZ {
type Output = MatZ;
fn rem(self, modulus: &Modulus) -> Self::Output {
let out = self.clone();
for i in 0..out.get_num_rows() {
for j in 0..out.get_num_columns() {
let entry = unsafe { fmpz_mat_entry(&out.matrix, i, j) };
unsafe { fmpz_mod_set_fmpz(entry, entry, modulus.get_fmpz_mod_ctx_struct()) }
}
}
out
}
}
arithmetic_trait_borrowed_to_owned!(Rem, rem, MatZ, Z, MatZ);
arithmetic_trait_mixed_borrowed_owned!(Rem, rem, MatZ, Z, MatZ);
arithmetic_trait_borrowed_to_owned!(Rem, rem, MatZ, Modulus, MatZ);
arithmetic_trait_mixed_borrowed_owned!(Rem, rem, MatZ, Modulus, MatZ);
implement_for_others!(Z, MatZ, Rem for i8 i16 i32 i64 u8 u16 u32 u64);
#[cfg(test)]
mod test_rem {
use super::Z;
use crate::{integer::MatZ, integer_mod_q::Modulus};
use std::str::FromStr;
#[test]
fn rem() {
let a = MatZ::from_str("[[2, 3],[42, 24]]").unwrap();
let b = Z::from(24);
let c1 = a.clone() % b;
let c2 = a % Modulus::from(24);
assert_eq!(c1, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
}
#[test]
fn rem_borrow() {
let a = MatZ::from_str("[[2, 3],[42, 24]]").unwrap();
let b = Z::from(24);
let c1 = &a % &b;
let c2 = &a % &Modulus::from(24);
assert_eq!(c1, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
}
#[test]
fn rem_first_borrowed() {
let a = MatZ::from_str("[[2, 3],[42, 24]]").unwrap();
let b = Z::from(24);
let c1 = &a % b;
let c2 = &a % Modulus::from(24);
assert_eq!(c1, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
}
#[test]
fn rem_second_borrowed() {
let a = MatZ::from_str("[[2, 3],[42, 24]]").unwrap();
let b = Z::from(24);
let c1 = a.clone() % &b;
let c2 = a % &Modulus::from(24);
assert_eq!(c1, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[2, 3],[18, 0]]").unwrap());
}
#[test]
fn rem_negative_representation() {
let a = MatZ::from_str("[[-2, 3],[42, 24]]").unwrap();
let b = Z::from(24);
let c1 = &a % &b;
let c2 = &a % &Modulus::from(24);
assert_eq!(c1, MatZ::from_str("[[22, 3],[18, 0]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[22, 3],[18, 0]]").unwrap());
}
#[test]
fn rem_large_numbers() {
let a = MatZ::from_str(&format!("[[2, 3],[{}, 24]]", u64::MAX)).unwrap();
let b = Z::from(u64::MAX - 2);
let c1 = &a % &b;
let c2 = &a % &Modulus::from(u64::MAX - 2);
assert_eq!(c1, MatZ::from_str("[[2, 3],[2, 24]]").unwrap());
assert_eq!(c2, MatZ::from_str("[[2, 3],[2, 24]]").unwrap());
}
#[test]
#[should_panic]
fn rem_negative_error() {
let a = MatZ::from_str("[[2, 3],[42, 24]]").unwrap();
let b = Z::from(-24);
_ = &a % &b;
}
#[test]
#[should_panic]
fn zero_modulus() {
_ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 0;
}
#[test]
fn availability() {
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2u8;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2u16;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2u32;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2u64;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2i8;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2i16;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2i32;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2i64;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % Z::from(2);
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % Modulus::from(2);
let _ = &MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % 2u8;
let _ = MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % &Z::from(2);
let _ = &MatZ::from_str("[[2, 3],[42, 24]]").unwrap() % &Z::from(2);
}
}