algebraeon_rings/isolated_algebraic/padic/
mod.rs

1use crate::{
2    isolated_algebraic::poly_tools::{root_product_poly, root_rat_mul_poly, root_sum_poly},
3    polynomial::*,
4    structure::*,
5    valuation::*,
6};
7use algebraeon_nzq::*;
8use algebraeon_sets::structure::*;
9mod isolate;
10
11#[derive(Debug, Clone)]
12pub struct IsolatingBall {
13    p: Natural,
14    c: Rational,
15    v: Valuation,
16}
17
18impl IsolatingBall {
19    pub fn overlap(x: &Self, y: &Self) -> bool {
20        let p = &x.p;
21        debug_assert_eq!(p, &y.p);
22        debug_assert!(p.is_irreducible());
23        let vdiff = padic_rat_valuation(p, &x.c - &y.c);
24        vdiff >= x.v && vdiff >= y.v
25    }
26}
27
28#[derive(Debug, Clone)]
29pub struct PAdicAlgebraicRoot {
30    // A prime number
31    p: Natural,
32    // An irreducible primitive fav-assoc polynomial of degree >= 2
33    poly: Polynomial<Integer>,
34    // A p-adic isolating ball containing exactly one root of the polynomial
35    approx: isolate::PAdicRationalBall,
36}
37
38impl PAdicAlgebraicRoot {
39    fn new(p: Natural, poly: Polynomial<Integer>, approx: isolate::PAdicRationalBall) -> Self {
40        debug_assert!(p.is_irreducible());
41        debug_assert!(poly.is_irreducible());
42        Self { p, poly, approx }
43    }
44
45    pub fn refine(&mut self, ndigits: &Integer) {
46        while self.approx.ndigits() < ndigits {
47            self.approx = isolate::refine(
48                &self.p,
49                &self.poly,
50                &self.approx,
51                self.approx.ndigits() + Integer::ONE,
52            );
53            // verify that the root was lifted correctly
54            debug_assert_eq!(
55                PAdicRational::from_rational(
56                    self.p.clone(),
57                    self.poly
58                        .apply_map(|coeff| Rational::from(coeff))
59                        .evaluate(self.approx.center())
60                )
61                .truncate(self.approx.ndigits())
62                .rational_value(),
63                Rational::ZERO
64            );
65        }
66    }
67
68    pub fn isolating_ball(&self) -> IsolatingBall {
69        IsolatingBall {
70            p: self.p.clone(),
71            c: self.approx.center().clone(),
72            v: Valuation::Finite(self.approx.ndigits().clone()),
73        }
74    }
75}
76
77#[derive(Debug, Clone)]
78pub struct PAdicRational {
79    // A prime number
80    p: Natural,
81    rat: Rational,
82}
83
84impl PAdicRational {
85    pub fn from_rational(p: Natural, rat: Rational) -> Self {
86        debug_assert!(p.is_irreducible());
87        Self { p, rat }
88    }
89
90    pub fn isolating_ball(&self) -> IsolatingBall {
91        IsolatingBall {
92            p: self.p.clone(),
93            c: self.rat.clone(),
94            v: Valuation::Infinity,
95        }
96    }
97}
98
99#[derive(Debug, Clone)]
100pub enum PAdicAlgebraic {
101    Rational(PAdicRational),
102    Algebraic(PAdicAlgebraicRoot),
103}
104
105impl PAdicAlgebraic {
106    pub fn structure(p: Natural) -> PAdicAlgebraicStructure {
107        PAdicAlgebraicStructure::new(p)
108    }
109}
110
111impl PAdicAlgebraic {
112    pub fn from_rational(p: Natural, rat: Rational) -> Self {
113        Self::Rational(PAdicRational::from_rational(p, rat))
114    }
115
116    pub fn p(&self) -> &Natural {
117        match self {
118            PAdicAlgebraic::Rational(x) => &x.p,
119            PAdicAlgebraic::Algebraic(x) => &x.p,
120        }
121    }
122
123    pub fn isolating_ball(&self) -> IsolatingBall {
124        match self {
125            PAdicAlgebraic::Rational(x) => x.isolating_ball(),
126            PAdicAlgebraic::Algebraic(x) => x.isolating_ball(),
127        }
128    }
129
130    pub fn refine(&mut self, ndigits: &Integer) {
131        match self {
132            PAdicAlgebraic::Rational(_) => {}
133            PAdicAlgebraic::Algebraic(x) => x.refine(ndigits),
134        }
135    }
136
137    pub fn min_poly(&self) -> Polynomial<Rational> {
138        match self {
139            PAdicAlgebraic::Rational(PAdicRational { rat, .. }) => {
140                Polynomial::from_coeffs(vec![-rat, Rational::ONE])
141            }
142            PAdicAlgebraic::Algebraic(alg) => alg.poly.apply_map(|c| Rational::from(c)),
143        }
144    }
145}
146
147impl std::fmt::Display for PAdicAlgebraic {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        let p = self.p();
150        let n = Integer::from(if p < &Natural::from(10u32) { 6 } else { 3 });
151        write!(f, "{}", self.clone().truncate(&n).string_repr())
152    }
153}
154
155pub mod truncation {
156    use algebraeon_nzq::traits::{Abs, DivMod, Fraction};
157
158    use super::*;
159
160    // Represent value * p^shift with 0 <= value < p^digits
161    #[derive(Debug, Clone)]
162    pub enum Truncated {
163        Zero {
164            p: Natural,
165        },
166        NonZero {
167            p: Natural,
168            value: Natural, // non-zero mod p i.e. valuation 0
169            shift: Integer,
170            num_digits: Natural, // >= 1
171        },
172    }
173
174    impl Truncated {
175        pub fn digits(&self) -> Option<(Vec<Natural>, Integer)> {
176            match self {
177                Truncated::Zero { .. } => None,
178                Truncated::NonZero {
179                    p,
180                    value,
181                    shift,
182                    num_digits,
183                } => Some({
184                    let mut k = Natural::ZERO;
185                    let mut digits = vec![];
186                    let mut v = value.clone();
187                    while &k < num_digits {
188                        let r;
189                        (v, r) = v.div_mod(p);
190                        digits.push(r);
191                        k += Natural::ONE;
192                    }
193                    (digits, shift.clone())
194                }),
195            }
196        }
197
198        pub fn rational_value(&self) -> Rational {
199            match self {
200                Truncated::Zero { .. } => Rational::ZERO,
201                Truncated::NonZero {
202                    p, value, shift, ..
203                } => Rational::from(value) * Rational::from(p).try_int_pow(shift).unwrap(),
204            }
205        }
206
207        pub fn string_repr(&self) -> String {
208            let p = match self {
209                Truncated::Zero { p } | Truncated::NonZero { p, .. } => p,
210            };
211            match self.digits() {
212                None => "0".into(),
213                Some((digits, mut shift)) => {
214                    use std::fmt::Write;
215                    let seps = p >= &Natural::from(10u32);
216                    let mut rev_digits = digits.into_iter().rev().collect::<Vec<_>>();
217                    while shift > Integer::ZERO {
218                        rev_digits.push(Natural::ZERO);
219                        shift -= Integer::ONE;
220                    }
221                    debug_assert!(shift <= Integer::ZERO);
222                    let shift = (-shift).abs();
223                    let mut s = String::new();
224                    write!(&mut s, "...").unwrap();
225                    for (i, d) in rev_digits.into_iter().rev().enumerate().rev() {
226                        write!(&mut s, "{}", d).unwrap();
227                        #[allow(clippy::collapsible_else_if)]
228                        if i != 0 {
229                            if seps {
230                                if Integer::from(i) == shift {
231                                    write!(&mut s, ";").unwrap();
232                                } else {
233                                    write!(&mut s, ",").unwrap();
234                                }
235                            } else {
236                                if Integer::from(i) == shift {
237                                    write!(&mut s, ".").unwrap();
238                                }
239                            }
240                        }
241                    }
242                    s
243                }
244            }
245        }
246    }
247
248    impl PAdicRational {
249        pub fn truncate(&self, cutoffv: &Integer) -> Truncated {
250            match padic_rat_valuation(&self.p, self.rat.clone()) {
251                Valuation::Finite(shift) => {
252                    let shifted_rat =
253                        &self.rat * Rational::from(&self.p).try_int_pow(&-&shift).unwrap();
254                    let (n, d) = shifted_rat.numerator_and_denominator();
255                    let d = Integer::from(d);
256                    debug_assert_eq!(
257                        padic_int_valuation(&self.p, n.clone()).unwrap_nat(),
258                        Natural::ZERO
259                    );
260                    debug_assert_eq!(
261                        padic_int_valuation(&self.p, d.clone()).unwrap_nat(),
262                        Natural::ZERO
263                    );
264                    if cutoffv <= &shift {
265                        Truncated::Zero { p: self.p.clone() }
266                    } else {
267                        let num_digits = cutoffv - &shift;
268                        debug_assert!(num_digits >= Integer::ONE);
269                        let num_digits = num_digits.abs();
270                        let pn = Integer::from(&self.p).nat_pow(&num_digits); // p^{num_digits}
271                        let (g, _, d_inv) = Integer::xgcd(&pn, &d);
272                        debug_assert_eq!(g, Integer::ONE);
273                        let value = Integer::rem(&(n * d_inv), &pn);
274                        debug_assert!(value > Integer::ZERO);
275                        let value = value.abs();
276                        Truncated::NonZero {
277                            p: self.p.clone(),
278                            value,
279                            shift,
280                            num_digits,
281                        }
282                    }
283                }
284                Valuation::Infinity => Truncated::Zero { p: self.p.clone() },
285            }
286        }
287    }
288
289    impl PAdicAlgebraicRoot {
290        pub fn truncate(&mut self, modulus_pow: &Integer) -> Truncated {
291            self.refine(modulus_pow);
292            let rat = self.approx.center();
293            PAdicRational {
294                p: self.p.clone(),
295                rat: rat.clone(),
296            }
297            .truncate(modulus_pow)
298        }
299    }
300
301    impl PAdicAlgebraic {
302        // Truncate modulo p^cutoffv
303        // e.g.
304        //  cutoffv=0 is modulo 1
305        //  cutoffv=1 is modulo p
306        pub fn truncate(&mut self, cutoffv: &Integer) -> Truncated {
307            match self {
308                PAdicAlgebraic::Rational(a) => a.truncate(cutoffv),
309                PAdicAlgebraic::Algebraic(a) => a.truncate(cutoffv),
310            }
311        }
312    }
313
314    #[cfg(test)]
315    mod tests {
316        use super::*;
317
318        #[test]
319        fn test_padic_digits() {
320            assert_eq!(
321                PAdicAlgebraic::from_rational(Natural::from(2u32), Rational::ZERO,)
322                    .truncate(&6.into())
323                    .digits(),
324                None
325            );
326
327            assert_eq!(
328                PAdicAlgebraic::from_rational(
329                    Natural::from(2u32),
330                    Rational::from_integers(Integer::from(9), Integer::from(1)),
331                )
332                .truncate(&0.into())
333                .digits(),
334                None
335            );
336
337            assert_eq!(
338                PAdicAlgebraic::from_rational(
339                    Natural::from(2u32),
340                    Rational::from_integers(Integer::from(9), Integer::from(1)),
341                )
342                .truncate(&6.into())
343                .digits(),
344                Some((
345                    vec![
346                        Natural::from(1u32),
347                        Natural::from(0u32),
348                        Natural::from(0u32),
349                        Natural::from(1u32),
350                        Natural::from(0u32),
351                        Natural::from(0u32),
352                    ],
353                    Integer::from(0)
354                ))
355            );
356
357            assert_eq!(
358                PAdicAlgebraic::from_rational(
359                    Natural::from(2u32),
360                    Rational::from_integers(Integer::from(10), Integer::from(1)),
361                )
362                .truncate(&6.into())
363                .digits(),
364                Some((
365                    vec![
366                        Natural::from(1u32),
367                        Natural::from(0u32),
368                        Natural::from(1u32),
369                        Natural::from(0u32),
370                        Natural::from(0u32),
371                    ],
372                    Integer::from(1)
373                ))
374            );
375
376            assert_eq!(
377                PAdicAlgebraic::from_rational(
378                    Natural::from(2u32),
379                    Rational::from_integers(Integer::from(31), Integer::from(36)),
380                )
381                .truncate(&10.into())
382                .digits(),
383                Some((
384                    vec![
385                        Natural::from(1u32),
386                        Natural::from(1u32),
387                        Natural::from(1u32),
388                        Natural::from(0u32),
389                        Natural::from(0u32),
390                        Natural::from(1u32),
391                        Natural::from(1u32),
392                        Natural::from(1u32),
393                        Natural::from(0u32),
394                        Natural::from(0u32),
395                        Natural::from(0u32),
396                        Natural::from(1u32),
397                    ],
398                    Integer::from(-2)
399                ))
400            );
401        }
402    }
403}
404
405impl Polynomial<Integer> {
406    fn all_padic_roots_irreducible(&self, p: &Natural) -> Vec<PAdicAlgebraic> {
407        debug_assert!(self.is_irreducible());
408        let n = self.degree().unwrap();
409        if n == 1 {
410            // Rational root
411            let a = self.coeff(1);
412            let b = self.coeff(0);
413            // f(x) = ax + b
414            // root = -b/a
415            vec![PAdicAlgebraic::Rational(PAdicRational {
416                p: p.clone(),
417                rat: -Rational::from_integers(b.as_ref(), a.as_ref()),
418            })]
419        } else {
420            isolate::isolate(p, self)
421                .into_iter()
422                .map(|root| {
423                    PAdicAlgebraic::Algebraic(PAdicAlgebraicRoot::new(
424                        p.clone(),
425                        self.clone(),
426                        root,
427                    ))
428                })
429                .collect()
430        }
431    }
432
433    pub fn all_padic_roots(&self, p: &Natural) -> Vec<PAdicAlgebraic> {
434        debug_assert!(p.is_irreducible());
435        assert_ne!(self, &Self::zero());
436        let factors = self.factor();
437        let mut roots = vec![];
438        for (factor, k) in factors.into_powers().unwrap() {
439            for root in factor.all_padic_roots_irreducible(p) {
440                let mut i = Natural::from(0u8);
441                while i < k {
442                    roots.push(root.clone());
443                    i += Natural::from(1u8);
444                }
445            }
446        }
447        roots
448    }
449}
450
451impl Polynomial<Rational> {
452    pub fn all_padic_roots(&self, p: &Natural) -> Vec<PAdicAlgebraic> {
453        assert_ne!(self, &Self::zero());
454        self.primitive_part_fof().all_padic_roots(p)
455    }
456}
457
458impl PAdicRational {
459    fn equal(a: &Self, b: &Self) -> bool {
460        debug_assert_eq!(a.p, b.p);
461        a.rat == b.rat
462    }
463
464    fn add(a: &Self, b: &Self) -> Self {
465        let p = &a.p;
466        debug_assert_eq!(p, &b.p);
467        Self {
468            p: p.clone(),
469            rat: &a.rat + &b.rat,
470        }
471    }
472
473    fn neg(self) -> Self {
474        Self {
475            p: self.p,
476            rat: -self.rat,
477        }
478    }
479
480    fn try_inv(self) -> Option<Self> {
481        Some(Self {
482            p: self.p,
483            rat: Rational::try_reciprocal(&self.rat)?,
484        })
485    }
486}
487
488impl PAdicAlgebraicRoot {
489    fn equal_mut(a: &mut Self, b: &mut Self) -> bool {
490        debug_assert_eq!(a.p, b.p);
491        if a.poly != b.poly {
492            return false;
493        }
494        let ndigits = Integer::min(a.approx.ndigits().clone(), b.approx.ndigits().clone());
495        a.truncate(&ndigits).rational_value() == b.truncate(&ndigits).rational_value()
496    }
497
498    fn neg(mut self) -> Self {
499        self.poly = Polynomial::compose(
500            &self.poly,
501            &Polynomial::from_coeffs(vec![Integer::from(0), Integer::from(-1)]),
502        );
503        self.approx = self.approx.neg();
504        self
505    }
506
507    fn add_rat(&self, rat: &PAdicRational) -> Self {
508        /*
509        Let x be the root approximated by a: |x - a| <= v
510        Let b be the rational value
511        Then x+b is approxmated by a+b:
512            |(x+b) - (a+b)| = |x-a| <= v
513        */
514        let p = self.p.clone();
515        debug_assert_eq!(p, rat.p);
516        let poly = Polynomial::compose(
517            &self.poly.apply_map(|c| Rational::from(c)),
518            &Polynomial::from_coeffs(vec![-&rat.rat, Rational::ONE]),
519        )
520        .primitive_part_fof();
521        let approx = self.approx.clone().add_rat(&rat.rat);
522        Self { p, poly, approx }
523    }
524
525    fn add_mut(a: &mut Self, b: &mut Self) -> PAdicAlgebraic {
526        /*
527        Let x be the root approximated by a: |x - a| <= v
528        Let y be the root approximated by b: |y - b| <= w
529        Then x+y is approximated by a+b:
530            |(x + y) - (a + b)|
531            = |(x - a) + (y - b)|
532            <= max(|x - a|, |y - b|)
533            <= max(v, w)
534        */
535        let p = a.p.clone();
536        debug_assert_eq!(p, b.p);
537        let rsp = root_sum_poly(&a.poly, &b.poly);
538        let rsppsqfp = rsp.primitive_squarefree_part();
539        let mut candidates = rsppsqfp.all_padic_roots(&p);
540        let mut k = Integer::ZERO;
541        while candidates.len() > 1 {
542            a.refine(&k);
543            b.refine(&k);
544            let aball = a.isolating_ball();
545            let bball = b.isolating_ball();
546            let sball = IsolatingBall {
547                p: p.clone(),
548                c: aball.c + bball.c,
549                v: std::cmp::min(aball.v.clone(), bball.v.clone()),
550            };
551            candidates = candidates
552                .into_iter()
553                .filter_map(|mut root| {
554                    root.refine(&k);
555                    let rball = root.isolating_ball();
556                    if IsolatingBall::overlap(&rball, &sball) {
557                        Some(root)
558                    } else {
559                        None
560                    }
561                })
562                .collect();
563            k += Integer::ONE;
564        }
565        debug_assert_eq!(candidates.len(), 1);
566        candidates.into_iter().next().unwrap()
567    }
568
569    fn mul_rat(&self, rat: &PAdicRational) -> PAdicAlgebraic {
570        /*
571        Let x be the root approximated by a: |x - a| <= v
572        Let b be the rational value
573        Then xb is approxmated by ab:
574            |(xb) - (ab)|
575            <= |x-a|.|b|
576            = v.|b|
577        */
578        let p = self.p.clone();
579        debug_assert_eq!(p, rat.p);
580        if rat.rat == Rational::ZERO {
581            PAdicAlgebraic::Rational(PAdicRational {
582                p,
583                rat: Rational::ZERO,
584            })
585        } else {
586            let poly = root_rat_mul_poly(self.poly.clone(), &rat.rat);
587            let approx = self.approx.clone().mul_rat(&p, &rat.rat);
588            PAdicAlgebraic::Algebraic(Self { p, poly, approx })
589        }
590    }
591
592    fn mul_mut(a: &mut Self, b: &mut Self) -> PAdicAlgebraic {
593        /*
594        Let x be the root approximated by a: |x - a| <= v
595        Let y be the root approximated by b: |y - b| <= w
596        Then xy is approximated by ab:
597            |xy - ab|
598            = |xy - xb + xb - ab|
599            = |x(y - b) + b(x - a)|
600            <= max(|x(y - b)|, |b(x - a)|)
601            = max(|x|.|y-b|, |b|.|x - a|)
602            <= max(|x|.w, |b|.v)
603            <= |b|.v
604            By a symmetric argument it is also <= |a|.w, so
605            |xy - ab| <= max(|b|.v, |a|.w)
606
607        */
608        let p = a.p.clone();
609        debug_assert_eq!(p, b.p);
610        let mut candidates = root_product_poly(&a.poly, &b.poly)
611            .primitive_squarefree_part()
612            .all_padic_roots(&p);
613        let mut k = Integer::ZERO;
614        while candidates.len() > 1 {
615            a.refine(&k);
616            b.refine(&k);
617            let aball = a.isolating_ball();
618            let bball = b.isolating_ball();
619            let v = std::cmp::min(
620                padic_rat_valuation(&p, bball.c.clone()) * aball.v.clone(),
621                padic_rat_valuation(&p, aball.c.clone()) * bball.v.clone(),
622            );
623            let sball = IsolatingBall {
624                p: p.clone(),
625                c: aball.c * bball.c,
626                v,
627            };
628            candidates = candidates
629                .into_iter()
630                .filter_map(|mut root| {
631                    root.refine(&k);
632                    let rball = root.isolating_ball();
633                    if IsolatingBall::overlap(&rball, &sball) {
634                        Some(root)
635                    } else {
636                        None
637                    }
638                })
639                .collect();
640            k += Integer::ONE;
641        }
642        debug_assert_eq!(candidates.len(), 1);
643        candidates.into_iter().next().unwrap()
644    }
645
646    #[allow(clippy::unnecessary_wraps)]
647    fn inv_mut(&mut self) -> Option<PAdicAlgebraic> {
648        /*
649        Let x be the root approximated by a: |x-a| <= v
650        Then 1/x is approximated by 1/a:
651            |1/x - 1/a|
652            = |(a - x) / xa|
653            = |a-x| / |x|.|a|
654            <= v / |x - a + a|.|a|
655            <= v / max(|x - a|, |a|).|a|
656            <= v / max(v, |a|).|a|
657        */
658        let inv_poly = Polynomial::<Integer>::from_coeffs(
659            self.poly
660                .coeffs()
661                .collect::<Vec<_>>()
662                .into_iter()
663                .rev()
664                .collect(),
665        )
666        .fav_assoc();
667        debug_assert!(inv_poly.is_irreducible());
668        let p = self.p.clone();
669        let mut candidates = inv_poly.all_padic_roots(&p);
670        let mut k = Integer::ZERO;
671        while candidates.len() > 1 {
672            self.refine(&k);
673            let sball = self.isolating_ball();
674            if !sball.c.is_zero() {
675                let vc = padic_rat_valuation(&p, sball.c.clone());
676                #[cfg(debug_assertions)]
677                vc.clone().unwrap_int();
678                let iball = IsolatingBall {
679                    p: p.clone(),
680                    c: sball.c.try_reciprocal().unwrap(),
681                    v: &sball.v - std::cmp::min(&sball.v, &vc) - vc,
682                };
683                candidates = candidates
684                    .into_iter()
685                    .filter_map(|mut root| {
686                        root.refine(&k);
687                        let rball = root.isolating_ball();
688                        if IsolatingBall::overlap(&rball, &iball) {
689                            Some(root)
690                        } else {
691                            None
692                        }
693                    })
694                    .collect();
695            }
696            k += Integer::ONE;
697        }
698        debug_assert_eq!(candidates.len(), 1);
699        Some(candidates.into_iter().next().unwrap())
700    }
701}
702
703impl PAdicAlgebraic {
704    fn neg(self) -> Self {
705        match self {
706            PAdicAlgebraic::Rational(x) => PAdicAlgebraic::Rational(x.neg()),
707            PAdicAlgebraic::Algebraic(x) => PAdicAlgebraic::Algebraic(x.neg()),
708        }
709    }
710}
711
712#[derive(Debug, Clone, PartialEq, Eq)]
713pub struct PAdicAlgebraicStructure {
714    p: Natural,
715}
716
717impl PAdicAlgebraicStructure {
718    pub fn new(p: Natural) -> Self {
719        assert!(p.is_irreducible(), "{} is not prime", p);
720        Self { p }
721    }
722
723    pub fn p(&self) -> &Natural {
724        &self.p
725    }
726}
727
728impl Signature for PAdicAlgebraicStructure {}
729
730impl SetSignature for PAdicAlgebraicStructure {
731    type Set = PAdicAlgebraic;
732
733    fn is_element(&self, x: &Self::Set) -> Result<(), String> {
734        if &self.p != x.p() {
735            return Err("primes don't match".to_string());
736        }
737        Ok(())
738    }
739}
740
741impl EqSignature for PAdicAlgebraicStructure {
742    fn equal(&self, a: &Self::Set, b: &Self::Set) -> bool {
743        debug_assert!(self.is_element(a).is_ok());
744        debug_assert!(self.is_element(b).is_ok());
745        match (a, b) {
746            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Rational(b)) => {
747                PAdicRational::equal(a, b)
748            }
749            (PAdicAlgebraic::Rational(_), PAdicAlgebraic::Algebraic(_))
750            | (PAdicAlgebraic::Algebraic(_), PAdicAlgebraic::Rational(_)) => false,
751            (PAdicAlgebraic::Algebraic(a), PAdicAlgebraic::Algebraic(b)) => {
752                PAdicAlgebraicRoot::equal_mut(&mut a.clone(), &mut b.clone())
753            }
754        }
755    }
756}
757
758impl RinglikeSpecializationSignature for PAdicAlgebraicStructure {}
759
760impl ZeroSignature for PAdicAlgebraicStructure {
761    fn zero(&self) -> Self::Set {
762        PAdicAlgebraic::Rational(PAdicRational {
763            p: self.p.clone(),
764            rat: Rational::ZERO,
765        })
766    }
767}
768
769impl AdditionSignature for PAdicAlgebraicStructure {
770    fn add(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
771        debug_assert!(self.is_element(a).is_ok());
772        debug_assert!(self.is_element(b).is_ok());
773        match (a, b) {
774            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Rational(b)) => {
775                PAdicAlgebraic::Rational(PAdicRational::add(a, b))
776            }
777            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Algebraic(b)) => {
778                PAdicAlgebraic::Algebraic(b.add_rat(a))
779            }
780            (PAdicAlgebraic::Algebraic(a), PAdicAlgebraic::Rational(b)) => {
781                PAdicAlgebraic::Algebraic(a.add_rat(b))
782            }
783            (PAdicAlgebraic::Algebraic(a), PAdicAlgebraic::Algebraic(b)) => {
784                PAdicAlgebraicRoot::add_mut(&mut a.clone(), &mut b.clone())
785            }
786        }
787    }
788}
789
790impl CancellativeAdditionSignature for PAdicAlgebraicStructure {
791    fn try_sub(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
792        Some(self.sub(a, b))
793    }
794}
795
796impl TryNegateSignature for PAdicAlgebraicStructure {
797    fn try_neg(&self, a: &Self::Set) -> Option<Self::Set> {
798        Some(self.neg(a))
799    }
800}
801
802impl AdditiveMonoidSignature for PAdicAlgebraicStructure {}
803
804impl AdditiveGroupSignature for PAdicAlgebraicStructure {
805    fn neg(&self, a: &Self::Set) -> Self::Set {
806        debug_assert!(self.is_element(a).is_ok());
807        a.clone().neg()
808    }
809}
810
811impl OneSignature for PAdicAlgebraicStructure {
812    fn one(&self) -> Self::Set {
813        PAdicAlgebraic::Rational(PAdicRational {
814            p: self.p.clone(),
815            rat: Rational::ONE,
816        })
817    }
818}
819
820impl MultiplicationSignature for PAdicAlgebraicStructure {
821    fn mul(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
822        debug_assert!(self.is_element(a).is_ok());
823        debug_assert!(self.is_element(b).is_ok());
824        match (a, b) {
825            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Rational(b)) => {
826                PAdicAlgebraic::Rational(PAdicRational {
827                    p: self.p.clone(),
828                    rat: &a.rat * &b.rat,
829                })
830            }
831            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Algebraic(b)) => b.mul_rat(a),
832            (PAdicAlgebraic::Algebraic(a), PAdicAlgebraic::Rational(b)) => a.mul_rat(b),
833            (PAdicAlgebraic::Algebraic(a), PAdicAlgebraic::Algebraic(b)) => {
834                PAdicAlgebraicRoot::mul_mut(&mut a.clone(), &mut b.clone())
835            }
836        }
837    }
838}
839
840impl CommutativeMultiplicationSignature for PAdicAlgebraicStructure {}
841
842impl MultiplicativeMonoidSignature for PAdicAlgebraicStructure {}
843
844impl MultiplicativeAbsorptionMonoidSignature for PAdicAlgebraicStructure {}
845
846impl LeftDistributiveMultiplicationOverAddition for PAdicAlgebraicStructure {}
847
848impl RightDistributiveMultiplicationOverAddition for PAdicAlgebraicStructure {}
849
850impl SemiRingSignature for PAdicAlgebraicStructure {}
851
852impl RingSignature for PAdicAlgebraicStructure {
853    fn is_reduced(&self) -> Result<bool, String> {
854        Ok(true)
855    }
856}
857
858impl CharacteristicSignature for PAdicAlgebraicStructure {
859    fn characteristic(&self) -> Natural {
860        Natural::ZERO
861    }
862}
863
864impl TryReciprocalSignature for PAdicAlgebraicStructure {
865    fn try_reciprocal(&self, a: &PAdicAlgebraic) -> Option<PAdicAlgebraic> {
866        debug_assert!(self.is_element(a).is_ok());
867        match a {
868            PAdicAlgebraic::Rational(a) => Some(PAdicAlgebraic::Rational(a.clone().try_inv()?)),
869            PAdicAlgebraic::Algebraic(a) => Some(a.clone().inv_mut()?),
870        }
871    }
872}
873
874impl CancellativeMultiplicationSignature for PAdicAlgebraicStructure {
875    fn try_divide(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
876        debug_assert!(self.is_element(a).is_ok());
877        debug_assert!(self.is_element(b).is_ok());
878        #[allow(clippy::single_match)]
879        match (a, b) {
880            (PAdicAlgebraic::Rational(a), PAdicAlgebraic::Rational(b)) => {
881                return Some(PAdicAlgebraic::Rational(PAdicRational {
882                    p: self.p.clone(),
883                    rat: Rational::try_divide(&a.rat, &b.rat)?,
884                }));
885            }
886            _ => {}
887        }
888        Some(self.mul(a, &self.try_reciprocal(b)?))
889    }
890}
891
892impl MultiplicativeIntegralMonoidSignature for PAdicAlgebraicStructure {}
893
894impl IntegralDomainSignature for PAdicAlgebraicStructure {
895    fn try_from_rat(&self, x: &Rational) -> Option<Self::Set> {
896        Some(PAdicAlgebraic::Rational(PAdicRational {
897            p: self.p.clone(),
898            rat: x.clone(),
899        }))
900    }
901}
902
903impl FieldSignature for PAdicAlgebraicStructure {}
904
905impl CharZeroRingSignature for PAdicAlgebraicStructure {
906    fn try_to_int(&self, x: &Self::Set) -> Option<Integer> {
907        match x {
908            PAdicAlgebraic::Rational(padic_rational) => {
909                Rational::structure().try_to_int(&padic_rational.rat)
910            }
911            PAdicAlgebraic::Algebraic(_) => None,
912        }
913    }
914}
915
916impl CharZeroFieldSignature for PAdicAlgebraicStructure {
917    fn try_to_rat(&self, x: &Self::Set) -> Option<Rational> {
918        match x {
919            PAdicAlgebraic::Rational(padic_rational) => Some(padic_rational.rat.clone()),
920            PAdicAlgebraic::Algebraic(_) => None,
921        }
922    }
923}
924
925impl<B: BorrowedStructure<PAdicAlgebraicStructure>>
926    IntegralDomainExtensionAllPolynomialRoots<IntegerCanonicalStructure, PAdicAlgebraicStructure>
927    for PrincipalIntegerMap<PAdicAlgebraicStructure, B>
928{
929    fn all_roots(&self, polynomial: &Polynomial<Integer>) -> Vec<PAdicAlgebraic> {
930        polynomial.all_padic_roots(&self.range().p)
931    }
932}
933
934impl<B: BorrowedStructure<PAdicAlgebraicStructure>>
935    IntegralDomainExtensionAllPolynomialRoots<RationalCanonicalStructure, PAdicAlgebraicStructure>
936    for PrincipalRationalMap<PAdicAlgebraicStructure, B>
937{
938    fn all_roots(&self, polynomial: &Polynomial<Rational>) -> Vec<PAdicAlgebraic> {
939        polynomial.all_padic_roots(&self.range().p)
940    }
941}
942
943impl PAdicAlgebraicStructure {
944    pub fn nth_roots(&self, a: &PAdicAlgebraic, n: usize) -> Vec<PAdicAlgebraic> {
945        let mut roots = vec![];
946        for root in a
947            .min_poly()
948            .evaluate_at_var_pow(n)
949            .all_padic_roots(self.p())
950        {
951            if self.equal(a, &self.nat_pow(&root, &n.into())) {
952                roots.push(root);
953            }
954        }
955        roots
956    }
957
958    pub fn square_roots(&self, a: &PAdicAlgebraic) -> Option<(PAdicAlgebraic, PAdicAlgebraic)> {
959        let square_roots = self.nth_roots(a, 2);
960        if square_roots.is_empty() {
961            None
962        } else {
963            assert_eq!(square_roots.len(), 2);
964            let mut square_roots = square_roots.into_iter();
965            let r1 = square_roots.next().unwrap();
966            let r2 = square_roots.next().unwrap();
967            Some((r1, r2))
968        }
969    }
970
971    pub fn is_square(&self, a: &PAdicAlgebraic) -> bool {
972        self.square_roots(a).is_some()
973    }
974}
975
976#[cfg(test)]
977mod structure_tests {
978    use super::*;
979
980    #[test]
981    fn test_padic_field_operations() {
982        let ring = PAdicAlgebraicStructure::new(Natural::from(5u32));
983        let x = Polynomial::<Integer>::var().into_ergonomic();
984
985        let a = {
986            let f = (x.pow(3) - 3 * x.pow(2) - x.pow(1) + 1).into_verbose();
987            let r = f.all_padic_roots(&Natural::from(5u32));
988            assert_eq!(r.len(), 1);
989            r.into_iter().next().unwrap()
990        };
991
992        let b = {
993            let f = (x.pow(4) + x.pow(2) - 2 * x.pow(1) - 1).into_verbose();
994            let r = f.all_padic_roots(&Natural::from(5u32));
995            assert_eq!(r.len(), 1);
996            r.into_iter().next().unwrap()
997        };
998
999        let c = {
1000            let f = (x.pow(5) + x.pow(2) + 2 * x.pow(1) + 1).into_verbose();
1001            let r = f.all_padic_roots(&Natural::from(5u32));
1002            assert_eq!(r.len(), 1);
1003            r.into_iter().next().unwrap()
1004        };
1005
1006        let d = PAdicAlgebraic::from_rational(
1007            Natural::from(5u32),
1008            Rational::from_integers(Integer::from(2), Integer::from(7)),
1009        );
1010
1011        let e = PAdicAlgebraic::from_rational(
1012            Natural::from(5u32),
1013            Rational::from_integers(Integer::from(-2), Integer::from(1)),
1014        );
1015
1016        println!("a = {}", a);
1017        assert_eq!(
1018            a.clone().truncate(&6.into()).digits(),
1019            Some((
1020                vec![2, 4, 2, 1, 1, 3]
1021                    .into_iter()
1022                    .map(|d| Natural::from(d as u8))
1023                    .collect(),
1024                0.into()
1025            ))
1026        );
1027        println!("b = {}", b);
1028        assert_eq!(
1029            b.clone().truncate(&6.into()).digits(),
1030            Some((
1031                vec![2, 3, 1, 2, 0, 1]
1032                    .into_iter()
1033                    .map(|d| Natural::from(d as u8))
1034                    .collect(),
1035                0.into()
1036            ))
1037        );
1038        println!("c = {}", c);
1039        assert_eq!(
1040            c.clone().truncate(&6.into()).digits(),
1041            Some((
1042                vec![1, 1, 3, 4, 1, 0]
1043                    .into_iter()
1044                    .map(|d| Natural::from(d as u8))
1045                    .collect(),
1046                0.into()
1047            ))
1048        );
1049        println!("d = {}", d);
1050        assert_eq!(
1051            d.clone().truncate(&6.into()).digits(),
1052            Some((
1053                vec![1, 2, 1, 4, 2, 3]
1054                    .into_iter()
1055                    .map(|d| Natural::from(d as u8))
1056                    .collect(),
1057                0.into()
1058            ))
1059        );
1060        println!("e = {}", e);
1061        assert_eq!(
1062            e.clone().truncate(&6.into()).digits(),
1063            Some((
1064                vec![3, 4, 4, 4, 4, 4]
1065                    .into_iter()
1066                    .map(|d| Natural::from(d as u8))
1067                    .collect(),
1068                0.into()
1069            ))
1070        );
1071
1072        println!("-a = {}", ring.neg(&a));
1073        assert_eq!(
1074            ring.neg(&a).truncate(&6.into()).digits(),
1075            Some((
1076                vec![3, 0, 2, 3, 3, 1]
1077                    .into_iter()
1078                    .map(|d| Natural::from(d as u8))
1079                    .collect(),
1080                0.into()
1081            ))
1082        );
1083        println!("-b = {}", ring.neg(&b));
1084        assert_eq!(
1085            ring.neg(&b).truncate(&6.into()).digits(),
1086            Some((
1087                vec![3, 1, 3, 2, 4, 3]
1088                    .into_iter()
1089                    .map(|d| Natural::from(d as u8))
1090                    .collect(),
1091                0.into()
1092            ))
1093        );
1094        println!("-c = {}", ring.neg(&c));
1095        assert_eq!(
1096            ring.neg(&c).truncate(&6.into()).digits(),
1097            Some((
1098                vec![4, 3, 1, 0, 3, 4]
1099                    .into_iter()
1100                    .map(|d| Natural::from(d as u8))
1101                    .collect(),
1102                0.into()
1103            ))
1104        );
1105        println!("-d = {}", ring.neg(&d));
1106        assert_eq!(
1107            ring.neg(&d).truncate(&6.into()).digits(),
1108            Some((
1109                vec![4, 2, 3, 0, 2, 1]
1110                    .into_iter()
1111                    .map(|d| Natural::from(d as u8))
1112                    .collect(),
1113                0.into()
1114            ))
1115        );
1116        println!("-e = {}", ring.neg(&e));
1117        assert_eq!(
1118            ring.neg(&e).truncate(&6.into()).digits(),
1119            Some((
1120                vec![2, 0, 0, 0, 0, 0]
1121                    .into_iter()
1122                    .map(|d| Natural::from(d as u8))
1123                    .collect(),
1124                0.into()
1125            ))
1126        );
1127
1128        println!("a+b = {}", ring.add(&a, &b));
1129        assert_eq!(
1130            ring.add(&a, &b).truncate(&6.into()).digits(),
1131            Some((
1132                vec![4, 2, 4, 3, 1, 4]
1133                    .into_iter()
1134                    .map(|d| Natural::from(d as u8))
1135                    .collect(),
1136                0.into()
1137            ))
1138        );
1139        println!("a+c = {}", ring.add(&a, &c));
1140        assert_eq!(
1141            ring.add(&a, &c).truncate(&6.into()).digits(),
1142            Some((
1143                vec![3, 0, 1, 1, 3, 3]
1144                    .into_iter()
1145                    .map(|d| Natural::from(d as u8))
1146                    .collect(),
1147                0.into()
1148            ))
1149        );
1150        println!("d+b = {}", ring.add(&d, &b));
1151        assert_eq!(
1152            ring.add(&d, &b).truncate(&6.into()).digits(),
1153            Some((
1154                vec![3, 0, 3, 1, 3, 4]
1155                    .into_iter()
1156                    .map(|d| Natural::from(d as u8))
1157                    .collect(),
1158                0.into()
1159            ))
1160        );
1161        println!("d+c = {}", ring.add(&d, &c));
1162        assert_eq!(
1163            ring.add(&d, &c).truncate(&6.into()).digits(),
1164            Some((
1165                vec![2, 3, 4, 3, 4, 3]
1166                    .into_iter()
1167                    .map(|d| Natural::from(d as u8))
1168                    .collect(),
1169                0.into()
1170            ))
1171        );
1172        println!("c+c = {}", ring.add(&c, &c));
1173        assert_eq!(
1174            ring.add(&c, &c).truncate(&6.into()).digits(),
1175            Some((
1176                vec![2, 2, 1, 4, 3, 0]
1177                    .into_iter()
1178                    .map(|d| Natural::from(d as u8))
1179                    .collect(),
1180                0.into()
1181            ))
1182        );
1183
1184        println!("a*b = {}", ring.mul(&a, &b));
1185        assert_eq!(
1186            ring.mul(&a, &b).truncate(&6.into()).digits(),
1187            Some((
1188                vec![4, 4, 0, 0, 4, 4]
1189                    .into_iter()
1190                    .map(|d| Natural::from(d as u8))
1191                    .collect(),
1192                0.into()
1193            ))
1194        );
1195        println!("a*c = {}", ring.mul(&a, &c));
1196        assert_eq!(
1197            ring.mul(&a, &c).truncate(&6.into()).digits(),
1198            Some((
1199                vec![2, 1, 3, 0, 1, 0]
1200                    .into_iter()
1201                    .map(|d| Natural::from(d as u8))
1202                    .collect(),
1203                0.into()
1204            ))
1205        );
1206        println!("d*b = {}", ring.mul(&d, &b));
1207        assert_eq!(
1208            ring.mul(&d, &b).truncate(&6.into()).digits(),
1209            Some((
1210                vec![2, 2, 0, 2, 4, 3]
1211                    .into_iter()
1212                    .map(|d| Natural::from(d as u8))
1213                    .collect(),
1214                0.into()
1215            ))
1216        );
1217        println!("d*c = {}", ring.mul(&d, &c));
1218        assert_eq!(
1219            ring.mul(&d, &c).truncate(&6.into()).digits(),
1220            Some((
1221                vec![1, 3, 1, 1, 1, 2]
1222                    .into_iter()
1223                    .map(|d| Natural::from(d as u8))
1224                    .collect(),
1225                0.into()
1226            ))
1227        );
1228        println!("c*c = {}", ring.mul(&c, &c));
1229        assert_eq!(
1230            ring.mul(&c, &c).truncate(&6.into()).digits(),
1231            Some((
1232                vec![1, 2, 2, 0, 2, 0]
1233                    .into_iter()
1234                    .map(|d| Natural::from(d as u8))
1235                    .collect(),
1236                0.into()
1237            ))
1238        );
1239        println!("a*e = {}", ring.mul(&a, &e));
1240        assert_eq!(
1241            ring.mul(&a, &e).truncate(&6.into()).digits(),
1242            Some((
1243                vec![1, 1, 4, 1, 2, 3]
1244                    .into_iter()
1245                    .map(|d| Natural::from(d as u8))
1246                    .collect(),
1247                0.into()
1248            ))
1249        );
1250
1251        println!("a^-1 = {}", ring.try_reciprocal(&a).unwrap());
1252        assert_eq!(
1253            ring.try_reciprocal(&a)
1254                .unwrap()
1255                .truncate(&6.into())
1256                .digits(),
1257            Some((
1258                vec![3, 1, 1, 4, 2, 1]
1259                    .into_iter()
1260                    .map(|d| Natural::from(d as u8))
1261                    .collect(),
1262                0.into()
1263            ))
1264        );
1265        println!("b^-1 = {}", ring.try_reciprocal(&b).unwrap());
1266        assert_eq!(
1267            ring.try_reciprocal(&b)
1268                .unwrap()
1269                .truncate(&6.into())
1270                .digits(),
1271            Some((
1272                vec![3, 0, 0, 4, 0, 0]
1273                    .into_iter()
1274                    .map(|d| Natural::from(d as u8))
1275                    .collect(),
1276                0.into()
1277            ))
1278        );
1279        println!("c^-1 = {}", ring.try_reciprocal(&c).unwrap());
1280        assert_eq!(
1281            ring.try_reciprocal(&c)
1282                .unwrap()
1283                .truncate(&6.into())
1284                .digits(),
1285            Some((
1286                vec![1, 4, 2, 0, 3, 4]
1287                    .into_iter()
1288                    .map(|d| Natural::from(d as u8))
1289                    .collect(),
1290                0.into()
1291            ))
1292        );
1293        println!("d^-1 = {}", ring.try_reciprocal(&d).unwrap());
1294        assert_eq!(
1295            ring.try_reciprocal(&d)
1296                .unwrap()
1297                .truncate(&6.into())
1298                .digits(),
1299            Some((
1300                vec![1, 3, 2, 2, 2, 2]
1301                    .into_iter()
1302                    .map(|d| Natural::from(d as u8))
1303                    .collect(),
1304                0.into()
1305            ))
1306        );
1307        println!("e^-1 = {}", ring.try_reciprocal(&e).unwrap());
1308        assert_eq!(
1309            ring.try_reciprocal(&e)
1310                .unwrap()
1311                .truncate(&6.into())
1312                .digits(),
1313            Some((
1314                vec![2, 2, 2, 2, 2, 2]
1315                    .into_iter()
1316                    .map(|d| Natural::from(d as u8))
1317                    .collect(),
1318                0.into()
1319            ))
1320        );
1321    }
1322}
1323
1324#[cfg(test)]
1325mod tests {
1326    use super::*;
1327
1328    #[test]
1329    fn test_all_padic_roots_example1() {
1330        let x = Polynomial::<Integer>::var().into_ergonomic();
1331        let f = (16 * x.pow(2) - 17).into_verbose();
1332        println!("f = {}", f);
1333        let roots = f.all_padic_roots(&Natural::from(2u32));
1334        assert_eq!(roots.len(), 2);
1335        for root in roots {
1336            println!("{}", root);
1337        }
1338    }
1339
1340    #[test]
1341    fn test_all_padic_roots_example2() {
1342        let x = Polynomial::<Integer>::var().into_ergonomic();
1343        let f = (x.pow(6) - 2).into_verbose();
1344        println!("f = {}", f);
1345        assert_eq!(f.all_padic_roots(&Natural::from(2u32)).len(), 0);
1346        assert_eq!(f.all_padic_roots(&Natural::from(7u32)).len(), 0);
1347        assert_eq!(f.all_padic_roots(&Natural::from(727u32)).len(), 6);
1348        for root in f.all_padic_roots(&Natural::from(727u32)) {
1349            println!("{}", root);
1350        }
1351    }
1352
1353    #[test]
1354    fn test_all_padic_roots_example3() {
1355        let x = Polynomial::<Integer>::var().into_ergonomic();
1356        let f = (3 * x - 2).into_verbose();
1357        println!("{:?}", f);
1358        assert_eq!(f.all_padic_roots(&Natural::from(2u32)).len(), 1);
1359        assert_eq!(f.all_padic_roots(&Natural::from(3u32)).len(), 1);
1360        assert_eq!(f.all_padic_roots(&Natural::from(5u32)).len(), 1);
1361    }
1362}