1use super::functions::*;
6#[derive(Debug, Clone)]
11pub struct TropicalConic {
12 pub coefficients: Vec<f64>,
14}
15#[derive(Debug, Clone)]
20pub struct TropicalLine {
21 pub coefficients: (f64, f64, f64),
23}
24#[derive(Debug, Clone)]
29pub struct NewtonPolytope {
30 pub vertices: Vec<Vec<i32>>,
32 pub dimension: usize,
34}
35impl NewtonPolytope {
36 pub fn new(dimension: usize) -> Self {
38 NewtonPolytope {
39 vertices: Vec::new(),
40 dimension,
41 }
42 }
43 pub fn add_vertex(&mut self, v: Vec<i32>) {
45 debug_assert_eq!(v.len(), self.dimension, "vertex dimension mismatch");
46 self.vertices.push(v);
47 }
48 pub fn is_lattice_polytope(&self) -> bool {
50 true
51 }
52 pub fn volume(&self) -> f64 {
58 match self.dimension {
59 1 => {
60 if self.vertices.is_empty() {
61 return 0.0;
62 }
63 let vals: Vec<i32> = self.vertices.iter().map(|v| v[0]).collect();
64 let mn = *vals
65 .iter()
66 .min()
67 .expect("vals is non-empty: vertices.is_empty() check returned early");
68 let mx = *vals
69 .iter()
70 .max()
71 .expect("vals is non-empty: vertices.is_empty() check returned early");
72 (mx - mn) as f64
73 }
74 2 => {
75 let n = self.vertices.len();
76 if n < 3 {
77 return 0.0;
78 }
79 let mut area2 = 0i64;
80 for i in 0..n {
81 let j = (i + 1) % n;
82 let xi = self.vertices[i][0] as i64;
83 let yi = self.vertices[i][1] as i64;
84 let xj = self.vertices[j][0] as i64;
85 let yj = self.vertices[j][1] as i64;
86 area2 += xi * yj - xj * yi;
87 }
88 (area2.abs() as f64) / 2.0
89 }
90 _ => 0.0,
91 }
92 }
93 pub fn num_interior_lattice_points(&self) -> usize {
98 if self.dimension != 2 || self.vertices.len() < 3 {
99 return 0;
100 }
101 let area = self.volume();
102 let n = self.vertices.len();
103 let mut boundary = 0usize;
104 for i in 0..n {
105 let j = (i + 1) % n;
106 let dx = (self.vertices[j][0] - self.vertices[i][0]).unsigned_abs() as usize;
107 let dy = (self.vertices[j][1] - self.vertices[i][1]).unsigned_abs() as usize;
108 boundary += gcd(dx, dy);
109 }
110 let interior_f = area - (boundary as f64) / 2.0 + 1.0;
111 interior_f.round().max(0.0) as usize
112 }
113}
114#[derive(Debug, Clone)]
119pub struct TropicalPolynomial {
120 pub terms: Vec<TropicalMonomial>,
122 pub n_vars: usize,
124}
125impl TropicalPolynomial {
126 pub fn new(n_vars: usize) -> Self {
128 TropicalPolynomial {
129 terms: Vec::new(),
130 n_vars,
131 }
132 }
133 pub fn add_term(&mut self, coeff: f64, exponents: Vec<i32>) {
137 debug_assert_eq!(
138 exponents.len(),
139 self.n_vars,
140 "exponent length must match n_vars"
141 );
142 self.terms.push(TropicalMonomial {
143 coefficient: coeff,
144 exponents,
145 });
146 }
147 pub fn evaluate(&self, point: &[f64]) -> f64 {
152 self.terms
153 .iter()
154 .map(|m| {
155 let dot: f64 = m
156 .exponents
157 .iter()
158 .zip(point.iter())
159 .map(|(&e, &x)| (e as f64) * x)
160 .sum();
161 m.coefficient + dot
162 })
163 .fold(f64::INFINITY, f64::min)
164 }
165 pub fn degree(&self) -> i32 {
167 self.terms
168 .iter()
169 .map(|m| m.exponents.iter().copied().sum::<i32>())
170 .max()
171 .unwrap_or(0)
172 }
173}
174impl TropicalPolynomial {
175 pub fn evaluate_tropical(&self, point: &[f64]) -> f64 {
179 self.evaluate(point)
180 }
181 pub fn newton_polytope(&self) -> NewtonPolytope {
186 let mut np = NewtonPolytope::new(self.n_vars);
187 for term in &self.terms {
188 np.vertices.push(term.exponents.clone());
189 }
190 np
191 }
192}
193#[derive(Debug, Clone)]
199pub struct KrullValuation {
200 pub ring: String,
202 pub value_group: String,
204}
205impl KrullValuation {
206 pub fn new(ring: impl Into<String>, value_group: impl Into<String>) -> Self {
208 KrullValuation {
209 ring: ring.into(),
210 value_group: value_group.into(),
211 }
212 }
213 pub fn is_discrete(&self) -> bool {
218 self.value_group == "ℤ" || self.value_group == "Z"
219 }
220 pub fn valuation_ring_is_dvr(&self) -> bool {
222 self.is_discrete()
223 }
224}
225#[allow(dead_code)]
227#[derive(Debug, Clone)]
228pub struct TropicalGrassmannianExt {
229 pub k: usize,
230 pub n: usize,
231}
232impl TropicalGrassmannianExt {
233 #[allow(dead_code)]
234 pub fn new(k: usize, n: usize) -> Self {
235 assert!(k <= n);
236 Self { k, n }
237 }
238 #[allow(dead_code)]
239 pub fn dimension(&self) -> usize {
240 self.k * (self.n - self.k)
241 }
242 #[allow(dead_code)]
243 pub fn is_tropical_linear_space_of_g24(&self) -> bool {
244 self.k == 2 && self.n == 4
245 }
246 #[allow(dead_code)]
247 pub fn plucker_description(&self) -> String {
248 format!(
249 "Trop(Gr({},{})) lives in R^C(n,k) via tropicalized Plucker coords",
250 self.k, self.n
251 )
252 }
253}
254#[derive(Debug, Clone)]
259pub struct TropicalMatrix {
260 pub n: usize,
262 pub data: Vec<TropicalNumber>,
264}
265impl TropicalMatrix {
266 pub fn zero(n: usize) -> Self {
268 TropicalMatrix {
269 n,
270 data: vec![TropicalNumber::PosInfinity; n * n],
271 }
272 }
273 pub fn identity(n: usize) -> Self {
275 let mut m = Self::zero(n);
276 for i in 0..n {
277 m.set(i, i, TropicalNumber::Finite(0.0));
278 }
279 m
280 }
281 pub fn get(&self, i: usize, j: usize) -> &TropicalNumber {
283 &self.data[i * self.n + j]
284 }
285 pub fn set(&mut self, i: usize, j: usize, v: TropicalNumber) {
287 self.data[i * self.n + j] = v;
288 }
289 pub fn trop_mul(&self, other: &Self) -> Self {
291 debug_assert_eq!(self.n, other.n, "matrix size mismatch");
292 let n = self.n;
293 let mut result = Self::zero(n);
294 for i in 0..n {
295 for j in 0..n {
296 let mut best = TropicalNumber::PosInfinity;
297 for k in 0..n {
298 let candidate = self.get(i, k).mul(other.get(k, j));
299 best = best.add(&candidate);
300 }
301 result.set(i, j, best);
302 }
303 }
304 result
305 }
306 pub fn trop_pow(&self, k: u32) -> Self {
308 if k == 0 {
309 return Self::identity(self.n);
310 }
311 let mut result = self.clone();
312 for _ in 1..k {
313 result = result.trop_mul(self);
314 }
315 result
316 }
317}
318#[allow(dead_code)]
320#[derive(Debug, Clone)]
321pub struct RegularSubdivision {
322 pub points: Vec<Vec<i64>>,
323 pub heights: Vec<f64>,
324 pub num_cells: usize,
325}
326impl RegularSubdivision {
327 #[allow(dead_code)]
328 pub fn new(points: Vec<Vec<i64>>, heights: Vec<f64>) -> Self {
329 let num_cells = if points.len() > 2 {
330 points.len() - 1
331 } else {
332 1
333 };
334 Self {
335 points,
336 heights,
337 num_cells,
338 }
339 }
340 #[allow(dead_code)]
341 pub fn is_unimodular(&self) -> bool {
342 true
343 }
344 #[allow(dead_code)]
345 pub fn dual_tropical_hypersurface_description(&self) -> String {
346 format!(
347 "Regular subdivision with {} cells dualizes to tropical hypersurface",
348 self.num_cells
349 )
350 }
351}
352#[derive(Debug, Clone)]
358pub struct TropicalLinearSpace {
359 pub matroid: String,
361 pub dimension: usize,
363}
364impl TropicalLinearSpace {
365 pub fn new(matroid: impl Into<String>, dimension: usize) -> Self {
367 TropicalLinearSpace {
368 matroid: matroid.into(),
369 dimension,
370 }
371 }
372 pub fn bergman_fan(&self) -> String {
374 format!(
375 "Bergman fan of matroid '{}' (dim {})",
376 self.matroid, self.dimension
377 )
378 }
379}
380#[derive(Debug, Clone)]
384pub struct TropicalSemiring;
385impl TropicalSemiring {
386 pub fn zero() -> TropicalElement {
388 TropicalElement::NegInfinity
389 }
390 pub fn one() -> TropicalElement {
392 TropicalElement::Finite(0.0)
393 }
394 pub fn add_identity() -> TropicalElement {
396 Self::zero()
397 }
398 pub fn mul_identity() -> TropicalElement {
400 Self::one()
401 }
402}
403impl TropicalSemiring {
404 pub fn tropical_add(a: f64, b: f64) -> f64 {
406 a.min(b)
407 }
408 pub fn tropical_mul(a: f64, b: f64) -> f64 {
410 a + b
411 }
412}
413#[allow(dead_code)]
415#[derive(Debug, Clone)]
416pub struct ValuatedMatroid {
417 pub ground_set_size: usize,
418 pub rank: usize,
419 pub name: String,
420}
421impl ValuatedMatroid {
422 #[allow(dead_code)]
423 pub fn new(n: usize, r: usize, name: &str) -> Self {
424 Self {
425 ground_set_size: n,
426 rank: r,
427 name: name.to_string(),
428 }
429 }
430 #[allow(dead_code)]
431 pub fn tropical_linear_space_description(&self) -> String {
432 format!(
433 "Valuated ({},{}) matroid -> tropical linear space of dim {} in R^{}",
434 self.rank,
435 self.ground_set_size,
436 self.ground_set_size - self.rank,
437 self.ground_set_size
438 )
439 }
440 #[allow(dead_code)]
441 pub fn is_realizable(&self) -> bool {
442 true
443 }
444}
445#[derive(Debug, Clone)]
448pub struct TropicalHyperplane {
449 pub normal: Vec<f64>,
451 pub constant: f64,
453}
454impl TropicalHyperplane {
455 pub fn new(normal: Vec<f64>, constant: f64) -> Self {
457 TropicalHyperplane { normal, constant }
458 }
459 pub fn evaluate_tropical(&self, point: &[f64]) -> f64 {
463 let linear_min = self
464 .normal
465 .iter()
466 .zip(point.iter())
467 .map(|(c, x)| c + x)
468 .fold(f64::INFINITY, f64::min);
469 linear_min.min(self.constant)
470 }
471}
472#[allow(dead_code)]
474#[derive(Debug, Clone)]
475pub struct TropicalAbelianVariety {
476 pub genus: usize,
477 pub lattice_rank: usize,
478}
479impl TropicalAbelianVariety {
480 #[allow(dead_code)]
481 pub fn jacobian(genus: usize) -> Self {
482 Self {
483 genus,
484 lattice_rank: genus,
485 }
486 }
487 #[allow(dead_code)]
488 pub fn dimension(&self) -> usize {
489 self.genus
490 }
491 #[allow(dead_code)]
492 pub fn is_principally_polarized_description(&self) -> String {
493 format!(
494 "Trop Jac^{}: principally polarized tropical abelian variety",
495 self.genus
496 )
497 }
498}
499#[allow(dead_code)]
501#[derive(Debug, Clone)]
502pub struct NewtonPolytopeExt {
503 pub vertices: Vec<Vec<i64>>,
504 pub dimension: usize,
505}
506impl NewtonPolytopeExt {
507 #[allow(dead_code)]
508 pub fn new(vertices: Vec<Vec<i64>>) -> Self {
509 let dim = vertices.first().map(|v| v.len()).unwrap_or(0);
510 Self {
511 vertices,
512 dimension: dim,
513 }
514 }
515 #[allow(dead_code)]
516 pub fn num_vertices(&self) -> usize {
517 self.vertices.len()
518 }
519 #[allow(dead_code)]
520 pub fn mixed_volume_description(&self) -> String {
521 format!("Mixed volume of Newton polytopes governs root count via BKK theorem")
522 }
523 #[allow(dead_code)]
524 pub fn bkk_bound_description(&self) -> String {
525 "BKK: #solutions of generic system = mixed volume of Newton polytopes".to_string()
526 }
527}
528#[derive(Debug, Clone, PartialEq)]
534pub enum TropicalElement {
535 Finite(f64),
537 NegInfinity,
539}
540impl TropicalElement {
541 pub fn tropical_add(&self, other: &Self) -> Self {
543 match (self, other) {
544 (TropicalElement::NegInfinity, _) => other.clone(),
545 (_, TropicalElement::NegInfinity) => self.clone(),
546 (TropicalElement::Finite(a), TropicalElement::Finite(b)) => {
547 TropicalElement::Finite(a.min(*b))
548 }
549 }
550 }
551 pub fn tropical_mul(&self, other: &Self) -> Self {
553 match (self, other) {
554 (TropicalElement::NegInfinity, _) | (_, TropicalElement::NegInfinity) => {
555 TropicalElement::NegInfinity
556 }
557 (TropicalElement::Finite(a), TropicalElement::Finite(b)) => {
558 TropicalElement::Finite(a + b)
559 }
560 }
561 }
562 pub fn is_zero(&self) -> bool {
564 matches!(self, TropicalElement::NegInfinity)
565 }
566 pub fn is_one(&self) -> bool {
568 matches!(self, TropicalElement::Finite(v) if * v == 0.0)
569 }
570}
571#[derive(Debug, Clone)]
573pub struct PluckerCoordinates {
574 pub k: usize,
576 pub n: usize,
578 pub coords: Vec<f64>,
580}
581impl PluckerCoordinates {
582 pub fn new(k: usize, n: usize, coords: Vec<f64>) -> Self {
584 PluckerCoordinates { k, n, coords }
585 }
586 pub fn num_coords(&self) -> usize {
588 binomial(self.n, self.k)
589 }
590}
591#[allow(dead_code)]
593#[derive(Debug, Clone)]
594pub struct TropicalRiemannSurface {
595 pub genus: u64,
596 pub num_edges: usize,
597 pub num_vertices: usize,
598 pub edge_lengths: Vec<f64>,
599}
600impl TropicalRiemannSurface {
601 #[allow(dead_code)]
602 pub fn new(genus: u64, edges: usize, vertices: usize) -> Self {
603 let lengths = vec![1.0; edges];
604 Self {
605 genus,
606 num_edges: edges,
607 num_vertices: vertices,
608 edge_lengths: lengths,
609 }
610 }
611 #[allow(dead_code)]
612 pub fn jacobian_dimension(&self) -> u64 {
613 self.genus
614 }
615 #[allow(dead_code)]
616 pub fn abel_jacobi_map_description(&self) -> String {
617 format!(
618 "Abel-Jacobi map: tropical curve -> Jac^{} (tropical torus = R^g / Lambda)",
619 self.genus
620 )
621 }
622 #[allow(dead_code)]
623 pub fn chip_firing_equivalence(&self) -> String {
624 "Divisors: chip firing game; linear equivalence = chip firing moves".to_string()
625 }
626}
627#[allow(dead_code)]
629#[derive(Debug, Clone)]
630pub struct TropicalLinearProgram {
631 pub num_variables: usize,
632 pub num_constraints: usize,
633 pub objective: Vec<f64>,
634 pub constraint_matrix: Vec<Vec<f64>>,
635 pub rhs: Vec<f64>,
636}
637impl TropicalLinearProgram {
638 #[allow(dead_code)]
639 pub fn new(vars: usize, obj: Vec<f64>, matrix: Vec<Vec<f64>>, rhs: Vec<f64>) -> Self {
640 let num_constraints = matrix.len();
641 Self {
642 num_variables: vars,
643 num_constraints,
644 objective: obj,
645 constraint_matrix: matrix,
646 rhs,
647 }
648 }
649 #[allow(dead_code)]
650 pub fn tropical_feasibility_description(&self) -> String {
651 format!(
652 "Tropical LP: min_{{x in R^{}}} c'x s.t. Ax >= b (tropically)",
653 self.num_variables
654 )
655 }
656 #[allow(dead_code)]
657 pub fn optimal_value_lower_bound(&self) -> f64 {
658 self.objective.iter().cloned().fold(f64::INFINITY, f64::min)
659 }
660}
661#[allow(dead_code)]
663#[derive(Debug, Clone)]
664pub struct TropicalHypersurfaceExt {
665 pub polynomial_support: Vec<Vec<i64>>,
666 pub coefficients: Vec<f64>,
667 pub ambient_dimension: usize,
668}
669impl TropicalHypersurfaceExt {
670 #[allow(dead_code)]
671 pub fn new(support: Vec<Vec<i64>>, coefficients: Vec<f64>) -> Self {
672 let dim = support.first().map(|v| v.len()).unwrap_or(0);
673 Self {
674 polynomial_support: support,
675 coefficients,
676 ambient_dimension: dim,
677 }
678 }
679 #[allow(dead_code)]
680 pub fn evaluate_at(&self, point: &[f64]) -> f64 {
681 self.polynomial_support
682 .iter()
683 .zip(&self.coefficients)
684 .map(|(alpha, &a)| {
685 let inner: f64 = alpha
686 .iter()
687 .zip(point)
688 .map(|(&ai, &xi)| ai as f64 * xi)
689 .sum();
690 a + inner
691 })
692 .fold(f64::NEG_INFINITY, f64::max)
693 }
694 #[allow(dead_code)]
695 pub fn is_on_hypersurface(&self, point: &[f64]) -> bool {
696 let vals: Vec<f64> = self
697 .polynomial_support
698 .iter()
699 .zip(&self.coefficients)
700 .map(|(alpha, &a)| {
701 let inner: f64 = alpha
702 .iter()
703 .zip(point)
704 .map(|(&ai, &xi)| ai as f64 * xi)
705 .sum();
706 a + inner
707 })
708 .collect();
709 let max_val = vals.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
710 vals.iter()
711 .filter(|&&v| (v - max_val).abs() < 1e-10)
712 .count()
713 >= 2
714 }
715}
716pub struct TropicalEigenvalueComputer {
724 pub matrix: Vec<Vec<f64>>,
726}
727impl TropicalEigenvalueComputer {
728 pub fn new(matrix: Vec<Vec<f64>>) -> Self {
730 TropicalEigenvalueComputer { matrix }
731 }
732 fn max_plus_mul(a: &[Vec<f64>], b: &[Vec<f64>]) -> Vec<Vec<f64>> {
734 let n = a.len();
735 let mut c = vec![vec![f64::NEG_INFINITY; n]; n];
736 for i in 0..n {
737 for j in 0..n {
738 for k in 0..n {
739 let v = a[i][k] + b[k][j];
740 if v > c[i][j] {
741 c[i][j] = v;
742 }
743 }
744 }
745 }
746 c
747 }
748 fn power(&self, k: usize) -> Vec<Vec<f64>> {
750 let n = self.matrix.len();
751 if k == 0 {
752 let mut id = vec![vec![f64::NEG_INFINITY; n]; n];
753 for i in 0..n {
754 id[i][i] = 0.0;
755 }
756 return id;
757 }
758 let mut result = self.matrix.clone();
759 for _ in 1..k {
760 result = Self::max_plus_mul(&result, &self.matrix);
761 }
762 result
763 }
764 pub fn compute_eigenvalue(&self) -> Option<f64> {
769 let n = self.matrix.len();
770 if n == 0 {
771 return None;
772 }
773 let powers: Vec<Vec<Vec<f64>>> = (0..=n).map(|k| self.power(k)).collect();
774 let mut global_max = f64::NEG_INFINITY;
775 for i in 0..n {
776 let mut node_min = f64::INFINITY;
777 for k in 0..n {
778 let a_n = powers[n][i][i];
779 let a_k = powers[k][i][i];
780 if a_n.is_finite() && a_k.is_finite() {
781 let val = (a_n - a_k) / (n - k) as f64;
782 if val < node_min {
783 node_min = val;
784 }
785 }
786 }
787 if node_min.is_finite() && node_min > global_max {
788 global_max = node_min;
789 }
790 }
791 if global_max.is_finite() {
792 Some(global_max)
793 } else {
794 None
795 }
796 }
797}
798#[derive(Debug, Clone)]
803pub struct TropicalConvexHull {
804 pub points: Vec<Vec<f64>>,
806}
807impl TropicalConvexHull {
808 pub fn new() -> Self {
810 TropicalConvexHull { points: Vec::new() }
811 }
812 pub fn add_point(&mut self, point: Vec<f64>) {
814 self.points.push(point);
815 }
816 pub fn contains_tropical(&self, point: &[f64]) -> bool {
825 if self.points.is_empty() {
826 return false;
827 }
828 self.points.iter().any(|v| {
829 if v.len() != point.len() {
830 return false;
831 }
832 let diffs: Vec<f64> = point.iter().zip(v.iter()).map(|(z, vi)| z - vi).collect();
833 let min_diff = diffs.iter().cloned().fold(f64::INFINITY, f64::min);
834 diffs.iter().all(|&d| (d - min_diff).abs() < 1e-10)
835 })
836 }
837 pub fn tropical_vertices(&self) -> Vec<Vec<f64>> {
843 self.points.clone()
844 }
845}
846#[derive(Debug, Clone)]
852pub struct DrinfeldModule {
853 pub rank: usize,
855 pub characteristic: u64,
857}
858impl DrinfeldModule {
859 pub fn new(rank: usize, characteristic: u64) -> Self {
861 DrinfeldModule {
862 rank,
863 characteristic,
864 }
865 }
866 pub fn is_ordinary(&self) -> bool {
871 self.rank <= 1 || self.characteristic % 2 != 0
872 }
873 pub fn is_supersingular(&self) -> bool {
878 !self.is_ordinary()
879 }
880 pub fn height(&self) -> usize {
885 if self.is_ordinary() {
886 0
887 } else {
888 self.rank
889 }
890 }
891}
892#[derive(Debug, Clone)]
897pub struct TropicalGrassmannian {
898 pub k: usize,
900 pub n: usize,
902}
903impl TropicalGrassmannian {
904 pub fn new(k: usize, n: usize) -> Self {
906 TropicalGrassmannian { k, n }
907 }
908 pub fn dimension(&self) -> usize {
910 self.k * (self.n.saturating_sub(self.k))
911 }
912 pub fn is_valid_plucker_coords(&self, coords: &[f64]) -> bool {
917 let expected = binomial(self.n, self.k);
918 coords.len() == expected
919 }
920}
921#[derive(Debug, Clone, PartialEq, PartialOrd)]
929pub enum TropicalNumber {
930 Finite(f64),
932 PosInfinity,
934}
935impl TropicalNumber {
936 pub fn zero() -> Self {
938 TropicalNumber::PosInfinity
939 }
940 pub fn one() -> Self {
942 TropicalNumber::Finite(0.0)
943 }
944 pub fn add(&self, other: &Self) -> Self {
946 match (self, other) {
947 (TropicalNumber::PosInfinity, x) | (x, TropicalNumber::PosInfinity) => x.clone(),
948 (TropicalNumber::Finite(a), TropicalNumber::Finite(b)) => {
949 TropicalNumber::Finite(a.min(*b))
950 }
951 }
952 }
953 pub fn mul(&self, other: &Self) -> Self {
955 match (self, other) {
956 (TropicalNumber::PosInfinity, _) | (_, TropicalNumber::PosInfinity) => {
957 TropicalNumber::PosInfinity
958 }
959 (TropicalNumber::Finite(a), TropicalNumber::Finite(b)) => TropicalNumber::Finite(a + b),
960 }
961 }
962 pub fn to_f64(&self) -> f64 {
964 match self {
965 TropicalNumber::Finite(v) => *v,
966 TropicalNumber::PosInfinity => f64::INFINITY,
967 }
968 }
969 pub fn from_f64(v: f64) -> Self {
971 if v.is_infinite() && v > 0.0 {
972 TropicalNumber::PosInfinity
973 } else {
974 TropicalNumber::Finite(v)
975 }
976 }
977}
978pub struct TropicalConvexHullComputer {
984 pub generators: Vec<Vec<f64>>,
986 pub dim: usize,
988}
989impl TropicalConvexHullComputer {
990 pub fn new(generators: Vec<Vec<f64>>) -> Option<Self> {
995 if generators.is_empty() {
996 return None;
997 }
998 let dim = generators[0].len();
999 if generators.iter().any(|g| g.len() != dim) {
1000 return None;
1001 }
1002 Some(TropicalConvexHullComputer { generators, dim })
1003 }
1004 pub fn contains(&self, point: &[f64]) -> bool {
1011 if point.len() != self.dim {
1012 return false;
1013 }
1014 self.generators.iter().any(|v| {
1015 let diffs: Vec<f64> = point.iter().zip(v.iter()).map(|(z, vi)| z - vi).collect();
1016 let min_diff = diffs.iter().cloned().fold(f64::INFINITY, f64::min);
1017 diffs.iter().all(|&d| (d - min_diff).abs() < 1e-10)
1018 })
1019 }
1020 pub fn tropical_vertices(&self) -> Vec<Vec<f64>> {
1025 let m = self.generators.len();
1026 let mut vertices = Vec::new();
1027 for i in 0..m {
1028 let others: Vec<Vec<f64>> = self
1029 .generators
1030 .iter()
1031 .enumerate()
1032 .filter(|(j, _)| *j != i)
1033 .map(|(_, g)| g.clone())
1034 .collect();
1035 if others.is_empty() {
1036 vertices.push(self.generators[i].clone());
1037 continue;
1038 }
1039 let sub_hull = TropicalConvexHullComputer {
1040 generators: others,
1041 dim: self.dim,
1042 };
1043 if !sub_hull.contains(&self.generators[i]) {
1044 vertices.push(self.generators[i].clone());
1045 }
1046 }
1047 vertices
1048 }
1049 pub fn tropical_centroid(&self) -> Vec<f64> {
1053 let mut centroid = vec![f64::INFINITY; self.dim];
1054 for g in &self.generators {
1055 for (j, &gj) in g.iter().enumerate() {
1056 if gj < centroid[j] {
1057 centroid[j] = gj;
1058 }
1059 }
1060 }
1061 centroid
1062 }
1063}
1064#[allow(dead_code)]
1066#[derive(Debug, Clone)]
1067pub struct TropicalCurveExt2 {
1068 pub genus: u64,
1069 pub degree: u64,
1070 pub ambient_dimension: usize,
1071}
1072impl TropicalCurveExt2 {
1073 #[allow(dead_code)]
1074 pub fn new(genus: u64, degree: u64, ambient_dim: usize) -> Self {
1075 Self {
1076 genus,
1077 degree,
1078 ambient_dimension: ambient_dim,
1079 }
1080 }
1081 #[allow(dead_code)]
1082 pub fn in_tropical_plane(degree: u64) -> Self {
1083 let genus = if degree >= 2 {
1084 (degree - 1) * (degree - 2) / 2
1085 } else {
1086 0
1087 };
1088 Self {
1089 genus,
1090 degree,
1091 ambient_dimension: 2,
1092 }
1093 }
1094 #[allow(dead_code)]
1095 pub fn euler_characteristic(&self) -> i64 {
1096 2 - 2 * self.genus as i64
1097 }
1098 #[allow(dead_code)]
1099 pub fn num_edges_description(&self) -> String {
1100 format!(
1101 "Tropical curve of degree {} genus {}: bounded edges",
1102 self.degree, self.genus
1103 )
1104 }
1105}
1106#[allow(dead_code)]
1108#[derive(Debug, Clone)]
1109pub struct TropicalGroebnerBasis {
1110 pub ideal_name: String,
1111 pub initial_ideal_name: String,
1112 pub tropical_variety_description: String,
1113}
1114impl TropicalGroebnerBasis {
1115 #[allow(dead_code)]
1116 pub fn new(ideal: &str) -> Self {
1117 Self {
1118 ideal_name: ideal.to_string(),
1119 initial_ideal_name: format!("in_w({})", ideal),
1120 tropical_variety_description: format!("Trop({}) = union of cones", ideal),
1121 }
1122 }
1123 #[allow(dead_code)]
1124 pub fn fundamental_theorem_description(&self) -> String {
1125 format!(
1126 "Fundamental theorem of tropical geometry: Trop({}) = closure of amoeba",
1127 self.ideal_name
1128 )
1129 }
1130}
1131#[allow(dead_code)]
1133#[derive(Debug, Clone)]
1134pub struct TropicalScheme {
1135 pub name: String,
1136 pub is_reduced: bool,
1137}
1138impl TropicalScheme {
1139 #[allow(dead_code)]
1140 pub fn new(name: &str) -> Self {
1141 Self {
1142 name: name.to_string(),
1143 is_reduced: true,
1144 }
1145 }
1146 #[allow(dead_code)]
1147 pub fn functor_of_points_description(&self) -> String {
1148 format!(
1149 "Trop scheme {}: functor Sch^op -> Set via tropical semiring",
1150 self.name
1151 )
1152 }
1153}
1154#[allow(dead_code)]
1156#[derive(Debug, Clone)]
1157pub struct TropicalFan {
1158 pub name: String,
1159 pub ambient_dimension: usize,
1160 pub fan_dimension: usize,
1161 pub is_balanced: bool,
1162}
1163impl TropicalFan {
1164 #[allow(dead_code)]
1165 pub fn new(name: &str, ambient_dim: usize, fan_dim: usize) -> Self {
1166 Self {
1167 name: name.to_string(),
1168 ambient_dimension: ambient_dim,
1169 fan_dimension: fan_dim,
1170 is_balanced: true,
1171 }
1172 }
1173 #[allow(dead_code)]
1174 pub fn balancing_condition(&self) -> String {
1175 "Sum of primitive generators weighted by multiplicities = 0 at each ridge".to_string()
1176 }
1177 #[allow(dead_code)]
1178 pub fn represents_tropical_variety(&self) -> bool {
1179 self.is_balanced
1180 }
1181}
1182#[allow(dead_code)]
1184#[derive(Debug, Clone)]
1185pub struct TropicalIntersection {
1186 pub variety_a: String,
1187 pub variety_b: String,
1188 pub codimension_a: usize,
1189 pub codimension_b: usize,
1190}
1191impl TropicalIntersection {
1192 #[allow(dead_code)]
1193 pub fn new(a: &str, b: &str, codim_a: usize, codim_b: usize) -> Self {
1194 Self {
1195 variety_a: a.to_string(),
1196 variety_b: b.to_string(),
1197 codimension_a: codim_a,
1198 codimension_b: codim_b,
1199 }
1200 }
1201 #[allow(dead_code)]
1202 pub fn expected_codimension(&self) -> usize {
1203 self.codimension_a + self.codimension_b
1204 }
1205 #[allow(dead_code)]
1206 pub fn stable_intersection_description(&self) -> String {
1207 format!(
1208 "Stable intersection {} cap {}: perturbation-independent",
1209 self.variety_a, self.variety_b
1210 )
1211 }
1212}
1213#[derive(Debug, Clone)]
1215pub struct TropicalCurveVertex {
1216 pub position: (f64, f64),
1218 pub valence: usize,
1220}
1221#[derive(Debug, Clone)]
1227pub struct MirrorSymmetry {
1228 pub a_model: String,
1230 pub b_model: String,
1232 pub is_homological: bool,
1234}
1235impl MirrorSymmetry {
1236 pub fn new(
1238 a_model: impl Into<String>,
1239 b_model: impl Into<String>,
1240 is_homological: bool,
1241 ) -> Self {
1242 MirrorSymmetry {
1243 a_model: a_model.into(),
1244 b_model: b_model.into(),
1245 is_homological,
1246 }
1247 }
1248 pub fn hodge_numbers_match(&self) -> bool {
1253 true
1254 }
1255 pub fn mirror_map_description(&self) -> String {
1257 if self.is_homological {
1258 format!(
1259 "Homological mirror symmetry: Fuk({}) ≃ D^b Coh({})",
1260 self.a_model, self.b_model
1261 )
1262 } else {
1263 format!(
1264 "SYZ mirror symmetry: T-duality fibers of {} ↔ {}",
1265 self.a_model, self.b_model
1266 )
1267 }
1268 }
1269}
1270#[allow(dead_code)]
1272#[derive(Debug, Clone)]
1273pub struct TropicalModuliM0n {
1274 pub n: usize,
1275}
1276impl TropicalModuliM0n {
1277 #[allow(dead_code)]
1278 pub fn new(n: usize) -> Self {
1279 assert!(n >= 3);
1280 Self { n }
1281 }
1282 #[allow(dead_code)]
1283 pub fn dimension(&self) -> usize {
1284 self.n - 3
1285 }
1286 #[allow(dead_code)]
1287 pub fn num_rays_description(&self) -> String {
1288 format!(
1289 "Trop M_{{0,{}}} has rays indexed by 2-subsets of [{}]",
1290 self.n, self.n
1291 )
1292 }
1293 #[allow(dead_code)]
1294 pub fn space_of_phylogenetic_trees(&self) -> String {
1295 format!(
1296 "Trop M_{{0,{}}} = space of metric trees with {} labeled leaves",
1297 self.n, self.n
1298 )
1299 }
1300}
1301#[derive(Debug, Clone)]
1303pub struct Valuation {
1304 pub name: String,
1306 pub field: String,
1308 pub value_group: String,
1310}
1311#[derive(Debug, Clone)]
1317pub struct TropicalCurveExt {
1318 pub degree: usize,
1320 pub genus: usize,
1322 pub vertices: Vec<TropicalCurveVertex>,
1324 pub edges: Vec<(usize, usize, f64)>,
1326}
1327impl TropicalCurveExt {
1328 pub fn new(degree: usize) -> Self {
1333 let d = degree as i64;
1334 let genus = if d >= 1 {
1335 ((d - 1) * (d - 2) / 2).max(0) as usize
1336 } else {
1337 0
1338 };
1339 TropicalCurveExt {
1340 degree,
1341 genus,
1342 vertices: Vec::new(),
1343 edges: Vec::new(),
1344 }
1345 }
1346 pub fn genus_formula(&self) -> i64 {
1348 let d = self.degree as i64;
1349 (d - 1) * (d - 2) / 2
1350 }
1351 pub fn is_smooth(&self) -> bool {
1356 let expected_genus = self.genus_formula().max(0) as usize;
1357 if self.genus != expected_genus {
1358 return false;
1359 }
1360 self.vertices.iter().all(|v| v.valence == 3)
1361 }
1362}
1363impl TropicalCurveExt {
1364 pub fn genus(&self) -> usize {
1366 self.genus
1367 }
1368 pub fn num_marked_points(&self) -> usize {
1373 3 * self.degree
1374 }
1375}
1376#[derive(Debug, Clone)]
1381pub struct TropicalMonomial {
1382 pub coefficient: f64,
1384 pub exponents: Vec<i32>,
1386}
1387#[derive(Debug, Clone)]
1393pub struct TropicalVariety {
1394 pub polynomial_system: Vec<TropicalPolynomial>,
1396 pub n_vars: usize,
1398}
1399impl TropicalVariety {
1400 pub fn new(n_vars: usize) -> Self {
1402 TropicalVariety {
1403 polynomial_system: Vec::new(),
1404 n_vars,
1405 }
1406 }
1407 pub fn add_equation(&mut self, poly: TropicalPolynomial) {
1409 self.polynomial_system.push(poly);
1410 }
1411 pub fn dimension(&self) -> usize {
1416 self.n_vars.saturating_sub(self.polynomial_system.len())
1417 }
1418}
1419impl TropicalVariety {
1420 pub fn stable_intersection(&self) -> String {
1426 format!(
1427 "Stable intersection of tropical variety in ℝ^{} (dim {})",
1428 self.n_vars,
1429 self.dimension()
1430 )
1431 }
1432}
1433#[derive(Debug, Clone)]
1435pub struct LaurentSeriesValuation {
1436 pub variable: String,
1438}
1439#[derive(Debug, Clone)]
1443pub struct PAdicValuation {
1444 pub p: u64,
1446}
1447impl PAdicValuation {
1448 pub fn new(p: u64) -> Self {
1450 PAdicValuation { p }
1451 }
1452 pub fn valuation(&self, n: i64) -> i64 {
1456 if n == 0 {
1457 return 0;
1458 }
1459 let mut n = n.unsigned_abs();
1460 let mut k = 0i64;
1461 while n % self.p == 0 {
1462 n /= self.p;
1463 k += 1;
1464 }
1465 k
1466 }
1467 pub fn ultrametric_triangle_inequality(&self) -> bool {
1470 true
1471 }
1472}
1473#[derive(Debug, Clone)]
1479pub struct TropicalHypersurface {
1480 pub polynomial: String,
1482}
1483impl TropicalHypersurface {
1484 pub fn new(polynomial: impl Into<String>) -> Self {
1486 TropicalHypersurface {
1487 polynomial: polynomial.into(),
1488 }
1489 }
1490 pub fn dual_subdivision(&self) -> String {
1496 format!(
1497 "Regular subdivision of Newton polytope dual to V({})",
1498 self.polynomial
1499 )
1500 }
1501 pub fn skeleton(&self) -> String {
1505 format!("Polyhedral skeleton of V({})", self.polynomial)
1506 }
1507}
1508#[derive(Debug, Clone)]
1513pub struct TropicalSegment {
1514 pub start: Vec<f64>,
1516 pub end: Vec<f64>,
1518}
1519impl TropicalSegment {
1520 pub fn new(start: Vec<f64>, end: Vec<f64>) -> Self {
1522 TropicalSegment { start, end }
1523 }
1524 pub fn parametric_point(&self, t: f64) -> Vec<f64> {
1529 self.start
1530 .iter()
1531 .zip(self.end.iter())
1532 .map(|(s, e)| (s + t).min(*e))
1533 .collect()
1534 }
1535}