use std::fmt;
use std::marker::PhantomData;
use num_bigint::BigInt;
use num_integer::ExtendedGcd;
use num_rational::Ratio;
use num_traits::{One, Signed, Zero};
use super::traits::{EuclideanDomain, Field, Ring};
use crate::base::numeric::Q;
pub trait CoeffDomain: Clone + fmt::Debug {
type El: Clone + PartialEq + fmt::Debug;
fn zero(&self) -> Self::El;
fn one(&self) -> Self::El;
fn embed_u64(&self, n: u64) -> Self::El;
fn is_zero(&self, a: &Self::El) -> bool;
fn is_one(&self, a: &Self::El) -> bool;
fn add(&self, a: &Self::El, b: &Self::El) -> Self::El;
fn sub(&self, a: &Self::El, b: &Self::El) -> Self::El;
fn mul(&self, a: &Self::El, b: &Self::El) -> Self::El;
fn neg(&self, a: &Self::El) -> Self::El;
fn inv(&self, a: &Self::El) -> Option<Self::El>;
fn dense_mul(&self, a: &[Self::El], b: &[Self::El]) -> Option<Vec<Self::El>> {
let _ = (a, b);
None
}
fn dense_gcd(&self, a: &[Self::El], b: &[Self::El]) -> Option<Vec<Self::El>> {
let _ = (a, b);
None
}
fn dense_extended_gcd(
&self,
a: &[Self::El],
b: &[Self::El],
) -> Option<ExtendedGcd<Vec<Self::El>>> {
let _ = (a, b);
None
}
fn dense_resultant(&self, a: &[Self::El], b: &[Self::El]) -> Option<Self::El> {
let _ = (a, b);
None
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct QQ;
impl CoeffDomain for QQ {
type El = Q;
#[inline]
fn zero(&self) -> Q {
<Q as Zero>::zero()
}
#[inline]
fn one(&self) -> Q {
<Q as One>::one()
}
#[inline]
fn embed_u64(&self, n: u64) -> Q {
Q::from_integer(BigInt::from(n))
}
#[inline]
fn is_zero(&self, a: &Q) -> bool {
Zero::is_zero(a)
}
#[inline]
fn is_one(&self, a: &Q) -> bool {
One::is_one(a)
}
#[inline]
fn add(&self, a: &Q, b: &Q) -> Q {
Ring::add(a, b)
}
#[inline]
fn sub(&self, a: &Q, b: &Q) -> Q {
Ring::sub(a, b)
}
#[inline]
fn mul(&self, a: &Q, b: &Q) -> Q {
Ring::mul(a, b)
}
#[inline]
fn neg(&self, a: &Q) -> Q {
Ring::neg(a)
}
#[inline]
fn inv(&self, a: &Q) -> Option<Q> {
(!Zero::is_zero(a)).then(|| Field::inv(a))
}
fn dense_mul(&self, a: &[Q], b: &[Q]) -> Option<Vec<Q>> {
<Q as Ring>::poly_mul(a, b)
}
fn dense_gcd(&self, a: &[Q], b: &[Q]) -> Option<Vec<Q>> {
<Q as Field>::poly_gcd(a, b)
}
fn dense_extended_gcd(&self, a: &[Q], b: &[Q]) -> Option<ExtendedGcd<Vec<Q>>> {
<Q as Field>::poly_extended_gcd(a, b)
}
fn dense_resultant(&self, a: &[Q], b: &[Q]) -> Option<Q> {
<Q as Field>::poly_resultant(a, b)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct ZZ;
impl CoeffDomain for ZZ {
type El = BigInt;
#[inline]
fn zero(&self) -> BigInt {
<BigInt as Zero>::zero()
}
#[inline]
fn one(&self) -> BigInt {
<BigInt as One>::one()
}
#[inline]
fn embed_u64(&self, n: u64) -> BigInt {
BigInt::from(n)
}
#[inline]
fn is_zero(&self, a: &BigInt) -> bool {
Zero::is_zero(a)
}
#[inline]
fn is_one(&self, a: &BigInt) -> bool {
One::is_one(a)
}
#[inline]
fn add(&self, a: &BigInt, b: &BigInt) -> BigInt {
a + b
}
#[inline]
fn sub(&self, a: &BigInt, b: &BigInt) -> BigInt {
a - b
}
#[inline]
fn mul(&self, a: &BigInt, b: &BigInt) -> BigInt {
a * b
}
#[inline]
fn neg(&self, a: &BigInt) -> BigInt {
-a
}
#[inline]
fn inv(&self, a: &BigInt) -> Option<BigInt> {
One::is_one(&a.abs()).then(|| a.clone())
}
}
pub struct FieldOf<C>(PhantomData<fn() -> C>);
impl<C> FieldOf<C> {
pub const fn new() -> Self {
FieldOf(PhantomData)
}
}
impl<C> Default for FieldOf<C> {
fn default() -> Self {
Self::new()
}
}
impl<C> Clone for FieldOf<C> {
fn clone(&self) -> Self {
*self
}
}
impl<C> Copy for FieldOf<C> {}
impl<C> fmt::Debug for FieldOf<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FieldOf<{}>", std::any::type_name::<C>())
}
}
impl<C: Field> CoeffDomain for FieldOf<C> {
type El = C;
#[inline]
fn zero(&self) -> C {
C::zero()
}
#[inline]
fn one(&self) -> C {
C::one()
}
fn embed_u64(&self, n: u64) -> C {
let mut acc = C::zero();
for i in (0..u64::BITS - n.leading_zeros()).rev() {
acc = acc.add(&acc);
if (n >> i) & 1 == 1 {
acc = acc.add(&C::one());
}
}
acc
}
#[inline]
fn is_zero(&self, a: &C) -> bool {
a.is_zero()
}
#[inline]
fn is_one(&self, a: &C) -> bool {
a.is_one()
}
#[inline]
fn add(&self, a: &C, b: &C) -> C {
a.add(b)
}
#[inline]
fn sub(&self, a: &C, b: &C) -> C {
a.sub(b)
}
#[inline]
fn mul(&self, a: &C, b: &C) -> C {
a.mul(b)
}
#[inline]
fn neg(&self, a: &C) -> C {
a.neg()
}
#[inline]
fn inv(&self, a: &C) -> Option<C> {
(!a.is_zero()).then(|| Field::inv(a))
}
fn dense_mul(&self, a: &[C], b: &[C]) -> Option<Vec<C>> {
C::poly_mul(a, b)
}
fn dense_gcd(&self, a: &[C], b: &[C]) -> Option<Vec<C>> {
C::poly_gcd(a, b)
}
fn dense_extended_gcd(&self, a: &[C], b: &[C]) -> Option<ExtendedGcd<Vec<C>>> {
C::poly_extended_gcd(a, b)
}
fn dense_resultant(&self, a: &[C], b: &[C]) -> Option<C> {
C::poly_resultant(a, b)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct GaussQ {
pub re: Q,
pub im: Q,
}
impl GaussQ {
pub fn real(re: Q) -> GaussQ {
GaussQ {
re,
im: <Q as Zero>::zero(),
}
}
pub fn i() -> GaussQ {
GaussQ {
re: <Q as Zero>::zero(),
im: <Q as One>::one(),
}
}
pub fn is_zero(&self) -> bool {
Zero::is_zero(&self.re) && Zero::is_zero(&self.im)
}
#[must_use]
pub fn add(&self, o: &GaussQ) -> GaussQ {
GaussQ {
re: &self.re + &o.re,
im: &self.im + &o.im,
}
}
#[must_use]
pub fn sub(&self, o: &GaussQ) -> GaussQ {
GaussQ {
re: &self.re - &o.re,
im: &self.im - &o.im,
}
}
#[must_use]
pub fn mul(&self, o: &GaussQ) -> GaussQ {
if Zero::is_zero(&self.im) && Zero::is_zero(&o.im) {
return GaussQ::real(&self.re * &o.re);
}
GaussQ {
re: &self.re * &o.re - &self.im * &o.im,
im: &self.re * &o.im + &self.im * &o.re,
}
}
#[must_use]
pub fn neg(&self) -> GaussQ {
GaussQ {
re: -&self.re,
im: -&self.im,
}
}
pub fn recip(&self) -> Option<GaussQ> {
if self.is_zero() {
return None;
}
if Zero::is_zero(&self.im) {
return Some(GaussQ::real(self.re.recip()));
}
let n = &self.re * &self.re + &self.im * &self.im;
Some(GaussQ {
re: &self.re / &n,
im: -(&self.im / &n),
})
}
}
impl Ring for GaussQ {
fn zero() -> Self {
GaussQ::real(<Q as Zero>::zero())
}
fn one() -> Self {
GaussQ::real(<Q as One>::one())
}
fn is_zero(&self) -> bool {
GaussQ::is_zero(self)
}
fn add(&self, rhs: &Self) -> Self {
GaussQ::add(self, rhs)
}
fn sub(&self, rhs: &Self) -> Self {
GaussQ::sub(self, rhs)
}
fn mul(&self, rhs: &Self) -> Self {
GaussQ::mul(self, rhs)
}
fn neg(&self) -> Self {
GaussQ::neg(self)
}
}
impl EuclideanDomain for GaussQ {
fn div_rem(&self, other: &Self) -> (Self, Self) {
(Field::div(self, other), <GaussQ as Ring>::zero())
}
}
impl Field for GaussQ {
fn div(&self, other: &Self) -> Self {
GaussQ::mul(self, &Field::inv(other))
}
fn inv(&self) -> Self {
self.recip().unwrap_or_else(<GaussQ as Ring>::zero)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct GaussQQ;
impl CoeffDomain for GaussQQ {
type El = GaussQ;
fn zero(&self) -> GaussQ {
<GaussQ as Ring>::zero()
}
fn one(&self) -> GaussQ {
<GaussQ as Ring>::one()
}
fn embed_u64(&self, n: u64) -> GaussQ {
GaussQ::real(Ratio::from_integer(BigInt::from(n)))
}
fn is_zero(&self, a: &GaussQ) -> bool {
a.is_zero()
}
fn is_one(&self, a: &GaussQ) -> bool {
Zero::is_zero(&a.im) && One::is_one(&a.re)
}
fn add(&self, a: &GaussQ, b: &GaussQ) -> GaussQ {
a.add(b)
}
fn sub(&self, a: &GaussQ, b: &GaussQ) -> GaussQ {
a.sub(b)
}
fn mul(&self, a: &GaussQ, b: &GaussQ) -> GaussQ {
a.mul(b)
}
fn neg(&self, a: &GaussQ) -> GaussQ {
a.neg()
}
fn inv(&self, a: &GaussQ) -> Option<GaussQ> {
a.recip()
}
}