use std::iter::{once, repeat, repeat_n};
use itertools::{Either, Itertools};
use crate::{
divisible::{Divisible, Prime},
error::{validate_digits_mod_p, AdicError, AdicResult},
local_num::{LocalOne, LocalZero},
normed::Valuation,
traits::{AdicInteger, AdicPrimitive, HasDigitDisplay, HasDigits},
EAdic, Polynomial, UAdic, Variety,
};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ZAdic {
pub (super) c: Valuation<usize>,
pub (super) variant: EAdic,
}
impl ZAdic {
pub fn new_approx<P>(p: P, certainty: usize, mut init_digits: Vec<u32>) -> Self
where P: Into<Prime> {
let p = p.into();
validate_digits_mod_p(p, &init_digits);
init_digits.truncate(certainty);
Self {
c: certainty.into(),
variant: UAdic::new(p, init_digits).into(),
}
}
pub fn empty<P>(p: P) -> Self
where P: Into<Prime> {
let p = p.into();
Self {
c: 0.into(),
variant: UAdic::zero(p).into(),
}
}
pub (crate) fn exact_variant_or_certainty(&self) -> Either<EAdic, usize> {
match self.c {
Valuation::PosInf => Either::Left(self.variant.clone()),
Valuation::Finite(c) => Either::Right(c),
}
}
pub (crate) fn exact_variant(&self) -> EAdic {
self.variant.clone()
}
pub fn is_approx_zero(&self) -> bool {
match self.c {
Valuation::PosInf => self.is_local_zero(),
Valuation::Finite(c) => self.digits().take(c).all(|d| d.is_local_zero())
}
}
pub fn is_approx_one(&self) -> bool {
match self.c {
Valuation::PosInf => self.is_local_one(),
Valuation::Finite(0) => true,
Valuation::Finite(c) => {
self.digits().next().is_some_and(|d| d.is_local_one())
&& self.digits().take(c).skip(1).all(|d| d.is_local_zero())
},
}
}
pub fn push_digit(&mut self, digit: u32) -> AdicResult<()> {
validate_digits_mod_p(self.p(), &[digit]);
if let Valuation::Finite(c) = &mut self.c {
if self.variant.digit(*c) != Ok(digit) {
self.variant.mut_raw().truncate_and_push(*c, digit);
}
*c += 1;
Ok(())
} else {
Err(AdicError::InappropriatePrecision(
"Cannot append to infinite certainty number".to_string()
))
}
}
pub fn pop_digit(&mut self) -> AdicResult<Option<u32>> {
match &mut self.c {
Valuation::Finite(0) => Ok(None),
Valuation::Finite(c) => {
let digit = self.variant.digit(*c - 1)?;
*c -= 1;
Ok(Some(digit))
},
Valuation::PosInf => {
Err(AdicError::InappropriatePrecision(
"Cannot pop from infinite certainty number".to_string()
))
},
}
}
pub fn set_certainty(&mut self, c: Valuation<usize>) {
if self.c < c {
if let Valuation::Finite(current_c) = self.c {
self.variant.mut_raw().truncate(current_c);
}
}
self.c = c;
}
pub fn roots_of_unity<P>(p: P, precision: usize) -> AdicResult<Variety<Self>>
where P: Into<Prime> {
let p = p.into();
let n = if p.is_two() { 2 } else { u32::from(p)-1 };
ZAdic::one(p).nth_root(n, precision)
}
pub fn teichmuller<P>(p: P, precision: usize) -> AdicResult<Variety<Self>>
where P: Into<Prime> {
let p = p.into();
let zero = ZAdic::zero(p);
let one = ZAdic::one(p);
let pm2 = usize::try_from(p.m2()).expect("prime -> usize conversion");
let coeffs = once(zero.clone())
.chain(once(-one.clone()))
.chain(repeat_n(zero.clone(), pm2))
.chain(once(one.clone()))
.collect::<Vec<_>>();
let poly = Polynomial::<ZAdic>::new(coeffs);
let precision = isize::try_from(precision)?;
let variety = poly.variety(precision)?;
let zadic_variety = variety.try_into_integer()?;
Ok(zadic_variety)
}
}
impl AdicPrimitive for ZAdic {
fn zero<P>(p: P) -> Self
where P: Into<Prime> {
Self::from(UAdic::zero(p))
}
fn one<P>(p: P) -> Self
where P: Into<Prime> {
Self::from(UAdic::one(p))
}
fn p(&self) -> Prime {
self.variant.p()
}
}
impl AdicInteger for ZAdic { }
impl HasDigitDisplay for ZAdic {
type DigitDisplay = String;
fn digit_display(&self) -> String {
match self.c {
Valuation::PosInf => self.variant.digit_display(),
Valuation::Finite(c) => {
let p = self.variant.p();
let ds = self.variant.digits().chain(repeat(0)).take(c).map(|d| p.display_digit(d)).collect::<Vec<_>>();
let digits = ds.into_iter().rev().join("");
format!("...{digits}")
},
}
}
}
#[cfg(test)]
mod tests {
use num::traits::Pow;
use crate::{
error::AdicError,
local_num::LocalZero,
normed::{UltraNormed, Valuation},
traits::{CanApproximate, HasApproximateDigits, HasDigits},
Variety,
};
use super::{AdicInteger, AdicPrimitive, ZAdic};
use Valuation::Finite;
#[test]
fn approximate_z_adic() {
let zero_4 = zadic_approx!(5, 4, [0, 0, 0, 0]);
assert!(!zero_4.is_local_zero());
let one_2 = zadic_approx!(5, 2, [1]);
let two_4 = zadic_approx!(5, 4, [2]);
let five_3 = zadic_approx!(5, 3, [0, 1]);
assert_eq!(Finite(2), (one_2.clone() + one_2.clone()).certainty());
assert_eq!(Finite(2), (one_2.clone() + two_4.clone()).certainty());
assert_eq!(Finite(4), (two_4.clone() + two_4.clone()).certainty());
assert_eq!(Finite(2), (one_2.clone() + five_3.clone()).certainty());
assert_eq!(Finite(3), (two_4.clone() + five_3.clone()).certainty());
assert_eq!(Finite(2), (one_2.clone() * one_2.clone()).certainty());
assert_eq!(Finite(2), (one_2.clone() * two_4.clone()).certainty());
assert_eq!(Finite(4), (two_4.clone() * two_4.clone()).certainty());
assert_eq!(Finite(3), (one_2.clone() * five_3.clone()).certainty());
assert_eq!(Finite(3), (two_4.clone() * five_3.clone()).certainty());
assert_eq!(Finite(4), (five_3.clone() * five_3.clone()).certainty());
let small_z = zadic_approx!(5, 3, [4, 3, 2, 1, 2]);
assert_eq!(Finite(0), small_z.valuation());
assert_eq!(Finite(3), small_z.certainty());
assert_eq!(Finite(3), small_z.significance());
assert_eq!(vec![4, 3, 2], small_z.digits().collect::<Vec<_>>());
}
#[test]
fn empty_z_adic() {
let empty = ZAdic::empty(5);
let (unit, val) = empty.unit_and_valuation();
assert_eq!(None, unit);
assert_eq!(Valuation::Finite(0), val);
assert_eq!(empty, empty.clone() + zadic_approx!(5, 4, [1]));
assert_eq!(empty, empty.clone() * zadic_approx!(5, 4, [1]));
assert_eq!(ZAdic::zero(5), empty.clone() * ZAdic::zero(5));
let smaller_empty = ZAdic::from_prime(5).into_approximation(1);
let (unit, val) = smaller_empty.unit_and_valuation();
assert_eq!(None, unit);
assert_eq!(Valuation::Finite(1), val);
}
#[test]
fn nth_root() {
let check = |a: &ZAdic, n: u32, precision: usize, roots: Vec<ZAdic>| {
for root in &roots {
assert_eq!(a.approximation(precision), root.clone().pow(n));
}
assert_eq!(Ok(Variety::new(roots)), a.nth_root(n, precision));
};
check(&ZAdic::from(uadic!(5, [1])), 2, 6, vec![
zadic_approx!(5, 6, [1]),
zadic_approx!(5, 6, [4, 4, 4, 4, 4, 4]),
]);
check(&zadic_approx!(5, 12, [1]), 2, 6, vec![
zadic_approx!(5, 6, [1]),
zadic_approx!(5, 6, [4, 4, 4, 4, 4, 4]),
]);
check(&ZAdic::from(uadic!(5, [2])), 2, 6, vec![]);
check(&zadic_approx!(5, 12, [2]), 2, 6, vec![]);
check(&ZAdic::from(uadic!(7, [2])), 2, 6, vec![
zadic_approx!(7, 6, [3, 1, 2, 6, 1, 2]),
zadic_approx!(7, 6, [4, 5, 4, 0, 5, 4]),
]);
check(&zadic_approx!(7, 12, [2]), 2, 6, vec![
zadic_approx!(7, 6, [3, 1, 2, 6, 1, 2]),
zadic_approx!(7, 6, [4, 5, 4, 0, 5, 4]),
]);
assert!(matches!(
zadic_approx!(7, 4, [2]).nth_root(2, 6),
Err(AdicError::InappropriatePrecision(_))
));
}
}