use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use super::types::{
ChainComplex, Cochain, CwComplex, HomologyGroup, HomotopyGroupData, SimplicialComplex,
};
pub fn app(f: Expr, a: Expr) -> Expr {
Expr::App(Box::new(f), Box::new(a))
}
pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
app(app(f, a), b)
}
pub fn cst(s: &str) -> Expr {
Expr::Const(Name::str(s), vec![])
}
pub fn prop() -> Expr {
Expr::Sort(Level::zero())
}
pub fn type0() -> Expr {
Expr::Sort(Level::succ(Level::zero()))
}
pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
}
pub fn arrow(a: Expr, b: Expr) -> Expr {
pi(BinderInfo::Default, "_", a, b)
}
pub fn bvar(n: u32) -> Expr {
Expr::BVar(n)
}
pub fn nat_ty() -> Expr {
cst("Nat")
}
pub fn group_ty() -> Expr {
cst("Group")
}
pub fn ring_ty() -> Expr {
cst("Ring")
}
pub fn space_ty() -> Expr {
cst("TopologicalSpace")
}
pub fn fundamental_group_ty() -> Expr {
arrow(space_ty(), group_ty())
}
pub fn higher_homotopy_group_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), group_ty()))
}
pub fn singular_homology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn cohomology_ring_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), ring_ty()))
}
pub fn covering_space_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn cw_complex_ty() -> Expr {
type0()
}
pub fn simplicial_complex_ty() -> Expr {
type0()
}
pub fn simplicial_homology_ty() -> Expr {
arrow(
nat_ty(),
arrow(cst("SimplicialComplex"), arrow(ring_ty(), group_ty())),
)
}
pub fn boundary_operator_ty() -> Expr {
arrow(
nat_ty(),
arrow(cst("SimplicialComplex"), arrow(group_ty(), group_ty())),
)
}
pub fn cellular_homology_ty() -> Expr {
arrow(
nat_ty(),
arrow(cst("CWComplex"), arrow(ring_ty(), group_ty())),
)
}
pub fn singular_cohomology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn cup_product_ty() -> Expr {
arrow(
nat_ty(),
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty()))),
)
}
pub fn cap_product_ty() -> Expr {
arrow(
nat_ty(),
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty()))),
)
}
pub fn kunneth_formula_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn lefschetz_fixed_point_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn alexander_duality_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn cech_cohomology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn sheaf_cohomology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(type0(), group_ty())))
}
pub fn steenrod_square_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), arrow(space_ty(), prop())))
}
pub fn k_theory_ty() -> Expr {
arrow(space_ty(), ring_ty())
}
pub fn bott_periodicity_ty() -> Expr {
arrow(space_ty(), prop())
}
pub fn clutching_construction_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn cobordism_ring_ty() -> Expr {
ring_ty()
}
pub fn stiefel_whitney_class_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn pontryagin_class_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn serre_spectral_sequence_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn eilenberg_maclane_space_ty() -> Expr {
arrow(nat_ty(), arrow(group_ty(), space_ty()))
}
pub fn postnikov_tower_ty() -> Expr {
arrow(space_ty(), arrow(nat_ty(), space_ty()))
}
pub fn whitehead_product_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), arrow(space_ty(), group_ty())))
}
pub fn james_construction_ty() -> Expr {
arrow(space_ty(), space_ty())
}
pub fn ehp_sequence_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), prop()))
}
pub fn fibration_long_exact_seq_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(space_ty(), prop())))
}
pub fn mayer_vietoris_sequence_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(space_ty(), prop())))
}
pub fn suspension_isomorphism_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn homology_functoriality_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(nat_ty(), prop())))
}
pub fn homotopy_invariance_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(nat_ty(), prop())))
}
pub fn persistent_homology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn barcode_decomposition_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), type0())))
}
pub fn persistence_diagram_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), type0()))
}
pub fn wasserstein_distance_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(space_ty(), type0())))
}
pub fn stability_theorem_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(space_ty(), prop())))
}
pub fn sheaf_ty() -> Expr {
arrow(space_ty(), arrow(type0(), type0()))
}
pub fn sheaf_morphism_ty() -> Expr {
arrow(space_ty(), arrow(type0(), arrow(type0(), prop())))
}
pub fn derived_functor_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(type0(), group_ty())))
}
pub fn grothendieck_topos_ty() -> Expr {
type0()
}
pub fn locally_constant_sheaf_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), type0()))
}
pub fn spectral_sequence_ty() -> Expr {
arrow(nat_ty(), arrow(ring_ty(), type0()))
}
pub fn adem_relations_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), arrow(space_ty(), prop())))
}
pub fn atiyah_hirzebruch_ss_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), prop()))
}
pub fn adams_spectral_sequence_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn chern_class_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn euler_class_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), group_ty()))
}
pub fn thom_isomorphism_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn characteristic_number_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), type0()))
}
pub fn real_k_theory_ty() -> Expr {
arrow(space_ty(), ring_ty())
}
pub fn equivariant_k_theory_ty() -> Expr {
arrow(space_ty(), arrow(group_ty(), ring_ty()))
}
pub fn k_group_exact_seq_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn oriented_cobordism_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn cobordism_invariant_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), type0()))
}
pub fn thom_transversality_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn fiber_bundle_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), arrow(space_ty(), prop())))
}
pub fn vector_bundle_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), type0()))
}
pub fn principal_bundle_ty() -> Expr {
arrow(group_ty(), arrow(space_ty(), type0()))
}
pub fn connection_ty() -> Expr {
arrow(space_ty(), arrow(type0(), type0()))
}
pub fn curvature_form_ty() -> Expr {
arrow(space_ty(), arrow(type0(), type0()))
}
pub fn gauge_transformation_ty() -> Expr {
arrow(space_ty(), arrow(group_ty(), type0()))
}
pub fn fredholm_operator_ty() -> Expr {
arrow(space_ty(), type0())
}
pub fn analytic_index_ty() -> Expr {
arrow(space_ty(), arrow(type0(), type0()))
}
pub fn topological_index_ty() -> Expr {
arrow(space_ty(), arrow(type0(), ring_ty()))
}
pub fn atiyah_singer_index_ty() -> Expr {
arrow(space_ty(), arrow(type0(), prop()))
}
pub fn dirac_operator_ty() -> Expr {
arrow(space_ty(), type0())
}
pub fn surgery_obstruction_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), group_ty()))
}
pub fn normal_map_ty() -> Expr {
arrow(space_ty(), arrow(space_ty(), prop()))
}
pub fn surgery_exact_sequence_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), prop()))
}
pub fn smooth_manifold_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn intersection_form_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), type0()))
}
pub fn intersection_homology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn intersection_cohomology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn de_rham_cohomology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), group_ty())))
}
pub fn de_rham_isomorphism_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), prop()))
}
pub fn operad_ty() -> Expr {
type0()
}
pub fn little_disks_operad_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn algebra_over_operad_ty() -> Expr {
arrow(type0(), arrow(type0(), type0()))
}
pub fn factorization_homology_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(type0(), group_ty())))
}
pub fn nonabelian_poincare_duality_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(type0(), prop())))
}
pub fn configuration_space_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), space_ty()))
}
pub fn unordered_config_space_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), space_ty()))
}
pub fn braid_group_ty() -> Expr {
arrow(nat_ty(), group_ty())
}
pub fn pure_braid_group_ty() -> Expr {
arrow(nat_ty(), group_ty())
}
pub fn arf_invariant_ty() -> Expr {
arrow(space_ty(), arrow(ring_ty(), type0()))
}
pub fn mapping_class_group_ty() -> Expr {
arrow(space_ty(), group_ty())
}
pub fn teichmuller_space_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), space_ty()))
}
pub fn moduli_space_curves_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), space_ty()))
}
pub fn dehn_twist_ty() -> Expr {
arrow(space_ty(), arrow(group_ty(), group_ty()))
}
pub fn weil_petersson_metric_ty() -> Expr {
arrow(nat_ty(), arrow(nat_ty(), type0()))
}
pub fn van_kampen_ty() -> Expr {
pi(
BinderInfo::Default,
"X",
space_ty(),
pi(
BinderInfo::Default,
"U",
space_ty(),
arrow(space_ty(), prop()),
),
)
}
pub fn hurewicz_ty() -> Expr {
pi(
BinderInfo::Default,
"n",
nat_ty(),
arrow(space_ty(), arrow(prop(), prop())),
)
}
pub fn whitehead_ty() -> Expr {
pi(
BinderInfo::Default,
"X",
space_ty(),
pi(
BinderInfo::Default,
"Y",
space_ty(),
arrow(prop(), arrow(prop(), arrow(prop(), prop()))),
),
)
}
pub fn universal_coefficient_ty() -> Expr {
arrow(nat_ty(), arrow(space_ty(), arrow(ring_ty(), prop())))
}
pub fn poincare_duality_hy_ty() -> Expr {
pi(
BinderInfo::Default,
"n",
nat_ty(),
pi(
BinderInfo::Default,
"k",
nat_ty(),
arrow(space_ty(), arrow(ring_ty(), arrow(prop(), prop()))),
),
)
}
pub fn build_algebraic_topology_env(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("TopologicalSpace", type0()),
("Group", type0()),
("Ring", type0()),
("FundamentalGroup", fundamental_group_ty()),
("HigherHomotopyGroup", higher_homotopy_group_ty()),
("SingularHomology", singular_homology_ty()),
("CohomologyRing", cohomology_ring_ty()),
("CoveringSpace", covering_space_ty()),
("CWComplex", cw_complex_ty()),
("SimplicialComplex", type0()),
("SimplicialHomology", simplicial_homology_ty()),
("BoundaryOperator", boundary_operator_ty()),
("CellularHomology", cellular_homology_ty()),
("SingularCohomology", singular_cohomology_ty()),
("CupProduct", cup_product_ty()),
("CapProduct", cap_product_ty()),
("CechCohomology", cech_cohomology_ty()),
("SheafCohomology", sheaf_cohomology_ty()),
("KTheory", k_theory_ty()),
("ClutchingConstruction", clutching_construction_ty()),
("StiefelWhitneyClass", stiefel_whitney_class_ty()),
("PontryaginClass", pontryagin_class_ty()),
("EilenbergMaclaneSpace", eilenberg_maclane_space_ty()),
("PostnikovTower", postnikov_tower_ty()),
("WhiteheadProduct", whitehead_product_ty()),
("JamesConstruction", james_construction_ty()),
("PathConnected", arrow(space_ty(), prop())),
("SimplyConnected", arrow(space_ty(), prop())),
(
"CompactOriented",
arrow(nat_ty(), arrow(space_ty(), prop())),
),
("WeakEquiv", arrow(space_ty(), arrow(space_ty(), prop()))),
(
"HomotopyEquiv",
arrow(space_ty(), arrow(space_ty(), prop())),
),
("van_kampen", van_kampen_ty()),
("hurewicz", hurewicz_ty()),
("whitehead", whitehead_ty()),
("universal_coefficient", universal_coefficient_ty()),
("poincare_duality", poincare_duality_hy_ty()),
("kunneth_formula", kunneth_formula_ty()),
("lefschetz_fixed_point", lefschetz_fixed_point_ty()),
("alexander_duality", alexander_duality_ty()),
("steenrod_square", steenrod_square_ty()),
("bott_periodicity", bott_periodicity_ty()),
("cobordism_ring", cobordism_ring_ty()),
("serre_spectral_sequence", serre_spectral_sequence_ty()),
("ehp_sequence", ehp_sequence_ty()),
("fibration_long_exact_seq", fibration_long_exact_seq_ty()),
("mayer_vietoris_sequence", mayer_vietoris_sequence_ty()),
("suspension_isomorphism", suspension_isomorphism_ty()),
("homology_functoriality", homology_functoriality_ty()),
("homotopy_invariance", homotopy_invariance_ty()),
("PersistentHomology", persistent_homology_ty()),
("BarcodeDecomposition", barcode_decomposition_ty()),
("PersistenceDiagram", persistence_diagram_ty()),
("WassersteinDistance", wasserstein_distance_ty()),
("stability_theorem", stability_theorem_ty()),
("Sheaf", sheaf_ty()),
("SheafMorphism", sheaf_morphism_ty()),
("DerivedFunctor", derived_functor_ty()),
("GrothendieckTopos", grothendieck_topos_ty()),
("LocallyConstantSheaf", locally_constant_sheaf_ty()),
("SpectralSequence", spectral_sequence_ty()),
("adem_relations", adem_relations_ty()),
("atiyah_hirzebruch_ss", atiyah_hirzebruch_ss_ty()),
("adams_spectral_sequence", adams_spectral_sequence_ty()),
("ChernClass", chern_class_ty()),
("EulerClass", euler_class_ty()),
("thom_isomorphism", thom_isomorphism_ty()),
("CharacteristicNumber", characteristic_number_ty()),
("RealKTheory", real_k_theory_ty()),
("EquivariantKTheory", equivariant_k_theory_ty()),
("k_group_exact_seq", k_group_exact_seq_ty()),
("oriented_cobordism", oriented_cobordism_ty()),
("CobordismInvariant", cobordism_invariant_ty()),
("thom_transversality", thom_transversality_ty()),
("fiber_bundle", fiber_bundle_ty()),
("VectorBundle", vector_bundle_ty()),
("PrincipalBundle", principal_bundle_ty()),
("Connection", connection_ty()),
("CurvatureForm", curvature_form_ty()),
("GaugeTransformation", gauge_transformation_ty()),
("FredholmOperator", fredholm_operator_ty()),
("AnalyticIndex", analytic_index_ty()),
("TopologicalIndex", topological_index_ty()),
("atiyah_singer_index", atiyah_singer_index_ty()),
("DiracOperator", dirac_operator_ty()),
("SurgeryObstruction", surgery_obstruction_ty()),
("NormalMap", normal_map_ty()),
("surgery_exact_sequence", surgery_exact_sequence_ty()),
("SmoothManifold", smooth_manifold_ty()),
("IntersectionForm", intersection_form_ty()),
("IntersectionHomology", intersection_homology_ty()),
("IntersectionCohomology", intersection_cohomology_ty()),
("DeRhamCohomology", de_rham_cohomology_ty()),
("de_rham_isomorphism", de_rham_isomorphism_ty()),
("Operad", operad_ty()),
("LittleDisksOperad", little_disks_operad_ty()),
("AlgebraOverOperad", algebra_over_operad_ty()),
("FactorizationHomology", factorization_homology_ty()),
(
"nonabelian_poincare_duality",
nonabelian_poincare_duality_ty(),
),
("ConfigurationSpace", configuration_space_ty()),
("UnorderedConfigSpace", unordered_config_space_ty()),
("BraidGroup", braid_group_ty()),
("PureBraidGroup", pure_braid_group_ty()),
("ArfInvariant", arf_invariant_ty()),
("MappingClassGroup", mapping_class_group_ty()),
("TeichmullerSpace", teichmuller_space_ty()),
("ModuliSpaceCurves", moduli_space_curves_ty()),
("DehnTwist", dehn_twist_ty()),
("WeilPeterssonMetric", weil_petersson_metric_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
pub fn matrix_rank(mat: &[Vec<i32>]) -> usize {
if mat.is_empty() {
return 0;
}
let rows = mat.len();
let cols = mat[0].len();
if cols == 0 {
return 0;
}
let mut a: Vec<Vec<f64>> = mat
.iter()
.map(|row| row.iter().map(|&v| v as f64).collect())
.collect();
let mut rank = 0usize;
let mut pivot_col = 0usize;
for r in 0..rows {
if pivot_col >= cols {
break;
}
let mut found = None;
for i in r..rows {
if a[i][pivot_col].abs() > 1e-9 {
found = Some(i);
break;
}
}
if found.is_none() {
pivot_col += 1;
continue;
}
let pivot_row = found.expect("found is Some: checked by is_none guard above");
a.swap(r, pivot_row);
let pivot = a[r][pivot_col];
for j in pivot_col..cols {
a[r][j] /= pivot;
}
for i in 0..rows {
if i != r && a[i][pivot_col].abs() > 1e-9 {
let factor = a[i][pivot_col];
for j in pivot_col..cols {
let sub = factor * a[r][j];
a[i][j] -= sub;
}
}
}
rank += 1;
pivot_col += 1;
}
rank
}
pub fn pi_n_sphere(n: u32, sphere_dim: u32) -> HomotopyGroupData {
let description = match (n, sphere_dim) {
(0, _) => "trivial",
(k, m) if k < m => "trivial",
(k, m) if k == m => "Z",
(2, 1) => "trivial",
(3, 2) => "Z",
(4, 2) => "Z/2Z",
(5, 2) => "Z/2Z",
(4, 3) => "Z/2Z",
(5, 3) => "Z/2Z",
(6, 3) => "Z/12Z",
(7, 3) => "Z/2Z",
(5, 4) => "Z/2Z",
(6, 4) => "Z/2Z",
(7, 4) => "Z x Z/12Z",
_ => "unknown",
};
let is_abelian = !(n == sphere_dim && sphere_dim == 1);
HomotopyGroupData {
space: format!("S^{sphere_dim}"),
base_point: "pt".to_string(),
degree: n,
description: description.to_string(),
is_abelian: is_abelian || n >= 2,
}
}
pub fn pi1_torus() -> HomotopyGroupData {
HomotopyGroupData {
space: "T^2".to_string(),
base_point: "pt".to_string(),
degree: 1,
description: "Z x Z".to_string(),
is_abelian: true,
}
}
pub fn pi1_sphere(n: u32) -> HomotopyGroupData {
let (description, is_abelian) = if n == 1 {
("Z", true)
} else {
("trivial", true)
};
HomotopyGroupData {
space: format!("S^{n}"),
base_point: "pt".to_string(),
degree: 1,
description: description.to_string(),
is_abelian,
}
}
pub fn combinations(items: &[usize], k: usize) -> Vec<Vec<usize>> {
if k == 0 {
return vec![vec![]];
}
if k > items.len() {
return vec![];
}
let mut result = Vec::new();
for i in 0..=items.len() - k {
let head = items[i];
for mut tail in combinations(&items[i + 1..], k - 1) {
let mut combo = vec![head];
combo.append(&mut tail);
result.push(combo);
}
}
result
}
pub fn smith_normal_form(mat: &[Vec<i32>]) -> Vec<i64> {
if mat.is_empty() {
return vec![];
}
let rows = mat.len();
let cols = mat[0].len();
let mut a: Vec<Vec<i64>> = mat
.iter()
.map(|r| r.iter().map(|&v| v as i64).collect())
.collect();
let mut diagonal: Vec<i64> = Vec::new();
let mut pivot_row = 0usize;
let mut pivot_col = 0usize;
while pivot_row < rows && pivot_col < cols {
let mut min_val: Option<i64> = None;
let mut min_pos = (pivot_row, pivot_col);
for r in pivot_row..rows {
for c in pivot_col..cols {
if a[r][c] != 0 {
let v = a[r][c].unsigned_abs();
match min_val {
None => {
min_val = Some(v as i64);
min_pos = (r, c);
}
Some(m) if (v as i64) < m => {
min_val = Some(v as i64);
min_pos = (r, c);
}
_ => {}
}
}
}
}
if min_val.is_none() {
break;
}
a.swap(pivot_row, min_pos.0);
for r in 0..rows {
a[r].swap(pivot_col, min_pos.1);
}
if a[pivot_row][pivot_col] < 0 {
for c in pivot_col..cols {
a[pivot_row][c] = -a[pivot_row][c];
}
}
let d = a[pivot_row][pivot_col];
let mut changed = true;
while changed {
changed = false;
for r in pivot_row + 1..rows {
if a[r][pivot_col] != 0 {
let q = a[r][pivot_col] / a[pivot_row][pivot_col];
for c in pivot_col..cols {
let sub = q * a[pivot_row][c];
a[r][c] -= sub;
}
if a[r][pivot_col] != 0 {
changed = true;
}
}
}
for c in pivot_col + 1..cols {
if a[pivot_row][c] != 0 {
let q = a[pivot_row][c] / a[pivot_row][pivot_col];
for r in pivot_row..rows {
let sub = q * a[r][pivot_col];
a[r][c] -= sub;
}
if a[pivot_row][c] != 0 {
changed = true;
}
}
}
if !changed {
'outer: for r in pivot_row + 1..rows {
for c in pivot_col + 1..cols {
if a[r][c] % d != 0 {
for cc in pivot_col..cols {
let v = a[r][cc];
a[pivot_row][cc] += v;
}
changed = true;
break 'outer;
}
}
}
}
}
diagonal.push(a[pivot_row][pivot_col].abs());
pivot_row += 1;
pivot_col += 1;
}
diagonal
}
pub fn compute_homology(sc: &SimplicialComplex, k: usize) -> HomologyGroup {
let max_dim = sc.simplices.iter().map(|s| s.len()).max().unwrap_or(0);
if k >= max_dim {
return HomologyGroup::trivial();
}
let rank_ck = sc.k_simplices(k).len();
if rank_ck == 0 {
return HomologyGroup::trivial();
}
let bm_k = sc.boundary_matrix(k);
let bm_k1 = sc.boundary_matrix(k + 1);
let snf_k1 = smith_normal_form(&bm_k1);
let image_free: usize = snf_k1.iter().filter(|&&v| v != 0).count();
let snf_k = smith_normal_form(&bm_k);
let rank_dk: usize = snf_k.iter().filter(|&&v| v != 0).count();
let ker_dim = rank_ck.saturating_sub(rank_dk);
let free_rank = ker_dim.saturating_sub(image_free) as u32;
let torsion: Vec<u64> = snf_k1
.iter()
.filter(|&&v| v > 1)
.map(|&v| v as u64)
.collect();
HomologyGroup { free_rank, torsion }
}
pub fn cup_product(sc: &SimplicialComplex, alpha: &Cochain, beta: &Cochain) -> Cochain {
let p = alpha.degree;
let q = beta.degree;
let pq = p + q;
let pq_sims = sc.k_simplices(pq);
let p_sims = sc.k_simplices(p);
let q_sims = sc.k_simplices(q);
let mut result = Cochain {
degree: pq,
values: vec![0; pq_sims.len()],
};
for (idx, sigma) in pq_sims.iter().enumerate() {
let front: Vec<usize> = sigma[..=p].to_vec();
let back: Vec<usize> = sigma[p..].to_vec();
let alpha_val = if let Some(pi) = p_sims.iter().position(|s| **s == front) {
alpha.eval(pi)
} else {
0
};
let beta_val = if let Some(qi) = q_sims.iter().position(|s| **s == back) {
beta.eval(qi)
} else {
0
};
result.values[idx] = alpha_val * beta_val;
}
result
}
pub fn betti_sphere(n: u32) -> Vec<u32> {
let mut b = vec![0u32; n as usize + 1];
b[0] = 1;
if n > 0 {
b[n as usize] = 1;
}
b
}
pub fn betti_torus() -> Vec<u32> {
vec![1, 2, 1]
}
pub fn betti_rpn(n: u32) -> Vec<u32> {
let mut b = vec![0u32; n as usize + 1];
b[0] = 1;
if n > 0 && n % 2 == 1 {
b[n as usize] = 1;
}
b
}
pub fn betti_sphere_product(m: u32, n: u32) -> Vec<u32> {
let dim = (m + n) as usize;
let mut b = vec![0u32; dim + 1];
b[0] += 1;
b[m as usize] += 1;
b[n as usize] += 1;
b[dim] += 1;
b
}
pub fn lefschetz_number(traces: &[i64]) -> i64 {
traces
.iter()
.enumerate()
.map(|(k, &tr)| {
let sign: i64 = if k % 2 == 0 { 1 } else { -1 };
sign * tr
})
.sum()
}
pub fn lefschetz_number_identity(betti: &[u32]) -> i64 {
let traces: Vec<i64> = betti.iter().map(|&b| b as i64).collect();
lefschetz_number(&traces)
}
pub fn lefschetz_antipodal_sphere(n: u32) -> i64 {
if n == 0 {
return 2;
}
let trace_n: i64 = if (n + 1) % 2 == 0 { 1 } else { -1 };
let sign_n: i64 = if n % 2 == 0 { 1 } else { -1 };
1 + sign_n * trace_n
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sphere_cw_structure() {
for n in [0u32, 1, 2, 3, 5] {
let s = CwComplex::sphere(n);
assert_eq!(s.n_cells(0), 1, "S^{n} has 1 zero-cell");
if n > 0 {
assert_eq!(s.n_cells(n), 1, "S^{n} has 1 top cell");
for k in 1..n {
assert_eq!(s.n_cells(k), 0, "S^{n} has no {k}-cells");
}
}
}
}
#[test]
fn test_torus_euler_char() {
let t2 = CwComplex::torus();
assert_eq!(t2.euler_characteristic(), 0, "χ(T²) = 0");
}
#[test]
fn test_sphere_euler_char_s2() {
let s2 = CwComplex::sphere(2);
assert_eq!(s2.euler_characteristic(), 2, "χ(S²) = 2");
}
#[test]
fn test_rp2_euler_char() {
let rp2 = CwComplex::real_projective_plane();
assert_eq!(rp2.euler_characteristic(), 1, "χ(RP²) = 1");
}
#[test]
fn test_cw_add_cell() {
let mut cw = CwComplex::new("test");
assert_eq!(cw.cells.len(), 0);
cw.add_cell(0, "v", vec![]);
assert_eq!(cw.cells.len(), 1);
cw.add_cell(1, "e", vec![(0, 0)]);
assert_eq!(cw.cells.len(), 2);
assert_eq!(cw.n_cells(0), 1);
assert_eq!(cw.n_cells(1), 1);
}
#[test]
fn test_pi1_sphere_s1() {
let pi1 = pi1_sphere(1);
assert_eq!(pi1.description, "Z");
assert!(pi1.is_abelian);
}
#[test]
fn test_pi1_sphere_s2() {
let pi1 = pi1_sphere(2);
assert_eq!(pi1.description, "trivial");
}
#[test]
fn test_betti_numbers_s2() {
let s2 = CwComplex::sphere(2);
let cc = ChainComplex::from_cw(&s2);
let b = cc.betti_numbers();
assert_eq!(b.len(), 3, "should have 3 Betti numbers, got {}", b.len());
assert_eq!(b[0], 1, "b_0(S²) = 1");
assert_eq!(b[1], 0, "b_1(S²) = 0");
assert_eq!(b[2], 1, "b_2(S²) = 1");
}
#[test]
fn test_simplicial_complex_triangle() {
let mut sc = SimplicialComplex::new("triangle");
sc.add_simplex(vec![0, 1, 2]);
assert_eq!(sc.k_simplices(0).len(), 3, "3 vertices");
assert_eq!(sc.k_simplices(1).len(), 3, "3 edges");
assert_eq!(sc.k_simplices(2).len(), 1, "1 face");
}
#[test]
fn test_sphere_triangulation_s1() {
let sc = SimplicialComplex::sphere_triangulation(2);
assert_eq!(sc.k_simplices(0).len(), 3, "3 vertices in ∂Δ²");
assert_eq!(sc.k_simplices(1).len(), 3, "3 edges in ∂Δ²");
}
#[test]
fn test_boundary_matrix_edge() {
let mut sc = SimplicialComplex::new("edge");
sc.add_simplex(vec![0, 1]);
let bm = sc.boundary_matrix(1);
assert_eq!(bm.len(), 2, "2 rows");
assert_eq!(bm[0].len(), 1, "1 column");
let sum: i32 = bm.iter().map(|r| r[0]).sum();
assert_eq!(sum, 0, "boundary of an edge sums to zero");
}
#[test]
fn test_homology_circle() {
let sc = SimplicialComplex::sphere_triangulation(2);
let h0 = compute_homology(&sc, 0);
let h1 = compute_homology(&sc, 1);
assert_eq!(h0.free_rank, 1, "H_0(S^1) = Z");
assert_eq!(h1.free_rank, 1, "H_1(S^1) = Z");
assert!(h1.torsion.is_empty(), "H_1(S^1) has no torsion");
}
#[test]
fn test_betti_sphere_function() {
let b2 = betti_sphere(2);
assert_eq!(b2, vec![1, 0, 1]);
let b0 = betti_sphere(0);
assert_eq!(b0, vec![1]);
let b1 = betti_sphere(1);
assert_eq!(b1, vec![1, 1]);
}
#[test]
fn test_betti_torus() {
let b = betti_torus();
assert_eq!(b, vec![1, 2, 1]);
}
#[test]
fn test_betti_rpn() {
assert_eq!(betti_rpn(1), vec![1, 1]);
assert_eq!(betti_rpn(2), vec![1, 0, 0]);
assert_eq!(betti_rpn(3), vec![1, 0, 0, 1]);
}
#[test]
fn test_lefschetz_identity() {
let b = betti_sphere(2);
assert_eq!(lefschetz_number_identity(&b), 2);
let bt = betti_torus();
assert_eq!(lefschetz_number_identity(&bt), 0);
}
#[test]
fn test_lefschetz_antipodal() {
assert_eq!(lefschetz_antipodal_sphere(1), 0);
assert_eq!(lefschetz_antipodal_sphere(2), 0);
}
#[test]
fn test_smith_normal_form_trivial() {
let mat: Vec<Vec<i32>> = vec![];
let snf = smith_normal_form(&mat);
assert!(snf.is_empty());
}
#[test]
fn test_smith_normal_form_identity_2x2() {
let mat = vec![vec![1, 0], vec![0, 1]];
let snf = smith_normal_form(&mat);
assert_eq!(snf, vec![1, 1]);
}
#[test]
fn test_homology_group_description() {
assert_eq!(HomologyGroup::trivial().description(), "0");
assert_eq!(HomologyGroup::integers().description(), "Z");
assert_eq!(HomologyGroup::free(2).description(), "Z^2");
assert_eq!(HomologyGroup::cyclic(2).description(), "Z/2Z");
}
#[test]
fn test_cup_product_trivial() {
let mut sc = SimplicialComplex::new("triangle");
sc.add_simplex(vec![0, 1, 2]);
let alpha = Cochain::zero(&sc, 0);
let beta = Cochain::zero(&sc, 0);
let gamma = cup_product(&sc, &alpha, &beta);
assert_eq!(gamma.degree, 0);
assert!(gamma.values.iter().all(|&v| v == 0));
}
#[test]
fn test_build_algebraic_topology_env() {
use oxilean_kernel::Environment;
let mut env = Environment::new();
build_algebraic_topology_env(&mut env);
let check_names = [
"SimplicialHomology",
"CupProduct",
"KTheory",
"bott_periodicity",
"serre_spectral_sequence",
"EilenbergMaclaneSpace",
"StiefelWhitneyClass",
"PontryaginClass",
"JamesConstruction",
"mayer_vietoris_sequence",
"homotopy_invariance",
"suspension_isomorphism",
];
for name in check_names {
assert!(
env.get(&oxilean_kernel::Name::str(name)).is_some(),
"axiom '{name}' should be registered"
);
}
}
}