use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use super::types::{
AlexanderPolynomial, BraidWord, HOMFLYPolynomial, HyperbolicVolumeEstimator, JonesPolynomial,
KauffmanBracketCalc, Knot, KnotDiagram, LaurentPoly, LorenzKnotData, RationalTangle,
SeifertMatrixComputer, SeifertSurface,
};
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 app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
app(app2(f, a, b), c)
}
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 int_ty() -> Expr {
cst("Int")
}
pub fn bool_ty() -> Expr {
cst("Bool")
}
pub fn ring_ty() -> Expr {
cst("Ring")
}
pub fn knot_ty() -> Expr {
cst("Knot")
}
pub fn link_ty() -> Expr {
cst("Link")
}
pub fn poly_ty() -> Expr {
cst("Polynomial")
}
pub fn braid_ty() -> Expr {
cst("Braid")
}
pub fn tangle_ty() -> Expr {
cst("Tangle")
}
pub fn surface_ty() -> Expr {
cst("Surface")
}
pub fn real_ty() -> Expr {
cst("Real")
}
pub fn knot_diagram_ty() -> Expr {
type0()
}
pub fn crossing_ty() -> Expr {
type0()
}
pub fn crossing_sign_ty() -> Expr {
type0()
}
pub fn gauss_code_ty() -> Expr {
type0()
}
pub fn planar_diagram_ty() -> Expr {
type0()
}
pub fn diagram_equivalence_ty() -> Expr {
arrow(knot_diagram_ty(), arrow(knot_diagram_ty(), prop()))
}
pub fn reidemeister_i_ty() -> Expr {
arrow(knot_diagram_ty(), arrow(knot_diagram_ty(), prop()))
}
pub fn reidemeister_ii_ty() -> Expr {
arrow(knot_diagram_ty(), arrow(knot_diagram_ty(), prop()))
}
pub fn reidemeister_iii_ty() -> Expr {
arrow(knot_diagram_ty(), arrow(knot_diagram_ty(), prop()))
}
pub fn reidemeister_completeness_ty() -> Expr {
pi(
BinderInfo::Default,
"D1",
knot_diagram_ty(),
pi(BinderInfo::Default, "D2", knot_diagram_ty(), prop()),
)
}
pub fn writhe_ty() -> Expr {
arrow(knot_diagram_ty(), int_ty())
}
pub fn alexander_polynomial_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn jones_polynomial_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn homfly_pt_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn kauffman_bracket_ty() -> Expr {
arrow(knot_diagram_ty(), arrow(ring_ty(), poly_ty()))
}
pub fn arc_index_ty() -> Expr {
arrow(knot_ty(), nat_ty())
}
pub fn bridge_number_ty() -> Expr {
arrow(knot_ty(), nat_ty())
}
pub fn crossing_number_ty() -> Expr {
arrow(knot_ty(), nat_ty())
}
pub fn unknot_criterion_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn linking_number_ty() -> Expr {
arrow(link_ty(), arrow(nat_ty(), arrow(nat_ty(), int_ty())))
}
pub fn seifert_surface_ty() -> Expr {
arrow(knot_ty(), surface_ty())
}
pub fn genus_ty() -> Expr {
arrow(knot_ty(), nat_ty())
}
pub fn seifert_matrix_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn seifert_genus_formula_ty() -> Expr {
pi(BinderInfo::Default, "K", knot_ty(), prop())
}
pub fn virtual_knot_diagram_ty() -> Expr {
type0()
}
pub fn virtual_crossing_ty() -> Expr {
type0()
}
pub fn parity_polynomial_ty() -> Expr {
arrow(virtual_knot_diagram_ty(), poly_ty())
}
pub fn arrow_polynomial_ty() -> Expr {
arrow(virtual_knot_diagram_ty(), poly_ty())
}
pub fn virtual_genus_ty() -> Expr {
arrow(virtual_knot_diagram_ty(), nat_ty())
}
pub fn rational_tangle_ty() -> Expr {
type0()
}
pub fn tangle_fraction_ty() -> Expr {
arrow(tangle_ty(), poly_ty())
}
pub fn tangle_sum_ty() -> Expr {
arrow(tangle_ty(), arrow(tangle_ty(), tangle_ty()))
}
pub fn tangle_prod_ty() -> Expr {
arrow(tangle_ty(), arrow(tangle_ty(), tangle_ty()))
}
pub fn tangle_closure_ty() -> Expr {
arrow(tangle_ty(), knot_ty())
}
pub fn conway_notation_ty() -> Expr {
type0()
}
pub fn braid_group_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn braid_word_ty() -> Expr {
arrow(nat_ty(), type0())
}
pub fn braid_closure_ty() -> Expr {
arrow(braid_ty(), knot_ty())
}
pub fn alexander_braid_theorem_ty() -> Expr {
pi(BinderInfo::Default, "K", knot_ty(), prop())
}
pub fn markov_theorem_ty() -> Expr {
pi(
BinderInfo::Default,
"b1",
braid_ty(),
pi(BinderInfo::Default, "b2", braid_ty(), prop()),
)
}
pub fn burau_representation_ty() -> Expr {
arrow(nat_ty(), arrow(braid_ty(), type0()))
}
pub fn lawrence_bigelow_ty() -> Expr {
arrow(nat_ty(), arrow(braid_ty(), type0()))
}
pub fn lorenz_template_ty() -> Expr {
type0()
}
pub fn lorenz_knot_ty() -> Expr {
type0()
}
pub fn lorenz_braid_ty() -> Expr {
arrow(lorenz_knot_ty(), braid_ty())
}
pub fn lorenz_fibered_ty() -> Expr {
arrow(lorenz_knot_ty(), prop())
}
pub fn lorenz_positive_ty() -> Expr {
arrow(lorenz_knot_ty(), prop())
}
pub fn build_knot_theory_env(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("Knot", type0()),
("Link", type0()),
("Braid", type0()),
("Tangle", type0()),
("Surface", type0()),
("Polynomial", type0()),
("Ring", type0()),
("KnotDiagram", knot_diagram_ty()),
("Crossing", crossing_ty()),
("CrossingSign", crossing_sign_ty()),
("GaussCode", gauss_code_ty()),
("PlanarDiagram", planar_diagram_ty()),
("DiagramEquivalence", diagram_equivalence_ty()),
("ReidemeisterI", reidemeister_i_ty()),
("ReidemeisterII", reidemeister_ii_ty()),
("ReidemeisterIII", reidemeister_iii_ty()),
("ReidemeisterCompleteness", reidemeister_completeness_ty()),
("Writhe", writhe_ty()),
("AlexanderPolynomial", alexander_polynomial_ty()),
("JonesPolynomial", jones_polynomial_ty()),
("HomflyPt", homfly_pt_ty()),
("KauffmanBracket", kauffman_bracket_ty()),
("ArcIndex", arc_index_ty()),
("BridgeNumber", bridge_number_ty()),
("CrossingNumber", crossing_number_ty()),
("UnknotCriterion", unknot_criterion_ty()),
("LinkingNumber", linking_number_ty()),
("SeifertSurface", seifert_surface_ty()),
("Genus", genus_ty()),
("SeifertMatrix", seifert_matrix_ty()),
("SeifertGenusFormula", seifert_genus_formula_ty()),
("VirtualKnotDiagram", virtual_knot_diagram_ty()),
("VirtualCrossing", virtual_crossing_ty()),
("ParityPolynomial", parity_polynomial_ty()),
("ArrowPolynomial", arrow_polynomial_ty()),
("VirtualGenus", virtual_genus_ty()),
("RationalTangle", rational_tangle_ty()),
("TangleFraction", tangle_fraction_ty()),
("TangleSum", tangle_sum_ty()),
("TangleProd", tangle_prod_ty()),
("TangleClosure", tangle_closure_ty()),
("ConwayNotation", conway_notation_ty()),
("BraidGroup", braid_group_ty()),
("BraidWord", braid_word_ty()),
("BraidClosure", braid_closure_ty()),
("AlexanderBraidTheorem", alexander_braid_theorem_ty()),
("MarkovTheorem", markov_theorem_ty()),
("BurauRepresentation", burau_representation_ty()),
("LawrenceBigelow", lawrence_bigelow_ty()),
("LorenzTemplate", lorenz_template_ty()),
("LorenzKnot", lorenz_knot_ty()),
("LorenzBraid", lorenz_braid_ty()),
("LorenzFibered", lorenz_fibered_ty()),
("LorenzPositive", lorenz_positive_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
pub fn compute_alexander_mock(diagram: &KnotDiagram) -> LaurentPoly {
let n = diagram.crossings.len();
match n {
0 => LaurentPoly::monomial(1, 0),
3 => LaurentPoly {
min_exp: 0,
coeffs: vec![1, -1, 1],
},
4 => LaurentPoly {
min_exp: -1,
coeffs: vec![-1, 3, -1],
},
2 => LaurentPoly {
min_exp: 0,
coeffs: vec![1, -1],
},
_ => LaurentPoly::monomial(1, 0),
}
}
pub fn linking_number(diagram: &KnotDiagram) -> i32 {
let sum: i32 = diagram.crossings.iter().map(|c| c.sign.value()).sum();
sum / 2
}
pub fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_env_nonempty() {
let mut env = Environment::new();
build_knot_theory_env(&mut env);
assert!(env.get(&Name::str("Knot")).is_some());
assert!(env.get(&Name::str("AlexanderPolynomial")).is_some());
assert!(env.get(&Name::str("JonesPolynomial")).is_some());
assert!(env.get(&Name::str("MarkovTheorem")).is_some());
assert!(env.get(&Name::str("LorenzFibered")).is_some());
}
#[test]
fn test_writhe_trefoil() {
let d = KnotDiagram::left_trefoil();
assert_eq!(d.writhe(), -3, "left trefoil has writhe -3");
}
#[test]
fn test_writhe_figure_eight() {
let d = KnotDiagram::figure_eight();
assert_eq!(d.writhe(), 0, "figure-eight knot has writhe 0");
}
#[test]
fn test_linking_number_hopf() {
let d = KnotDiagram::hopf_link();
assert_eq!(linking_number(&d), 1, "Hopf link has linking number 1");
}
#[test]
fn test_alexander_polynomial_trefoil() {
let d = KnotDiagram::left_trefoil();
let poly = compute_alexander_mock(&d);
assert_eq!(poly.coeff(0), 1);
assert_eq!(poly.coeff(1), -1);
assert_eq!(poly.coeff(2), 1);
}
#[test]
fn test_alexander_polynomial_figure_eight() {
let d = KnotDiagram::figure_eight();
let poly = compute_alexander_mock(&d);
assert_eq!(poly.coeff(-1), -1);
assert_eq!(poly.coeff(0), 3);
assert_eq!(poly.coeff(1), -1);
}
#[test]
fn test_braid_word_trefoil() {
let b = BraidWord::trefoil_braid();
assert_eq!(b.strands, 2);
assert_eq!(b.word_length(), 3);
assert!(b.is_positive());
assert_eq!(b.algebraic_length(), 3);
}
#[test]
fn test_lorenz_knot_trefoil() {
let lk = LorenzKnotData::trefoil_lorenz();
assert_eq!(lk.period, 3);
assert_eq!(lk.left_count(), 2);
assert_eq!(lk.right_count(), 1);
assert!(lk.is_fibered());
assert!(lk.is_positive());
}
#[test]
fn test_rational_tangle_add() {
let t1 = RationalTangle::integer(1);
let t2 = RationalTangle::integer(2);
let sum = t1.add(&t2);
assert_eq!(sum.numerator, 3);
assert_eq!(sum.denominator, 1);
}
}
pub fn build_env() -> Environment {
let mut env = Environment::new();
build_knot_theory_env(&mut env);
env
}
pub fn homfly_skein_relation_ty() -> Expr {
prop()
}
pub fn homfly_normalization_ty() -> Expr {
prop()
}
pub fn kauffman_polynomial_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn kauffman_bracket_skein_ty() -> Expr {
arrow(knot_diagram_ty(), prop())
}
pub fn kauffman_bracket_normalization_ty() -> Expr {
arrow(knot_diagram_ty(), prop())
}
pub fn jones_from_kauffman_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn quantum_group_ty() -> Expr {
type0()
}
pub fn colored_jones_ty() -> Expr {
arrow(knot_ty(), arrow(nat_ty(), poly_ty()))
}
pub fn quantum_representation_ty() -> Expr {
arrow(quantum_group_ty(), arrow(nat_ty(), type0()))
}
pub fn r_matrix_ty() -> Expr {
arrow(quantum_group_ty(), type0())
}
pub fn yang_baxter_equation_ty() -> Expr {
arrow(r_matrix_ty(), prop())
}
pub fn quantum_trace_invariant_ty() -> Expr {
arrow(quantum_group_ty(), arrow(knot_ty(), poly_ty()))
}
pub fn reshetikhin_turaev_ty() -> Expr {
arrow(quantum_group_ty(), arrow(knot_ty(), poly_ty()))
}
pub fn knot_group_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn wirtinger_presentation_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn alexander_ideal_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn fox_calculus_ty() -> Expr {
arrow(knot_group_ty(), type0())
}
pub fn alexander_matrix_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn abelianization_knot_group_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn seifert_signature_ty() -> Expr {
arrow(knot_ty(), int_ty())
}
pub fn s_equivalence_ty() -> Expr {
arrow(
cst("SeifertMatrixData"),
arrow(cst("SeifertMatrixData"), prop()),
)
}
pub fn fiber_knot_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn seifert_algorithm_ty() -> Expr {
arrow(knot_diagram_ty(), surface_ty())
}
pub fn seifert_circle_ty() -> Expr {
arrow(knot_diagram_ty(), nat_ty())
}
pub fn satellite_knot_ty() -> Expr {
arrow(knot_ty(), arrow(knot_ty(), knot_ty()))
}
pub fn cable_knot_ty() -> Expr {
arrow(knot_ty(), arrow(nat_ty(), arrow(nat_ty(), knot_ty())))
}
pub fn whitehead_double_ty() -> Expr {
arrow(knot_ty(), knot_ty())
}
pub fn satellite_alexander_ty() -> Expr {
arrow(knot_ty(), arrow(knot_ty(), prop()))
}
pub fn companion_genus_ty() -> Expr {
arrow(knot_ty(), arrow(nat_ty(), nat_ty()))
}
pub fn legendrian_knot_ty() -> Expr {
type0()
}
pub fn transverse_knot_ty() -> Expr {
type0()
}
pub fn thurston_bennequin_inequality_ty() -> Expr {
arrow(legendrian_knot_ty(), prop())
}
pub fn front_projection_ty() -> Expr {
arrow(legendrian_knot_ty(), knot_diagram_ty())
}
pub fn loss_invariant_ty() -> Expr {
arrow(legendrian_knot_ty(), type0())
}
pub fn self_linking_number_ty() -> Expr {
arrow(transverse_knot_ty(), int_ty())
}
pub fn hyperbolic_knot_ty() -> Expr {
type0()
}
pub fn hyperbolic_volume_ty() -> Expr {
arrow(hyperbolic_knot_ty(), real_ty())
}
pub fn thurston_hyperbolic_theorem_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn a_polynomial_ty() -> Expr {
arrow(hyperbolic_knot_ty(), poly_ty())
}
pub fn rigidity_theorem_ty() -> Expr {
arrow(hyperbolic_knot_ty(), prop())
}
pub fn geometric_dehn_ty() -> Expr {
arrow(
hyperbolic_knot_ty(),
arrow(int_ty(), arrow(int_ty(), knot_ty())),
)
}
pub fn contact_homology_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn augmentation_polynomial_ty() -> Expr {
arrow(knot_ty(), poly_ty())
}
pub fn chekanov_dga_ty() -> Expr {
arrow(legendrian_knot_ty(), type0())
}
pub fn kch_invariance_ty() -> Expr {
prop()
}
pub fn tau_invariant_ty() -> Expr {
arrow(knot_ty(), int_ty())
}
pub fn s_invariant_ty() -> Expr {
arrow(knot_ty(), int_ty())
}
pub fn upsilon_invariant_ty() -> Expr {
arrow(knot_ty(), arrow(real_ty(), real_ty()))
}
pub fn ossz_invariant_ty() -> Expr {
arrow(knot_ty(), int_ty())
}
pub fn slice_genus_ty() -> Expr {
arrow(knot_ty(), nat_ty())
}
pub fn slice_genus_lower_bound_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn ribbon_knot_ty() -> Expr {
arrow(knot_ty(), prop())
}
pub fn grid_diagram_ty() -> Expr {
type0()
}
pub fn grid_move_ty() -> Expr {
arrow(grid_diagram_ty(), arrow(grid_diagram_ty(), prop()))
}
pub fn grid_homology_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn grid_homology_invariance_ty() -> Expr {
prop()
}
pub fn grid_alexander_grading_ty() -> Expr {
arrow(grid_diagram_ty(), int_ty())
}
pub fn grid_maslov_grading_ty() -> Expr {
arrow(grid_diagram_ty(), int_ty())
}
pub fn lee_spectral_sequence_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn lee_homology_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn rasmussen_from_lee_ty() -> Expr {
arrow(lee_spectral_sequence_ty(), int_ty())
}
pub fn loss_filtration_ty() -> Expr {
arrow(legendrian_knot_ty(), type0())
}
pub fn categorified_quantum_group_ty() -> Expr {
type0()
}
pub fn sl2_categorification_ty() -> Expr {
type0()
}
pub fn khovanov_homology_functor_ty() -> Expr {
arrow(knot_ty(), type0())
}
pub fn cube_of_resolutions_ty() -> Expr {
arrow(knot_diagram_ty(), type0())
}
pub fn khovanov_differential_ty() -> Expr {
arrow(knot_diagram_ty(), prop())
}
pub fn foam_evaluation_ty() -> Expr {
arrow(sl2_categorification_ty(), int_ty())
}
pub fn build_knot_theory_ext_env(env: &mut Environment) {
let axioms: &[(&str, Expr)] = &[
("QuantumGroup", quantum_group_ty()),
("LegendriankKnot", legendrian_knot_ty()),
("TransverseKnot", transverse_knot_ty()),
("HyperbolicKnot", hyperbolic_knot_ty()),
("GridDiagram", grid_diagram_ty()),
("LeeSpectralSequence", lee_spectral_sequence_ty()),
("CategorifiedQuantumGroup", categorified_quantum_group_ty()),
("SL2Categorification", sl2_categorification_ty()),
("SeifertMatrixData", type0()),
("homfly_skein_relation", homfly_skein_relation_ty()),
("homfly_normalization", homfly_normalization_ty()),
("KauffmanPolynomial", kauffman_polynomial_ty()),
("kauffman_bracket_skein", kauffman_bracket_skein_ty()),
(
"kauffman_bracket_normalization",
kauffman_bracket_normalization_ty(),
),
("JonesFromKauffman", jones_from_kauffman_ty()),
("ColoredJones", colored_jones_ty()),
("QuantumRepresentation", quantum_representation_ty()),
("RMatrix", r_matrix_ty()),
("yang_baxter_equation", yang_baxter_equation_ty()),
("QuantumTraceInvariant", quantum_trace_invariant_ty()),
("ReshetikhinTuraev", reshetikhin_turaev_ty()),
("KnotGroup", knot_group_ty()),
("WirtingerPresentation", wirtinger_presentation_ty()),
("AlexanderIdeal", alexander_ideal_ty()),
("FoxCalculus", fox_calculus_ty()),
("AlexanderMatrix", alexander_matrix_ty()),
("abelianization_knot_group", abelianization_knot_group_ty()),
("SeifertSignature", seifert_signature_ty()),
("s_equivalence", s_equivalence_ty()),
("fiber_knot", fiber_knot_ty()),
("SeifertAlgorithm", seifert_algorithm_ty()),
("SeifertCircle", seifert_circle_ty()),
("SatelliteKnot", satellite_knot_ty()),
("CableKnot", cable_knot_ty()),
("WhiteheadDouble", whitehead_double_ty()),
("satellite_alexander", satellite_alexander_ty()),
("CompanionGenus", companion_genus_ty()),
(
"thurston_bennequin_inequality",
thurston_bennequin_inequality_ty(),
),
("FrontProjection", front_projection_ty()),
("LOSSInvariant", loss_invariant_ty()),
("SelfLinkingNumber", self_linking_number_ty()),
("HyperbolicVolume", hyperbolic_volume_ty()),
(
"thurston_hyperbolic_theorem",
thurston_hyperbolic_theorem_ty(),
),
("APolynomial", a_polynomial_ty()),
("rigidity_theorem", rigidity_theorem_ty()),
("GeometricDehn", geometric_dehn_ty()),
("ContactHomology", contact_homology_ty()),
("AugmentationPolynomial", augmentation_polynomial_ty()),
("ChekanovDGA", chekanov_dga_ty()),
("kch_invariance", kch_invariance_ty()),
("TauInvariant", tau_invariant_ty()),
("SInvariant", s_invariant_ty()),
("UpsilonInvariant", upsilon_invariant_ty()),
("OSSZInvariant", ossz_invariant_ty()),
("SliceGenus", slice_genus_ty()),
("slice_genus_lower_bound", slice_genus_lower_bound_ty()),
("ribbon_knot", ribbon_knot_ty()),
("GridMove", grid_move_ty()),
("GridHomology", grid_homology_ty()),
("grid_homology_invariance", grid_homology_invariance_ty()),
("GridAlexanderGrading", grid_alexander_grading_ty()),
("GridMaslovGrading", grid_maslov_grading_ty()),
("LeeHomology", lee_homology_ty()),
("rasmussen_from_lee", rasmussen_from_lee_ty()),
("LOSSFiltration", loss_filtration_ty()),
("KhovanovHomologyFunctor", khovanov_homology_functor_ty()),
("CubeOfResolutions", cube_of_resolutions_ty()),
("khovanov_differential", khovanov_differential_ty()),
("FoamEvaluation", foam_evaluation_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
}
#[cfg(test)]
mod ext_tests {
use super::*;
#[test]
fn test_build_ext_env() {
let mut env = Environment::new();
build_knot_theory_env(&mut env);
build_knot_theory_ext_env(&mut env);
assert!(env.get(&Name::str("HyperbolicVolume")).is_some());
assert!(env.get(&Name::str("ColoredJones")).is_some());
assert!(env.get(&Name::str("TauInvariant")).is_some());
assert!(env.get(&Name::str("GridHomology")).is_some());
assert!(env.get(&Name::str("KhovanovHomologyFunctor")).is_some());
}
#[test]
fn test_homfly_unknot() {
let p = HOMFLYPolynomial::unknot();
assert_eq!(p.get(0, 0), 1);
assert_eq!(p.num_terms(), 1);
}
#[test]
fn test_homfly_amphichirality() {
let fig8 = HOMFLYPolynomial::figure_eight();
assert!(fig8.is_amphichiral(), "Figure-eight should be amphichiral");
let ltrefoil = HOMFLYPolynomial::left_trefoil();
assert!(
!ltrefoil.is_amphichiral(),
"Left trefoil should not be amphichiral"
);
}
#[test]
fn test_homfly_evaluate_unknot_at_one() {
let p = HOMFLYPolynomial::unknot();
let val = p.evaluate(1.0, 0.0);
assert!((val - 1.0).abs() < 1e-12, "P(unknot)(1,0) should be 1");
}
#[test]
fn test_kauffman_bracket_loop_value() {
let calc = KauffmanBracketCalc::new(1.0);
assert!((calc.loop_value() - (-2.0)).abs() < 1e-12);
}
#[test]
fn test_kauffman_bracket_unknot() {
let calc = KauffmanBracketCalc::new(1.0);
assert!((calc.bracket_unknot() - 1.0).abs() < 1e-12);
}
#[test]
fn test_kauffman_bracket_with_loops() {
let calc = KauffmanBracketCalc::new(1.0);
let val = calc.bracket_with_loops(1.0, 2);
assert!((val - 4.0).abs() < 1e-12);
}
#[test]
fn test_seifert_matrix_trefoil() {
let sm = SeifertMatrixComputer::trefoil();
assert_eq!(sm.size, 2);
assert_eq!(sm.knot_determinant(), 3, "Trefoil determinant should be 3");
}
#[test]
fn test_seifert_matrix_figure_eight() {
let sm = SeifertMatrixComputer::figure_eight();
assert_eq!(
sm.knot_determinant(),
5,
"Figure-eight determinant should be 5"
);
}
#[test]
fn test_seifert_signature_trefoil() {
let sm = SeifertMatrixComputer::trefoil();
assert_eq!(sm.signature_2x2(), -2, "Trefoil signature should be -2");
}
#[test]
fn test_seifert_signature_figure_eight() {
let sm = SeifertMatrixComputer::figure_eight();
assert_eq!(sm.signature_2x2(), 0, "Figure-eight signature should be 0");
}
#[test]
fn test_hyperbolic_volume_figure_eight() {
let est = HyperbolicVolumeEstimator::new();
let vol = est.volume("4_1");
assert!(vol.is_some());
let v = vol.expect("vol should be valid");
assert!(
(v - 2.0298832128_f64).abs() < 1e-6,
"Volume of 4_1 should be ~2.0299, got {v}"
);
}
#[test]
fn test_hyperbolic_trefoil_not_hyperbolic() {
let est = HyperbolicVolumeEstimator::new();
assert!(!est.is_hyperbolic("trefoil"), "Trefoil is not hyperbolic");
}
#[test]
fn test_lackenby_bound() {
let est = HyperbolicVolumeEstimator::new();
let bound = est.lackenby_bound(4);
assert!(
bound > 0.0,
"Lackenby bound for 4-crossing knot should be positive"
);
}
#[test]
fn test_dehn_filling_volume() {
let est = HyperbolicVolumeEstimator::new();
let base_vol = est.figure_eight_volume();
let filled = est.dehn_filling_volume("4_1", 10);
assert!(filled < base_vol, "Dehn filling should reduce volume");
assert!(
filled > 0.0,
"Non-trivial Dehn filling should have positive volume"
);
}
}