tsdynamics 3.0.0__tar.gz → 3.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/PKG-INFO +1 -1
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-core/src/bridge.rs +133 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-core/src/lib.rs +98 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/pyproject.toml +1 -1
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/__init__.py +1 -1
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/__init__.py +11 -0
- tsdynamics-3.0.2/src/tsdynamics/analysis/_result.py +692 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/_common.py +18 -19
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/attractors.py +17 -13
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/basins.py +67 -10
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/continuation.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/basins/metrics.py +9 -4
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/chaos/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/chaos/_common.py +14 -14
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/chaos/expansion.py +10 -5
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/chaos/gali.py +52 -8
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/chaos/zero_one.py +7 -2
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/_common.py +63 -7
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/_scaling.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/correlation.py +11 -6
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/fixedmass.py +8 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/dimensions/generalized.py +11 -6
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/embedding/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/embedding/_common.py +13 -8
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/embedding/delay.py +8 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/embedding/dimension.py +8 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/embedding/embed.py +9 -4
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/core.py +27 -1
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/dispersion.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/lz.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/multiscale.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/permutation.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/entropy/sample.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/fixedpoints/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/fixedpoints/fixed.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/fixedpoints/periodic.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/lyapunov/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/lyapunov/from_data.py +56 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/orbits/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/orbits/orbit_diagram.py +37 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/orbits/poincare.py +22 -2
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/orbits/return_map.py +44 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/recurrence/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/recurrence/_common.py +16 -11
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/recurrence/matrix.py +42 -4
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/recurrence/rqa.py +40 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/recurrence/windowed.py +7 -2
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/surrogate/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/surrogate/_common.py +12 -7
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/surrogate/generators.py +13 -8
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/surrogate/hypothesis.py +49 -3
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/surrogate/statistics.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/data/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/data/sampling.py +5 -0
- tsdynamics-3.0.2/src/tsdynamics/data/trajectory.py +421 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/_base.py +25 -1
- tsdynamics-3.0.2/src/tsdynamics/derived/_crossings.py +194 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/_variational.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/ensemble.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/poincare.py +89 -9
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/projected.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/stroboscopic.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/tangent.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/derived/wrapped.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/engine/__init__.py +10 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/engine/compile.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/engine/problem.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/engine/run.py +121 -0
- tsdynamics-3.0.2/src/tsdynamics/errors.py +172 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/__init__.py +5 -0
- tsdynamics-3.0.2/src/tsdynamics/families/_accessors.py +507 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/_dde_lyapunov.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/base.py +300 -2
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/continuous.py +93 -17
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/delay.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/discrete.py +43 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/protocol.py +27 -2
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/families/stochastic.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/plugins.py +24 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/registry.py +30 -9
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/solvers/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/solvers/select.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/__init__.py +9 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/transforms/__init__.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/transforms/features.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/transforms/preprocessing.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/transforms/spectral.py +5 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/utils/__init__.py +5 -0
- tsdynamics-3.0.2/src/tsdynamics/utils/grids.py +75 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/utils/sagitta_dt.py +5 -0
- tsdynamics-3.0.2/src/tsdynamics/viz/__init__.py +97 -0
- tsdynamics-3.0.2/src/tsdynamics/viz/spec.py +779 -0
- tsdynamics-3.0.0/src/tsdynamics/data/trajectory.py +0 -235
- tsdynamics-3.0.0/src/tsdynamics/utils/grids.py +0 -40
- tsdynamics-3.0.0/src/tsdynamics/viz/__init__.py +0 -10
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/LICENSE +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/README.md +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-core/Cargo.lock +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-core/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/dde.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/ensemble.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/event.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/integrate.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/lib.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/map.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/problem.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/rng.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/sde.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-engine/src/testkit.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/builder.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/eval.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/lib.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/op.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/reference.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/src/tape.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/coverage_tape.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/CircadianRhythm.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/Lorenz.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/SanUmSrisuchinwong.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/SprottMore.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/Torus.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/fixtures/YuWang2.txt +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/gen_fixtures.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/golden_fixtures.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-ir/tests/roundtrip.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/src/codegen.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/src/error.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/src/evaluator.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/src/lib.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/src/shims.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/tests/compile_latency.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/tests/golden_fixtures.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-jit/tests/interpreter_equivalence.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/caps.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/control.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/dop853.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/mod.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/rk4.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/rk45.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/testkit.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/explicit/tsit5.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/bdf.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/control.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/linalg.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/mod.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/rosenbrock.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/implicit/trbdf2.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/lib.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/registry.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/sde/euler_maruyama.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/sde/milstein.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/sde/mod.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/sde/testkit.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/src/solver.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/tests/explicit_accuracy.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/tests/implicit_stiff.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-solvers/tests/registry.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-vm/Cargo.toml +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-vm/src/interp.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-vm/src/lib.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-vm/tests/golden_fixtures.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/crates/tsdyn-vm/tests/oracle_equivalence.rs +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/analysis/fixedpoints/_common.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/engine/symbols.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/py.typed +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/solvers/explicit.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/solvers/implicit.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/solvers/stochastic.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/chaotic_attractors.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/chem_bio_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/climate_geophysics.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/coupled_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/delayed_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/exotic_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/oscillatory_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/physical_systems.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/continuous/population_dynamics.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/chaotic_maps.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/exotic_maps.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/geometric_maps.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/polynomial_maps.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/systems/discrete/population_maps.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/transforms/_common.py +0 -0
- {tsdynamics-3.0.0 → tsdynamics-3.0.2}/src/tsdynamics/utils/general.py +0 -0
|
@@ -28,9 +28,10 @@
|
|
|
28
28
|
|
|
29
29
|
use tsdyn_engine::rng::SplitMix64;
|
|
30
30
|
use tsdyn_engine::{
|
|
31
|
-
ensemble_final as engine_ensemble, integrate_dde_grid,
|
|
32
|
-
iterate_ensemble_final as engine_iterate_ensemble,
|
|
33
|
-
|
|
31
|
+
ensemble_final as engine_ensemble, integrate_dde_grid, integrate_events, integrate_grid,
|
|
32
|
+
iterate_dense, iterate_ensemble_final as engine_iterate_ensemble,
|
|
33
|
+
sde_ensemble_final as engine_sde_ensemble, sde_integrate_grid, DelaySlot, EventDirection,
|
|
34
|
+
EventSpec, IntegrateConfig, IntegrateError, MapError, SdeConfig, SdeError,
|
|
34
35
|
};
|
|
35
36
|
use tsdyn_ir::{Evaluator, Tape};
|
|
36
37
|
use tsdyn_jit::JitEvaluator;
|
|
@@ -950,6 +951,135 @@ pub fn sde_ensemble_final(
|
|
|
950
951
|
Ok(result.states)
|
|
951
952
|
}
|
|
952
953
|
|
|
954
|
+
/// Map a Python-side direction code (`+1` / `-1` / `0`) to an [`EventDirection`].
|
|
955
|
+
fn event_direction(direction: i32) -> Result<EventDirection, EngineError> {
|
|
956
|
+
match direction {
|
|
957
|
+
1 => Ok(EventDirection::Rising),
|
|
958
|
+
-1 => Ok(EventDirection::Falling),
|
|
959
|
+
0 => Ok(EventDirection::Either),
|
|
960
|
+
other => Err(EngineError::BadShape(format!(
|
|
961
|
+
"event direction must be +1 (rising), -1 (falling) or 0 (either), got {other}"
|
|
962
|
+
))),
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/// Integrate `[t0, t1]` and return every crossing of the event function
|
|
967
|
+
/// `g(u, t) = 0` in `direction`, refined with the engine's O(h⁴) cubic-Hermite
|
|
968
|
+
/// dense output (stream WS-CROSSKERNEL — wiring the previously dead
|
|
969
|
+
/// [`tsdyn_engine::integrate_events`]).
|
|
970
|
+
///
|
|
971
|
+
/// `rhs` is the system right-hand side; `g` a single-output tape evaluated over
|
|
972
|
+
/// the full state (`g.dim() == 1`, `g.n_param() <= rhs.n_param()`). `first_step`
|
|
973
|
+
/// seeds the solver; with the fixed-step `rk4` it *is* the march step, so a caller
|
|
974
|
+
/// that wants the Python `PoincareMap`'s dt-grid detection (no skipped crossings,
|
|
975
|
+
/// answer-identical refinement) passes `method = "rk4"`, `first_step = dt`.
|
|
976
|
+
///
|
|
977
|
+
/// Returns `(times, states_flat, t_final, u_final, terminated)` — the `K` crossing
|
|
978
|
+
/// times, the row-major `(K, dim)` crossing states, the time/state the run stopped
|
|
979
|
+
/// at (so a caller can resume the next span exactly), and whether a terminal event
|
|
980
|
+
/// stopped it. Divergence raises ([`EngineError::Diverged`]), preserving the
|
|
981
|
+
/// "diverge loudly" contract of the per-`dt` Python path.
|
|
982
|
+
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
|
983
|
+
pub fn integrate_events_dense(
|
|
984
|
+
rhs: Tape,
|
|
985
|
+
g: Tape,
|
|
986
|
+
ic: &[f64],
|
|
987
|
+
p: &[f64],
|
|
988
|
+
t0: f64,
|
|
989
|
+
t1: f64,
|
|
990
|
+
first_step: f64,
|
|
991
|
+
direction: i32,
|
|
992
|
+
terminal: bool,
|
|
993
|
+
method: &str,
|
|
994
|
+
rtol: f64,
|
|
995
|
+
atol: f64,
|
|
996
|
+
jit: bool,
|
|
997
|
+
) -> Result<(Vec<f64>, Vec<f64>, f64, Vec<f64>, bool), EngineError> {
|
|
998
|
+
guard_continuous(&rhs)?;
|
|
999
|
+
check_inputs(&rhs, ic, p)?;
|
|
1000
|
+
if let Some(&bad) = ic.iter().find(|x| !x.is_finite()) {
|
|
1001
|
+
return Err(EngineError::BadShape(format!(
|
|
1002
|
+
"initial state must be finite, found {bad}"
|
|
1003
|
+
)));
|
|
1004
|
+
}
|
|
1005
|
+
let dim = rhs.dim();
|
|
1006
|
+
if dim == 0 {
|
|
1007
|
+
return Err(EngineError::BadShape(
|
|
1008
|
+
"system dimension is zero (the tape has no outputs)".to_string(),
|
|
1009
|
+
));
|
|
1010
|
+
}
|
|
1011
|
+
// The event function is a single-output tape over the full state; it shares
|
|
1012
|
+
// the system parameter vector (it may declare fewer and read the leading
|
|
1013
|
+
// slice). `eval_event` in the engine asserts both, so reject violations here
|
|
1014
|
+
// as a clean `ValueError` rather than a release-build panic.
|
|
1015
|
+
if g.dim() != 1 {
|
|
1016
|
+
return Err(EngineError::BadShape(format!(
|
|
1017
|
+
"event function must have a single output, got {}",
|
|
1018
|
+
g.dim()
|
|
1019
|
+
)));
|
|
1020
|
+
}
|
|
1021
|
+
if g.n_state() > dim {
|
|
1022
|
+
return Err(EngineError::BadShape(format!(
|
|
1023
|
+
"event function reads {} state inputs but the system has dim = {dim}",
|
|
1024
|
+
g.n_state()
|
|
1025
|
+
)));
|
|
1026
|
+
}
|
|
1027
|
+
if g.n_param() > p.len() {
|
|
1028
|
+
return Err(EngineError::BadShape(format!(
|
|
1029
|
+
"event function declares {} parameters but the system has {}",
|
|
1030
|
+
g.n_param(),
|
|
1031
|
+
p.len()
|
|
1032
|
+
)));
|
|
1033
|
+
}
|
|
1034
|
+
if !(t0.is_finite() && t1.is_finite()) {
|
|
1035
|
+
return Err(EngineError::BadShape(format!(
|
|
1036
|
+
"event integration span must be finite, got t0 = {t0}, t1 = {t1}"
|
|
1037
|
+
)));
|
|
1038
|
+
}
|
|
1039
|
+
if t1 < t0 {
|
|
1040
|
+
return Err(EngineError::BadShape(format!(
|
|
1041
|
+
"integrate_events is forward only: need t1 >= t0, got t0 = {t0}, t1 = {t1}"
|
|
1042
|
+
)));
|
|
1043
|
+
}
|
|
1044
|
+
// The engine asserts a finite, positive first step (a hard `assert!`, not a
|
|
1045
|
+
// debug one) — turn a bad value into a clean error at the boundary.
|
|
1046
|
+
if !(first_step.is_finite() && first_step > 0.0) {
|
|
1047
|
+
return Err(EngineError::BadShape(format!(
|
|
1048
|
+
"first step (the detection dt) must be finite and positive, got {first_step}"
|
|
1049
|
+
)));
|
|
1050
|
+
}
|
|
1051
|
+
let dir = event_direction(direction)?;
|
|
1052
|
+
let name = resolve_solver(method)?;
|
|
1053
|
+
require_jacobian_if_needed(&rhs, name)?;
|
|
1054
|
+
|
|
1055
|
+
let rhs_ev = build_evaluator(rhs, jit)?;
|
|
1056
|
+
let g_ev = build_evaluator(g, jit)?;
|
|
1057
|
+
let mut solver = build_solver(name, rtol, atol);
|
|
1058
|
+
let cfg = IntegrateConfig::new(first_step);
|
|
1059
|
+
|
|
1060
|
+
let spec = if terminal {
|
|
1061
|
+
EventSpec::terminal(&*g_ev, dir)
|
|
1062
|
+
} else {
|
|
1063
|
+
EventSpec::new(&*g_ev, dir)
|
|
1064
|
+
};
|
|
1065
|
+
let outcome = integrate_events(&*rhs_ev, &mut *solver, &ic[..dim], p, t0, t1, &[spec], &cfg)
|
|
1066
|
+
.map_err(|e| EngineError::Diverged(diverge_msg(&e)))?;
|
|
1067
|
+
|
|
1068
|
+
let mut times = Vec::with_capacity(outcome.hits.len());
|
|
1069
|
+
let mut states = Vec::with_capacity(outcome.hits.len() * dim);
|
|
1070
|
+
for hit in &outcome.hits {
|
|
1071
|
+
times.push(hit.t);
|
|
1072
|
+
states.extend_from_slice(&hit.u);
|
|
1073
|
+
}
|
|
1074
|
+
Ok((
|
|
1075
|
+
times,
|
|
1076
|
+
states,
|
|
1077
|
+
outcome.t_final,
|
|
1078
|
+
outcome.u_final,
|
|
1079
|
+
outcome.terminated,
|
|
1080
|
+
))
|
|
1081
|
+
}
|
|
1082
|
+
|
|
953
1083
|
/// Prefix the engine's diverge message so the Python `RuntimeError` reads clearly.
|
|
954
1084
|
fn diverge_msg(e: &IntegrateError) -> String {
|
|
955
1085
|
format!("integration diverged before reaching the final time: {e}")
|
|
@@ -591,6 +591,103 @@ fn integrate_sde_ensemble_final<'py>(
|
|
|
591
591
|
PyArray1::from_vec(py, flat).reshape([n_ic, dim])
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
+
// ---------------------------------------------------------------------------
|
|
595
|
+
// Event detection (two tapes: right-hand side + event function g)
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
|
|
598
|
+
/// Integrate `[t0, t1]` and return the crossings of the event function
|
|
599
|
+
/// `g(u, t) = 0` in `direction` (`+1` rising / `-1` falling / `0` either),
|
|
600
|
+
/// refined with the engine's O(h⁴) cubic-Hermite dense output.
|
|
601
|
+
///
|
|
602
|
+
/// The two tapes are passed back to back — first the right-hand side `f`, then the
|
|
603
|
+
/// single-output event function `g` (`g`'s `outputs.len() == 1`; it reads the full
|
|
604
|
+
/// state and may declare fewer parameters than the system, reading the leading
|
|
605
|
+
/// slice). `first_step` seeds the solver; with the fixed-step `rk4` it *is* the
|
|
606
|
+
/// detection step, so `method="rk4"`, `first_step=dt` reproduces the Python
|
|
607
|
+
/// `PoincareMap` dt-grid march and its refinement (answer-identical). `terminal`
|
|
608
|
+
/// stops the run at the first crossing. Divergence raises `RuntimeError`.
|
|
609
|
+
///
|
|
610
|
+
/// Returns `(times, states, t_final, u_final, terminated)`: the `(K,)` crossing
|
|
611
|
+
/// times, the `(K, dim)` crossing states, the time and state the run stopped at
|
|
612
|
+
/// (to resume the next span exactly), and whether a terminal event stopped it.
|
|
613
|
+
#[pyfunction]
|
|
614
|
+
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
|
615
|
+
fn integrate_events_dense<'py>(
|
|
616
|
+
py: Python<'py>,
|
|
617
|
+
ops: PyReadonlyArray1<i32>,
|
|
618
|
+
a: PyReadonlyArray1<i32>,
|
|
619
|
+
b: PyReadonlyArray1<i32>,
|
|
620
|
+
imm: PyReadonlyArray1<f64>,
|
|
621
|
+
outputs: PyReadonlyArray1<i32>,
|
|
622
|
+
jac_outputs: PyReadonlyArray1<i32>,
|
|
623
|
+
n_state: usize,
|
|
624
|
+
n_param: usize,
|
|
625
|
+
ops_g: PyReadonlyArray1<i32>,
|
|
626
|
+
a_g: PyReadonlyArray1<i32>,
|
|
627
|
+
b_g: PyReadonlyArray1<i32>,
|
|
628
|
+
imm_g: PyReadonlyArray1<f64>,
|
|
629
|
+
outputs_g: PyReadonlyArray1<i32>,
|
|
630
|
+
jac_outputs_g: PyReadonlyArray1<i32>,
|
|
631
|
+
n_state_g: usize,
|
|
632
|
+
n_param_g: usize,
|
|
633
|
+
ic: PyReadonlyArray1<f64>,
|
|
634
|
+
p: PyReadonlyArray1<f64>,
|
|
635
|
+
t0: f64,
|
|
636
|
+
t1: f64,
|
|
637
|
+
first_step: f64,
|
|
638
|
+
direction: i32,
|
|
639
|
+
terminal: bool,
|
|
640
|
+
method: String,
|
|
641
|
+
rtol: f64,
|
|
642
|
+
atol: f64,
|
|
643
|
+
jit: bool,
|
|
644
|
+
) -> PyResult<(
|
|
645
|
+
Bound<'py, PyArray1<f64>>,
|
|
646
|
+
Bound<'py, PyArray2<f64>>,
|
|
647
|
+
f64,
|
|
648
|
+
Bound<'py, PyArray1<f64>>,
|
|
649
|
+
bool,
|
|
650
|
+
)> {
|
|
651
|
+
let rhs = OwnedTape::copy_in(&ops, &a, &b, &imm, &outputs, &jac_outputs, n_state, n_param)?;
|
|
652
|
+
let g = OwnedTape::copy_in(
|
|
653
|
+
&ops_g,
|
|
654
|
+
&a_g,
|
|
655
|
+
&b_g,
|
|
656
|
+
&imm_g,
|
|
657
|
+
&outputs_g,
|
|
658
|
+
&jac_outputs_g,
|
|
659
|
+
n_state_g,
|
|
660
|
+
n_param_g,
|
|
661
|
+
)?;
|
|
662
|
+
let dim = rhs.dim();
|
|
663
|
+
let ic = vec_f64("ic", &ic)?;
|
|
664
|
+
let p = vec_f64("p", &p)?;
|
|
665
|
+
let (times, states, t_final, u_final, terminated) = py
|
|
666
|
+
.detach(|| {
|
|
667
|
+
bridge::integrate_events_dense(
|
|
668
|
+
rhs.build()?,
|
|
669
|
+
g.build()?,
|
|
670
|
+
&ic,
|
|
671
|
+
&p,
|
|
672
|
+
t0,
|
|
673
|
+
t1,
|
|
674
|
+
first_step,
|
|
675
|
+
direction,
|
|
676
|
+
terminal,
|
|
677
|
+
&method,
|
|
678
|
+
rtol,
|
|
679
|
+
atol,
|
|
680
|
+
jit,
|
|
681
|
+
)
|
|
682
|
+
})
|
|
683
|
+
.map_err(to_py_err)?;
|
|
684
|
+
let n_hits = times.len();
|
|
685
|
+
let times = PyArray1::from_vec(py, times);
|
|
686
|
+
let states = PyArray1::from_vec(py, states).reshape([n_hits, dim])?;
|
|
687
|
+
let u_final = PyArray1::from_vec(py, u_final);
|
|
688
|
+
Ok((times, states, t_final, u_final, terminated))
|
|
689
|
+
}
|
|
690
|
+
|
|
594
691
|
// ---------------------------------------------------------------------------
|
|
595
692
|
// Introspection
|
|
596
693
|
// ---------------------------------------------------------------------------
|
|
@@ -644,6 +741,7 @@ fn _rust(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
644
741
|
m.add_function(wrap_pyfunction!(integrate_ensemble_final, m)?)?;
|
|
645
742
|
m.add_function(wrap_pyfunction!(integrate_sde_dense, m)?)?;
|
|
646
743
|
m.add_function(wrap_pyfunction!(integrate_sde_ensemble_final, m)?)?;
|
|
744
|
+
m.add_function(wrap_pyfunction!(integrate_events_dense, m)?)?;
|
|
647
745
|
m.add_function(wrap_pyfunction!(solvers, m)?)?;
|
|
648
746
|
m.add_function(wrap_pyfunction!(_version, m)?)?;
|
|
649
747
|
Ok(())
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tsdynamics"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.2"
|
|
8
8
|
description = "Zero-warmup Rust-engine ODE/DDE/SDE integration, discrete maps, and chaos analysis for dynamical systems."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12,<4.0"
|
|
@@ -124,7 +124,7 @@ from .families import (
|
|
|
124
124
|
)
|
|
125
125
|
|
|
126
126
|
# Single source of truth for the package version; rewritten by python-semantic-release.
|
|
127
|
-
__version__ = "3.0.
|
|
127
|
+
__version__ = "3.0.2"
|
|
128
128
|
|
|
129
129
|
# Built-in system classes are NOT bound into this namespace — that would bury the
|
|
130
130
|
# submodules (``analysis``, ``data``, ``systems``, …) under ~149 model names in
|
|
@@ -177,6 +177,7 @@ __all__ = [
|
|
|
177
177
|
"correlation_dimension",
|
|
178
178
|
"correlation_sum",
|
|
179
179
|
"dimension_spectrum",
|
|
180
|
+
"discover_plugins",
|
|
180
181
|
"dispersion_entropy",
|
|
181
182
|
"embed",
|
|
182
183
|
"embedding_dimension",
|
|
@@ -250,3 +251,13 @@ def discover_plugins(*, strict: bool = False) -> list[str]:
|
|
|
250
251
|
# analyses register themselves from their own subpackages (the analysis streams);
|
|
251
252
|
# plugin failures are isolated inside `register_entry_points`.
|
|
252
253
|
discover_plugins()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def __dir__() -> list[str]:
|
|
257
|
+
"""Expose only the curated public API (``__all__``) to ``dir()`` / autocomplete.
|
|
258
|
+
|
|
259
|
+
The capability subpackages (``basins``, ``chaos``, …) and plugin-wiring
|
|
260
|
+
helpers are re-exported flat or used internally; they stay importable but are
|
|
261
|
+
kept off the tab-completion surface so only the public quantifiers show.
|
|
262
|
+
"""
|
|
263
|
+
return sorted(__all__)
|