use super::Z;
use crate::traits::AsInteger;
use flint_sys::fmpz::{
fmpz, fmpz_abs, fmpz_cmpabs, fmpz_init_set, fmpz_init_set_si, fmpz_init_set_ui, fmpz_sub,
fmpz_swap,
};
pub(crate) fn find_max_abs(fmpz_vector: &Vec<fmpz>) -> Z {
let mut max = &fmpz(0);
for entry in fmpz_vector {
if unsafe { fmpz_cmpabs(max, entry) } < 0 {
max = entry;
}
}
let mut result = Z::ZERO;
unsafe { fmpz_abs(&mut result.value, max) }
result
}
pub(crate) fn distance(value_1: &fmpz, value_2: &fmpz) -> Z {
let mut out = Z::ZERO;
unsafe { fmpz_sub(&mut out.value, value_1, value_2) };
unsafe { fmpz_abs(&mut out.value, &out.value) };
out
}
unsafe impl AsInteger for u64 {
unsafe fn into_fmpz(self) -> fmpz {
unsafe { (&self).into_fmpz() }
}
}
unsafe impl AsInteger for &u64 {
unsafe fn into_fmpz(self) -> fmpz {
let mut ret_value = fmpz(0);
unsafe { fmpz_init_set_ui(&mut ret_value, *self) };
ret_value
}
}
macro_rules! implement_as_integer_over_i64 {
($($type:ident)*) => {
$(
unsafe impl AsInteger for $type {
unsafe fn into_fmpz(self) -> fmpz {
unsafe { (&self).into_fmpz() }
}
}
unsafe impl AsInteger for &$type {
unsafe fn into_fmpz(self) -> fmpz {
let mut ret_value = fmpz(0);
unsafe { fmpz_init_set_si(&mut ret_value, *self as i64) };
ret_value
}
}
)*
};
}
implement_as_integer_over_i64!(i8 u8 i16 u16 i32 u32 i64);
unsafe impl AsInteger for Z {
unsafe fn into_fmpz(mut self) -> fmpz {
let mut out = fmpz(0);
unsafe { fmpz_swap(&mut out, &mut self.value) };
out
}
fn get_fmpz_ref(&self) -> Option<&fmpz> {
Some(&self.value)
}
}
unsafe impl AsInteger for &Z {
unsafe fn into_fmpz(self) -> fmpz {
let mut value = fmpz(0);
unsafe { fmpz_init_set(&mut value, &self.value) };
value
}
fn get_fmpz_ref(&self) -> Option<&fmpz> {
Some(&self.value)
}
}
unsafe impl AsInteger for fmpz {
unsafe fn into_fmpz(self) -> fmpz {
unsafe { (&self).into_fmpz() }
}
fn get_fmpz_ref(&self) -> Option<&fmpz> {
Some(self)
}
}
unsafe impl AsInteger for &fmpz {
unsafe fn into_fmpz(self) -> fmpz {
let mut value = fmpz(0);
unsafe { fmpz_init_set(&mut value, self) };
value
}
fn get_fmpz_ref(&self) -> Option<&fmpz> {
Some(self)
}
}
#[cfg(test)]
mod test_as_integer_rust_ints {
use crate::{integer::Z, traits::AsInteger};
#[test]
fn get_fmpz_ref_none() {
assert!(10u8.get_fmpz_ref().is_none());
assert!(10u16.get_fmpz_ref().is_none());
assert!(10u32.get_fmpz_ref().is_none());
assert!(10u64.get_fmpz_ref().is_none());
assert!(10i8.get_fmpz_ref().is_none());
assert!(10i16.get_fmpz_ref().is_none());
assert!(10i32.get_fmpz_ref().is_none());
assert!(10i64.get_fmpz_ref().is_none());
}
#[test]
fn into_fmpz_small() {
let z = Z::from(10);
unsafe {
assert_eq!(z, Z::from_fmpz(10u8.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10u16.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10u32.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10u64.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10i8.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10i16.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10i32.into_fmpz()));
assert_eq!(z, Z::from_fmpz(10i64.into_fmpz()));
}
}
}
#[cfg(test)]
mod test_as_integer_z {
use super::*;
#[test]
fn small_into_fmpz() {
let z = Z::from(42);
let copy_1 = unsafe { Z::from_fmpz((&z).into_fmpz()) };
let copy_2 = unsafe { Z::from_fmpz(z.into_fmpz()) };
assert_eq!(copy_1, Z::from(42));
assert_eq!(copy_2, Z::from(42));
}
#[test]
fn large_into_fmpz() {
let z = Z::from(u64::MAX);
let copy_1 = unsafe { Z::from_fmpz((&z).into_fmpz()) };
let copy_2 = unsafe { Z::from_fmpz(z.into_fmpz()) };
assert_eq!(copy_1, Z::from(u64::MAX));
assert_eq!(copy_2, Z::from(u64::MAX));
}
#[test]
fn memory_safety() {
let z = Z::from(i64::MAX);
let value = unsafe { (&z).into_fmpz() };
assert_ne!(value.0, z.value.0);
}
#[test]
#[allow(clippy::needless_borrow)]
fn get_ref_small() {
let z = Z::from(10);
let z_ref_1 = z.get_fmpz_ref().unwrap();
let z_ref_2 = (&z).get_fmpz_ref().unwrap();
assert_eq!(z.value.0, z_ref_1.0);
assert_eq!(z.value.0, z_ref_2.0);
}
#[test]
#[allow(clippy::needless_borrow)]
fn get_ref_large() {
let z = Z::from(u64::MAX);
let z_ref_1 = z.get_fmpz_ref().unwrap();
let z_ref_2 = (&z).get_fmpz_ref().unwrap();
assert_eq!(z.value.0, z_ref_1.0);
assert_eq!(z.value.0, z_ref_2.0);
}
}
#[cfg(test)]
mod test_find_max_abs {
use super::*;
use crate::integer::MatZ;
use std::str::FromStr;
#[test]
fn positive_small() {
let mat = MatZ::from_str("[[1, 10, 100]]").unwrap();
let fmpz_vector = mat.collect_entries();
let abs_max = find_max_abs(&fmpz_vector);
assert_eq!(abs_max, Z::from(100));
}
#[test]
fn positive_large() {
let mat = MatZ::from_str(&format!("[[1, {}, {}, 10]]", i64::MAX, u64::MAX)).unwrap();
let fmpz_vector = mat.collect_entries();
let abs_max = find_max_abs(&fmpz_vector);
assert_eq!(abs_max, Z::from(u64::MAX));
}
#[test]
fn negative_small() {
let mat = MatZ::from_str("[[1, -10, -100]]").unwrap();
let fmpz_vector = mat.collect_entries();
let abs_max = find_max_abs(&fmpz_vector);
assert_eq!(abs_max, Z::from(100));
}
#[test]
fn negative_large() {
let mat = MatZ::from_str(&format!("[[1, {}, -{}, 10]]", i64::MAX, u64::MAX)).unwrap();
let fmpz_vector = mat.collect_entries();
let abs_max = find_max_abs(&fmpz_vector);
assert_eq!(abs_max, Z::from(u64::MAX));
}
}
#[cfg(test)]
mod test_distance {
use super::Z;
use super::distance;
use flint_sys::fmpz::fmpz;
#[test]
fn small_values() {
let a = fmpz(1);
let b = fmpz(-15);
let zero = fmpz(0);
assert_eq!(Z::ONE, distance(&a, &zero));
assert_eq!(Z::ONE, distance(&zero, &a));
assert_eq!(Z::from(16), distance(&a, &b));
assert_eq!(Z::from(16), distance(&b, &a));
assert_eq!(Z::from(15), distance(&b, &zero));
assert_eq!(Z::from(15), distance(&zero, &b));
assert_eq!(Z::ZERO, distance(&b, &b));
assert_eq!(Z::ZERO, distance(&a, &a));
assert_eq!(Z::ZERO, distance(&zero, &zero));
}
#[test]
fn large_values() {
let a = Z::from(i64::MAX);
let b = Z::from(i64::MIN);
let zero = Z::ZERO;
let b_abs = Z::ZERO - &b;
assert_eq!(&a - &b, distance(&a.value, &b.value));
assert_eq!(&a - &b, distance(&b.value, &a.value));
assert_eq!(a, distance(&a.value, &zero.value));
assert_eq!(a, distance(&zero.value, &a.value));
assert_eq!(b_abs, distance(&b.value, &zero.value));
assert_eq!(b_abs, distance(&zero.value, &b.value));
assert_eq!(zero, distance(&a.value, &a.value));
assert_eq!(zero, distance(&b.value, &b.value));
}
}