oxilean_std/diophantine_geometry/
types.rs1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8#[derive(Debug, Clone)]
13pub struct NevanlinnaData {
14 pub numerator_degree: usize,
16 pub denominator_degree: usize,
18}
19impl NevanlinnaData {
20 pub fn new(numerator_degree: usize, denominator_degree: usize) -> Self {
22 NevanlinnaData {
23 numerator_degree,
24 denominator_degree,
25 }
26 }
27 pub fn order_of_growth(&self) -> usize {
29 self.numerator_degree.max(self.denominator_degree)
30 }
31 pub fn picard_omitted_values(&self) -> usize {
33 if self.denominator_degree == 0 {
34 1
35 } else {
36 0
37 }
38 }
39 pub fn deficiency_sum_bound(&self) -> f64 {
41 2.0
42 }
43}
44#[derive(Debug, Clone)]
46pub struct ProjectiveCurve {
47 pub genus: usize,
49 pub description: String,
51}
52impl ProjectiveCurve {
53 pub fn new(genus: usize, description: &str) -> Self {
55 ProjectiveCurve {
56 genus,
57 description: description.to_string(),
58 }
59 }
60 pub fn has_finitely_many_rational_points(&self) -> bool {
62 self.genus >= 2
63 }
64 pub fn is_rational(&self) -> bool {
66 self.genus == 0
67 }
68 pub fn is_elliptic(&self) -> bool {
70 self.genus == 1
71 }
72 pub fn riemann_roch_dim(&self, degree: i64) -> i64 {
74 if degree >= self.genus as i64 {
75 degree - self.genus as i64 + 1
76 } else {
77 0
78 }
79 }
80}
81#[allow(dead_code)]
83#[derive(Debug, Clone)]
84pub struct MordellWeilData {
85 pub variety: String,
87 pub field: String,
89 pub rank: usize,
91 pub torsion: String,
93 pub generators: Vec<String>,
95}
96#[allow(dead_code)]
97impl MordellWeilData {
98 pub fn new(variety: &str, field: &str) -> Self {
100 MordellWeilData {
101 variety: variety.to_string(),
102 field: field.to_string(),
103 rank: 0,
104 torsion: "trivial".to_string(),
105 generators: Vec::new(),
106 }
107 }
108 pub fn with_rank(mut self, r: usize) -> Self {
110 self.rank = r;
111 self
112 }
113 pub fn with_torsion(mut self, t: &str) -> Self {
115 self.torsion = t.to_string();
116 self
117 }
118 pub fn add_generator(&mut self, gen: &str) {
120 self.generators.push(gen.to_string());
121 }
122 pub fn structure_theorem(&self) -> String {
124 format!(
125 "{}({}) ≅ Z^{} ⊕ ({})",
126 self.variety, self.field, self.rank, self.torsion
127 )
128 }
129 pub fn mw_rank(&self) -> usize {
131 self.rank
132 }
133}
134#[derive(Debug, Clone)]
136pub struct NaiveHeightComputer {
137 pub coords: Vec<i64>,
139}
140#[allow(dead_code)]
141impl NaiveHeightComputer {
142 pub fn new(coords: Vec<i64>) -> Self {
144 NaiveHeightComputer { coords }
145 }
146 pub fn naive_height(&self) -> i64 {
148 self.coords.iter().map(|x| x.abs()).max().unwrap_or(0)
149 }
150 pub fn log_height(&self) -> f64 {
152 let h = self.naive_height();
153 if h == 0 {
154 0.0
155 } else {
156 (h as f64).ln()
157 }
158 }
159 pub fn number_of_coords(&self) -> usize {
161 self.coords.len()
162 }
163 pub fn is_zero(&self) -> bool {
165 self.coords.iter().all(|&x| x == 0)
166 }
167}
168#[allow(dead_code)]
170#[derive(Debug, Clone)]
171pub struct HeightFunction {
172 pub name: String,
174 pub northcott: bool,
176 pub base_field: String,
178}
179#[allow(dead_code)]
180impl HeightFunction {
181 pub fn new(name: &str, base_field: &str) -> Self {
183 HeightFunction {
184 name: name.to_string(),
185 northcott: false,
186 base_field: base_field.to_string(),
187 }
188 }
189 pub fn with_northcott(mut self) -> Self {
191 self.northcott = true;
192 self
193 }
194 pub fn weil_height_rational(p: i64, q: i64) -> f64 {
196 if q == 0 {
197 return f64::INFINITY;
198 }
199 (p.abs().max(q.abs()) as f64).ln()
200 }
201 pub fn projective_height(coords: &[i64]) -> f64 {
203 coords.iter().map(|&x| x.unsigned_abs()).max().unwrap_or(0) as f64
204 }
205 pub fn log_height(coords: &[i64]) -> f64 {
207 Self::projective_height(coords).max(1.0).ln()
208 }
209 pub fn northcott_bound(&self, bound: f64) -> String {
211 if self.northcott {
212 format!(
213 "Finitely many points P over {} with h(P) <= {bound:.2}",
214 self.base_field
215 )
216 } else {
217 format!("Northcott property not established for {}", self.name)
218 }
219 }
220}
221#[derive(Debug, Clone)]
223pub struct LineBundleData {
224 pub self_intersection: i64,
226 pub curve_intersections: Vec<i64>,
228}
229impl LineBundleData {
230 pub fn new(self_intersection: i64, curve_intersections: Vec<i64>) -> Self {
232 LineBundleData {
233 self_intersection,
234 curve_intersections,
235 }
236 }
237 pub fn is_ample_nakai_moishezon(&self) -> bool {
239 self.self_intersection > 0 && self.curve_intersections.iter().all(|&c| c > 0)
240 }
241 pub fn is_nef(&self) -> bool {
243 self.curve_intersections.iter().all(|&c| c >= 0)
244 }
245 pub fn seshadri_constant(&self, multiplicities: &[u64]) -> f64 {
247 self.curve_intersections
248 .iter()
249 .zip(multiplicities.iter())
250 .filter(|(_, &m)| m > 0)
251 .map(|(&lc, &m)| lc as f64 / m as f64)
252 .fold(f64::INFINITY, f64::min)
253 }
254}
255#[derive(Debug, Clone)]
257pub struct ABCTriple {
258 pub a: u64,
259 pub b: u64,
260 pub c: u64,
261}
262impl ABCTriple {
263 pub fn new(a: u64, b: u64, c: u64) -> Option<Self> {
265 if a + b == c && gcd(a, b) == 1 && gcd(b, c) == 1 {
266 Some(ABCTriple { a, b, c })
267 } else {
268 None
269 }
270 }
271 pub fn radical(&self) -> u64 {
273 radical(self.a) / gcd(radical(self.a), 1)
274 * (radical(self.b) / gcd(radical(self.b), 1))
275 * (radical(self.c) / gcd(radical(self.c), 1))
276 }
277 pub fn quality(&self) -> f64 {
279 let r = self.radical();
280 if r <= 1 {
281 return 0.0;
282 }
283 (self.c as f64).ln() / (r as f64).ln()
284 }
285}
286#[allow(dead_code)]
288#[derive(Debug, Clone)]
289pub struct FaltingsData {
290 pub curve: String,
292 pub genus: usize,
294 pub rational_points_count: Option<usize>,
296 pub finitely_many: bool,
298}
299#[allow(dead_code)]
300impl FaltingsData {
301 pub fn new(curve: &str, genus: usize) -> Self {
303 FaltingsData {
304 curve: curve.to_string(),
305 genus,
306 rational_points_count: None,
307 finitely_many: genus >= 2,
308 }
309 }
310 pub fn with_point_count(mut self, n: usize) -> Self {
312 self.rational_points_count = Some(n);
313 self
314 }
315 pub fn faltings_statement(&self) -> String {
317 if self.genus >= 2 {
318 format!(
319 "C = {} has only finitely many rational points (Faltings 1983)",
320 self.curve
321 )
322 } else {
323 format!(
324 "C = {} genus {} - Faltings does not apply",
325 self.curve, self.genus
326 )
327 }
328 }
329 pub fn applies(&self) -> bool {
331 self.genus >= 2
332 }
333}
334#[derive(Debug, Clone)]
339pub struct SelmerGroupEstimator {
340 pub num_bad_primes: usize,
342 pub two_torsion_rank: usize,
344}
345#[allow(dead_code)]
346impl SelmerGroupEstimator {
347 pub fn new(num_bad_primes: usize, two_torsion_rank: usize) -> Self {
349 SelmerGroupEstimator {
350 num_bad_primes,
351 two_torsion_rank,
352 }
353 }
354 pub fn rank_upper_bound(&self) -> usize {
356 self.two_torsion_rank + self.num_bad_primes + 1
357 }
358 pub fn is_trivially_trivial(&self) -> bool {
360 self.num_bad_primes == 0 && self.two_torsion_rank == 0
361 }
362 pub fn parity_conjecture_rank_lower_bound(&self) -> usize {
365 0
366 }
367}
368#[allow(dead_code)]
370#[derive(Debug, Clone)]
371pub struct ArakelovData {
372 pub surface: String,
374 pub arithmetic_degree: f64,
376 pub green_function_values: Vec<(f64, f64)>,
378}
379#[allow(dead_code)]
380impl ArakelovData {
381 pub fn new(surface: &str) -> Self {
383 ArakelovData {
384 surface: surface.to_string(),
385 arithmetic_degree: 0.0,
386 green_function_values: Vec::new(),
387 }
388 }
389 pub fn with_arith_degree(mut self, d: f64) -> Self {
391 self.arithmetic_degree = d;
392 self
393 }
394 pub fn add_green_value(&mut self, x: f64, g: f64) {
396 self.green_function_values.push((x, g));
397 }
398 pub fn faltings_height_estimate(&self) -> f64 {
400 self.arithmetic_degree / 2.0
401 }
402 pub fn noether_formula(&self) -> String {
404 format!(
405 "χ(O_{{{}}}) = (K² + e(X))/12 (Noether formula)",
406 self.surface
407 )
408 }
409}
410#[allow(dead_code)]
412#[derive(Debug, Clone)]
413pub struct EllipticCurveArithmetic {
414 pub a: i64,
416 pub b: i64,
418 pub rational_points: Vec<(i64, i64)>,
420 pub rank: usize,
422 pub torsion_order: usize,
424 pub conductor: Option<u64>,
426}
427#[allow(dead_code)]
428impl EllipticCurveArithmetic {
429 pub fn new(a: i64, b: i64) -> Self {
431 EllipticCurveArithmetic {
432 a,
433 b,
434 rational_points: Vec::new(),
435 rank: 0,
436 torsion_order: 1,
437 conductor: None,
438 }
439 }
440 pub fn add_rational_point(&mut self, x: i64, y: i64) {
442 if y * y == x * x * x + self.a * x + self.b {
443 self.rational_points.push((x, y));
444 }
445 }
446 pub fn discriminant(&self) -> i64 {
448 -16 * (4 * self.a.pow(3) + 27 * self.b.pow(2))
449 }
450 pub fn j_invariant(&self) -> Option<f64> {
452 let disc = self.discriminant();
453 if disc == 0 {
454 return None;
455 }
456 let num = 1728.0 * (4.0 * self.a as f64).powi(3);
457 Some(num / disc as f64)
458 }
459 pub fn is_smooth(&self) -> bool {
461 self.discriminant() != 0
462 }
463 pub fn is_on_curve(&self, x: i64, y: i64) -> bool {
465 y * y == x * x * x + self.a * x + self.b
466 }
467 pub fn mordell_theorem(&self) -> String {
469 format!("E(Q) ≅ Z^{} ⊕ Z/{}", self.rank, self.torsion_order)
470 }
471 pub fn double_point(&self, x: i64, y: i64) -> Option<(f64, f64)> {
473 if y == 0 {
474 return None;
475 }
476 let xf = x as f64;
477 let yf = y as f64;
478 let af = self.a as f64;
479 let lambda = (3.0 * xf * xf + af) / (2.0 * yf);
480 let x3 = lambda * lambda - 2.0 * xf;
481 let y3 = lambda * (xf - x3) - yf;
482 Some((x3, y3))
483 }
484}
485#[derive(Debug, Clone)]
489pub struct ThueSolver {
490 pub coeffs: Vec<i64>,
492 pub rhs: i64,
494}
495#[allow(dead_code)]
496impl ThueSolver {
497 pub fn new(coeffs: Vec<i64>, rhs: i64) -> Self {
499 ThueSolver { coeffs, rhs }
500 }
501 pub fn degree(&self) -> usize {
503 self.coeffs.len().saturating_sub(1)
504 }
505 pub fn evaluate(&self, x: i64, y: i64) -> i64 {
507 let d = self.degree();
508 let mut result = 0i64;
509 for (i, &c) in self.coeffs.iter().enumerate() {
510 let x_pow = (d - i) as u32;
511 let y_pow = i as u32;
512 let term = c
513 .saturating_mul(x.saturating_pow(x_pow))
514 .saturating_mul(y.saturating_pow(y_pow));
515 result = result.saturating_add(term);
516 }
517 result
518 }
519 pub fn small_solutions(&self, bound: i64) -> Vec<(i64, i64)> {
521 let mut solutions = Vec::new();
522 for x in -bound..=bound {
523 for y in -bound..=bound {
524 if self.evaluate(x, y) == self.rhs {
525 solutions.push((x, y));
526 }
527 }
528 }
529 solutions
530 }
531}
532#[derive(Debug, Clone)]
537pub struct WeilHeight {
538 pub coords: Vec<i64>,
540}
541impl WeilHeight {
542 pub fn new(coords: Vec<i64>) -> Self {
544 WeilHeight { coords }
545 }
546 pub fn naive_height(&self) -> i64 {
548 self.coords.iter().map(|x| x.abs()).max().unwrap_or(0)
549 }
550 pub fn logarithmic_height(&self) -> f64 {
552 let h = self.naive_height();
553 if h == 0 {
554 0.0
555 } else {
556 (h as f64).ln()
557 }
558 }
559 pub fn northcott_property_holds(&self) -> bool {
563 true
564 }
565}
566#[derive(Debug, Clone)]
570pub struct MordellWeilGroup {
571 pub rank: usize,
573 pub torsion_orders: Vec<u32>,
575}
576impl MordellWeilGroup {
577 pub fn new(rank: usize, torsion_orders: Vec<u32>) -> Self {
579 MordellWeilGroup {
580 rank,
581 torsion_orders,
582 }
583 }
584 pub fn torsion_size(&self) -> u64 {
586 self.torsion_orders.iter().map(|&n| n as u64).product()
587 }
588 pub fn is_finite(&self) -> bool {
590 self.rank == 0
591 }
592 pub fn num_generators(&self) -> usize {
594 self.rank + self.torsion_orders.len()
595 }
596}
597#[derive(Debug, Clone)]
602pub struct ChabautyBound {
603 pub genus: usize,
605 pub rank: usize,
607 pub prime: u64,
609}
610#[allow(dead_code)]
611impl ChabautyBound {
612 pub fn new(genus: usize, rank: usize, prime: u64) -> Self {
614 ChabautyBound { genus, rank, prime }
615 }
616 pub fn is_applicable(&self) -> bool {
618 self.rank < self.genus
619 }
620 pub fn point_bound(&self) -> u64 {
622 if !self.is_applicable() {
623 return u64::MAX;
624 }
625 let g = self.genus as u64;
626 let p = self.prime;
627 if p == 0 {
628 return 2 * g;
629 }
630 2 * g - 2 + (p - 1)
631 }
632 pub fn stoll_bound(&self) -> u64 {
634 if !self.is_applicable() {
635 return u64::MAX;
636 }
637 let g = self.genus as u64;
638 2 * g - 2 + (self.prime - 1) / 2
639 }
640}