use super::super::MatZ;
use crate::integer::Z;
use crate::macros::arithmetics::{
arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
};
use crate::rational::MatQ;
use crate::traits::MatrixDimensions;
use flint_sys::fmpq_mat::fmpq_mat_set_fmpz_mat_div_fmpz;
use flint_sys::fmpz_mat::fmpz_mat_scalar_divexact_fmpz;
use std::ops::Div;
impl MatZ {
pub unsafe fn div_exact(mut self, divisor: impl Into<Z>) -> MatZ {
let divisor: Z = divisor.into();
assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
unsafe { fmpz_mat_scalar_divexact_fmpz(&mut self.matrix, &self.matrix, &divisor.value) };
self
}
pub unsafe fn div_exact_ref(&self, divisor: impl Into<Z>) -> MatZ {
let divisor: Z = divisor.into();
assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
unsafe { fmpz_mat_scalar_divexact_fmpz(&mut out.matrix, &self.matrix, &divisor.value) };
out
}
}
impl Div<&Z> for &MatZ {
type Output = MatQ;
fn div(self, divisor: &Z) -> Self::Output {
assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
unsafe {
fmpq_mat_set_fmpz_mat_div_fmpz(&mut out.matrix, &self.matrix, &divisor.value);
}
out
}
}
arithmetic_trait_borrowed_to_owned!(Div, div, MatZ, Z, MatQ);
arithmetic_trait_mixed_borrowed_owned!(Div, div, MatZ, Z, MatQ);
#[cfg(test)]
mod test_div_exact {
use super::*;
use crate::integer_mod_q::Modulus;
use std::str::FromStr;
#[test]
#[allow(clippy::needless_borrows_for_generic_args)]
fn availability() {
let mat = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
let _ = unsafe { mat.div_exact_ref(3i64) };
let _ = unsafe { mat.div_exact_ref(3i32) };
let _ = unsafe { mat.div_exact_ref(3i16) };
let _ = unsafe { mat.div_exact_ref(3i8) };
let _ = unsafe { mat.div_exact_ref(3u64) };
let _ = unsafe { mat.div_exact_ref(3u32) };
let _ = unsafe { mat.div_exact_ref(3u16) };
let _ = unsafe { mat.div_exact_ref(3u8) };
let _ = unsafe { mat.div_exact_ref(Z::from(3)) };
let _ = unsafe { mat.div_exact_ref(Modulus::from(3)) };
let _ = unsafe { mat.div_exact_ref(&Z::from(3)) };
let _ = unsafe { mat.div_exact_ref(&Modulus::from(3)) };
let _ = unsafe { mat.clone().div_exact(3i64) };
let _ = unsafe { mat.clone().div_exact(3i32) };
let _ = unsafe { mat.clone().div_exact(3i16) };
let _ = unsafe { mat.clone().div_exact(3i8) };
let _ = unsafe { mat.clone().div_exact(3u64) };
let _ = unsafe { mat.clone().div_exact(3u32) };
let _ = unsafe { mat.clone().div_exact(3u16) };
let _ = unsafe { mat.clone().div_exact(3u8) };
let _ = unsafe { mat.clone().div_exact(Z::from(3)) };
let _ = unsafe { mat.clone().div_exact(Modulus::from(3)) };
let _ = unsafe { mat.clone().div_exact(&Z::from(3)) };
let _ = unsafe { mat.div_exact(&Modulus::from(3)) };
}
#[test]
fn division_correctness() {
let mat = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
let mat_divided_1 = unsafe { mat.div_exact_ref(3) };
let mat_divided_2 = unsafe { mat.div_exact(3) };
let mat_cmp = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
assert_eq!(mat_cmp, mat_divided_1);
assert_eq!(mat_cmp, mat_divided_2);
}
#[test]
fn negative_correctness() {
let mat = MatZ::from_str("[[6, -3],[3, -6]]").unwrap();
let mat_divided_1 = unsafe { mat.div_exact_ref(3) };
let mat_divided_2 = unsafe { mat.div_exact_ref(-3) };
let mat_cmp_1 = MatZ::from_str("[[2, -1],[1, -2]]").unwrap();
let mat_cmp_2 = MatZ::from_str("[[-2, 1],[-1, 2]]").unwrap();
assert_eq!(mat_cmp_1, mat_divided_1);
assert_eq!(mat_cmp_2, mat_divided_2);
}
#[test]
fn different_dimensions_correctness() {
let mat_1 = MatZ::from_str("[[-3],[0],[12]]").unwrap();
let mat_2 = MatZ::from_str("[[6, 15, 18],[3, -9, 3]]").unwrap();
let mat_cmp_1 = MatZ::from_str("[[-1],[0],[4]]").unwrap();
let mat_cmp_2 = MatZ::from_str("[[2, 5, 6],[1, -3, 1]]").unwrap();
assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact_ref(3) });
assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact_ref(3) });
assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact(3) });
assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact(3) });
}
#[test]
fn large_entries() {
let mat_1 =
MatZ::from_str(&format!("[[6],[{}],[{}]]", i64::MAX / 3, i64::MIN / 3)).unwrap();
let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MAX)).unwrap();
let mat_3 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
let mat_cmp_1 =
MatZ::from_str(&format!("[[3],[{}],[{}]]", (i64::MAX / 6), (i64::MIN / 6))).unwrap();
let mat_cmp_2 = MatZ::from_str("[[1]]").unwrap();
assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact_ref(2) });
assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact_ref(i64::MAX) });
assert_eq!(mat_cmp_2, unsafe { mat_3.div_exact_ref(i64::MIN) });
assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact(2) });
assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact(i64::MAX) });
assert_eq!(mat_cmp_2, unsafe { mat_3.div_exact(i64::MIN) });
}
#[test]
#[should_panic]
fn div_by_0_error() {
let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
let _mat = unsafe { mat.div_exact(0) };
}
#[test]
#[should_panic]
fn div_by_0_error_ref() {
let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
let _mat = unsafe { mat.div_exact_ref(0) };
}
}
#[cfg(test)]
mod test_div {
use super::*;
use std::str::FromStr;
#[test]
fn availability() {
let mat = MatZ::from_str("[[6, 5],[2, 6]]").unwrap();
let divisor = Z::from(3);
let _ = &mat / &divisor;
let _ = mat.clone() / &divisor;
let _ = &mat / divisor.clone();
let _ = mat / divisor;
}
#[test]
fn division_correctness() {
let mat = MatZ::from_str("[[6, 5],[2, 6]]").unwrap();
let divisor = Z::from(3);
let mat_q = &mat / &divisor;
let mat_cmp = MatQ::from_str("[[2, 5/3],[2/3, 2]]").unwrap();
assert_eq!(mat_cmp, mat_q);
}
#[test]
fn different_dimensions_correctness() {
let mat_1 = MatZ::from_str("[[4],[0],[12]]").unwrap();
let mat_2 = MatZ::from_str("[[6, 15, 18],[3, 10, 3]]").unwrap();
let divisor = Z::from(3);
let mat_cmp_1 = MatQ::from_str("[[4/3],[0],[4]]").unwrap();
let mat_cmp_2 = MatQ::from_str("[[2, 5, 6],[1, 10/3, 1]]").unwrap();
assert_eq!(mat_cmp_1, mat_1 / &divisor);
assert_eq!(mat_cmp_2, mat_2 / divisor);
}
#[test]
fn large_entries() {
let mat_1 =
MatZ::from_str(&format!("[[6],[{}],[{}]]", i64::MAX / 3, i64::MIN / 3)).unwrap();
let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MAX)).unwrap();
let mat_3 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
let divisor_1 = Z::from(2);
let divisor_2 = Z::from(i64::MAX);
let divisor_3 = Z::from(i64::MIN);
let mat_cmp_1 =
MatQ::from_str(&format!("[[3],[{}],[{}]]", (i64::MAX / 6), (i64::MIN / 6))).unwrap();
let mat_cmp_2 = MatQ::from_str("[[1]]").unwrap();
assert_eq!(mat_cmp_1, mat_1 / divisor_1);
assert_eq!(mat_cmp_2, mat_2 / divisor_2);
assert_eq!(mat_cmp_2, mat_3 / divisor_3);
}
#[test]
#[should_panic]
fn div_by_0_error() {
let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
let divisor = Z::ZERO;
let _mat = mat / divisor;
}
#[test]
fn doctest_correct() {
let mat = MatZ::from_str("[[3, 5],[9, 22]]").unwrap();
let divisor = Z::from(3);
let mat_q = &mat / &divisor;
assert_eq!("[[1, 5/3],[3, 22/3]]", mat_q.to_string());
}
}