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 p: Natural,
32 poly: Polynomial<Integer>,
34 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 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 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 #[derive(Debug, Clone)]
162 pub enum Truncated {
163 Zero {
164 p: Natural,
165 },
166 NonZero {
167 p: Natural,
168 value: Natural, shift: Integer,
170 num_digits: Natural, },
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); 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 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 let a = self.coeff(1);
412 let b = self.coeff(0);
413 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 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 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 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 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 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}