use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
use super::types::{
ActionAngleVariables, BifurcationDiagram, BoxCounting, CantorSet, ChaoticSystem,
DiophantineCondition, EntropyOfMap, FeigenbaumData, FeigenbaumLogisticMap, Fractal,
FractalDimensionEstimator, HausdorffDimension, HenonMap, HopfBifurcation,
IteratedFunctionSystem, IteratedFunctionSystemExt, KAMTorus, KochCurve, KolmogorovThm,
LogisticMap, LorenzAttractorSimulator, LorenzSystem, LyapunovExponentEstimator,
LyapunovStabilityData, MandelbrotSet, MixingProperty, PeriodDoublingCascade,
PerturbedHamiltonian, PitchforkBifurcation, SaddleNodeBifurcation, SensitiveDependence,
ShiftSpace, StabilityType, TopologicalTransitivity,
};
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 real_ty() -> Expr {
cst("Real")
}
pub fn list_ty(elem: Expr) -> Expr {
app(cst("List"), elem)
}
pub fn bool_ty() -> Expr {
cst("Bool")
}
pub fn map_ty(dim: usize) -> Expr {
let rn = list_ty(real_ty());
let _ = dim;
arrow(rn.clone(), rn)
}
pub fn flow_ty() -> Expr {
let rn = list_ty(real_ty());
arrow(rn.clone(), arrow(real_ty(), rn))
}
pub fn chaotic_system_ty() -> Expr {
prop()
}
pub fn lorenz_system_ty() -> Expr {
pi(
BinderInfo::Default,
"sigma",
real_ty(),
pi(
BinderInfo::Default,
"rho",
real_ty(),
pi(BinderInfo::Default, "beta", real_ty(), prop()),
),
)
}
pub fn henon_map_ty() -> Expr {
pi(
BinderInfo::Default,
"a",
real_ty(),
pi(BinderInfo::Default, "b", real_ty(), prop()),
)
}
pub fn logistic_map_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn mandelbrot_set_ty() -> Expr {
prop()
}
pub fn bifurcation_diagram_ty() -> Expr {
prop()
}
pub fn saddle_node_bifurcation_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn pitchfork_bifurcation_ty() -> Expr {
arrow(real_ty(), arrow(bool_ty(), prop()))
}
pub fn hopf_bifurcation_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn period_doubling_cascade_ty() -> Expr {
prop()
}
pub fn fractal_ty() -> Expr {
prop()
}
pub fn hausdorff_dimension_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn box_counting_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn iterated_function_system_ty() -> Expr {
arrow(list_ty(map_ty(0)), prop())
}
pub fn koch_curve_ty() -> Expr {
prop()
}
pub fn cantor_set_ty() -> Expr {
prop()
}
pub fn kam_torus_ty() -> Expr {
prop()
}
pub fn action_angle_variables_ty() -> Expr {
prop()
}
pub fn perturbed_hamiltonian_ty() -> Expr {
arrow(real_ty(), prop())
}
pub fn diophantine_ty() -> Expr {
arrow(
list_ty(real_ty()),
arrow(real_ty(), arrow(nat_ty(), prop())),
)
}
pub fn kolmogorov_thm_ty() -> Expr {
prop()
}
pub fn mixing_property_ty() -> Expr {
prop()
}
pub fn sensitive_dependence_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn topological_transitivity_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn devaney_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn entropy_of_map_ty() -> Expr {
arrow(map_ty(0), real_ty())
}
pub fn build_chaos_theory_env(env: &mut Environment) -> Result<(), String> {
let axioms: &[(&str, Expr)] = &[
("ChaoticSystem", chaotic_system_ty()),
("LorenzSystem", lorenz_system_ty()),
("HenonMap", henon_map_ty()),
("LogisticMap", logistic_map_ty()),
("MandelbrotSet", mandelbrot_set_ty()),
("LyapunovExponent", arrow(map_ty(0), real_ty())),
("HasStrangeAttractor", arrow(map_ty(0), prop())),
("IsChaotic", arrow(map_ty(0), prop())),
("PeriodDoublingRatio", arrow(map_ty(0), real_ty())),
("BifurcationDiagram", bifurcation_diagram_ty()),
("SaddleNodeBifurcation", saddle_node_bifurcation_ty()),
("PitchforkBifurcation", pitchfork_bifurcation_ty()),
("HopfBifurcation", hopf_bifurcation_ty()),
("PeriodDoublingCascade", period_doubling_cascade_ty()),
("FeigenbaumDelta", real_ty()),
("FeigenbaumAlpha", real_ty()),
("BifurcationValue", arrow(map_ty(0), real_ty())),
("NormalForm", arrow(map_ty(0), map_ty(0))),
("Fractal", fractal_ty()),
("HausdorffDimension", hausdorff_dimension_ty()),
("BoxCountingDimension", box_counting_ty()),
("IteratedFunctionSystem", iterated_function_system_ty()),
("KochCurve", koch_curve_ty()),
("CantorSet", cantor_set_ty()),
("IsSelfSimilar", arrow(prop(), prop())),
("TopologicalDimension", arrow(prop(), nat_ty())),
("KAMTorus", kam_torus_ty()),
("ActionAngleVariables", action_angle_variables_ty()),
("PerturbedHamiltonian", perturbed_hamiltonian_ty()),
("DiophantineCondition", diophantine_ty()),
("KolmogorovThm", kolmogorov_thm_ty()),
("KAMThm", prop()),
("ArnoldThm", prop()),
("MixingProperty", mixing_property_ty()),
("SensitiveDependence", sensitive_dependence_ty()),
("TopologicalTransitivity", topological_transitivity_ty()),
("DevaneyChaoticMap", devaney_ty()),
("EntropyOfMap", entropy_of_map_ty()),
("ErgodicMeasure", prop()),
("BirkhoffErgodicThm", prop()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
Ok(())
}
pub const FEIGENBAUM_DELTA: f64 = 4.669_201_609_102_991;
pub const FEIGENBAUM_ALPHA: f64 = -2.502_907_875_095_892;
pub fn lyapunov_spectrum_ty() -> Expr {
arrow(map_ty(0), list_ty(real_ty()))
}
pub fn srb_measure_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn stretching_folding_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn lyapunov_dimension_ty() -> Expr {
arrow(list_ty(real_ty()), real_ty())
}
pub fn information_dimension_ty() -> Expr {
arrow(map_ty(0), real_ty())
}
pub fn correlation_dimension_ty() -> Expr {
arrow(map_ty(0), real_ty())
}
pub fn smale_horseshoe_ty() -> Expr {
prop()
}
pub fn symbolic_dynamics_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn topological_conjugacy_ty() -> Expr {
arrow(map_ty(0), arrow(map_ty(0), prop()))
}
pub fn subshift_finite_type_ty() -> Expr {
arrow(list_ty(list_ty(nat_ty())), prop())
}
pub fn dynamical_zeta_fn_ty() -> Expr {
arrow(map_ty(0), arrow(real_ty(), real_ty()))
}
pub fn lorenz_attractor_ty() -> Expr {
prop()
}
pub fn lorenz_flow_ty() -> Expr {
lorenz_system_ty()
}
pub fn geometric_lorenz_model_ty() -> Expr {
prop()
}
pub fn lorenz_template_ty() -> Expr {
prop()
}
pub fn homoclinic_bifurcation_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn heteroclinic_bifurcation_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn global_bifurcation_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn center_manifold_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn renormalization_group_ty() -> Expr {
prop()
}
pub fn arnold_diffusion_ty() -> Expr {
prop()
}
pub fn cantorus_ty() -> Expr {
prop()
}
pub fn twist_map_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn poincare_birkhoff_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn birkhoff_ergodic_ty() -> Expr {
pi(
BinderInfo::Default,
"f",
arrow(real_ty(), real_ty()),
pi(BinderInfo::Default, "mu", prop(), prop()),
)
}
pub fn ergodic_decomposition_ty() -> Expr {
arrow(prop(), prop())
}
pub fn poincare_recurrence_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn ks_entropy_ty() -> Expr {
arrow(map_ty(0), real_ty())
}
pub fn pecora_carroll_ty() -> Expr {
arrow(map_ty(0), arrow(map_ty(0), prop()))
}
pub fn adaptive_synchronization_ty() -> Expr {
arrow(map_ty(0), arrow(map_ty(0), prop()))
}
pub fn generalized_synchronization_ty() -> Expr {
arrow(map_ty(0), arrow(map_ty(0), prop()))
}
pub fn phase_synchronization_ty() -> Expr {
arrow(map_ty(0), arrow(map_ty(0), prop()))
}
pub fn gutzwiller_trace_ty() -> Expr {
arrow(real_ty(), real_ty())
}
pub fn energy_level_statistics_ty() -> Expr {
prop()
}
pub fn quantum_ergodicity_ty() -> Expr {
prop()
}
pub fn berry_tabor_ty() -> Expr {
prop()
}
pub fn bgs_conjecture_ty() -> Expr {
prop()
}
pub fn self_affine_ty() -> Expr {
arrow(list_ty(map_ty(0)), prop())
}
pub fn multifractal_spectrum_ty() -> Expr {
arrow(real_ty(), real_ty())
}
pub fn julia_set_ty() -> Expr {
arrow(real_ty(), arrow(real_ty(), prop()))
}
pub fn sierpinski_gasket_ty() -> Expr {
prop()
}
pub fn menger_sponge_ty() -> Expr {
prop()
}
pub fn auslander_yorke_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn li_yorke_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn sharkovskii_ty() -> Expr {
arrow(map_ty(0), arrow(nat_ty(), prop()))
}
pub fn topological_horseshoe_ty() -> Expr {
arrow(map_ty(0), prop())
}
pub fn build_chaos_theory_env_extended(env: &mut Environment) -> Result<(), String> {
let axioms: &[(&str, Expr)] = &[
("LyapunovSpectrum", lyapunov_spectrum_ty()),
("SRBMeasure", srb_measure_ty()),
("StretchingFolding", stretching_folding_ty()),
("LyapunovDimension", lyapunov_dimension_ty()),
("InformationDimension", information_dimension_ty()),
("CorrelationDimension", correlation_dimension_ty()),
("SmaleHorseshoe", smale_horseshoe_ty()),
("SymbolicDynamics", symbolic_dynamics_ty()),
("TopologicalConjugacy", topological_conjugacy_ty()),
("SubshiftFiniteType", subshift_finite_type_ty()),
("DynamicalZetaFn", dynamical_zeta_fn_ty()),
("LorenzAttractor", lorenz_attractor_ty()),
("LorenzFlow", lorenz_flow_ty()),
("GeometricLorenzModel", geometric_lorenz_model_ty()),
("LorenzTemplate", lorenz_template_ty()),
("HomoclinicBifurcation", homoclinic_bifurcation_ty()),
("HeteroclinicBifurcation", heteroclinic_bifurcation_ty()),
("GlobalBifurcation", global_bifurcation_ty()),
("CenterManifold", center_manifold_ty()),
("RenormalizationGroup", renormalization_group_ty()),
("ArnoldDiffusion", arnold_diffusion_ty()),
("Cantorus", cantorus_ty()),
("TwistMap", twist_map_ty()),
("PoincareBirkhoff", poincare_birkhoff_ty()),
("BirkhoffErgodicThm2", birkhoff_ergodic_ty()),
("ErgodicDecomposition", ergodic_decomposition_ty()),
("PoincareRecurrence", poincare_recurrence_ty()),
("KSEntropy", ks_entropy_ty()),
("PecoraCarroll", pecora_carroll_ty()),
("AdaptiveSynchronization", adaptive_synchronization_ty()),
(
"GeneralizedSynchronization",
generalized_synchronization_ty(),
),
("PhaseSynchronization", phase_synchronization_ty()),
("GutzwillerTrace", gutzwiller_trace_ty()),
("EnergyLevelStatistics", energy_level_statistics_ty()),
("QuantumErgodicity", quantum_ergodicity_ty()),
("BerryTabor", berry_tabor_ty()),
("BGSConjecture", bgs_conjecture_ty()),
("SelfAffineSet", self_affine_ty()),
("MultifractalSpectrum", multifractal_spectrum_ty()),
("JuliaSet", julia_set_ty()),
("SierpinskiGasket", sierpinski_gasket_ty()),
("MengerSponge", menger_sponge_ty()),
("AuslanderYorke", auslander_yorke_ty()),
("LiYorke", li_yorke_ty()),
("Sharkovskii", sharkovskii_ty()),
("TopologicalHorseshoe", topological_horseshoe_ty()),
];
for (name, ty) in axioms {
env.add(Declaration::Axiom {
name: Name::str(*name),
univ_params: vec![],
ty: ty.clone(),
})
.ok();
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lyapunov_estimator_logistic_chaotic() {
let est = LyapunovExponentEstimator::new();
let le = est.estimate_logistic(4.0);
assert!(le > 0.5, "Expected positive LE for r=4, got {le}");
}
#[test]
fn test_lyapunov_estimator_logistic_stable() {
let est = LyapunovExponentEstimator::new();
let le = est.estimate_logistic(2.0);
assert!(le < 0.0, "Expected negative LE for r=2, got {le}");
}
#[test]
fn test_lorenz_simulator_rk4() {
let sim = LorenzAttractorSimulator::classic(0.01);
let traj = sim.simulate(1.0, 0.0, 0.0, 100);
assert_eq!(traj.len(), 101);
let (x0, y0, z0) = traj[0];
let (xn, yn, zn) = traj[100];
let dist = ((xn - x0).powi(2) + (yn - y0).powi(2) + (zn - z0).powi(2)).sqrt();
assert!(dist > 0.01, "Trajectory should move: dist={dist}");
}
#[test]
fn test_lorenz_simulator_le() {
let sim = LorenzAttractorSimulator::classic(0.01);
let le = sim.lyapunov_exponent(5000);
assert!(le > 0.0, "Classic Lorenz should have positive LE, got {le}");
}
#[test]
fn test_feigenbaum_logistic_map() {
let fg = FeigenbaumLogisticMap::new();
let deltas = fg.estimated_delta();
assert!(!deltas.is_empty());
let last = *deltas.last().expect("last should succeed");
assert!(
(last - FEIGENBAUM_DELTA).abs() < 1.0,
"Estimated δ={last} far from Feigenbaum {FEIGENBAUM_DELTA}"
);
assert!(fg.is_converging_to_feigenbaum());
}
#[test]
fn test_feigenbaum_period_detection() {
let fg = FeigenbaumLogisticMap::new();
let p = fg.detect_period(3.2, 0.5);
assert_eq!(p, 2, "r=3.2 should give period 2, got {p}");
let p1 = fg.detect_period(2.5, 0.5);
assert_eq!(p1, 1, "r=2.5 should give period 1, got {p1}");
}
#[test]
fn test_fractal_dimension_henon() {
let est = FractalDimensionEstimator::from_henon_attractor(5000);
let dim = est.estimate_dimension();
assert!(dim.is_some(), "Should get a dimension estimate");
let d = dim.expect("dim should be valid");
assert!(
d > 1.0 && d < 2.0,
"Hénon attractor dimension should be in (1,2), got {d}"
);
}
#[test]
fn test_fractal_dimension_is_fractal() {
let est = FractalDimensionEstimator::from_henon_attractor(3000);
assert!(
est.is_fractal(),
"Hénon attractor should be detected as fractal"
);
}
#[test]
fn test_build_chaos_theory_env() {
let mut env = Environment::new();
build_chaos_theory_env(&mut env).expect("build_chaos_theory_env should succeed");
build_chaos_theory_env_extended(&mut env)
.expect("build_chaos_theory_env_extended should succeed");
assert!(env.get(&Name::str("SRBMeasure")).is_some());
assert!(env.get(&Name::str("SmaleHorseshoe")).is_some());
assert!(env.get(&Name::str("LorenzAttractor")).is_some());
assert!(env.get(&Name::str("HomoclinicBifurcation")).is_some());
assert!(env.get(&Name::str("ArnoldDiffusion")).is_some());
assert!(env.get(&Name::str("PecoraCarroll")).is_some());
assert!(env.get(&Name::str("GutzwillerTrace")).is_some());
assert!(env.get(&Name::str("MultifractalSpectrum")).is_some());
assert!(env.get(&Name::str("LiYorke")).is_some());
assert!(env.get(&Name::str("KSEntropy")).is_some());
}
}
#[cfg(test)]
mod tests_chaos_ext {
use super::*;
#[test]
fn test_lyapunov_stability_asymp_stable() {
let ls = LyapunovStabilityData::new("origin", vec![-1.0, -2.0]);
assert_eq!(ls.stability, StabilityType::AsymptoticallyStable);
assert!(ls.is_stable());
assert!(ls.hartman_grobman().contains("linearization"));
}
#[test]
fn test_lyapunov_stability_unstable() {
let ls = LyapunovStabilityData::new("saddle", vec![-1.0, 0.5]);
assert_eq!(ls.stability, StabilityType::Unstable);
assert!(!ls.is_stable());
}
#[test]
fn test_cantor_set_hausdorff_dim() {
let cantor = IteratedFunctionSystemExt::cantor_set();
let expected = 2.0f64.ln() / 3.0f64.ln();
assert!(
(cantor.hausdorff_dim - expected).abs() < 0.001,
"Cantor dim = {:.4}, expected {:.4}",
cantor.hausdorff_dim,
expected
);
}
#[test]
fn test_sierpinski_hausdorff_dim() {
let sier = IteratedFunctionSystemExt::sierpinski();
let expected = 3.0f64.ln() / 2.0f64.ln();
assert!(
(sier.hausdorff_dim - expected).abs() < 0.001,
"Sierpinski dim = {:.4}, expected {:.4}",
sier.hausdorff_dim,
expected
);
}
#[test]
fn test_feigenbaum() {
let mut f = FeigenbaumData::new();
assert!((f.delta - 4.6692).abs() < 0.001);
f.add_bifurcation(3.0);
f.add_bifurcation(3.449);
f.add_bifurcation(3.5441);
let ratio = f.check_scaling().expect("check_scaling should succeed");
assert!(ratio > 2.0 && ratio < 10.0, "Ratio = {ratio}");
assert!(f.universality_description().contains("Feigenbaum"));
}
}
#[cfg(test)]
mod tests_chaos_ext2 {
use super::*;
#[test]
fn test_shift_space_full() {
let fs = ShiftSpace::full_shift(3);
assert_eq!(fs.alphabet_size, 3);
let ent = fs.topological_entropy_approx();
assert!((ent - 3.0f64.ln()).abs() < 1e-10);
assert!(fs.is_topologically_mixing_approx());
}
#[test]
fn test_golden_mean_shift() {
let mat = vec![vec![true, true], vec![true, false]];
let gm = ShiftSpace::from_transition_matrix(mat);
let ent = gm.topological_entropy_approx();
assert!((ent - 2.0f64.ln()).abs() < 1e-10);
assert!(ShiftSpace::golden_mean_description().contains("golden mean"));
}
}