1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8pub struct PAdicValuation {
10 pub p: u64,
12}
13impl PAdicValuation {
14 pub fn new(p: u64) -> Self {
16 Self { p }
17 }
18 pub fn valuation_of(&self, n: i64) -> i64 {
21 if n == 0 {
22 return i64::MAX;
23 }
24 let mut k = 0i64;
25 let mut m = n.unsigned_abs();
26 while m % self.p == 0 {
27 m /= self.p;
28 k += 1;
29 }
30 k
31 }
32 pub fn is_ultrametric(&self) -> bool {
35 true
36 }
37}
38pub struct PolynomialMod {
40 pub coeffs: Vec<i64>,
42 pub modulus: u64,
44}
45impl PolynomialMod {
46 pub fn new(coeffs: Vec<i64>, modulus: u64) -> Self {
48 Self { coeffs, modulus }
49 }
50 pub fn evaluate(&self, x: i64) -> i64 {
52 let m = self.modulus as i64;
53 let mut result = 0i64;
54 let mut power = 1i64;
55 for &c in &self.coeffs {
56 result = (result + c.wrapping_mul(power)) % m;
57 power = power.wrapping_mul(x) % m;
58 }
59 ((result % m) + m) % m
60 }
61 pub fn derivative(&self) -> Self {
63 if self.coeffs.is_empty() {
64 return Self::new(vec![], self.modulus);
65 }
66 let d: Vec<i64> = self
67 .coeffs
68 .iter()
69 .enumerate()
70 .skip(1)
71 .map(|(i, &c)| c.wrapping_mul(i as i64))
72 .collect();
73 Self::new(d, self.modulus)
74 }
75}
76pub struct IwasawaAlgebra {
79 pub p: u64,
81 pub group_ring: String,
83}
84impl IwasawaAlgebra {
85 pub fn new(p: u64) -> Self {
87 Self {
88 p,
89 group_ring: format!("ℤ_{p}[[Γ]]"),
90 }
91 }
92 pub fn is_noetherian(&self) -> bool {
94 true
95 }
96 pub fn krull_dimension(&self) -> usize {
98 2
99 }
100}
101pub struct PAdicNumberV2 {
106 pub p: u64,
108 pub digits: Vec<u64>,
110 pub valuation: i64,
112}
113impl PAdicNumberV2 {
114 pub fn new(p: u64, digits: Vec<u64>, valuation: i64) -> Self {
116 Self {
117 p,
118 digits,
119 valuation,
120 }
121 }
122 pub fn norm(&self) -> f64 {
124 if self.valuation == i64::MAX {
125 return 0.0;
126 }
127 (self.p as f64).powi(-(self.valuation as i32))
128 }
129 pub fn is_unit(&self) -> bool {
131 self.valuation == 0
132 }
133 pub fn is_integer(&self) -> bool {
135 self.valuation >= 0
136 }
137}
138pub struct MahlerExpansion {
141 pub coefficients: Vec<f64>,
143}
144impl MahlerExpansion {
145 pub fn new(coefficients: Vec<f64>) -> Self {
147 Self { coefficients }
148 }
149 pub fn evaluate_at_integer(&self, n: i64) -> f64 {
153 let mut result = 0.0f64;
154 for (k, &ak) in self.coefficients.iter().enumerate() {
155 if k as i64 > n {
156 break;
157 }
158 let binom = binomial_f64(n, k);
159 result += ak * binom;
160 }
161 result
162 }
163}
164pub struct PAdicValuationRing {
166 pub p: u64,
168}
169impl PAdicValuationRing {
170 pub fn new(p: u64) -> Self {
172 Self { p }
173 }
174 pub fn contains(&self, x: &PAdicNumber) -> bool {
176 x.is_integer()
177 }
178}
179pub struct LocalField {
181 pub p: u64,
183 pub residue_char: u64,
185 pub degree: usize,
187 pub ramification_index: usize,
189 pub inertia_degree: usize,
191}
192impl LocalField {
193 pub fn new(p: u64, e: usize, f: usize) -> Self {
195 Self {
196 p,
197 residue_char: p,
198 degree: e * f,
199 ramification_index: e,
200 inertia_degree: f,
201 }
202 }
203 pub fn discriminant_valuation(&self) -> i64 {
205 let e = self.ramification_index as i64;
206 let p = self.p as i64;
207 let mut vp_e = 0i64;
208 let mut tmp = e;
209 while tmp % p == 0 {
210 tmp /= p;
211 vp_e += 1;
212 }
213 (e - 1) + vp_e
214 }
215 pub fn is_tamely_ramified(&self) -> bool {
217 let e = self.ramification_index as u64;
218 e > 1 && e % self.p != 0
219 }
220 pub fn is_wildly_ramified(&self) -> bool {
222 let e = self.ramification_index as u64;
223 e % self.p == 0 && e > 1
224 }
225}
226pub struct VolkenbornIntegral {
228 pub p: u64,
230}
231impl VolkenbornIntegral {
232 pub fn new(p: u64) -> Self {
234 Self { p }
235 }
236 pub fn finite_sum_approximation(&self, poly: &[f64], precision: u32) -> f64 {
240 let pn = (self.p as f64).powi(precision as i32);
241 let n = (self.p as usize).pow(precision);
242 let sum: f64 = (0..n).map(|j| evaluate_poly(poly, j as f64)).sum();
243 sum / pn
244 }
245 pub fn normalizes_to_one(&self) -> bool {
247 true
248 }
249 pub fn bernoulli_connection_statement(&self) -> String {
251 format!(
252 "∫_{{ℤ_{}}} x^n dx_{} = B_n (the n-th Bernoulli number), \
253 relating the Volkenborn integral to special values of the Riemann zeta function.",
254 self.p, self.p
255 )
256 }
257}
258pub struct ProfiniteGroup {
260 pub name: String,
262 pub index_list: Vec<u64>,
264}
265impl ProfiniteGroup {
266 pub fn new(name: impl Into<String>) -> Self {
268 Self {
269 name: name.into(),
270 index_list: vec![],
271 }
272 }
273 pub fn is_pro_p(&self, p: u64) -> bool {
275 self.index_list.iter().all(|&idx| {
276 let mut n = idx;
277 while n > 1 {
278 if n % p != 0 {
279 return false;
280 }
281 n /= p;
282 }
283 true
284 })
285 }
286 pub fn is_abelian(&self) -> bool {
288 true
289 }
290}
291pub struct PAdicInteger {
293 pub p: u64,
295 pub digits: Vec<u64>,
297}
298impl PAdicInteger {
299 pub fn new(p: u64, n: i64) -> Self {
301 assert!(p >= 2, "p must be at least 2");
302 if n <= 0 {
303 return Self { p, digits: vec![0] };
304 }
305 let mut rem = n as u64;
306 let mut digits = Vec::new();
307 while rem > 0 {
308 digits.push(rem % p);
309 rem /= p;
310 }
311 Self { p, digits }
312 }
313 pub fn zero(p: u64) -> Self {
315 Self { p, digits: vec![0] }
316 }
317 pub fn one(p: u64) -> Self {
319 Self { p, digits: vec![1] }
320 }
321 pub fn from_digits(p: u64, digits: Vec<u64>) -> Self {
323 Self { p, digits }
324 }
325}
326pub struct ZpStar {
328 pub p: u64,
330}
331impl ZpStar {
332 pub fn new(p: u64) -> Self {
334 Self { p }
335 }
336 pub fn order(&self) -> Option<u64> {
339 None
340 }
341 pub fn generators(&self) -> Vec<u64> {
343 if self.p == 2 {
344 vec![3]
345 } else {
346 let primitive_root = (2..self.p)
347 .find(|&g| {
348 let mut seen = std::collections::HashSet::new();
349 let mut x = 1u64;
350 for _ in 0..self.p - 1 {
351 x = (x * g) % self.p;
352 seen.insert(x);
353 }
354 seen.len() == (self.p - 1) as usize
355 })
356 .unwrap_or(2);
357 vec![primitive_root, 1 + self.p]
358 }
359 }
360}
361pub struct PAdicBall {
363 pub center: PAdicNumber,
365 pub radius: f64,
367}
368impl PAdicBall {
369 pub fn new(center: PAdicNumber, radius: f64) -> Self {
371 Self { center, radius }
372 }
373 pub fn contains(&self, x: &PAdicNumber) -> bool {
375 let diff_val = x.valuation.min(self.center.valuation);
376 let dist = (x.numerator.p as f64).powi(-diff_val as i32);
377 dist < self.radius
378 }
379 pub fn is_open(&self) -> bool {
381 true
382 }
383}
384pub struct WittVector {
386 pub p: u64,
388 pub components: Vec<i64>,
390}
391impl WittVector {
392 pub fn new(p: u64, n: usize) -> Self {
394 Self {
395 p,
396 components: vec![0; n],
397 }
398 }
399 pub fn ghost_components(&self) -> Vec<i64> {
401 let n = self.components.len();
402 (0..n)
403 .map(|m| {
404 self.components
405 .iter()
406 .enumerate()
407 .take(m + 1)
408 .map(|(k, &x)| {
409 let pk = (self.p as i64).pow(k as u32);
410 let exp = (self.p as u32).pow((m - k) as u32);
411 pk * x.pow(exp)
412 })
413 .sum()
414 })
415 .collect()
416 }
417 pub fn from_integer(p: u64, x: i64) -> Self {
419 Self {
420 p,
421 components: vec![x],
422 }
423 }
424}
425pub struct IntegralExtension {
427 pub base: String,
429 pub degree: u64,
431}
432impl IntegralExtension {
433 pub fn new(base: String, degree: u64) -> Self {
435 Self { base, degree }
436 }
437 pub fn is_totally_ramified(&self) -> bool {
439 self.degree > 1
440 }
441 pub fn is_unramified(&self) -> bool {
443 self.degree == 1
444 }
445}
446pub struct PAdicDifferentialEquation {
448 pub p: u64,
450 pub rank: usize,
452}
453impl PAdicDifferentialEquation {
454 pub fn new(p: u64, rank: usize) -> Self {
456 Self { p, rank }
457 }
458 pub fn dworks_theorem_statement(&self) -> String {
461 format!(
462 "Dwork's Theorem: A rank-{} p-adic differential equation over the Robba ring \
463 R_{{p = {}}} is solvable (has a full set of solutions in the Robba ring) \
464 if and only if its Newton polygon has slopes in ℤ_p.",
465 self.rank, self.p
466 )
467 }
468 pub fn monodromy_theorem_statement(&self) -> String {
470 format!(
471 "p-adic Monodromy Theorem (Berger, 2002): Every de Rham p-adic representation \
472 of Gal(ℚ̄_p/ℚ_p) on a rank-{} Q_{}-vector space is potentially semistable \
473 (becomes semistable over a finite extension).",
474 self.rank, self.p
475 )
476 }
477 pub fn frobenius_structure_statement(&self) -> String {
479 format!(
480 "A Frobenius structure on a rank-{} differential module over ℚ_{} is an \
481 isomorphism φ*M ≅ M of differential modules, where φ is the Frobenius \
482 endomorphism (x ↦ x^p). Such a structure is unique when it exists.",
483 self.rank, self.p
484 )
485 }
486}
487pub struct PAdicLogarithm {
489 pub p: u64,
491}
492impl PAdicLogarithm {
493 pub fn new(p: u64) -> Self {
495 Self { p }
496 }
497 pub fn converges_on(&self, x: f64) -> bool {
499 (1.0 - x).abs() < 1.0
500 }
501 pub fn log_p(&self, x: f64) -> f64 {
503 let u = 1.0 - x;
504 let mut sum = 0.0f64;
505 let mut power = u;
506 for n in 1u32..=50 {
507 sum -= power / n as f64;
508 power *= u;
509 }
510 sum
511 }
512}
513pub struct IwasawaModule {
515 pub algebra: IwasawaAlgebra,
517 pub rank: usize,
519 pub torsion: String,
521}
522impl IwasawaModule {
523 pub fn new(algebra: IwasawaAlgebra, rank: usize, torsion: String) -> Self {
525 Self {
526 algebra,
527 rank,
528 torsion,
529 }
530 }
531 pub fn structural_theorem_statement(&self) -> String {
533 format!(
534 "Every finitely generated module M over the Iwasawa algebra Λ = {} is \
535 pseudo-isomorphic to Λ^r ⊕ (⊕ Λ/(f_i)) ⊕ (⊕ Λ/(p^{{n_j}})) where r = {} \
536 is the rank and the torsion part is described by {}.",
537 self.algebra.group_ring, self.rank, self.torsion
538 )
539 }
540}
541pub struct PAdicBanachSpace {
543 pub p: u64,
545 pub description: String,
547 pub is_separable: bool,
549}
550impl PAdicBanachSpace {
551 pub fn new(p: u64, description: impl Into<String>, is_separable: bool) -> Self {
553 Self {
554 p,
555 description: description.into(),
556 is_separable,
557 }
558 }
559 pub fn is_complete(&self) -> bool {
561 true
562 }
563 pub fn mahler_basis_orthonormal(&self) -> bool {
565 true
566 }
567 pub fn banach_steinhaus_statement(&self) -> String {
569 format!(
570 "Banach-Steinhaus for p-adic Banach spaces: If {{T_n}} is a sequence of \
571 continuous linear maps on {} that is pointwise bounded, then {{T_n}} is \
572 equicontinuous (uniformly bounded in operator norm).",
573 self.description
574 )
575 }
576}
577pub struct OverconvergentFunctions {
579 pub p: u64,
581 pub overconvergence_radius: f64,
583}
584impl OverconvergentFunctions {
585 pub fn new(p: u64, overconvergence_radius: f64) -> Self {
587 Self {
588 p,
589 overconvergence_radius,
590 }
591 }
592 pub fn is_subspace_of_formal_series(&self) -> bool {
594 true
595 }
596 pub fn robba_ring_statement(&self) -> String {
598 format!(
599 "The Robba ring R_p = ∪_{{r>0}} A_{{p,r}} is the ring of overconvergent \
600 functions for p = {}: power series convergent on some annulus \
601 (p^{{-r}} < |x|_p ≤ 1). It is the natural setting for p-adic \
602 differential equations and (φ, Γ)-modules.",
603 self.p
604 )
605 }
606}
607pub struct ColemanPowerSeries {
609 pub p: u64,
611 pub series_coefficients: Vec<f64>,
613}
614impl ColemanPowerSeries {
615 pub fn new(p: u64, series_coefficients: Vec<f64>) -> Self {
617 Self {
618 p,
619 series_coefficients,
620 }
621 }
622 pub fn colemans_theorem_statement(&self) -> String {
624 format!(
625 "Coleman's Theorem (1979): Let (u_n) be a norm-compatible sequence in \
626 ℤ_{}^× (i.e. N_{{K_n/K_{{n-1}}}}(u_n) = u_{{n-1}}). Then there exists a \
627 unique power series f ∈ ℤ_{}[[T]]^× such that f(ζ_{{p^n}} - 1) = u_n \
628 for all n, where ζ_{{p^n}} is a primitive p^n-th root of unity.",
629 self.p, self.p
630 )
631 }
632 pub fn evaluate_at(&self, t: f64) -> f64 {
634 evaluate_poly(&self.series_coefficients, t)
635 }
636 pub fn converges_on_unit_disk(&self) -> bool {
638 true
639 }
640}
641pub struct TeichmullerRepresentative {
646 pub p: u64,
648 pub residue: u64,
650}
651impl TeichmullerRepresentative {
652 pub fn new(p: u64, residue: u64) -> Self {
654 assert!(p >= 2, "p must be prime");
655 assert!(residue > 0 && residue < p, "residue must be in 1..p-1");
656 Self { p, residue }
657 }
658 pub fn is_root_of_unity(&self) -> bool {
660 true
661 }
662}
663pub struct PAdicAbsoluteValue {
665 pub p: u64,
667}
668impl PAdicAbsoluteValue {
669 pub fn new(p: u64) -> Self {
671 Self { p }
672 }
673 pub fn evaluate(&self, n: i64) -> f64 {
675 if n == 0 {
676 return 0.0;
677 }
678 let mut m = n.unsigned_abs();
679 let mut val = 0i32;
680 while m % self.p == 0 {
681 m /= self.p;
682 val += 1;
683 }
684 (self.p as f64).powi(-val)
685 }
686 pub fn ultrametric_inequality(&self) -> bool {
688 true
689 }
690}
691pub struct MahlerTransform {
693 pub coefficients: Vec<f64>,
695 pub p: u64,
697}
698impl MahlerTransform {
699 pub fn new(p: u64, coefficients: Vec<f64>) -> Self {
701 Self { coefficients, p }
702 }
703 pub fn mahler_coefficient(&self, k: usize) -> f64 {
706 if k >= self.coefficients.len() {
707 return 0.0;
708 }
709 let mut result = 0.0f64;
710 for j in 0..=k {
711 let binom = mahler_binomial(k as i64, j);
712 let sign = if (k - j) % 2 == 0 { 1.0 } else { -1.0 };
713 let fj = if j < self.coefficients.len() {
714 self.coefficients[j]
715 } else {
716 0.0
717 };
718 result += sign * binom * fj;
719 }
720 result
721 }
722 pub fn is_bijection_onto_null_sequences(&self) -> bool {
725 true
726 }
727 pub fn characteristic_series_description(&self) -> String {
730 format!(
731 "The characteristic series of the Iwasawa module associated to the \
732 Mahler expansion with {} coefficients: Char_Λ(M) ∈ Λ.",
733 self.coefficients.len()
734 )
735 }
736}
737pub struct RigidAnalyticSpace {
739 pub p: u64,
741 pub dimension: usize,
743 pub description: String,
745}
746impl RigidAnalyticSpace {
747 pub fn new(p: u64, dimension: usize, description: impl Into<String>) -> Self {
749 Self {
750 p,
751 dimension,
752 description: description.into(),
753 }
754 }
755 pub fn is_separated(&self) -> bool {
757 true
758 }
759 pub fn gaga_statement(&self) -> String {
761 format!(
762 "Rigid GAGA: For a proper rigid analytic space X over ℚ_{} of dimension {}, \
763 the categories of coherent algebraic sheaves and coherent analytic sheaves \
764 are equivalent (Kiehl's theorem).",
765 self.p, self.dimension
766 )
767 }
768}
769pub struct LocallyAnalyticFunctions {
771 pub p: u64,
773 pub target: String,
775}
776impl LocallyAnalyticFunctions {
777 pub fn new(p: u64, target: impl Into<String>) -> Self {
779 Self {
780 p,
781 target: target.into(),
782 }
783 }
784 pub fn dense_in_continuous(&self) -> bool {
786 true
787 }
788 pub fn locally_analytic_rep_statement(&self) -> String {
790 format!(
791 "A locally analytic representation of G (a p-adic Lie group) on {} \
792 is a continuous representation such that every orbit map g ↦ π(g)v \
793 is locally analytic (i.e. locally given by a convergent power series in p-adic coordinates).",
794 self.target
795 )
796 }
797}
798pub struct PAdicDistributions {
800 pub p: u64,
802}
803impl PAdicDistributions {
804 pub fn new(p: u64) -> Self {
806 Self { p }
807 }
808 pub fn is_locally_convex(&self) -> bool {
810 true
811 }
812 pub fn amice_transform_statement(&self) -> String {
814 format!(
815 "The Amice transform A : D(ℤ_{}, ℚ_{}) → ℚ_{}[[T]] sends a distribution μ \
816 to its generating series A(μ)(T) = ∫ (1+T)^x dμ(x). \
817 This gives an isomorphism of Λ-modules.",
818 self.p, self.p, self.p
819 )
820 }
821}
822pub struct KubotaLeopoldt {
824 pub p: u64,
826 pub conductor: u64,
828}
829impl KubotaLeopoldt {
830 pub fn new(p: u64, conductor: u64) -> Self {
832 Self { p, conductor }
833 }
834 pub fn interpolation_statement(&self) -> String {
836 format!(
837 "The Kubota-Leopoldt p-adic L-function L_{}(s, χ) for a Dirichlet character χ \
838 of conductor {} satisfies the interpolation formula: \
839 L_{}(1-n, χ) = (1 - χω^{{-n}}(p)p^{{n-1}}) · L(1-n, χω^{{-n}}) \
840 for positive integers n, where ω is the Teichmüller character.",
841 self.p, self.conductor, self.p
842 )
843 }
844 pub fn is_padic_analytic(&self) -> bool {
846 true
847 }
848}
849pub struct LubinTateFormalGroup {
851 pub p: u64,
853 pub q: u64,
855}
856impl LubinTateFormalGroup {
857 pub fn new(p: u64, q: u64) -> Self {
859 Self { p, q }
860 }
861 pub fn formal_group_law_description(&self) -> String {
863 format!(
864 "The Lubin-Tate formal group F associated to uniformizer π (norm q = {}) \
865 satisfies F(X, Y) ≡ X + Y (mod degree 2) and [π]_F(X) ≡ πX (mod degree 2), \
866 with [π]_F(X) = X^q + πX (the distinguished endomorphism).",
867 self.q
868 )
869 }
870 pub fn formal_exponential_statement(&self) -> String {
872 format!(
873 "The formal exponential exp_F : pℤ_{} → m_K of the Lubin-Tate formal group \
874 converges on the maximal ideal and provides an isomorphism of formal groups \
875 between the additive formal group G_a and F over pℤ_{}.",
876 self.p, self.p
877 )
878 }
879 pub fn formal_logarithm_statement(&self) -> String {
881 format!(
882 "The formal logarithm log_F : m_K → pℤ_{} of the Lubin-Tate formal group \
883 is the functional inverse of exp_F. Together they give the p-adic logarithm \
884 on the group of principal units (1 + m_K) ≅ K via the Lubin-Tate theory.",
885 self.p
886 )
887 }
888 pub fn local_cft_via_lubin_tate(&self) -> String {
890 format!(
891 "Lubin-Tate theory: The torsion points F[π^n] of the Lubin-Tate formal group \
892 generate the totally ramified abelian extensions of K (local field with \
893 residue characteristic p = {}). The local Artin map sends π to the \
894 Frobenius in Gal(K^{{ab}}/K).",
895 self.p
896 )
897 }
898}
899pub struct AffinoidSpace {
901 pub p: u64,
903 pub tate_algebra: TateAlgebra,
905 pub ideal_description: String,
907}
908impl AffinoidSpace {
909 pub fn new(p: u64, n: usize, ideal_description: impl Into<String>) -> Self {
911 Self {
912 p,
913 tate_algebra: TateAlgebra::new(p, n),
914 ideal_description: ideal_description.into(),
915 }
916 }
917 pub fn is_noetherian(&self) -> bool {
919 true
920 }
921}
922pub struct WeierstrausPrepTheorem {
925 pub p: u64,
927 pub degree: usize,
929}
930impl WeierstrausPrepTheorem {
931 pub fn new(p: u64, degree: usize) -> Self {
933 Self { p, degree }
934 }
935 pub fn factorization_exists(&self) -> bool {
938 true
939 }
940 pub fn statement(&self) -> String {
942 format!(
943 "Weierstrass Preparation Theorem: Every f ∈ ℤ_{}[[T]] not divisible by p \
944 factors uniquely as f = u · P where u ∈ ℤ_{}[[T]]^× is a unit \
945 and P is a Weierstrass polynomial of degree {}.",
946 self.p, self.p, self.degree
947 )
948 }
949 pub fn factorization_is_unique(&self) -> bool {
951 true
952 }
953}
954pub struct PAdicLieGroup {
956 pub p: u64,
958 pub dimension: usize,
960}
961impl PAdicLieGroup {
962 pub fn new(p: u64, dimension: usize) -> Self {
964 Self { p, dimension }
965 }
966 pub fn is_compact(&self) -> bool {
968 true
969 }
970 pub fn is_abelian(&self) -> bool {
972 self.dimension <= 1
973 }
974}
975pub struct IwasawaInvariants {
977 pub p: u64,
979 pub mu_invariant: i64,
981 pub lambda_invariant: usize,
983}
984impl IwasawaInvariants {
985 pub fn new(p: u64, mu: i64, lambda: usize) -> Self {
987 Self {
988 p,
989 mu_invariant: mu,
990 lambda_invariant: lambda,
991 }
992 }
993 pub fn mu_zero_conjecture_statement(&self) -> String {
995 format!(
996 "Iwasawa's μ-conjecture: For p = {} and all primitive Dirichlet characters χ, \
997 the p-adic L-function L_p(s, χ) has μ-invariant = 0 (i.e. no factor of p \
998 in the characteristic power series), and λ-invariant = {} (number of zeros).",
999 self.p, self.lambda_invariant
1000 )
1001 }
1002}
1003pub struct TateAlgebra {
1005 pub p: u64,
1007 pub num_vars: usize,
1009}
1010impl TateAlgebra {
1011 pub fn new(p: u64, num_vars: usize) -> Self {
1013 Self { p, num_vars }
1014 }
1015 pub fn is_noetherian(&self) -> bool {
1017 true
1018 }
1019 pub fn is_ufd(&self) -> bool {
1021 true
1022 }
1023 pub fn krull_dimension(&self) -> usize {
1025 self.num_vars
1026 }
1027 pub fn polydisk_statement(&self) -> String {
1029 format!(
1030 "The Tate algebra ℚ_{}⟨X_1, …, X_{}⟩ consists of power series \
1031 ∑_{{ν}} a_ν X^ν that converge on the closed unit polydisk \
1032 {{(x_1, …, x_{}) : |x_i|_p ≤ 1}}. It is the ring of analytic \
1033 functions on the closed polydisk.",
1034 self.p, self.num_vars, self.num_vars
1035 )
1036 }
1037}
1038pub struct StickelbergerThm {
1040 pub prime: u64,
1042}
1043impl StickelbergerThm {
1044 pub fn new(prime: u64) -> Self {
1046 Self { prime }
1047 }
1048 pub fn annihilates_class_group(&self) -> String {
1050 format!(
1051 "The Stickelberger element θ = ∑_{{a=1}}^{{{}−1}} (a/{}) σ_a^{{−1}} annihilates the class group of ℚ(ζ_{}) (Stickelberger's theorem).",
1052 self.prime, self.prime, self.prime
1053 )
1054 }
1055}
1056pub struct NewtonPolygon {
1058 pub polynomial: PolynomialMod,
1060 pub vertices: Vec<(i64, i64)>,
1062}
1063impl NewtonPolygon {
1064 pub fn new(poly: PolynomialMod) -> Self {
1066 let p = poly.modulus;
1067 let vertices: Vec<(i64, i64)> = poly
1068 .coeffs
1069 .iter()
1070 .enumerate()
1071 .filter(|(_, &c)| c != 0)
1072 .map(|(i, &c)| {
1073 let mut val = 0i64;
1074 let mut m = c.unsigned_abs();
1075 while p > 1 && m % p == 0 {
1076 m /= p;
1077 val += 1;
1078 }
1079 (i as i64, val)
1080 })
1081 .collect();
1082 Self {
1083 polynomial: poly,
1084 vertices,
1085 }
1086 }
1087 pub fn slopes(&self) -> Vec<f64> {
1089 if self.vertices.len() < 2 {
1090 return vec![];
1091 }
1092 self.vertices
1093 .windows(2)
1094 .map(|w| {
1095 let (d1, v1) = w[0];
1096 let (d2, v2) = w[1];
1097 let dd = (d2 - d1) as f64;
1098 if dd == 0.0 {
1099 0.0
1100 } else {
1101 (v1 - v2) as f64 / dd
1102 }
1103 })
1104 .collect()
1105 }
1106}
1107pub struct PAdicLog {
1109 pub p: u64,
1111}
1112impl PAdicLog {
1113 pub fn new(p: u64) -> Self {
1115 Self { p }
1116 }
1117 pub fn evaluate_series(&self, x: f64, terms: u32) -> f64 {
1119 let u = 1.0 - x;
1120 let mut sum = 0.0f64;
1121 let mut power = u;
1122 for n in 1..=terms {
1123 sum -= power / n as f64;
1124 power *= u;
1125 }
1126 sum
1127 }
1128}
1129pub struct ContinuousCohomology {
1131 pub group: String,
1133 pub module: String,
1135 pub degree: usize,
1137}
1138impl ContinuousCohomology {
1139 pub fn new(group: impl Into<String>, module: impl Into<String>, degree: usize) -> Self {
1141 Self {
1142 group: group.into(),
1143 module: module.into(),
1144 degree,
1145 }
1146 }
1147 pub fn description(&self) -> String {
1149 format!(
1150 "H^{}({}, {}) — continuous group cohomology of {} with coefficients in {}",
1151 self.degree, self.group, self.module, self.group, self.module
1152 )
1153 }
1154 pub fn vanishes_above_dimension(&self, dim: usize) -> bool {
1156 self.degree > dim
1157 }
1158 pub fn ext_group_statement(&self) -> String {
1160 format!(
1161 "The Ext groups Ext^n_Λ(M, Λ) for the Iwasawa algebra Λ compute the \
1162 Iwasawa cohomology of the module M (the {}-module {}), \
1163 generalizing group cohomology to the Iwasawa algebra setting.",
1164 self.group, self.module
1165 )
1166 }
1167}
1168pub struct PAdicNumber {
1170 pub numerator: PAdicInteger,
1172 pub valuation: i64,
1174}
1175impl PAdicNumber {
1176 pub fn new(p: u64, n: i64) -> Self {
1178 if n == 0 {
1179 return Self {
1180 numerator: PAdicInteger::zero(p),
1181 valuation: i64::MAX,
1182 };
1183 }
1184 let mut val = 0i64;
1185 let mut m = n.unsigned_abs();
1186 while m % p == 0 {
1187 m /= p;
1188 val += 1;
1189 }
1190 let sign_n = if n < 0 { -(m as i64) } else { m as i64 };
1191 Self {
1192 numerator: PAdicInteger::new(p, sign_n),
1193 valuation: val,
1194 }
1195 }
1196 pub fn p_adic_valuation(&self) -> i64 {
1198 self.valuation
1199 }
1200 pub fn is_integer(&self) -> bool {
1202 self.valuation >= 0
1203 }
1204 pub fn is_unit(&self) -> bool {
1206 self.valuation == 0
1207 }
1208}
1209pub struct HenselsLemma {
1211 pub poly: String,
1213 pub prime: u64,
1215}
1216impl HenselsLemma {
1217 pub fn new(poly: String, prime: u64) -> Self {
1219 Self { poly, prime }
1220 }
1221 pub fn lifting_applies(&self) -> bool {
1223 true
1224 }
1225 pub fn lift_root(&self, root: i64, precision: u32) -> i64 {
1228 let modulus = (self.prime as i64).pow(precision);
1229 root.rem_euclid(modulus)
1230 }
1231}
1232pub struct WittRing {
1234 pub p: u64,
1236}
1237impl WittRing {
1238 pub fn new(p: u64) -> Self {
1240 Self { p }
1241 }
1242 pub fn characteristic(&self) -> u64 {
1244 0
1245 }
1246}
1247pub struct PAdicExp {
1249 pub p: u64,
1251 pub convergence_radius: f64,
1253}
1254impl PAdicExp {
1255 pub fn new(p: u64) -> Self {
1257 let convergence_radius = padic_exp_convergence(p);
1258 Self {
1259 p,
1260 convergence_radius,
1261 }
1262 }
1263 pub fn converges_at(&self, x: &PAdicNumber) -> bool {
1265 if x.valuation == i64::MAX {
1266 return true;
1267 }
1268 let abs_x = (self.p as f64).powi(-(x.valuation as i32));
1269 abs_x < self.convergence_radius
1270 }
1271 pub fn evaluate_series(&self, x: f64, terms: u32) -> f64 {
1273 let mut sum = 0.0f64;
1274 let mut term = 1.0f64;
1275 for n in 1..=terms {
1276 sum += term;
1277 term *= x / n as f64;
1278 }
1279 sum
1280 }
1281}
1282pub struct PAdicExponential {
1284 pub p: u64,
1286}
1287impl PAdicExponential {
1288 pub fn new(p: u64) -> Self {
1290 Self { p }
1291 }
1292 pub fn radius_of_convergence(&self) -> f64 {
1294 if self.p == 2 {
1295 0.25
1296 } else {
1297 let exp = -1.0 / (self.p as f64 - 1.0);
1298 (self.p as f64).powf(exp)
1299 }
1300 }
1301 pub fn exp_p(&self, x: f64) -> f64 {
1303 let mut sum = 0.0f64;
1304 let mut term = 1.0f64;
1305 for n in 1u32..=50 {
1306 sum += term;
1307 term *= x / n as f64;
1308 }
1309 sum
1310 }
1311}
1312pub struct UnramifiedExtension {
1314 pub base_p: u64,
1316 pub degree: usize,
1318}
1319impl UnramifiedExtension {
1320 pub fn new(p: u64, f: usize) -> Self {
1322 Self {
1323 base_p: p,
1324 degree: f,
1325 }
1326 }
1327 pub fn residue_field_size(&self) -> u64 {
1329 self.base_p.pow(self.degree as u32)
1330 }
1331}