use crate::{
divisible::Prime,
error::{AdicError, AdicResult},
normed::{Valuation, ValuationRing},
traits::{AdicInteger, AdicPrimitive, CanTruncate},
Polynomial, UAdic, Variety, ZAdic,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct QAdic<A>
where A: AdicInteger {
pub (super) internal_int: A,
pub (super) valuation: Valuation<isize>,
}
impl<A> QAdic<A>
where A: AdicInteger {
pub fn new<V>(adic_int: A, valuation: V) -> Self
where V: Into<Valuation<isize>> {
let p = adic_int.p();
let (adic_unit, int_valuation) = adic_int.unit_and_valuation();
match (valuation.into(), int_valuation) {
(Valuation::Finite(v), Valuation::Finite(iv)) => {
let iv = iv.try_into_isize().expect("valuation conversion");
let adjusted_valuation = v + iv;
let internal_int = if let Some(unit) = adic_unit {
unit
} else if iv > 0 {
let uv = iv.try_into_usize().expect("valuation conversion");
adic_int.quotient(uv)
} else {
let val_adjust = A::from_prime_power((p, (-iv).try_into_u32().expect("valuation conversion")));
adic_int * val_adjust
};
Self {
internal_int,
valuation: adjusted_valuation.into(),
}
},
_ => Self::zero(p),
}
}
pub fn frac_and_int(&self) -> (QAdic<UAdic>, A) {
self.split(0)
}
pub fn from_integer(adic_int: A) -> Self {
Self::new(adic_int, 0)
}
pub fn try_into_integer(self) -> AdicResult<A> {
let (frac, int) = self.frac_and_int();
if frac == QAdic::zero(self.p()) {
Ok(int)
} else {
Err(AdicError::AdicIntegerExpected)
}
}
pub fn nth_root(&self, n: u32, precision: isize) -> AdicResult<Variety<QAdic<ZAdic>>>
where Self: Into<QAdic<ZAdic>> {
let adic_frac: QAdic<ZAdic> = self.clone().into();
let variety = Polynomial::<QAdic<ZAdic>>::nth_root_polynomial(adic_frac, n).variety(precision)?;
Ok(variety)
}
pub fn num_nth_roots(&self, n: u32) -> AdicResult<usize>
where Self: Into<QAdic<ZAdic>> {
let adic_frac: QAdic<ZAdic> = self.clone().into();
Polynomial::<QAdic<ZAdic>>::nth_root_polynomial(adic_frac.clone(), n).variety_size()
}
}
impl QAdic<ZAdic> {
pub fn empty<P, V>(p: P, v: V) -> Self
where P: Into<Prime>, V: Into<Valuation<isize>> {
QAdic::new(ZAdic::empty(p), v)
}
}
impl<A> AdicPrimitive for QAdic<A>
where A: AdicInteger {
fn zero<P>(p: P) -> Self
where P: Into<Prime> {
Self {
internal_int: A::zero(p),
valuation: Valuation::PosInf,
}
}
fn one<P>(p: P) -> Self
where P: Into<Prime> {
Self {
internal_int: A::one(p),
valuation: Valuation::Finite(0),
}
}
fn p(&self) -> Prime {
self.internal_int.p()
}
}