use std::fmt::{Debug, Display};
use std::hash::Hash;
use num_complex::Complex64;
use num_integer::Integer;
use num_traits::{FromPrimitive, One, ToPrimitive};
use super::numtraits::{InnerIntType, IntField, IntRing, ZSigned};
pub type IntT = i64;
pub trait Ccw {
fn ccw() -> Self;
fn is_ccw(&self) -> bool;
}
pub trait Conj {
fn conj(&self) -> Self;
}
pub trait OneImag {
fn one_i() -> Self;
fn is_one_i(&self) -> bool;
}
pub trait ReImSign {
fn re_sign(&self) -> i8;
fn im_sign(&self) -> i8;
}
pub trait IntersectUnitSegments: Sized {
fn intersect_unit_segments(s1: &(Self, Self), s2: &(Self, Self)) -> bool;
}
pub trait CellFloor: SymNum {
fn cell_floor_exact(&self) -> (i64, i64);
#[inline]
fn cell_floor(&self) -> (i64, i64) {
let exact = self.cell_floor_exact();
debug_assert_eq!(
{
let c = self.complex64();
(c.re.floor() as i64, c.im.floor() as i64)
},
exact,
"f64 fast cell_floor disagrees with cell_floor_exact",
);
exact
}
}
pub trait WithinRadius {
fn within_radius(&self, radius: i64) -> bool;
}
pub trait SymScalar: IntField + FromPrimitive + ZSigned + Debug + Display {}
impl<T: IntField + FromPrimitive + ZSigned + Debug + Display> SymScalar for T {}
pub trait SymNum: Clone + Copy + PartialEq + Eq + Hash + Debug + Display {
type Scalar: SymScalar;
fn turn() -> i8;
#[inline]
fn hturn() -> i8 {
Self::turn() / 2
}
#[inline]
fn has_qturn() -> bool {
Self::turn() % 4 == 0
}
#[inline]
fn qturn() -> i8 {
Self::turn() / 4
}
#[inline]
fn opt_qturn() -> Option<i8> {
if Self::has_qturn() {
Some(Self::qturn())
} else {
None
}
}
#[inline]
fn scale<I: Integer + ToPrimitive>(&self, scalar: I) -> Self
where
Self: Sized + Copy,
{
let sc = Self::Scalar::from_i64(scalar.to_i64().unwrap()).unwrap();
let mut ret = *self;
for c in ret.zz_coeffs_mut().iter_mut() {
*c = *c * sc;
}
ret
}
fn complex64(&self) -> Complex64;
#[inline]
fn xy(&self) -> (f64, f64) {
let c = self.complex64();
(c.re, c.im)
}
fn zz_coeffs(&self) -> &[Self::Scalar];
fn zz_coeffs_mut(&mut self) -> &mut [Self::Scalar];
fn zz_pow(&self, i: u8) -> Self
where
Self: IsRing,
{
let mut base = *self;
let mut exp = i;
let mut acc = Self::one();
while exp != 0 {
if (exp & 1) == 1 {
acc = acc * base;
}
exp >>= 1;
if exp != 0 {
base = base * base;
}
}
acc
}
}
pub trait ZZComplex {
fn is_real(&self) -> bool;
fn is_imag(&self) -> bool;
fn is_complex(&self) -> bool {
!self.is_real() && !self.is_imag()
}
}
pub trait Units: Copy + One + Ccw {
fn unit(angle: i8) -> Self;
}
pub trait IsRing:
SymNum
+ Ccw
+ Conj
+ ZZComplex
+ ReImSign
+ IntersectUnitSegments
+ WithinRadius
+ CellFloor
+ Units
+ InnerIntType
+ IntRing
+ From<IntT>
+ From<<Self as InnerIntType>::IntType>
+ crate::cyclotomic::integral_basis::IntCoeffsSlice
{
}
pub trait IsZZ4Impl {}
pub trait HasZZ4Impl {}
pub trait HasZZ4: IsRing + HasZZ4Impl + From<(IntT, IntT)> {}
impl<T: IsRing + HasZZ4Impl + From<(IntT, IntT)>> HasZZ4 for T {}
pub trait IsZZ4: IsRing + IsZZ4Impl {}
impl<T: IsRing + IsZZ4Impl> IsZZ4 for T {}
pub trait HasZZ6Impl {}
pub trait HasZZ6: IsRing + HasZZ6Impl {}
impl<T: IsRing + HasZZ6Impl> HasZZ6 for T {}
pub trait HasZZ8Impl {}
pub trait HasZZ8: IsRing + HasZZ8Impl {}
impl<T: IsRing + HasZZ8Impl> HasZZ8 for T {}
pub trait HasZZ10Impl {}
pub trait HasZZ10: IsRing + HasZZ10Impl {}
impl<T: IsRing + HasZZ10Impl> HasZZ10 for T {}
pub trait HasZZ12Impl {}
pub trait HasZZ12: IsRing + HasZZ12Impl {}
impl<T: IsRing + HasZZ12Impl> HasZZ12 for T {}
impl<T: HasZZ4> OneImag for T {
fn one_i() -> Self {
<Self as Units>::unit(Self::qturn())
}
fn is_one_i(&self) -> bool {
*self == Self::one_i()
}
}