1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8use std::collections::HashMap;
9
10#[allow(dead_code)]
12#[derive(Debug, Clone)]
13pub struct FiberBundle {
14 pub total_space: String,
16 pub base_space: String,
18 pub fiber: String,
20 pub has_section: bool,
22 pub is_trivial: bool,
24 pub structure_group: Option<String>,
26}
27#[allow(dead_code)]
28impl FiberBundle {
29 pub fn new(total: &str, base: &str, fiber: &str) -> Self {
31 FiberBundle {
32 total_space: total.to_string(),
33 base_space: base.to_string(),
34 fiber: fiber.to_string(),
35 has_section: false,
36 is_trivial: false,
37 structure_group: None,
38 }
39 }
40 pub fn with_structure_group(mut self, g: &str) -> Self {
42 self.structure_group = Some(g.to_string());
43 self
44 }
45 pub fn trivial(mut self) -> Self {
47 self.is_trivial = true;
48 self.has_section = true;
49 self
50 }
51 pub fn les_description(&self) -> String {
53 format!(
54 "... → π_n({}) → π_n({}) → π_n({}) → π_{{n-1}}({}) → ...",
55 self.fiber, self.total_space, self.base_space, self.fiber
56 )
57 }
58 pub fn is_principal(&self) -> bool {
60 match &self.structure_group {
61 Some(g) => *g == self.fiber,
62 None => false,
63 }
64 }
65}
66pub struct SimplicialComplex {
72 pub vertices: Vec<usize>,
74 pub simplices: Vec<Vec<usize>>,
76}
77impl SimplicialComplex {
78 pub fn new() -> Self {
80 SimplicialComplex {
81 vertices: Vec::new(),
82 simplices: Vec::new(),
83 }
84 }
85 pub fn add_simplex(&mut self, mut simplex: Vec<usize>) {
90 simplex.sort_unstable();
91 simplex.dedup();
92 for &v in &simplex {
93 if !self.vertices.contains(&v) {
94 self.vertices.push(v);
95 }
96 }
97 self.vertices.sort_unstable();
98 if !self.simplices.contains(&simplex) {
99 self.simplices.push(simplex);
100 }
101 }
102 pub(super) fn simplices_of_dim(&self, dim: usize) -> Vec<&Vec<usize>> {
106 self.simplices
107 .iter()
108 .filter(|s| s.len() == dim + 1)
109 .collect()
110 }
111 pub fn boundary_matrix(&self, dim: usize) -> Vec<Vec<i64>> {
119 if dim == 0 {
120 return Vec::new();
121 }
122 let lower = self.simplices_of_dim(dim - 1);
123 let upper = self.simplices_of_dim(dim);
124 let rows = lower.len();
125 let cols = upper.len();
126 let mut mat = vec![vec![0i64; cols]; rows];
127 for (col, sigma) in upper.iter().enumerate() {
128 for i in 0..sigma.len() {
129 let mut face = sigma[..i].to_vec();
130 face.extend_from_slice(&sigma[i + 1..]);
131 if let Some(row) = lower.iter().position(|f| **f == face) {
132 mat[row][col] = if i % 2 == 0 { 1 } else { -1 };
133 }
134 }
135 }
136 mat
137 }
138 pub fn euler_characteristic(&self) -> i64 {
140 let max_dim = self.simplices.iter().map(|s| s.len()).max().unwrap_or(0);
141 let mut chi = 0i64;
142 for k in 0..max_dim {
143 let count = self.simplices_of_dim(k).len() as i64;
144 if k % 2 == 0 {
145 chi += count;
146 } else {
147 chi -= count;
148 }
149 }
150 chi
151 }
152 pub fn betti_numbers(&self, max_dim: usize) -> Vec<usize> {
159 homology_ranks(self, max_dim)
160 }
161}
162#[allow(dead_code)]
164#[derive(Debug, Clone, PartialEq)]
165pub struct PersistencePoint {
166 pub birth: f64,
168 pub death: f64,
170 pub dimension: usize,
172}
173#[allow(dead_code)]
174impl PersistencePoint {
175 pub fn new(birth: f64, death: f64, dimension: usize) -> Self {
177 PersistencePoint {
178 birth,
179 death,
180 dimension,
181 }
182 }
183 pub fn persistence(&self) -> f64 {
185 self.death - self.birth
186 }
187 pub fn is_essential(&self) -> bool {
189 self.death == f64::INFINITY
190 }
191 pub fn midpoint(&self) -> f64 {
193 if self.is_essential() {
194 self.birth
195 } else {
196 (self.birth + self.death) / 2.0
197 }
198 }
199}
200#[derive(Debug, Clone)]
202pub struct TopologicalInvariantTable {
203 pub cell_counts: Vec<usize>,
205 pub euler_characteristic: i64,
207 pub betti_numbers: Vec<usize>,
209}
210impl TopologicalInvariantTable {
211 pub fn compute(complex: &SimplicialComplex, max_dim: usize) -> Self {
214 let cell_counts: Vec<usize> = (0..=max_dim)
215 .map(|k| complex.simplices_of_dim(k).len())
216 .collect();
217 let euler_characteristic = complex.euler_characteristic();
218 let betti_numbers = homology_ranks(complex, max_dim);
219 TopologicalInvariantTable {
220 cell_counts,
221 euler_characteristic,
222 betti_numbers,
223 }
224 }
225 pub fn display(&self) -> String {
227 let mut out = String::new();
228 out.push_str("Topological Invariants\n");
229 out.push_str("======================\n");
230 for (k, &c) in self.cell_counts.iter().enumerate() {
231 out.push_str(&format!(" #{k}-cells = {c}\n"));
232 }
233 out.push_str(&format!(" χ (Euler) = {}\n", self.euler_characteristic));
234 for (k, &b) in self.betti_numbers.iter().enumerate() {
235 out.push_str(&format!(" β_{k} = {b}\n"));
236 }
237 out
238 }
239}
240pub struct CharacteristicClassComputer {
246 pub chern_roots: Vec<f64>,
248}
249impl CharacteristicClassComputer {
250 pub fn new(chern_roots: Vec<f64>) -> Self {
252 CharacteristicClassComputer { chern_roots }
253 }
254 pub fn total_chern_class(&self) -> Vec<f64> {
258 let n = self.chern_roots.len();
259 let mut c = vec![0.0f64; n + 1];
260 c[0] = 1.0;
261 for &x in &self.chern_roots {
262 for k in (1..=n).rev() {
263 c[k] += x * c[k - 1];
264 }
265 }
266 c
267 }
268 pub fn chern_character(&self, max_deg: usize) -> Vec<f64> {
270 let mut ch = vec![0.0f64; max_deg + 1];
271 for &x in &self.chern_roots {
272 let mut power = 1.0f64;
273 let mut factorial = 1.0f64;
274 for k in 0..=max_deg {
275 if k > 0 {
276 power *= x;
277 factorial *= k as f64;
278 }
279 ch[k] += power / factorial;
280 }
281 }
282 ch
283 }
284 pub fn euler_number(&self) -> f64 {
287 let c = self.total_chern_class();
288 *c.last().unwrap_or(&0.0)
289 }
290}
291#[allow(dead_code)]
293#[derive(Debug, Clone)]
294pub struct SpectralSequencePage {
295 pub r: usize,
297 pub data: std::collections::HashMap<(i32, i32), String>,
299}
300#[allow(dead_code)]
301impl SpectralSequencePage {
302 pub fn new(r: usize) -> Self {
304 SpectralSequencePage {
305 r,
306 data: std::collections::HashMap::new(),
307 }
308 }
309 pub fn set(&mut self, p: i32, q: i32, group: &str) {
311 self.data.insert((p, q), group.to_string());
312 }
313 pub fn get(&self, p: i32, q: i32) -> &str {
315 self.data.get(&(p, q)).map(|s| s.as_str()).unwrap_or("0")
316 }
317 pub fn total_degree(&self, n: i32) -> Vec<&str> {
319 self.data
320 .iter()
321 .filter(|&(&(p, q), _)| p + q == n)
322 .map(|(_, v)| v.as_str())
323 .collect()
324 }
325 pub fn differential_target(&self, p: i32, q: i32) -> (i32, i32) {
327 (p + self.r as i32, q - self.r as i32 + 1)
328 }
329}
330pub struct UltrametricBallTree {
336 pub points: Vec<f64>,
338 pub prime: u32,
340}
341impl UltrametricBallTree {
342 pub fn new(points: Vec<f64>, prime: u32) -> Self {
344 UltrametricBallTree { points, prime }
345 }
346 pub fn padic_valuation(&self, x: f64) -> i32 {
351 let n = x.round().abs() as u64;
352 if n == 0 {
353 return i32::MAX;
354 }
355 let p = self.prime as u64;
356 let mut val = 0i32;
357 let mut m = n;
358 while m % p == 0 {
359 val += 1;
360 m /= p;
361 }
362 val
363 }
364 pub fn ultrametric_dist(&self, x: f64, y: f64) -> f64 {
366 let diff = x - y;
367 if diff.abs() < f64::EPSILON {
368 return 0.0;
369 }
370 let v = self.padic_valuation(diff);
371 if v == i32::MAX {
372 0.0
373 } else {
374 (self.prime as f64).powi(-v)
375 }
376 }
377 pub fn check_ultrametric_inequality(&self, x: f64, y: f64, z: f64) -> bool {
379 let dxz = self.ultrametric_dist(x, z);
380 let dxy = self.ultrametric_dist(x, y);
381 let dyz = self.ultrametric_dist(y, z);
382 dxz <= dxy.max(dyz) + f64::EPSILON
383 }
384 pub fn ball(&self, center: f64, radius: f64) -> Vec<f64> {
386 self.points
387 .iter()
388 .filter(|&&p| self.ultrametric_dist(center, p) <= radius)
389 .copied()
390 .collect()
391 }
392}
393#[allow(dead_code)]
395#[derive(Debug, Clone)]
396pub struct CWComplex {
397 pub name: String,
399 pub cells: Vec<u32>,
401}
402#[allow(dead_code)]
403impl CWComplex {
404 pub fn new(name: &str) -> Self {
406 CWComplex {
407 name: name.to_string(),
408 cells: Vec::new(),
409 }
410 }
411 pub fn add_cells(mut self, dim: usize, count: u32) -> Self {
413 while self.cells.len() <= dim {
414 self.cells.push(0);
415 }
416 self.cells[dim] += count;
417 self
418 }
419 pub fn sphere(n: usize) -> Self {
421 let mut cw = CWComplex::new(&format!("S^{n}"));
422 cw = cw.add_cells(0, 1);
423 cw = cw.add_cells(n, 1);
424 cw
425 }
426 pub fn torus() -> Self {
428 CWComplex::new("T^2")
429 .add_cells(0, 1)
430 .add_cells(1, 2)
431 .add_cells(2, 1)
432 }
433 pub fn rp2() -> Self {
435 CWComplex::new("RP^2")
436 .add_cells(0, 1)
437 .add_cells(1, 1)
438 .add_cells(2, 1)
439 }
440 pub fn euler_characteristic(&self) -> i64 {
442 self.cells
443 .iter()
444 .enumerate()
445 .map(|(k, &c)| {
446 let sign: i64 = if k % 2 == 0 { 1 } else { -1 };
447 sign * c as i64
448 })
449 .sum()
450 }
451 pub fn dimension(&self) -> Option<usize> {
453 self.cells
454 .iter()
455 .enumerate()
456 .rev()
457 .find(|(_, &c)| c > 0)
458 .map(|(k, _)| k)
459 }
460}
461#[allow(dead_code)]
463#[derive(Debug, Clone)]
464pub struct DiscreteMorseFunction {
465 pub cells: Vec<usize>,
467 pub critical_cells: Vec<Vec<usize>>,
469 pub gradient_pairs: Vec<(usize, usize, usize, usize)>,
471}
472#[allow(dead_code)]
473impl DiscreteMorseFunction {
474 pub fn new(cells: Vec<usize>) -> Self {
476 let n = cells.len();
477 DiscreteMorseFunction {
478 cells,
479 critical_cells: vec![Vec::new(); n],
480 gradient_pairs: Vec::new(),
481 }
482 }
483 pub fn mark_critical(&mut self, dim: usize, idx: usize) {
485 if dim < self.critical_cells.len() {
486 self.critical_cells[dim].push(idx);
487 }
488 }
489 pub fn add_gradient_pair(&mut self, dim: usize, lower_idx: usize, upper_idx: usize) {
491 if dim + 1 < self.cells.len() {
492 self.gradient_pairs
493 .push((dim, lower_idx, dim + 1, upper_idx));
494 }
495 }
496 pub fn morse_inequalities_lhs(&self) -> Vec<usize> {
498 self.critical_cells.iter().map(|v| v.len()).collect()
499 }
500 pub fn check_weak_morse_inequality(&self, betti: &[usize]) -> bool {
502 let critical = self.morse_inequalities_lhs();
503 betti
504 .iter()
505 .enumerate()
506 .all(|(k, &b)| critical.get(k).copied().unwrap_or(0) >= b)
507 }
508 pub fn euler_characteristic(&self) -> i64 {
510 self.critical_cells
511 .iter()
512 .enumerate()
513 .map(|(k, cells)| {
514 let sign: i64 = if k % 2 == 0 { 1 } else { -1 };
515 sign * cells.len() as i64
516 })
517 .sum()
518 }
519}
520pub struct UniformContinuityChecker<'a> {
529 pub source: &'a MetricSpace,
531 pub target: &'a MetricSpace,
533 pub mapping: Vec<usize>,
535}
536impl<'a> UniformContinuityChecker<'a> {
537 pub fn new(source: &'a MetricSpace, target: &'a MetricSpace, mapping: Vec<usize>) -> Self {
539 UniformContinuityChecker {
540 source,
541 target,
542 mapping,
543 }
544 }
545 pub fn is_uniformly_continuous(&self, epsilon: f64, delta: f64) -> bool {
548 let n = self.source.n;
549 for i in 0..n {
550 for j in 0..n {
551 if self.source.dist[i][j] < delta {
552 let fi = self.mapping[i];
553 let fj = self.mapping[j];
554 if self.target.dist[fi][fj] >= epsilon {
555 return false;
556 }
557 }
558 }
559 }
560 true
561 }
562}
563pub struct MetricSpace {
569 pub n: usize,
571 pub dist: Vec<Vec<f64>>,
573}
574impl MetricSpace {
575 pub fn new(dist: Vec<Vec<f64>>) -> Self {
579 let n = dist.len();
580 for row in &dist {
581 assert_eq!(row.len(), n, "distance matrix must be square");
582 }
583 MetricSpace { n, dist }
584 }
585 pub fn distance(&self, i: usize, j: usize) -> f64 {
587 self.dist[i][j]
588 }
589 pub fn is_totally_bounded(&self, epsilon: f64) -> bool {
593 if self.n == 0 {
594 return true;
595 }
596 let net = self.greedy_epsilon_net(epsilon);
597 (0..self.n).all(|i| net.iter().any(|&j| self.dist[i][j] <= epsilon))
598 }
599 pub fn greedy_epsilon_net(&self, epsilon: f64) -> Vec<usize> {
602 let mut net: Vec<usize> = Vec::new();
603 for i in 0..self.n {
604 if !net.iter().any(|&j| self.dist[i][j] <= epsilon) {
605 net.push(i);
606 }
607 }
608 net
609 }
610 pub fn looks_complete(&self, epsilon: f64) -> bool {
616 self.is_totally_bounded(epsilon)
617 }
618}
619pub struct ProObjectLimit {
624 pub levels: Vec<Vec<u32>>,
626 pub projections: Vec<Vec<usize>>,
629}
630impl ProObjectLimit {
631 pub fn new(levels: Vec<Vec<u32>>, projections: Vec<Vec<usize>>) -> Self {
633 ProObjectLimit {
634 levels,
635 projections,
636 }
637 }
638 pub fn compute_limit(&self) -> Vec<Vec<usize>> {
643 if self.levels.is_empty() {
644 return vec![];
645 }
646 let mut threads: Vec<Vec<usize>> = (0..self.levels[0].len()).map(|i| vec![i]).collect();
647 for (level_idx, proj) in self.projections.iter().enumerate() {
648 let next_level_size = if level_idx + 1 < self.levels.len() {
649 self.levels[level_idx + 1].len()
650 } else {
651 break;
652 };
653 let mut new_threads: Vec<Vec<usize>> = Vec::new();
654 for j in 0..next_level_size {
655 let parent = proj[j];
656 for thread in &threads {
657 if *thread
658 .last()
659 .expect("threads are always non-empty: initialized with vec![i]")
660 == parent
661 {
662 let mut new_thread = thread.clone();
663 new_thread.push(j);
664 new_threads.push(new_thread);
665 }
666 }
667 }
668 threads = new_threads;
669 }
670 threads
671 }
672 pub fn limit_size(&self) -> usize {
674 self.compute_limit().len()
675 }
676}
677pub struct ShapeEquivalenceChecker {
683 pub betti_x: Vec<usize>,
685 pub betti_y: Vec<usize>,
687}
688impl ShapeEquivalenceChecker {
689 pub fn from_complexes(cx: &SimplicialComplex, cy: &SimplicialComplex, max_dim: usize) -> Self {
691 ShapeEquivalenceChecker {
692 betti_x: homology_ranks(cx, max_dim),
693 betti_y: homology_ranks(cy, max_dim),
694 }
695 }
696 fn euler_from_betti(betti: &[usize]) -> i64 {
698 betti
699 .iter()
700 .enumerate()
701 .map(|(k, &b)| if k % 2 == 0 { b as i64 } else { -(b as i64) })
702 .sum()
703 }
704 pub fn euler_agrees(&self) -> bool {
706 Self::euler_from_betti(&self.betti_x) == Self::euler_from_betti(&self.betti_y)
707 }
708 pub fn betti_agree(&self) -> bool {
710 let len = self.betti_x.len().max(self.betti_y.len());
711 for k in 0..len {
712 let bx = self.betti_x.get(k).copied().unwrap_or(0);
713 let by = self.betti_y.get(k).copied().unwrap_or(0);
714 if bx != by {
715 return false;
716 }
717 }
718 true
719 }
720 pub fn are_shape_equivalent(&self) -> bool {
722 self.betti_agree()
723 }
724}
725#[allow(dead_code)]
727#[derive(Debug, Clone)]
728pub struct KnotInvariant {
729 pub name: String,
731 pub alexander_poly: Vec<i64>,
733 pub jones_data: Vec<(i32, i64)>,
735 pub signature: i64,
737 pub determinant: u64,
739}
740#[allow(dead_code)]
741impl KnotInvariant {
742 pub fn new(name: &str) -> Self {
744 KnotInvariant {
745 name: name.to_string(),
746 alexander_poly: Vec::new(),
747 jones_data: Vec::new(),
748 signature: 0,
749 determinant: 1,
750 }
751 }
752 pub fn with_alexander(mut self, coeffs: Vec<i64>) -> Self {
754 self.alexander_poly = coeffs;
755 self
756 }
757 pub fn with_signature(mut self, sig: i64) -> Self {
759 self.signature = sig;
760 self
761 }
762 pub fn with_determinant(mut self, det: u64) -> Self {
764 self.determinant = det;
765 self
766 }
767 pub fn alexander_at_one(&self) -> i64 {
769 self.alexander_poly.iter().sum()
770 }
771 pub fn alexander_degree(&self) -> usize {
773 self.alexander_poly.len().saturating_sub(1)
774 }
775 pub fn potentially_fibered(&self) -> bool {
777 if let (Some(&first), Some(&last)) =
778 (self.alexander_poly.first(), self.alexander_poly.last())
779 {
780 first.abs() == 1 && last.abs() == 1
781 } else {
782 false
783 }
784 }
785}
786#[derive(Debug, Clone)]
788pub struct Cell {
789 pub dim: usize,
791 pub label: String,
793 pub attaching_map: Vec<usize>,
795}
796#[allow(dead_code)]
798#[derive(Debug, Clone, Default)]
799pub struct PersistenceDiagram {
800 pub points: Vec<PersistencePoint>,
802}
803#[allow(dead_code)]
804impl PersistenceDiagram {
805 pub fn new() -> Self {
807 PersistenceDiagram { points: Vec::new() }
808 }
809 pub fn add(&mut self, p: PersistencePoint) {
811 self.points.push(p);
812 }
813 pub fn in_dimension(&self, dim: usize) -> Vec<&PersistencePoint> {
815 self.points.iter().filter(|p| p.dimension == dim).collect()
816 }
817 pub fn betti(&self, dim: usize) -> usize {
819 self.points
820 .iter()
821 .filter(|p| p.dimension == dim && p.is_essential())
822 .count()
823 }
824 pub fn bottleneck_distance_approx(&self, other: &PersistenceDiagram) -> f64 {
826 let mut max_dist: f64 = 0.0;
827 for p in &self.points {
828 let d = other
829 .points
830 .iter()
831 .map(|q| ((p.birth - q.birth).abs()).max((p.death - q.death).abs()))
832 .fold(f64::INFINITY, f64::min);
833 max_dist = max_dist.max(d);
834 }
835 max_dist
836 }
837 pub fn total_persistence(&self) -> f64 {
839 self.points
840 .iter()
841 .filter(|p| !p.is_essential())
842 .map(|p| p.persistence())
843 .sum()
844 }
845 pub fn significant_features(&self, threshold: f64) -> Vec<&PersistencePoint> {
847 self.points
848 .iter()
849 .filter(|p| p.persistence() > threshold || p.is_essential())
850 .collect()
851 }
852}
853pub struct CWComplexBuilder {
858 pub cells: Vec<Cell>,
860}
861impl CWComplexBuilder {
862 pub fn new() -> Self {
864 CWComplexBuilder { cells: Vec::new() }
865 }
866 pub fn add_cell(
870 &mut self,
871 dim: usize,
872 label: impl Into<String>,
873 attaching: Vec<usize>,
874 ) -> usize {
875 let idx = self.cells.len();
876 self.cells.push(Cell {
877 dim,
878 label: label.into(),
879 attaching_map: attaching,
880 });
881 idx
882 }
883 pub fn cell_counts(&self, max_dim: usize) -> Vec<usize> {
885 let mut counts = vec![0usize; max_dim + 1];
886 for cell in &self.cells {
887 if cell.dim <= max_dim {
888 counts[cell.dim] += 1;
889 }
890 }
891 counts
892 }
893 pub fn euler_characteristic(&self) -> i64 {
895 let max_dim = self.cells.iter().map(|c| c.dim).max().unwrap_or(0);
896 let counts = self.cell_counts(max_dim);
897 counts
898 .iter()
899 .enumerate()
900 .map(|(k, &c)| if k % 2 == 0 { c as i64 } else { -(c as i64) })
901 .sum()
902 }
903}
904#[derive(Debug)]
914pub struct BaireCategoryGame {
915 pub grid_size: usize,
917 pub left: usize,
919 pub right: usize,
921 pub round: usize,
923}
924impl BaireCategoryGame {
925 pub fn new(grid_size: usize) -> Self {
927 assert!(grid_size >= 2, "grid must have at least 2 points");
928 BaireCategoryGame {
929 grid_size,
930 left: 0,
931 right: grid_size - 1,
932 round: 0,
933 }
934 }
935 pub fn player_one_move(&mut self) {
937 let width = self.right - self.left;
938 let new_right = self.left + width / 3;
939 if new_right > self.left {
940 self.right = new_right;
941 }
942 self.round += 1;
943 }
944 pub fn player_two_move(&mut self) {
946 let width = self.right - self.left;
947 let third = width / 3;
948 self.left += third;
949 self.right = self.right.saturating_sub(third);
950 self.round += 1;
951 }
952 pub fn player_two_winning(&self) -> bool {
954 self.left <= self.right
955 }
956 pub fn simulate(&mut self, rounds: usize) -> bool {
958 for _ in 0..rounds {
959 self.player_one_move();
960 if !self.player_two_winning() {
961 return false;
962 }
963 self.player_two_move();
964 if !self.player_two_winning() {
965 return false;
966 }
967 }
968 self.player_two_winning()
969 }
970}